Day 2 part I
This commit is contained in:
		
							
								
								
									
										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); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user