Initial commit

This commit is contained in:
2024-11-14 19:16:08 -05:00
commit 4f0091f23f
18 changed files with 2277 additions and 0 deletions

393
d1/main.odin Normal file
View File

@@ -0,0 +1,393 @@
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()
}