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()
|
||||||
|
}
|
||||||
100
d2/d2.input
Normal file
100
d2/d2.input
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
Game 1: 1 red, 3 blue, 11 green; 1 blue, 5 red; 3 blue, 5 green, 13 red; 6 red, 1 blue, 4 green; 16 red, 12 green
|
||||||
|
Game 2: 3 red, 13 blue, 5 green; 14 green, 14 blue; 9 blue, 10 green, 3 red; 2 green, 5 blue; 11 green, 3 blue, 3 red; 16 blue, 2 red, 9 green
|
||||||
|
Game 3: 17 blue, 5 red; 3 red, 11 green, 17 blue; 1 red, 6 blue, 9 green; 3 blue, 11 green, 1 red; 3 green, 10 red, 11 blue; 12 red, 3 green, 15 blue
|
||||||
|
Game 4: 14 green, 14 red, 1 blue; 15 red, 13 green, 1 blue; 6 green, 15 red; 7 green
|
||||||
|
Game 5: 3 green, 1 blue, 3 red; 6 red, 2 green, 2 blue; 12 red, 3 green, 1 blue; 2 green, 9 red; 1 blue; 2 blue, 10 red
|
||||||
|
Game 6: 5 blue, 5 green; 4 blue, 1 red, 10 green; 16 green, 1 red, 6 blue; 1 red, 1 blue, 13 green; 1 red, 5 blue, 7 green; 14 green, 17 blue
|
||||||
|
Game 7: 1 green, 8 blue, 4 red; 1 green, 4 blue, 4 red; 6 blue, 4 red, 4 green; 1 red, 8 green
|
||||||
|
Game 8: 2 red, 5 blue, 1 green; 1 blue, 4 red, 8 green; 6 blue, 12 green, 6 red; 3 blue, 5 red; 8 red, 2 blue, 13 green; 5 green, 4 red, 3 blue
|
||||||
|
Game 9: 11 red; 1 green, 2 red, 2 blue; 1 blue, 2 green, 9 red; 4 red, 2 green, 2 blue; 1 blue, 2 green; 1 blue, 9 red, 2 green
|
||||||
|
Game 10: 9 red, 4 green; 1 blue, 3 red, 7 green; 3 green, 1 red, 1 blue; 7 green, 4 red, 1 blue; 1 blue, 5 green, 10 red; 1 red, 5 green
|
||||||
|
Game 11: 2 blue, 4 red, 3 green; 1 blue, 7 red; 4 green, 7 red, 1 blue; 3 blue, 6 green, 4 red; 3 red, 1 green, 3 blue
|
||||||
|
Game 12: 1 green, 6 red, 5 blue; 3 green, 2 red, 4 blue; 3 green, 1 red, 3 blue
|
||||||
|
Game 13: 6 green, 1 red, 9 blue; 11 red, 4 blue, 12 green; 6 green, 9 red, 19 blue; 2 green, 6 blue; 10 green, 1 red, 16 blue; 4 green, 14 blue
|
||||||
|
Game 14: 7 blue, 2 red; 1 green, 2 red, 19 blue; 12 blue, 6 green, 11 red
|
||||||
|
Game 15: 4 red, 4 green, 7 blue; 15 blue, 1 green, 8 red; 2 red, 10 green, 11 blue; 5 red, 4 blue, 6 green; 9 red, 8 blue, 3 green; 9 blue, 9 red
|
||||||
|
Game 16: 7 red, 2 blue, 19 green; 6 blue, 9 green; 8 green, 6 red, 19 blue; 11 green, 7 red, 1 blue; 9 blue, 3 red, 17 green
|
||||||
|
Game 17: 3 blue, 4 green, 5 red; 2 red, 4 green, 11 blue; 6 blue, 13 green; 3 blue, 12 green, 7 red
|
||||||
|
Game 18: 9 red, 6 blue, 7 green; 3 green, 3 blue, 5 red; 18 red, 6 blue, 4 green; 3 green, 10 red, 8 blue
|
||||||
|
Game 19: 3 red, 6 green; 1 red, 5 green, 4 blue; 3 red, 14 blue
|
||||||
|
Game 20: 2 green, 2 blue, 4 red; 14 red, 6 blue, 5 green; 1 blue, 5 red, 3 green; 10 red, 6 green, 6 blue
|
||||||
|
Game 21: 10 blue, 12 green, 3 red; 1 green, 14 red; 5 blue, 7 green; 12 blue, 1 red, 13 green; 7 red, 4 green
|
||||||
|
Game 22: 2 red, 1 blue; 1 red, 2 blue; 1 red, 1 green, 3 blue; 3 blue; 1 red; 1 green, 2 red
|
||||||
|
Game 23: 4 blue, 4 green, 1 red; 3 blue, 1 red, 6 green; 1 red, 1 blue
|
||||||
|
Game 24: 5 blue, 15 green, 13 red; 20 green, 13 blue, 6 red; 5 blue, 11 red, 16 green; 6 red, 5 blue, 13 green; 12 blue, 13 green, 3 red
|
||||||
|
Game 25: 10 blue, 17 red; 12 red, 16 blue, 3 green; 4 green, 12 blue, 10 red; 8 blue, 3 green, 10 red; 5 green, 2 red, 12 blue
|
||||||
|
Game 26: 11 red, 9 blue; 3 blue, 3 red, 3 green; 10 blue, 3 green, 4 red; 1 green, 4 blue, 9 red; 5 green, 1 red, 7 blue; 1 red, 3 blue, 3 green
|
||||||
|
Game 27: 1 green, 12 red, 4 blue; 5 red, 2 green, 1 blue; 3 green, 6 blue, 10 red; 1 green, 4 red, 3 blue
|
||||||
|
Game 28: 6 blue; 2 green; 2 green, 8 blue, 1 red; 2 green, 2 blue; 6 blue, 8 green; 9 green, 5 blue
|
||||||
|
Game 29: 1 green, 9 blue, 9 red; 13 green, 4 red, 9 blue; 3 green, 8 blue, 15 red; 15 green, 18 blue, 3 red; 16 green, 10 red; 16 green, 12 blue, 16 red
|
||||||
|
Game 30: 14 blue, 4 green, 1 red; 7 red, 14 blue; 2 blue, 4 red, 1 green
|
||||||
|
Game 31: 2 red, 14 green, 3 blue; 3 blue, 3 green, 4 red; 8 blue, 4 red, 1 green; 8 green, 3 blue; 10 blue, 1 red, 11 green; 13 green, 2 red, 3 blue
|
||||||
|
Game 32: 8 blue, 16 red; 2 green, 8 blue, 16 red; 16 blue, 4 green, 17 red; 2 red, 5 green, 4 blue
|
||||||
|
Game 33: 2 red, 2 green, 1 blue; 5 red, 1 blue; 8 green, 14 red
|
||||||
|
Game 34: 4 red, 4 green; 9 green; 1 blue, 16 green; 1 blue, 5 red, 9 green; 2 red, 15 green, 1 blue
|
||||||
|
Game 35: 1 green, 5 red; 1 green, 15 red, 13 blue; 2 red, 13 blue, 17 green; 9 blue, 3 red, 11 green; 7 green, 8 blue, 14 red
|
||||||
|
Game 36: 19 green; 3 green, 1 blue, 1 red; 1 green, 8 blue; 13 green, 5 red, 5 blue
|
||||||
|
Game 37: 12 red, 7 green, 3 blue; 12 blue, 10 red, 9 green; 17 green, 8 red, 13 blue; 9 blue, 9 green, 8 red; 4 red, 13 green, 13 blue; 15 green, 12 red, 14 blue
|
||||||
|
Game 38: 5 blue, 1 green, 20 red; 1 green, 13 red, 18 blue; 17 blue, 9 red, 10 green; 4 blue, 4 red, 12 green; 12 blue, 12 red, 6 green; 12 green, 13 red, 2 blue
|
||||||
|
Game 39: 7 blue, 6 red, 2 green; 6 blue, 1 red; 7 blue, 1 red
|
||||||
|
Game 40: 1 blue, 3 red; 15 blue, 1 green; 1 green, 16 red, 2 blue
|
||||||
|
Game 41: 2 blue, 4 green; 8 green, 3 red; 2 blue, 9 red, 4 green; 4 red, 3 blue, 10 green; 5 green, 3 blue, 2 red
|
||||||
|
Game 42: 7 green, 2 blue, 1 red; 8 green, 4 red; 5 blue, 1 red, 3 green
|
||||||
|
Game 43: 3 red, 1 blue; 1 blue, 2 green, 2 red; 1 red, 2 blue; 3 blue
|
||||||
|
Game 44: 3 green, 14 blue, 1 red; 16 blue, 5 red, 11 green; 12 green, 1 blue; 13 blue, 1 red; 5 blue, 2 red, 6 green; 3 blue, 5 red, 11 green
|
||||||
|
Game 45: 7 blue, 1 red; 1 red, 3 blue; 3 green, 14 blue, 1 red; 4 blue, 3 green, 1 red; 15 blue, 1 red, 3 green
|
||||||
|
Game 46: 15 red, 4 blue; 15 red, 11 blue, 3 green; 14 red, 2 green, 2 blue; 14 red, 8 blue, 3 green; 4 red, 1 blue
|
||||||
|
Game 47: 4 green, 2 blue, 3 red; 8 red, 2 green, 18 blue; 1 green, 17 blue, 1 red
|
||||||
|
Game 48: 2 green, 4 red, 2 blue; 15 blue, 16 red, 5 green; 14 blue, 2 green, 10 red; 3 green, 13 red, 6 blue; 8 green, 4 red, 12 blue; 15 red, 3 green, 9 blue
|
||||||
|
Game 49: 1 green, 6 red, 7 blue; 1 blue, 9 green, 9 red; 4 green, 8 red; 9 blue, 1 red, 14 green; 2 blue, 9 red
|
||||||
|
Game 50: 3 red, 10 blue, 14 green; 2 red, 9 blue, 7 green; 4 blue, 12 green; 1 red, 4 green, 5 blue
|
||||||
|
Game 51: 2 green, 6 blue; 1 green, 10 blue, 1 red; 3 blue, 2 green
|
||||||
|
Game 52: 1 green, 4 red, 1 blue; 3 red, 5 green, 4 blue; 1 blue, 3 red, 5 green; 1 red, 1 green, 1 blue; 12 green, 2 red, 4 blue; 10 blue, 7 green, 1 red
|
||||||
|
Game 53: 12 red, 1 blue; 8 red, 11 blue, 11 green; 8 red, 6 blue, 13 green; 11 blue, 11 red, 16 green; 6 red, 9 green, 4 blue
|
||||||
|
Game 54: 2 red, 8 blue, 15 green; 4 green, 3 blue, 6 red; 12 green, 13 blue, 4 red
|
||||||
|
Game 55: 1 green, 16 blue, 4 red; 3 red, 1 blue, 1 green; 12 red, 16 blue; 3 red
|
||||||
|
Game 56: 4 green; 1 red, 4 green; 2 red, 3 blue, 7 green; 2 red, 3 blue, 15 green
|
||||||
|
Game 57: 17 green; 1 green, 9 blue; 1 red, 1 green, 9 blue
|
||||||
|
Game 58: 3 green, 8 red, 7 blue; 4 green, 9 blue, 2 red; 1 red, 2 green, 11 blue; 8 blue, 4 green
|
||||||
|
Game 59: 6 green, 1 red; 4 blue, 6 green; 4 green, 5 blue
|
||||||
|
Game 60: 3 green, 5 blue, 1 red; 7 green, 5 blue, 16 red; 14 red, 1 green, 1 blue; 7 green, 2 blue; 13 red, 5 green, 5 blue
|
||||||
|
Game 61: 1 green, 2 blue, 2 red; 2 green; 6 red, 1 blue, 1 green
|
||||||
|
Game 62: 5 red, 8 blue, 1 green; 1 red, 1 blue; 2 green, 8 blue
|
||||||
|
Game 63: 2 red, 2 blue, 2 green; 9 blue, 7 green; 1 green, 4 blue; 18 green, 3 blue
|
||||||
|
Game 64: 13 green, 1 blue, 6 red; 13 green, 15 red, 8 blue; 5 green, 14 red, 4 blue; 2 green, 8 blue, 12 red; 1 blue, 5 red, 13 green; 7 blue, 8 green, 2 red
|
||||||
|
Game 65: 7 blue, 12 red, 6 green; 11 red, 8 green, 8 blue; 9 red, 7 green, 7 blue; 14 red, 2 blue, 17 green
|
||||||
|
Game 66: 2 green, 5 red; 7 red, 14 blue; 19 blue, 2 green; 7 blue, 4 green, 6 red
|
||||||
|
Game 67: 4 green, 17 red, 7 blue; 4 blue, 6 green; 7 green, 7 red, 12 blue; 2 red, 14 blue
|
||||||
|
Game 68: 1 red, 11 green, 4 blue; 17 blue, 1 red, 10 green; 3 red, 7 green, 1 blue; 7 green, 3 red, 6 blue; 2 red, 3 green; 2 green, 2 red, 4 blue
|
||||||
|
Game 69: 5 blue, 4 red; 3 red, 11 green, 1 blue; 6 green, 2 blue; 10 green, 4 red, 5 blue; 2 red, 11 green
|
||||||
|
Game 70: 16 red, 7 blue, 1 green; 14 red, 1 blue, 4 green; 4 red, 4 green; 7 blue, 5 red, 2 green
|
||||||
|
Game 71: 14 red, 2 blue, 13 green; 7 green, 5 red, 2 blue; 3 blue, 9 green, 11 red; 10 red, 4 blue, 1 green
|
||||||
|
Game 72: 1 green, 2 red, 6 blue; 4 green, 4 red, 9 blue; 6 green, 8 blue, 1 red; 5 red, 4 green, 9 blue; 15 blue, 2 green, 7 red; 10 blue, 2 green, 10 red
|
||||||
|
Game 73: 7 green, 6 red, 7 blue; 6 blue, 5 red, 8 green; 5 blue, 5 red
|
||||||
|
Game 74: 11 red, 1 blue; 2 green, 4 blue, 1 red; 1 green, 2 blue, 11 red; 9 red, 5 blue; 15 red, 10 blue; 9 red, 3 blue
|
||||||
|
Game 75: 1 blue, 6 red, 9 green; 5 red, 1 blue, 8 green; 2 green, 2 red, 1 blue; 7 red, 1 green; 3 green, 6 red, 2 blue; 1 green, 1 red
|
||||||
|
Game 76: 16 red, 3 blue, 9 green; 4 blue, 4 green; 5 blue, 1 green, 10 red; 6 blue, 13 red; 1 blue, 2 green, 8 red
|
||||||
|
Game 77: 4 red, 4 blue; 5 blue, 5 red; 6 red, 3 green
|
||||||
|
Game 78: 11 green, 1 red; 1 blue, 18 green, 1 red; 6 green, 5 red, 2 blue; 6 red, 1 blue, 15 green; 5 green, 5 red
|
||||||
|
Game 79: 2 red, 3 green, 13 blue; 7 blue, 5 green; 4 blue, 2 red, 6 green; 6 green, 15 blue
|
||||||
|
Game 80: 9 green, 2 blue, 1 red; 8 green, 1 red; 1 blue, 7 green; 2 green, 1 blue; 3 green; 5 green, 1 red, 2 blue
|
||||||
|
Game 81: 2 blue, 8 green, 1 red; 3 green, 1 blue; 6 blue, 1 green; 3 blue, 3 green, 1 red; 2 green, 8 blue; 1 red, 8 blue, 2 green
|
||||||
|
Game 82: 5 blue, 4 red, 1 green; 9 red, 12 green, 8 blue; 9 red, 6 green, 15 blue; 8 blue, 10 red, 6 green
|
||||||
|
Game 83: 2 green, 7 blue, 4 red; 2 blue, 11 red, 9 green; 7 red, 7 green, 6 blue; 12 blue, 4 red, 11 green; 11 green, 7 blue; 7 green, 5 red, 2 blue
|
||||||
|
Game 84: 9 red, 1 blue, 7 green; 5 red, 5 green; 4 green, 4 blue; 4 green, 5 red
|
||||||
|
Game 85: 5 green, 13 red, 11 blue; 5 blue, 19 green, 15 red; 17 red, 3 green, 8 blue; 13 green, 10 red; 3 green, 17 red, 11 blue
|
||||||
|
Game 86: 1 green, 11 blue; 11 blue, 1 green, 8 red; 6 blue, 4 red; 4 blue, 17 red; 1 green, 15 red
|
||||||
|
Game 87: 3 green, 8 red, 6 blue; 6 red, 13 green, 1 blue; 4 blue, 8 red, 8 green
|
||||||
|
Game 88: 5 green, 5 blue; 3 green, 10 blue, 2 red; 6 blue, 7 red, 1 green; 5 green, 3 red, 11 blue; 8 red, 4 green, 6 blue
|
||||||
|
Game 89: 5 green, 10 blue, 12 red; 1 green, 13 red, 8 blue; 4 red, 11 green, 12 blue
|
||||||
|
Game 90: 4 green, 3 red, 11 blue; 1 green, 12 red, 12 blue; 9 blue, 5 red, 1 green; 2 green, 12 blue, 12 red
|
||||||
|
Game 91: 5 red, 8 blue, 1 green; 5 green, 3 blue; 9 blue, 7 green, 5 red; 1 green, 3 blue, 6 red; 9 blue, 11 green, 4 red; 2 green, 4 red, 10 blue
|
||||||
|
Game 92: 11 blue, 1 red, 6 green; 10 blue, 2 red; 4 red, 6 green, 19 blue
|
||||||
|
Game 93: 1 green, 3 blue, 3 red; 3 red; 5 blue, 3 red; 1 green, 4 red
|
||||||
|
Game 94: 9 red, 4 blue, 4 green; 1 blue, 6 red, 15 green; 10 red, 5 blue, 1 green; 2 blue, 4 green, 8 red
|
||||||
|
Game 95: 13 blue, 4 green, 3 red; 15 green, 3 red, 2 blue; 16 green, 8 blue, 2 red
|
||||||
|
Game 96: 15 blue, 7 green, 3 red; 5 red, 7 green, 17 blue; 6 red, 12 blue; 5 green, 10 blue, 4 red
|
||||||
|
Game 97: 5 red, 2 green; 8 red; 1 blue, 7 green, 2 red; 7 red, 15 green
|
||||||
|
Game 98: 6 green, 1 blue, 1 red; 3 green, 3 red; 1 blue, 13 green, 4 red
|
||||||
|
Game 99: 16 red, 5 blue, 9 green; 2 green, 7 blue, 2 red; 10 blue, 3 green; 9 red, 8 blue, 13 green; 16 green, 13 red, 10 blue
|
||||||
|
Game 100: 16 blue, 12 red, 3 green; 2 green, 7 blue; 5 blue, 4 green; 10 blue, 6 red, 6 green; 5 red, 12 blue, 2 green; 9 red, 12 blue, 11 green
|
||||||
100
d2/d2.structured-input
Normal file
100
d2/d2.structured-input
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
001: 1r/3b/11g/1b/5r/3b/5b/13r/6r/1b/4g/16r/12g/
|
||||||
|
002: 3r/13b/5g/14b/14b/9b/10b/3r/2b/5b/11b/3b/3r/16b/2r/9g/
|
||||||
|
003: 17b/5r/3r/11b/17b/1r/6b/9g/3b/11b/1r/3b/10r/11b/12r/3b/15b/
|
||||||
|
004: 14b/14r/1b/15r/13b/1b/6b/15r/7g/
|
||||||
|
005: 3b/1b/3r/6r/2b/2b/12r/3b/1b/2b/9r/1b/2b/10r/
|
||||||
|
006: 5b/5g/4b/1r/10g/16b/1r/6b/1r/1b/13g/1r/5b/7g/14b/17b/
|
||||||
|
007: 1b/8b/4r/1b/4b/4r/6b/4r/4g/1r/8g/
|
||||||
|
008: 2r/5b/1g/1b/4r/8g/6b/12b/6r/3b/5r/8r/2b/13g/5b/4r/3b/
|
||||||
|
009: 11r/1b/2r/2b/1b/2b/9r/4r/2b/2b/1b/2g/1b/9r/2g/
|
||||||
|
010: 9r/4g/1b/3r/7g/3b/1r/1b/7b/4r/1b/1b/5b/10r/1r/5g/
|
||||||
|
011: 2b/4r/3g/1b/7r/4b/7r/1b/3b/6b/4r/3r/1b/3b/
|
||||||
|
012: 1b/6r/5b/3b/2r/4b/3b/1r/3b/
|
||||||
|
013: 6b/1r/9b/11r/4b/12g/6b/9r/19b/2b/6b/10b/1r/16b/4b/14b/
|
||||||
|
014: 7b/2r/1b/2r/19b/12b/6b/11r/
|
||||||
|
015: 4r/4b/7b/15b/1b/8r/2r/10b/11b/5r/4b/6g/9r/8b/3g/9b/9r/
|
||||||
|
016: 7r/2b/19g/6b/9g/8b/6r/19b/11b/7r/1b/9b/3r/17g/
|
||||||
|
017: 3b/4b/5r/2r/4b/11b/6b/13g/3b/12b/7r/
|
||||||
|
018: 9r/6b/7g/3b/3b/5r/18r/6b/4g/3b/10r/8b/
|
||||||
|
019: 3r/6g/1r/5b/4b/3r/14b/
|
||||||
|
020: 2b/2b/4r/14r/6b/5g/1b/5r/3g/10r/6b/6b/
|
||||||
|
021: 10b/12b/3r/1b/14r/5b/7g/12b/1r/13g/7r/4g/
|
||||||
|
022: 2r/1b/1r/2b/1r/1b/3b/3b/1r/1b/2r/
|
||||||
|
023: 4b/4b/1r/3b/1r/6g/1r/1b/
|
||||||
|
024: 5b/15b/13r/20b/13b/6r/5b/11r/16g/6r/5b/13g/12b/13b/3r/
|
||||||
|
025: 10b/17r/12r/16b/3g/4b/12b/10r/8b/3b/10r/5b/2r/12b/
|
||||||
|
026: 11r/9b/3b/3r/3g/10b/3b/4r/1b/4b/9r/5b/1r/7b/1r/3b/3g/
|
||||||
|
027: 1b/12r/4b/5r/2b/1b/3b/6b/10r/1b/4r/3b/
|
||||||
|
028: 6b/2g/2b/8b/1r/2b/2b/6b/8g/9b/5b/
|
||||||
|
029: 1b/9b/9r/13b/4r/9b/3b/8b/15r/15b/18b/3r/16b/10r/16b/12b/16r/
|
||||||
|
030: 14b/4b/1r/7r/14b/2b/4r/1g/
|
||||||
|
031: 2r/14b/3b/3b/3b/4r/8b/4r/1g/8b/3b/10b/1r/11g/13b/2r/3b/
|
||||||
|
032: 8b/16r/2b/8b/16r/16b/4b/17r/2r/5b/4b/
|
||||||
|
033: 2r/2b/1b/5r/1b/8b/14r/
|
||||||
|
034: 4r/4g/9g/1b/16g/1b/5r/9g/2r/15b/1b/
|
||||||
|
035: 1b/5r/1b/15r/13b/2r/13b/17g/9b/3r/11g/7b/8b/14r/
|
||||||
|
036: 19g/3b/1b/1r/1b/8b/13b/5r/5b/
|
||||||
|
037: 12r/7b/3b/12b/10r/9g/17b/8r/13b/9b/9b/8r/4r/13b/13b/15b/12r/14b/
|
||||||
|
038: 5b/1b/20r/1b/13r/18b/17b/9r/10g/4b/4r/12g/12b/12r/6g/12b/13r/2b/
|
||||||
|
039: 7b/6r/2g/6b/1r/7b/1r/
|
||||||
|
040: 1b/3r/15b/1g/1b/16r/2b/
|
||||||
|
041: 2b/4g/8b/3r/2b/9r/4g/4r/3b/10g/5b/3b/2r/
|
||||||
|
042: 7b/2b/1r/8b/4r/5b/1r/3g/
|
||||||
|
043: 3r/1b/1b/2b/2r/1r/2b/3b/
|
||||||
|
044: 3b/14b/1r/16b/5r/11g/12b/1b/13b/1r/5b/2r/6g/3b/5r/11g/
|
||||||
|
045: 7b/1r/1r/3b/3b/14b/1r/4b/3b/1r/15b/1r/3g/
|
||||||
|
046: 15r/4b/15r/11b/3g/14r/2b/2b/14r/8b/3g/4r/1b/
|
||||||
|
047: 4b/2b/3r/8r/2b/18b/1b/17b/1r/
|
||||||
|
048: 2b/4r/2b/15b/16r/5g/14b/2b/10r/3b/13r/6b/8b/4r/12b/15r/3b/9b/
|
||||||
|
049: 1b/6r/7b/1b/9b/9r/4b/8r/9b/1r/14g/2b/9r/
|
||||||
|
050: 3r/10b/14g/2r/9b/7g/4b/12g/1r/4b/5b/
|
||||||
|
051: 2b/6b/1b/10b/1r/3b/2g/
|
||||||
|
052: 1b/4r/1b/3r/5b/4b/1b/3r/5g/1r/1b/1b/12b/2r/4b/10b/7b/1r/
|
||||||
|
053: 12r/1b/8r/11b/11g/8r/6b/13g/11b/11r/16g/6r/9b/4b/
|
||||||
|
054: 2r/8b/15g/4b/3b/6r/12b/13b/4r/
|
||||||
|
055: 1b/16b/4r/3r/1b/1g/12r/16b/3r/
|
||||||
|
056: 4g/1r/4g/2r/3b/7g/2r/3b/15g/
|
||||||
|
057: 17g/1b/9b/1r/1b/9b/
|
||||||
|
058: 3b/8r/7b/4b/9b/2r/1r/2b/11b/8b/4g/
|
||||||
|
059: 6b/1r/4b/6g/4b/5b/
|
||||||
|
060: 3b/5b/1r/7b/5b/16r/14r/1b/1b/7b/2b/13r/5b/5b/
|
||||||
|
061: 1b/2b/2r/2g/6r/1b/1g/
|
||||||
|
062: 5r/8b/1g/1r/1b/2b/8b/
|
||||||
|
063: 2r/2b/2g/9b/7g/1b/4b/18b/3b/
|
||||||
|
064: 13b/1b/6r/13b/15r/8b/5b/14r/4b/2b/8b/12r/1b/5r/13g/7b/8b/2r/
|
||||||
|
065: 7b/12r/6g/11r/8b/8b/9r/7b/7b/14r/2b/17g/
|
||||||
|
066: 2b/5r/7r/14b/19b/2g/7b/4b/6r/
|
||||||
|
067: 4b/17r/7b/4b/6g/7b/7r/12b/2r/14b/
|
||||||
|
068: 1r/11b/4b/17b/1r/10g/3r/7b/1b/7b/3r/6b/2r/3g/2b/2r/4b/
|
||||||
|
069: 5b/4r/3r/11b/1b/6b/2b/10b/4r/5b/2r/11g/
|
||||||
|
070: 16r/7b/1g/14r/1b/4g/4r/4g/7b/5r/2g/
|
||||||
|
071: 14r/2b/13g/7b/5r/2b/3b/9b/11r/10r/4b/1g/
|
||||||
|
072: 1b/2r/6b/4b/4r/9b/6b/8b/1r/5r/4b/9b/15b/2b/7r/10b/2b/10r/
|
||||||
|
073: 7b/6r/7b/6b/5r/8g/5b/5r/
|
||||||
|
074: 11r/1b/2b/4b/1r/1b/2b/11r/9r/5b/15r/10b/9r/3b/
|
||||||
|
075: 1b/6r/9g/5r/1b/8g/2b/2r/1b/7r/1g/3b/6r/2b/1b/1r/
|
||||||
|
076: 16r/3b/9g/4b/4g/5b/1b/10r/6b/13r/1b/2b/8r/
|
||||||
|
077: 4r/4b/5b/5r/6r/3g/
|
||||||
|
078: 11b/1r/1b/18b/1r/6b/5r/2b/6r/1b/15g/5b/5r/
|
||||||
|
079: 2r/3b/13b/7b/5g/4b/2r/6g/6b/15b/
|
||||||
|
080: 9b/2b/1r/8b/1r/1b/7g/2b/1b/3g/5b/1r/2b/
|
||||||
|
081: 2b/8b/1r/3b/1b/6b/1g/3b/3b/1r/2b/8b/1r/8b/2g/
|
||||||
|
082: 5b/4r/1g/9r/12b/8b/9r/6b/15b/8b/10r/6g/
|
||||||
|
083: 2b/7b/4r/2b/11r/9g/7r/7b/6b/12b/4r/11g/11b/7b/7b/5r/2b/
|
||||||
|
084: 9r/1b/7g/5r/5g/4b/4b/4b/5r/
|
||||||
|
085: 5b/13r/11b/5b/19b/15r/17r/3b/8b/13b/10r/3b/17r/11b/
|
||||||
|
086: 1b/11b/11b/1b/8r/6b/4r/4b/17r/1b/15r/
|
||||||
|
087: 3b/8r/6b/6r/13b/1b/4b/8r/8g/
|
||||||
|
088: 5b/5b/3b/10b/2r/6b/7r/1g/5b/3r/11b/8r/4b/6b/
|
||||||
|
089: 5b/10b/12r/1b/13r/8b/4r/11b/12b/
|
||||||
|
090: 4b/3r/11b/1b/12r/12b/9b/5r/1g/2b/12b/12r/
|
||||||
|
091: 5r/8b/1g/5b/3b/9b/7b/5r/1b/3b/6r/9b/11b/4r/2b/4r/10b/
|
||||||
|
092: 11b/1r/6g/10b/2r/4r/6b/19b/
|
||||||
|
093: 1b/3b/3r/3r/5b/3r/1b/4r/
|
||||||
|
094: 9r/4b/4g/1b/6r/15g/10r/5b/1g/2b/4b/8r/
|
||||||
|
095: 13b/4b/3r/15b/3r/2b/16b/8b/2r/
|
||||||
|
096: 15b/7b/3r/5r/7b/17b/6r/12b/5b/10b/4r/
|
||||||
|
097: 5r/2g/8r/1b/7b/2r/7r/15g/
|
||||||
|
098: 6b/1b/1r/3b/3r/1b/13b/4r/
|
||||||
|
099: 16r/5b/9g/2b/7b/2r/10b/3g/9r/8b/13g/16b/13r/10b/
|
||||||
|
100: 16b/12r/3g/2b/7b/5b/4g/10b/6r/6g/5r/12b/2g/9r/12b/11g/
|
||||||
33
d2/d2.test.input
Normal file
33
d2/d2.test.input
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
Game 1:
|
||||||
|
3 blue, 4 red;
|
||||||
|
1 red, 2 green, 6 blue;
|
||||||
|
2 green
|
||||||
|
|
||||||
|
Game 2:
|
||||||
|
1 blue, 2 green;
|
||||||
|
3 green, 4 blue, 1 red;
|
||||||
|
1 green, 1 blue
|
||||||
|
|
||||||
|
Game 3:
|
||||||
|
8 green, 6 blue, 20 red;
|
||||||
|
5 blue, 4 red, 13 green;
|
||||||
|
5 green, 1 red
|
||||||
|
|
||||||
|
Game 4:
|
||||||
|
1 green, 3 red, 6 blue;
|
||||||
|
3 green, 6 red;
|
||||||
|
3 green, 15 blue, 14 red
|
||||||
|
|
||||||
|
Game 5:
|
||||||
|
6 red, 1 blue, 3 green;
|
||||||
|
2 blue, 1 red, 2 green
|
||||||
|
|
||||||
|
|
||||||
|
982
|
||||||
|
|
||||||
|
0 * 10 = 0
|
||||||
|
0 + 9 = 9
|
||||||
|
9 * 10 = 90
|
||||||
|
90 + 8 = 98
|
||||||
|
98 * 10 = 980
|
||||||
|
980 + 2 = 982
|
||||||
5
d2/d2.test.structured-input
Normal file
5
d2/d2.test.structured-input
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
1: 4/3/1; 1/2/6; 0/2/0;
|
||||||
|
2: 0/2/1; 1/3/4; 0/1/1;
|
||||||
|
3: 20/8/6; 4/13/5; 1/5/0;
|
||||||
|
4: 3/1/6; 6/3/0; 14/3/15;
|
||||||
|
5: 6/3/1; 1/2/2;
|
||||||
102
d2/main.odin
Normal file
102
d2/main.odin
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package d2;
|
||||||
|
|
||||||
|
import "core:os"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
die :: proc (eno: os.Errno) {
|
||||||
|
fmt.printf("Fatal error: %s\n", os.get_last_error_string());
|
||||||
|
os.exit(int(eno));
|
||||||
|
}
|
||||||
|
|
||||||
|
usage :: proc() {
|
||||||
|
fmt.printf("Usage: ./%s FILENAME\n", os.args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
BUFFER_SIZE :: 1024;
|
||||||
|
State :: enum {
|
||||||
|
NONE, READ_ID, READ_RESULT, READ_DELIM, READ_COLON, READ_NEWLINE
|
||||||
|
}
|
||||||
|
Result :: struct{
|
||||||
|
red: int, green: int, blue: int,
|
||||||
|
};
|
||||||
|
TARGET_GAME :: Result{12, 13, 14};
|
||||||
|
games: [dynamic]Result = make([dynamic]Result);
|
||||||
|
stack: [dynamic]State = make([dynamic]State);
|
||||||
|
|
||||||
|
collect_digits :: proc(buffer: []u8, index: ^int) -> int {
|
||||||
|
assert(index^ < len(buffer));
|
||||||
|
result := 0
|
||||||
|
for '0' <= buffer[index^] && buffer[index^] <= '9' && index^ < len(buffer) {
|
||||||
|
result *= 10;
|
||||||
|
result += int(buffer[index^] - '0');
|
||||||
|
index^ += 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
consume_token :: proc(token: string, buffer: []u8, index: ^int) -> bool {
|
||||||
|
bi := index^;
|
||||||
|
ti := 0;
|
||||||
|
for ti < len(token) {
|
||||||
|
if bi >= len(buffer) || buffer[bi] != token[ti] {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
ti += 1; bi += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
attempt_1 :: proc() {
|
||||||
|
if len(os.args) < 2 {
|
||||||
|
usage();
|
||||||
|
os.exit(-1);
|
||||||
|
}
|
||||||
|
fh, eno := os.open(os.args[1], os.O_RDONLY);
|
||||||
|
if eno != os.ERROR_NONE { die(eno); }
|
||||||
|
defer os.close(fh);
|
||||||
|
id := -1;
|
||||||
|
red, green, blue, num_read: int;
|
||||||
|
state := State.READ_ID;
|
||||||
|
total := 0;
|
||||||
|
buffer, ok := os.read_entire_file_from_handle(fh);
|
||||||
|
if !ok {
|
||||||
|
// die(os.get_last_error());
|
||||||
|
// TODO
|
||||||
|
os.exit(-1);
|
||||||
|
}
|
||||||
|
ix := 0;
|
||||||
|
for ix < len(buffer) {
|
||||||
|
if eno != os.ERROR_NONE { die(eno); }
|
||||||
|
switch pop(&stack) {
|
||||||
|
case .READ_ID:
|
||||||
|
id = collect_digits(buffer, &ix);
|
||||||
|
append(&stack, State.READ_RESULT);
|
||||||
|
append(&stack, State.READ_DELIM);
|
||||||
|
append(&stack, State.READ_COLON);
|
||||||
|
case .READ_COLON:
|
||||||
|
if !consume_token(":", buffer, &ix) {
|
||||||
|
// TODO
|
||||||
|
os.exit(-1);
|
||||||
|
}
|
||||||
|
case .READ_DELIM:
|
||||||
|
for ix < len(buffer) && buffer[ix] == ' ' {
|
||||||
|
ix += 1;
|
||||||
|
}
|
||||||
|
case .READ_NEWLINE:
|
||||||
|
if !consume_token("\n", buffer, &ix) {
|
||||||
|
// TODO
|
||||||
|
os.exit(-1);
|
||||||
|
}
|
||||||
|
case .READ_RESULT:
|
||||||
|
append(&stack, State.READ_ID);
|
||||||
|
append(&stack, State.READ_NEWLINE);
|
||||||
|
case .NONE:
|
||||||
|
os.exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
attempt_1();
|
||||||
|
}
|
||||||
BIN
lexer_gen.bin
Executable file
BIN
lexer_gen.bin
Executable file
Binary file not shown.
20
lexer_gen/main.odin
Normal file
20
lexer_gen/main.odin
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package lexer_gen
|
||||||
|
|
||||||
|
import "core:os"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
if len(os.args) < 2 {
|
||||||
|
// TODO
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buf, ok := os.read_entire_file_from_filename(os.args[1])
|
||||||
|
if !ok {
|
||||||
|
// TODO
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tokenizer := tokenize(buf)
|
||||||
|
parser := parse_token_stream(tokenizer)
|
||||||
|
print_parse_tree(parser)
|
||||||
|
fmt.print('\n')
|
||||||
|
}
|
||||||
500
lexer_gen/re.odin
Normal file
500
lexer_gen/re.odin
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
package lexer_gen
|
||||||
|
|
||||||
|
import "core:os"
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:strings"
|
||||||
|
import "core:testing"
|
||||||
|
import "core:log"
|
||||||
|
|
||||||
|
logger := log.create_console_logger()
|
||||||
|
|
||||||
|
INDENTATION :: " "
|
||||||
|
|
||||||
|
print_indentation :: proc (level: int) {
|
||||||
|
for ii := 0; ii < level; ii += 1 {
|
||||||
|
fmt.print(INDENTATION)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Tokens :: enum {
|
||||||
|
ASTERISK,
|
||||||
|
BACK_SLASH,
|
||||||
|
CARROT,
|
||||||
|
CLOSE_BRACKET,
|
||||||
|
CLOSE_PAREN,
|
||||||
|
DOLLAR,
|
||||||
|
DOT,
|
||||||
|
FORWARD_SLASH,
|
||||||
|
LITERAL,
|
||||||
|
OPEN_BRACKET,
|
||||||
|
OPEN_PAREN,
|
||||||
|
PIPE,
|
||||||
|
TACK,
|
||||||
|
UNDERLINE,
|
||||||
|
_EOS,
|
||||||
|
}
|
||||||
|
|
||||||
|
token_type_string :: proc (tt: Tokens) -> string {
|
||||||
|
switch tt {
|
||||||
|
case .ASTERISK:
|
||||||
|
return "ASTERISK"
|
||||||
|
case .BACK_SLASH:
|
||||||
|
return "BACK_SLASH"
|
||||||
|
case .CARROT:
|
||||||
|
return "CARROT"
|
||||||
|
case .CLOSE_BRACKET:
|
||||||
|
return "CLOSE_BRACKET"
|
||||||
|
case .CLOSE_PAREN:
|
||||||
|
return "CLOSE_PAREN"
|
||||||
|
case .DOLLAR:
|
||||||
|
return "DOLLAR"
|
||||||
|
case .DOT:
|
||||||
|
return "DOT"
|
||||||
|
case .FORWARD_SLASH:
|
||||||
|
return "FORWARD_SLASH"
|
||||||
|
case .LITERAL:
|
||||||
|
return "LITERAL"
|
||||||
|
case .OPEN_BRACKET:
|
||||||
|
return "OPEN_BRACKET"
|
||||||
|
case .OPEN_PAREN:
|
||||||
|
return "OPEN_PAREN"
|
||||||
|
case .PIPE:
|
||||||
|
return "PIPE"
|
||||||
|
case .TACK:
|
||||||
|
return "TACK"
|
||||||
|
case .UNDERLINE:
|
||||||
|
return "UNDERLINE"
|
||||||
|
case ._EOS:
|
||||||
|
return "_EOS"
|
||||||
|
}
|
||||||
|
panic("Unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_token_type :: proc(tt: Tokens) {
|
||||||
|
fmt.print(token_type_string(tt));
|
||||||
|
}
|
||||||
|
|
||||||
|
Token :: struct {
|
||||||
|
type_: Tokens,
|
||||||
|
start: int,
|
||||||
|
end: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
print_token :: proc (token: ^Token) {
|
||||||
|
using token
|
||||||
|
fmt.printf("(%s start=%d end=%d)", token_type_string(type_), start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
Tokenizer :: struct {
|
||||||
|
buffer: []u8,
|
||||||
|
tokens: [dynamic](^Token),
|
||||||
|
idx: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
Parser :: struct {
|
||||||
|
tokenizer: ^Tokenizer,
|
||||||
|
ast: ^AstNode,
|
||||||
|
current: ^AstNode,
|
||||||
|
stack: [dynamic]^AstNode
|
||||||
|
}
|
||||||
|
|
||||||
|
new_parser :: proc(tokenizer: ^Tokenizer) -> ^Parser {
|
||||||
|
p := new(Parser);
|
||||||
|
p.tokenizer = tokenizer;
|
||||||
|
p.ast = new_ast_node(Group);
|
||||||
|
p.current = p.ast;
|
||||||
|
p.ast.start = 0;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode :: struct {
|
||||||
|
start: int,
|
||||||
|
end: int,
|
||||||
|
next: ^AstNode,
|
||||||
|
variant: union{
|
||||||
|
^Group, ^Literal, ^Range, ^Repeater
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_ast_node :: proc($T: typeid) -> ^T {
|
||||||
|
e := new(T)
|
||||||
|
e.variant = e
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
Literal :: struct {
|
||||||
|
using node: AstNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
print_literal :: proc(parser: ^Parser, node: ^Literal, level := 0) {
|
||||||
|
using parser
|
||||||
|
value := tokenizer.buffer[node.start:node.end]
|
||||||
|
print_indentation(level)
|
||||||
|
fmt.printf("(Literal start=%d end=%d value='%s'", node.start, node.end, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
Range :: struct {
|
||||||
|
using node: AstNode,
|
||||||
|
lbound: rune,
|
||||||
|
ubound: rune,
|
||||||
|
};
|
||||||
|
|
||||||
|
print_range :: proc (parser: ^Parser, range: ^Range, level := 0) {
|
||||||
|
print_indentation(level);
|
||||||
|
fmt.printf("(range %s %c)", range.lbound, range.ubound);
|
||||||
|
}
|
||||||
|
|
||||||
|
Group :: struct {
|
||||||
|
using node: AstNode,
|
||||||
|
child: ^AstNode
|
||||||
|
};
|
||||||
|
|
||||||
|
print_group :: proc(parser: ^Parser, group: ^Group, level := 0) {
|
||||||
|
// TODO
|
||||||
|
if parser == nil || group == nil {
|
||||||
|
// TODO handle error
|
||||||
|
}
|
||||||
|
fmt.print("(group ")
|
||||||
|
current: ^AstNode = group.child;
|
||||||
|
for current != nil {
|
||||||
|
print_node(parser, current, level + 1)
|
||||||
|
current = current.next
|
||||||
|
}
|
||||||
|
fmt.print(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
RepeaterType :: enum {
|
||||||
|
One,
|
||||||
|
OneOrMore,
|
||||||
|
ZeroOrMore,
|
||||||
|
ExactRange,
|
||||||
|
_None
|
||||||
|
}
|
||||||
|
|
||||||
|
repeater_type_string :: proc(rt: RepeaterType) -> string {
|
||||||
|
switch rt {
|
||||||
|
case .One:
|
||||||
|
return "One"
|
||||||
|
case .OneOrMore:
|
||||||
|
return "OneOrMore"
|
||||||
|
case .ZeroOrMore:
|
||||||
|
return "ZeroOrMore"
|
||||||
|
case .ExactRange:
|
||||||
|
return "ExactRange"
|
||||||
|
case ._None:
|
||||||
|
return "_None"
|
||||||
|
}
|
||||||
|
panic("Unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater :: struct {
|
||||||
|
using node: AstNode,
|
||||||
|
target: ^AstNode,
|
||||||
|
type_: RepeaterType
|
||||||
|
}
|
||||||
|
|
||||||
|
print_repeater :: proc(parser: ^Parser, node: ^Repeater, level := 0) {
|
||||||
|
using node
|
||||||
|
print_indentation(level);
|
||||||
|
fmt.printf("(repeat %s \n", repeater_type_string(type_));
|
||||||
|
print_node(parser, target, level + 1);
|
||||||
|
fmt.print(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_node :: proc(parser: ^Parser, node: $T/^AstNode, level := 0) {
|
||||||
|
switch node_ in node.variant {
|
||||||
|
case ^Group: print_group(parser, node_, level);
|
||||||
|
case ^Literal: print_literal(parser, node_, level);
|
||||||
|
case ^Repeater: print_repeater(parser, node_, level);
|
||||||
|
case ^Range: print_range(parser, node_, level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_tokenizer :: proc() -> (state: ^Tokenizer) {
|
||||||
|
state = new(Tokenizer)
|
||||||
|
using state
|
||||||
|
tokens = make([dynamic](^Token))
|
||||||
|
idx = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
scan_one :: proc(tokenizer: ^Tokenizer, tt: Tokens) {
|
||||||
|
using tokenizer;
|
||||||
|
fmt.printf("%s: Call with type %s\n", #procedure, tt);
|
||||||
|
new_tok := new(Token);
|
||||||
|
new_tok.type_ = tt;
|
||||||
|
new_tok.start = idx;
|
||||||
|
new_tok.end = idx + 1;
|
||||||
|
append(&tokens, new_tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
peek_front_safe :: proc(array: [dynamic]$E) -> (E, bool) {
|
||||||
|
if array == nil {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
return array[0], true;
|
||||||
|
}
|
||||||
|
|
||||||
|
peek_safe :: proc(array: [dynamic]$E) -> (E, bool) {
|
||||||
|
if array == nil || len(array) == 0 {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
return array[len(array) - 1], true;
|
||||||
|
}
|
||||||
|
|
||||||
|
peek_type :: proc (tokens: [dynamic]^Token, start := 0) -> Tokens {
|
||||||
|
tok, ok := peek_front_safe(tokens);
|
||||||
|
if !ok {
|
||||||
|
return ._EOS;
|
||||||
|
}
|
||||||
|
return tok.type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
scan_one_maybe :: proc(tokenizer: ^Tokenizer) -> bool {
|
||||||
|
switch tokenizer.buffer[tokenizer.idx] {
|
||||||
|
case '[':
|
||||||
|
scan_one(tokenizer, Tokens.OPEN_BRACKET);
|
||||||
|
case ']':
|
||||||
|
scan_one(tokenizer, Tokens.CLOSE_BRACKET);
|
||||||
|
case '(':
|
||||||
|
scan_one(tokenizer, Tokens.OPEN_PAREN);
|
||||||
|
case ')':
|
||||||
|
scan_one(tokenizer, Tokens.CLOSE_PAREN);
|
||||||
|
case '|':
|
||||||
|
scan_one(tokenizer, Tokens.PIPE);
|
||||||
|
case '^':
|
||||||
|
scan_one(tokenizer, Tokens.CARROT);
|
||||||
|
case '$':
|
||||||
|
scan_one(tokenizer, Tokens.DOLLAR);
|
||||||
|
case '*':
|
||||||
|
scan_one(tokenizer, Tokens.ASTERISK);
|
||||||
|
case '-':
|
||||||
|
scan_one(tokenizer, Tokens.TACK);
|
||||||
|
case '_':
|
||||||
|
scan_one(tokenizer, Tokens.UNDERLINE);
|
||||||
|
case '.':
|
||||||
|
scan_one(tokenizer, Tokens.DOT);
|
||||||
|
case '\\':
|
||||||
|
scan_one(tokenizer, Tokens.BACK_SLASH);
|
||||||
|
case '/':
|
||||||
|
scan_one(tokenizer, Tokens.FORWARD_SLASH);
|
||||||
|
case:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenize :: proc (buffer: []u8) -> ^Tokenizer {
|
||||||
|
tokenizer := new_tokenizer();
|
||||||
|
tokenizer.buffer = buffer;
|
||||||
|
new_tok: ^Token = nil;
|
||||||
|
literal_tok: ^Token = nil;
|
||||||
|
|
||||||
|
for ; tokenizer.idx < len(tokenizer.buffer); tokenizer.idx += 1 {
|
||||||
|
scanned := scan_one_maybe(tokenizer);
|
||||||
|
if scanned && literal_tok != nil {
|
||||||
|
// End a literal
|
||||||
|
literal_tok.end = tokenizer.idx;
|
||||||
|
literal_tok = nil;
|
||||||
|
} else if !scanned && literal_tok == nil {
|
||||||
|
// Start a literal
|
||||||
|
literal_tok = new(Token);
|
||||||
|
literal_tok.type_ = .LITERAL;
|
||||||
|
literal_tok.start = tokenizer.idx;
|
||||||
|
literal_tok.end = tokenizer.idx;
|
||||||
|
fmt.printf("Appending!\n");
|
||||||
|
append(&tokenizer.tokens, literal_tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(len(tokenizer.tokens) > 0);
|
||||||
|
return tokenizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_token_stream :: proc(stream: []^Token) {
|
||||||
|
for tok, index in stream {
|
||||||
|
fmt.printf("%d: ", index);
|
||||||
|
print_token(tok);
|
||||||
|
fmt.print("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_tokenize_basic :: proc(sig: ^testing.T) {
|
||||||
|
buf, ok := os.read_entire_file_from_filename("./test/test_tokenizer__basic.input");
|
||||||
|
tokenizer := tokenize(buf);
|
||||||
|
assert(
|
||||||
|
len(tokenizer.tokens) == 2,
|
||||||
|
fmt.tprintf("len(tokens) = %d != 2\n", len(tokenizer.tokens)));
|
||||||
|
print_token_stream(tokenizer.tokens[:]);
|
||||||
|
assert(
|
||||||
|
tokenizer.tokens[0].type_ == Tokens.LITERAL,
|
||||||
|
fmt.tprintf("tt = %s\n", tokenizer.tokens[0].type_));
|
||||||
|
assert(
|
||||||
|
tokenizer.tokens[1].type_ == Tokens.ASTERISK,
|
||||||
|
fmt.tprintf("tt = %s\n", tokenizer.tokens[0].type_));
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_escape :: proc(parser: ^Parser) -> ^AstNode {
|
||||||
|
using parser
|
||||||
|
node := new_ast_node(Literal)
|
||||||
|
tok, ok := pop_front_safe(&(tokenizer.tokens))
|
||||||
|
if !ok {
|
||||||
|
free(node)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
node.start = tok.start
|
||||||
|
assert(tok.type_ == .BACK_SLASH)
|
||||||
|
tok, ok = pop_front_safe(&tokenizer.tokens)
|
||||||
|
if !ok {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
if tok.type_ == .LITERAL {
|
||||||
|
// TODO Cannot escape a literal
|
||||||
|
}
|
||||||
|
node.end = tok.end
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_zero_or_more_repeater :: proc(parser: ^Parser) -> ^AstNode {
|
||||||
|
using parser
|
||||||
|
|
||||||
|
// Create an AST node representing the repeater
|
||||||
|
ok: bool
|
||||||
|
repeater_token: ^Token
|
||||||
|
repeater_token, ok = pop_safe(&tokenizer.tokens)
|
||||||
|
if !ok {
|
||||||
|
// TODO Handle error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
assert(repeater_token.type_ == .ASTERISK)
|
||||||
|
|
||||||
|
// Attach the ast node that the repeater operates on
|
||||||
|
node := new_ast_node(Repeater)
|
||||||
|
node.type_ = .ZeroOrMore
|
||||||
|
node.start = repeater_token.start
|
||||||
|
node.end = repeater_token.end
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_literal :: proc(parser: ^Parser) -> ^AstNode {
|
||||||
|
tok, ok := pop_front_safe(&parser.tokenizer.tokens)
|
||||||
|
if !ok { return nil }
|
||||||
|
node := new(Literal)
|
||||||
|
node.start = tok.start
|
||||||
|
node.end = tok.end
|
||||||
|
node.next = nil
|
||||||
|
value := parser.tokenizer.buffer[node.start:node.end]
|
||||||
|
log.debugf("Finished parsing type=Literal with value='%s'\n", value)
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_token_stream :: proc(tokenizer: ^Tokenizer) -> ^Parser {
|
||||||
|
parser := new_parser(tokenizer)
|
||||||
|
parser.ast = parse_token_stream__inner(parser)
|
||||||
|
fmt.printf("%x\n", &parser.ast)
|
||||||
|
return parser
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_token_stream__inner :: proc(parser: ^Parser) -> ^AstNode {
|
||||||
|
using parser
|
||||||
|
next: ^AstNode
|
||||||
|
for len(tokenizer.tokens) > 0 {
|
||||||
|
type_ := peek_type(tokenizer.tokens)
|
||||||
|
log.debugf("Parsing token of type=%s\n", type_)
|
||||||
|
#partial switch type_ {
|
||||||
|
case .LITERAL:
|
||||||
|
next = parse_literal(parser)
|
||||||
|
case .BACK_SLASH:
|
||||||
|
next = parse_escape(parser)
|
||||||
|
case .ASTERISK:
|
||||||
|
next = parse_zero_or_more_repeater(parser)
|
||||||
|
case:
|
||||||
|
msg := fmt.tprintf("Don't know how to handle token of type=%s\n", type_)
|
||||||
|
assert(false, msg)
|
||||||
|
}
|
||||||
|
if next == nil {
|
||||||
|
return current
|
||||||
|
} else if current != nil {
|
||||||
|
current.next = next
|
||||||
|
}
|
||||||
|
current = next
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
print_parse_tree :: proc(parser: ^Parser) {
|
||||||
|
for current := parser.ast; current != nil; current = current.next {
|
||||||
|
print_node(parser, current, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_parse_token_stream :: proc(sig: ^testing.T) {
|
||||||
|
buf, ok := os.read_entire_file_from_filename("./test/test_parser__basic.input");
|
||||||
|
assert(ok)
|
||||||
|
tokenizer := tokenize(buf)
|
||||||
|
parser := parse_token_stream(tokenizer)
|
||||||
|
print_parse_tree(parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
iter_lines :: proc(buffer: []u8, index: ^int) -> ([]u8, bool) {
|
||||||
|
if index^ < 0 || index^ >= len(buffer) {
|
||||||
|
return buffer, true
|
||||||
|
}
|
||||||
|
lbound := index^
|
||||||
|
for index^ < len(buffer) {
|
||||||
|
if buffer[index^] == '\n' {
|
||||||
|
index^ += 1 // Skip the newline
|
||||||
|
return buffer[lbound:index^ - 1], false
|
||||||
|
}
|
||||||
|
index^ += 1
|
||||||
|
}
|
||||||
|
return buffer[lbound:index^], false
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_iter_lines :: proc(sig: ^testing.T) {
|
||||||
|
input, ok_ := os.read_entire_file_from_filename("./test/test_iter_lines__basic.input")
|
||||||
|
assert(ok_)
|
||||||
|
linum := 1
|
||||||
|
index := 0
|
||||||
|
line, stop_iter := iter_lines(input, &index)
|
||||||
|
for !stop_iter {
|
||||||
|
linum += 1
|
||||||
|
fmt.printf("Line %0d: %s\n", linum, line)
|
||||||
|
line, stop_iter = iter_lines(input, &index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_token_expectation :: proc(filename: string) {
|
||||||
|
buffer, ok := os.read_entire_file_from_filename(filename);
|
||||||
|
if !ok {
|
||||||
|
// TODO handle error
|
||||||
|
log.errorf("%s\n", os.get_last_error_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
start := 0
|
||||||
|
line, ok_ := iter_lines(buffer, &start)
|
||||||
|
for ; ok; line, ok = iter_lines(buffer, &start) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
re_compile :: proc(pattern: string) -> ^AstNode {
|
||||||
|
pattern_ := strings.clone(pattern);
|
||||||
|
tokenizer := tokenize(transmute([]u8)pattern_)
|
||||||
|
parser := parse_token_stream(tokenizer);
|
||||||
|
return parser.ast;
|
||||||
|
}
|
||||||
|
|
||||||
|
re_match :: proc() {
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
re_search :: proc() {
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
7
test/test_iter_lines__basic.expected
Normal file
7
test/test_iter_lines__basic.expected
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Line 1: Hello world!
|
||||||
|
Line 2: How
|
||||||
|
Line 3: ,.sd1
|
||||||
|
Line 4: Are
|
||||||
|
Line 5: you? ??? !
|
||||||
|
Line 6:
|
||||||
|
Line 7: I'm doing well, thanks
|
||||||
7
test/test_iter_lines__basic.input
Normal file
7
test/test_iter_lines__basic.input
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Hello world!
|
||||||
|
How
|
||||||
|
,.sd1
|
||||||
|
Are
|
||||||
|
you? ??? !
|
||||||
|
|
||||||
|
I'm doing well, thanks
|
||||||
1
test/test_parse_token_stream__basic.input
Normal file
1
test/test_parse_token_stream__basic.input
Normal file
@@ -0,0 +1 @@
|
|||||||
|
\(a
|
||||||
1
test/test_parser__basic.input
Normal file
1
test/test_parser__basic.input
Normal file
@@ -0,0 +1 @@
|
|||||||
|
A*
|
||||||
1
test/test_tokenizer__basic.input
Normal file
1
test/test_tokenizer__basic.input
Normal file
@@ -0,0 +1 @@
|
|||||||
|
A*
|
||||||
Reference in New Issue
Block a user