393 lines
12 KiB
Odin
393 lines
12 KiB
Odin
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()
|
|
} |