Day 2 part I

This commit is contained in:
Szymon Nowakowski 2024-12-05 22:01:27 +01:00
parent b6c66136f7
commit 941ee5f329
3 changed files with 129 additions and 0 deletions

View File

@ -14,5 +14,9 @@ bin/%: src/%.c $(STDLIB_SOURCES) $(STDLIB_HEADERS)
gcc $(CFLAGS) $< $(STDLIB_SOURCES) -o $@ gcc $(CFLAGS) $< $(STDLIB_SOURCES) -o $@
strip -R .comment $@ strip -R .comment $@
out/%.txt: in/%.txt bin/%
@mkdir -p $(@D)
<$< bin/$* >$@
clean: clean:
rm -rf bin rm -rf bin

View File

@ -14,3 +14,7 @@ Run `make` to build everything.
## Running ## Running
Every program accepts the input through `stdin` and outputs through `stdout`. Every program accepts the input through `stdin` and outputs through `stdout`.
If you place puzzle inputs in files at `in/01.txt`, `in/02.txt`, etc., then you
can use make to compile and compute the answer by running `make out/01.txt`,
`make out/02.txt`, etc.

121
src/02.c Normal file
View File

@ -0,0 +1,121 @@
#include <common.h>
#include <buffer.h>
#include <syscall.h>
#define BUFFER_SIZE 4096UL
typedef enum parser_state {
parser_state_digits_start,
parser_state_digits_rest,
parser_state_whitespace,
} parser_state;
typedef struct parser {
i8 prev;
i8 current;
i8 diff;
bool unsafe;
parser_state state;
} parser;
void parser_process(parser* parser, const c8* ptr, usize len);
bool is_digit(c8 c);
void println_u64(u64 value);
u64 safe_count = 0;
i32 main(i32 argc, char *argv[])
{
c8* buffer = buffer_init(BUFFER_SIZE);
usize buffer_ptr = 0;
isize bytes_read = 0;
parser parser = {0};
while ((bytes_read = read(stdin, &buffer[buffer_ptr], BUFFER_SIZE)) > 0) {
parser_process(&parser, &buffer[buffer_ptr], bytes_read);
buffer_ptr = (buffer_ptr + bytes_read) % BUFFER_SIZE;
}
println_u64(safe_count);
return 0;
}
void parser_process(parser* parser, const c8* ptr, usize len)
{
const c8* end = &ptr[len];
while (ptr < end) {
c8 c = *ptr;
switch (parser->state) {
case parser_state_digits_start:
if (is_digit(c)) {
parser->prev = parser->prev * 10 + (c - '0');
ptr += 1;
} else {
parser->state = parser_state_whitespace;
}
break;
case parser_state_digits_rest:
if (is_digit(c)) {
parser->current = parser->current * 10 + (c - '0');
ptr += 1;
} else {
i8 diff = parser->current - parser->prev;
if (diff * parser->diff < 0 || diff < -3 || diff == 0 || diff > 3) {
parser->unsafe = true;
}
parser->prev = parser->current;
parser->current = 0;
parser->diff = diff;
parser->state = parser_state_whitespace;
}
break;
case parser_state_whitespace:
if (c == '\n') {
if (!parser->unsafe) {
safe_count += 1;
}
parser->prev = 0;
parser->current = 0;
parser->diff = 0;
parser->unsafe = false;
parser->state = parser_state_digits_start;
ptr += 1;
} else if (is_digit(c)) {
parser->state = parser_state_digits_rest;
} else {
ptr += 1;
}
break;
}
}
}
bool is_digit(c8 c)
{
return c >= '0' && c <= '9';
}
void println_u64(u64 value)
{
/* The longest string we produce would be "18446744073709551615\n", which is
* 21 bytes long (we don't care about the null terminator).
*/
c8 buffer[21];
usize strlen = 1;
buffer[20] = '\n';
do
{
c8 digit = (value % 10) + '0';
buffer[20 - strlen] = digit;
strlen += 1;
value /= 10;
} while (value > 0);
write(stdout, &buffer[21 - strlen], strlen);
}