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 $@ | 	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 | ||||||
|   | |||||||
| @@ -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
									
								
							
							
						
						
									
										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