Initial commit
This commit is contained in:
7
d1/d1-p2-test.input
Normal file
7
d1/d1-p2-test.input
Normal file
@@ -0,0 +1,7 @@
|
||||
two1nine
|
||||
eightwothree
|
||||
abcone2threexyz
|
||||
xtwone3four
|
||||
4nineeightseven2
|
||||
zoneight234
|
||||
7pqrstsixteen
|
||||
1000
d1/d1.input
Normal file
1000
d1/d1.input
Normal file
File diff suppressed because it is too large
Load Diff
393
d1/main.odin
Normal file
393
d1/main.odin
Normal 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()
|
||||
}
|
||||
Reference in New Issue
Block a user