Day 2 part I
This commit is contained in:
parent
b6c66136f7
commit
941ee5f329
4
Makefile
4
Makefile
@ -14,5 +14,9 @@ bin/%: src/%.c $(STDLIB_SOURCES) $(STDLIB_HEADERS)
|
||||
gcc $(CFLAGS) $< $(STDLIB_SOURCES) -o $@
|
||||
strip -R .comment $@
|
||||
|
||||
out/%.txt: in/%.txt bin/%
|
||||
@mkdir -p $(@D)
|
||||
<$< bin/$* >$@
|
||||
|
||||
clean:
|
||||
rm -rf bin
|
||||
|
@ -14,3 +14,7 @@ Run `make` to build everything.
|
||||
## Running
|
||||
|
||||
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
121
src/02.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user