package d1; import "core:os" import "core:fmt" import "core:testing" main_attempt_1 :: proc () { if len(os.args) < 2 { fmt.printf("Usage: ./d1 FILENAME\n") os.exit(-1) } fh: os.Handle eno: os.Errno fmt.printf("Reached line 13!\n") if fh, eno = os.open(os.args[1]); eno != os.ERROR_NONE { fmt.printf("Cannot open %s: %s", os.args[1], os.get_last_error_string()) os.exit(-1) } defer os.close(fh) buffer: []u8 = make([]u8, 1024) defer delete(buffer) idx := -1 n_read := 0 digits: []u8 = make([]u8, 2) defer delete(digits) digits[0] = 'A' digits[1] = 'A' total := 0 line_ctr := 0 outer_loop: for { n_read, eno = os.read(fh, buffer) if eno != os.ERROR_NONE { break outer_loop; } if n_read <= 0 { if digits[0] != 'A' { fmt.printf("DEBUG: Line %d: First digit: %c\n", line_ctr, digits[0]) total += 10 * int(digits[0] - '0') if digits[1] == 'A' { fmt.printf("DEBUG: Line %d: Repeating first digit\n", line_ctr) total += int(digits[0] - '0') } else { fmt.printf("DEBUG: Line %d: Second digit: %c\n", line_ctr, digits[1]) total += int(digits[1] - '0') } } break outer_loop; } for idx = 0; idx < n_read; idx += 1 { switch buffer[idx] { case '\n': assert(digits[0] != 'A') fmt.printf("DEBUG: Line %d: First digit: %c\n", line_ctr, digits[0]) total += 10 * int(digits[0] - '0') if digits[1] == 'A' { fmt.printf("DEBUG: Line %d: Repeating first digit\n", line_ctr) total += int(digits[0] - '0') } else { fmt.printf("DEBUG: Line %d: Second digit: %c\n", line_ctr, digits[0]) total += int(digits[1] - '0') } digits[0] = 'A' digits[1] = 'A' line_ctr += 1 case '0'..='9': if digits[0] == 'A' { digits[0] = buffer[idx] } else { digits[1] = buffer[idx] } } } } fmt.printf("total: %d\n", total) } line_no := 0 fmt_debug :: proc(msg: string, args: ..any) { fmt.printf("DEBUG: L%d: ", line_no) fmt.printf(msg, ..args) } digit_int :: proc(digit: u8) -> int { return int(digit - '0') } add_digits :: proc(digits: []u8) -> (x: int) { x = 0 assert(len(digits) == 2) assert(digits[0] != 'A') fmt_debug("First digit: %c\n", digits[0]) x += 10 * digit_int(digits[0]) if digits[1] == 'A' { fmt_debug("No second digit, reusing first digit: %c\n", digits[0]) x += digit_int(digits[0]) } else { fmt_debug("Second digit: %c\n", digits[1]) x += digit_int(digits[1]) } fmt_debug("Total value: %d\n", x) return } main_attempt_2 :: proc () { if len(os.args) < 2 { fmt.printf("Usage: ./d1 FILENAME\n") os.exit(-1) } fh: os.Handle eno: os.Errno fmt.printf("Reached line 13!\n") if fh, eno = os.open(os.args[1]); eno != os.ERROR_NONE { fmt.printf("Cannot open %s: %s", os.args[1], os.get_last_error_string()) os.exit(-1) } defer os.close(fh) buffer: []u8 = make([]u8, 1024) defer delete(buffer) idx := -1 n_read := 0 digits: []u8 = make([]u8, 2) defer delete(digits) digits[0] = 'A' digits[1] = 'A' total := 0 outer_loop: for { n_read, eno = os.read(fh, buffer) if eno != os.ERROR_NONE { break outer_loop; } if n_read <= 0 { if digits[0] != 'A' { total += add_digits(digits) fmt_debug("Total: %d\n", total) } break outer_loop; } for idx = 0; idx < n_read; idx += 1 { switch buffer[idx] { case '\n': total += add_digits(digits) fmt_debug("Total: %d\n", total) digits[0] = 'A' digits[1] = 'A' line_no += 1 case '0'..='9': if digits[0] == 'A' { digits[0] = buffer[idx] } else { digits[1] = buffer[idx] } } } } fmt.printf("Total: %d\n", total) } WORD_LITERALS := []string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}; string_at :: proc(buffer: []u8, prefix: string, start: int = 0) -> bool { for idx := 0; idx < len(prefix); idx += 1 { buffer_idx := start + idx; if buffer_idx >= len(buffer) { return false; } if prefix[idx] != buffer[buffer_idx] { return false; } } return true; } starts_with :: proc(buffer: []u8, prefix: string) -> bool { return string_at(buffer, prefix, 0); } looking_at_numword :: proc(buffer: []u8, start: int = 0) -> (bool, int, int) { assert(start < len(buffer)) for idx := 0; idx < len(WORD_LITERALS); idx += 1 { if string_at(buffer, WORD_LITERALS[idx], start) { return true, idx, start + len(WORD_LITERALS[idx]); } } return false, 0, 0; }; looking_at_num :: proc(buffer: []u8, start: int = 0) -> (bool, int, int) { assert(0 <= start); switch buffer[start] { case '0'..='9': return true, digit_int(buffer[start]), start + 1; case 'z','o','t','f','s','e','n': return looking_at_numword(buffer, start) } return false, 0, 0; } @(test) test_looking_at_num :: proc(t: ^testing.T) { input: []u8; num: int; ok: bool; next_num: int; input = transmute([]u8) string("fivethreeonezblqnsfk1"); next_num = 5; ok, num, _ = looking_at_num(input, 0); testing.expect(t, ok, "Failure: not looking at a number or digit"); testing.expect(t, num == next_num, fmt.tprint("%d != %d\n", next_num, num)); next_num = 3; ok, num, _ = looking_at_num(input, 4); testing.expect(t, ok, "Failure: not looking at a number or digit"); testing.expect(t, num == next_num, fmt.tprintf("%d != %d\n", next_num, num)); input = transmute([]u8) string("two74119onebtqgnine"); next_num = 2; ok, num, _ = looking_at_num(input, 0); testing.expect(t, ok, "Failure: not looking at a number or digit"); testing.expect(t, num == next_num, fmt.tprintf("%d != %d\n", next_num, num)); next_num = 1; ok, num, _ = looking_at_num(input, 6); testing.expect(t, ok, "Failure: not looking at a number or digit"); testing.expect(t, num == next_num, fmt.tprintf("%d != %d\n", next_num, num)); // input = transmute([]u8) string("jrjh5vsrxbhsfour3"); // input = transmute([]u8) string("tn5eightfncnzcdtthree8"); // input = transmute([]u8) string("kpmrk5flx"); // input = transmute([]u8) string("fkxxqxdfsixgthreepvzjxrkcfk6twofour"); // input = transmute([]u8) string("dqbx6six5twoone"); // input = transmute([]u8) string("glmsckj2bvmts1spctnjrtqhmbxzq"); // input = transmute([]u8) string("7sixthreerzmpbffcx"); // input = transmute([]u8) string("zhss9gfxfgmrmzthreefivevpkljfourtwoeight"); } slice_next_line :: proc(buffer: []u8, start: uint) -> (int, []u8) { assert(start < len(buffer)) for idx := 0; idx < len(buffer); idx += 1 { if buffer[idx] == '\n' { return idx, buffer[start:idx] } } return -1, buffer[start:] } BUFFER_SIZE :: 1024 process_line :: proc(buffer: []u8, start: int) -> (int, int) { assert(0 <= start && start < len(buffer)) a, b := -1, -1 index := start for index < len(buffer) { ok, x, _ := looking_at_num(buffer, index) if !ok { index += 1; } else if a == -1 { // Save first digit a = 10 * int(x); index += len(WORD_LITERALS[x]) } else { // Save second digit b += int(x) index += len(WORD_LITERALS[x]) } } assert(a > -1); if b == -1 { return index, 10 * a + a; } return index, 10 * a + b; } os_blksize :: proc() -> i32 { info := os.OS_Stat{}; _ = os._unix_stat("/", &info); return info.block_size; } scan_to_next :: proc(fh: os.Handle, chr: u8, pos: uint = 0) -> (success: bool, char_pos: uint) { buf := make([]u8, os_blksize()); file_pos := pos; char_pos = 0 success = false for { nr, errno := os.read_at(fh, buf, i64(file_pos)); if errno == os.EINVAL { break; } else if errno != os.ERROR_NONE { fmt.printf("Fatal error: %s\n", os.get_last_error_string()); os.exit(int(errno)); } for idx : uint = 0; idx < len(buf); idx += 1 { if buf[idx] == '\n' { success = true; char_pos = file_pos + idx; break; } } if success || nr < len(buf) { break; } file_pos += len(buf); } os.seek(fh, i64(pos), os.SEEK_SET) return; } die :: proc (eno: os.Errno) { fmt.printf("Fatal error: %s\n", os.get_last_error_string()); os.exit(int(eno)); } main_attempt_3 :: proc() { if len(os.args) < 2 { fmt.printf("Usage: ./d1 FILENAME\n") os.exit(-1) } fh: os.Handle eno: os.Errno if fh, eno = os.open(os.args[1]); eno != os.ERROR_NONE { die(eno); } defer os.close(fh); buffer: []u8 = make([]u8, BUFFER_SIZE); defer delete(buffer); nr: int; num: int; ok: bool; total := 0 digits: []int = {-1, -1}; for { nr, eno = os.read(fh, buffer); if eno != os.ERROR_NONE { die(eno); } assert(0 < nr && nr <= BUFFER_SIZE); for idx := 0; idx < nr; idx += 1 { if buffer[idx] == '\n' { if digits[0] > -1 { total += 10 * digits[0]; if digits[1] < 0 { fmt_debug("Number for line: %d%d\n", digits[0], digits[0]); total += digits[0]; } else { fmt_debug("Number for line: %d%d\n", digits[0], digits[1]); total += digits[1]; } digits[0] = -1; digits[1] = -1; } else { fmt_debug("Hit newline without setting digits\n"); } line_no += 1 continue; } new_idx: int; ok, num, new_idx = looking_at_num(buffer, idx); if ok && digits[0] == -1 { fmt_debug("Found first number: %d\n", num); digits[0] = num; idx = new_idx - 1; } else if ok { fmt_debug("Found additional number: %d\n", num); digits[1] = num; idx = new_idx - 1; } } if nr != BUFFER_SIZE { break; } } // off by one, as usual if digits[0] != -1 { total += 10 * digits[0]; if digits[1] < 0 { fmt_debug("Number for line: %d%d\n", digits[0], digits[0]); total += digits[0]; } else { fmt_debug("Number for line: %d%d\n", digits[0], digits[1]); total += digits[1]; } } fmt.printf("Total: %d\n", total); } main :: proc() { main_attempt_3() }