From 14079d39ed5ea15befaaf343b68f7d27d9139c3e Mon Sep 17 00:00:00 2001 From: Akuli Date: Wed, 4 Dec 2024 17:28:07 +0200 Subject: [PATCH 01/14] day2 part1 --- examples/aoc2024/day02/part1.jou | 66 ++++++++++++++++++++++++++ examples/aoc2024/day02/sampleinput.txt | 6 +++ 2 files changed, 72 insertions(+) create mode 100644 examples/aoc2024/day02/part1.jou create mode 100644 examples/aoc2024/day02/sampleinput.txt diff --git a/examples/aoc2024/day02/part1.jou b/examples/aoc2024/day02/part1.jou new file mode 100644 index 00000000..2936c58d --- /dev/null +++ b/examples/aoc2024/day02/part1.jou @@ -0,0 +1,66 @@ +import "stdlib/io.jou" +import "stdlib/mem.jou" +import "stdlib/math.jou" +import "stdlib/str.jou" +import "stdlib/ascii.jou" + + +class Report: + data: int* + len: int + + def free(self) -> None: + free(self->data) + + def is_safe(self) -> bool: + inc = True + dec = True + + for i = 0; i < self->len - 1; i++: + d = self->data[i+1] - self->data[i] + + if d <= 0: + inc = False + if d >= 0: + dec = False + + if not (1 <= abs(d) and abs(d) <= 3): + return False + + return inc or dec + + +# mutates the line in-place through split_by_ascii_whitespace() +def parse_report(line: byte*) -> Report: + words = split_by_ascii_whitespace(line) + + n = 0 + while words[n] != NULL: + n++ + + report = Report{len=n} + report.data = malloc(sizeof(report.data[0]) * n) + for i = 0; i < n; i++: + report.data[i] = atoi(words[i]) + + free(words) + return report + + +def main() -> int: + f = fopen("sampleinput.txt", "r") + assert f != NULL + + num_safe = 0 + + line: byte[1024] + while fgets(line, sizeof(line) as int, f) != NULL: + report = parse_report(line) + if report.is_safe(): + num_safe++ + report.free() + + printf("%d\n", num_safe) # Output: 2 + + fclose(f) + return 0 diff --git a/examples/aoc2024/day02/sampleinput.txt b/examples/aoc2024/day02/sampleinput.txt new file mode 100644 index 00000000..b49c10d7 --- /dev/null +++ b/examples/aoc2024/day02/sampleinput.txt @@ -0,0 +1,6 @@ +7 6 4 2 1 +1 2 7 8 9 +9 7 6 2 1 +1 3 2 4 5 +8 6 4 4 1 +1 3 6 7 9 From 4462e303a431bb51f17652fd394cf2da9919d6e7 Mon Sep 17 00:00:00 2001 From: Akuli Date: Wed, 4 Dec 2024 17:35:39 +0200 Subject: [PATCH 02/14] day2 part 2 --- examples/aoc2024/day02/part2.jou | 84 ++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 examples/aoc2024/day02/part2.jou diff --git a/examples/aoc2024/day02/part2.jou b/examples/aoc2024/day02/part2.jou new file mode 100644 index 00000000..779482b3 --- /dev/null +++ b/examples/aoc2024/day02/part2.jou @@ -0,0 +1,84 @@ +import "stdlib/io.jou" +import "stdlib/mem.jou" +import "stdlib/math.jou" +import "stdlib/str.jou" +import "stdlib/ascii.jou" + + +class Report: + data: int* + len: int + + def free(self) -> None: + free(self->data) + + def is_safe(self) -> bool: + inc = True + dec = True + + for i = 0; i < self->len - 1; i++: + d = self->data[i+1] - self->data[i] + + if d <= 0: + inc = False + if d >= 0: + dec = False + + if not (1 <= abs(d) and abs(d) <= 3): + return False + + return inc or dec + + def pop(self, i: int) -> int: + bye = self->data[i] + memmove(&self->data[i], &self->data[i+1], sizeof(self->data[0]) * (--self->len - i)) + return bye + + def insert(self, i: int, value: int) -> None: + # assumes there is enough room in the array and no reallocation is needed + memmove(&self->data[i+1], &self->data[i], sizeof(self->data[0]) * (self->len++ - i)) + self->data[i] = value + + +# mutates the line in-place through split_by_ascii_whitespace() +def parse_report(line: byte*) -> Report: + words = split_by_ascii_whitespace(line) + + n = 0 + while words[n] != NULL: + n++ + + report = Report{len=n} + report.data = malloc(sizeof(report.data[0]) * n) + for i = 0; i < n; i++: + report.data[i] = atoi(words[i]) + + free(words) + return report + + +def main() -> int: + f = fopen("sampleinput.txt", "r") + assert f != NULL + + num_safe = 0 + + line: byte[1024] + while fgets(line, sizeof(line) as int, f) != NULL: + report = parse_report(line) + if report.is_safe(): + num_safe++ + else: + for i = 0; i < report.len; i++: + temp_missing = report.pop(i) + if report.is_safe(): + num_safe++ + break + report.insert(i, temp_missing) + + report.free() + + printf("%d\n", num_safe) # Output: 4 + + fclose(f) + return 0 From b3c9dbf26c67911892fe1cf499d91311f9f56df1 Mon Sep 17 00:00:00 2001 From: Akuli Date: Wed, 4 Dec 2024 17:51:38 +0200 Subject: [PATCH 03/14] day3 part1 --- examples/aoc2024/day03/part1.jou | 56 ++++++++++++++++++++++++++ examples/aoc2024/day03/sampleinput.txt | 1 + 2 files changed, 57 insertions(+) create mode 100644 examples/aoc2024/day03/part1.jou create mode 100644 examples/aoc2024/day03/sampleinput.txt diff --git a/examples/aoc2024/day03/part1.jou b/examples/aoc2024/day03/part1.jou new file mode 100644 index 00000000..27e66c8c --- /dev/null +++ b/examples/aoc2024/day03/part1.jou @@ -0,0 +1,56 @@ +import "stdlib/str.jou" +import "stdlib/io.jou" +import "stdlib/mem.jou" +import "stdlib/ascii.jou" + + +# Moves s in-place beyond used characters. Returns 0 on failure. +def parse_int(s: byte**) -> int: + result = 0 + while is_ascii_digit(**s): + result *= 10 + result += (*(*s)++ - '0') + return result + + +# Returns 0 if doesn't match. +def parse_mul(s: byte*) -> int: + if not starts_with(s, "mul("): + return 0 + s = &s[4] + + a = parse_int(&s) + if *s++ != ',': + return 0 + b = parse_int(&s) + if *s++ != ')': + return 0 + return a*b + + +def main() -> int: + max_size = 100000 + big_string: byte* = malloc(max_size) + + f = fopen("sampleinput.txt", "r") + assert f != NULL + + i = 0 + while True: + c = fgetc(f) + EOF = -1 # TODO: belongs to stdlib + if c == EOF: + break + assert i < max_size + big_string[i++] = c as byte + + fclose(f) + + result = 0 as long + s = big_string + while *s != '\0': + result += parse_mul(s++) + + free(big_string) + printf("%d\n", result) # Output: 161 + return 0 diff --git a/examples/aoc2024/day03/sampleinput.txt b/examples/aoc2024/day03/sampleinput.txt new file mode 100644 index 00000000..f274bdae --- /dev/null +++ b/examples/aoc2024/day03/sampleinput.txt @@ -0,0 +1 @@ +xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5)) From b9a9da5b151a0a266ce43a4db4642c7089355257 Mon Sep 17 00:00:00 2001 From: Akuli Date: Wed, 4 Dec 2024 17:52:17 +0200 Subject: [PATCH 04/14] rename to sampleinput1 --- examples/aoc2024/day03/part1.jou | 2 +- examples/aoc2024/day03/{sampleinput.txt => sampleinput1.txt} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename examples/aoc2024/day03/{sampleinput.txt => sampleinput1.txt} (100%) diff --git a/examples/aoc2024/day03/part1.jou b/examples/aoc2024/day03/part1.jou index 27e66c8c..4fe0abe3 100644 --- a/examples/aoc2024/day03/part1.jou +++ b/examples/aoc2024/day03/part1.jou @@ -32,7 +32,7 @@ def main() -> int: max_size = 100000 big_string: byte* = malloc(max_size) - f = fopen("sampleinput.txt", "r") + f = fopen("sampleinput1.txt", "r") assert f != NULL i = 0 diff --git a/examples/aoc2024/day03/sampleinput.txt b/examples/aoc2024/day03/sampleinput1.txt similarity index 100% rename from examples/aoc2024/day03/sampleinput.txt rename to examples/aoc2024/day03/sampleinput1.txt From 74a19070c8f81caee8523d67e13bb3cb3abe2f19 Mon Sep 17 00:00:00 2001 From: Akuli Date: Wed, 4 Dec 2024 18:38:45 +0200 Subject: [PATCH 05/14] day4 part2 not working with actual input --- examples/aoc2024/day03/part2.jou | 74 ++++++++++++++ examples/aoc2024/day03/sampleinput2.txt | 1 + examples/aoc2024/day04/part1.jou | 56 +++++++++++ examples/aoc2024/day04/part2.jou | 46 +++++++++ examples/aoc2024/day04/part2_templates.txt | 31 ++++++ examples/aoc2024/day04/sampleinput.txt | 10 ++ examples/aoc2024/grid.jou | 112 +++++++++++++++++++++ 7 files changed, 330 insertions(+) create mode 100644 examples/aoc2024/day03/part2.jou create mode 100644 examples/aoc2024/day03/sampleinput2.txt create mode 100644 examples/aoc2024/day04/part1.jou create mode 100644 examples/aoc2024/day04/part2.jou create mode 100644 examples/aoc2024/day04/part2_templates.txt create mode 100644 examples/aoc2024/day04/sampleinput.txt create mode 100644 examples/aoc2024/grid.jou diff --git a/examples/aoc2024/day03/part2.jou b/examples/aoc2024/day03/part2.jou new file mode 100644 index 00000000..ba2eec01 --- /dev/null +++ b/examples/aoc2024/day03/part2.jou @@ -0,0 +1,74 @@ +import "stdlib/str.jou" +import "stdlib/io.jou" +import "stdlib/mem.jou" +import "stdlib/ascii.jou" + + +# Moves s in-place beyond used characters. Returns 0 on failure. +def parse_int(s: byte**) -> int: + result = 0 + while is_ascii_digit(**s): + result *= 10 + result += (*(*s)++ - '0') + return result + + +# Returns 0 if doesn't match. +def parse_mul(s: byte*) -> int: + if not starts_with(s, "mul("): + return 0 + s = &s[4] + + a = parse_int(&s) + if *s++ != ',': + return 0 + b = parse_int(&s) + if *s++ != ')': + return 0 + return a*b + + +def remove_disabled_sections(s: byte*) -> None: + while True: + dont = strstr(s, "don't()") + if dont == NULL: + break + + do = strstr(dont, "do()") + if do == NULL: + # disable to end + *dont = '\0' + else: + # delete dont()...do() + do_end = &do[4] + memmove(dont, do_end, strlen(do_end) + 1) + + +def main() -> int: + max_size = 100000 + big_string: byte* = malloc(max_size) + + f = fopen("sampleinput.txt", "r") + assert f != NULL + + i = 0 + while True: + c = fgetc(f) + EOF = -1 # TODO: belongs to stdlib + if c == EOF: + break + assert i < max_size + big_string[i++] = c as byte + + fclose(f) + + remove_disabled_sections(big_string) + + result = 0 as long + s = big_string + while *s != '\0': + result += parse_mul(s++) + + free(big_string) + printf("%d\n", result) # Output: 48 + return 0 diff --git a/examples/aoc2024/day03/sampleinput2.txt b/examples/aoc2024/day03/sampleinput2.txt new file mode 100644 index 00000000..30032cbe --- /dev/null +++ b/examples/aoc2024/day03/sampleinput2.txt @@ -0,0 +1 @@ +xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5)) diff --git a/examples/aoc2024/day04/part1.jou b/examples/aoc2024/day04/part1.jou new file mode 100644 index 00000000..7fc60c9a --- /dev/null +++ b/examples/aoc2024/day04/part1.jou @@ -0,0 +1,56 @@ +import "../grid.jou" +import "stdlib/str.jou" +import "stdlib/mem.jou" +import "stdlib/io.jou" + + +def count_in_string(s: byte*) -> int: + n = 0 + for i = 0; s[i] != '\0'; i++: + if starts_with(&s[i], "XMAS") or starts_with(&s[i], "SAMX"): + n++ + return n + + +def count_diagonals(grid: Grid*) -> int: + big_size = grid->width + grid->height + 69 + temp_string: byte* = malloc(big_size) + assert temp_string != NULL + + result = 0 + + for c = -big_size; c <= big_size; c++: + # diagonals like /, along lines whose equation is y = x + c + p = temp_string + for x = 0; x < grid->width; x++: + y = x + c + if 0 <= y and y < grid->height: + *p++ = grid->get([x, y]) + *p = '\0' + result += count_in_string(temp_string) + + # diagonals like \, along lines whose equation is y = -x + c + p = temp_string + for x = 0; x < grid->width; x++: + y = -x + c + if 0 <= y and y < grid->height: + *p++ = grid->get([x, y]) + *p = '\0' + result += count_in_string(temp_string) + + free(temp_string) + return result + + +def main() -> int: + f = fopen("sampleinput.txt", "r") + grid = read_grid_from_file(f) + fclose(f) + + horizontal = count_in_string(grid.data) + grid.transpose() + vertical = count_in_string(grid.data) + diagonal = count_diagonals(&grid) + printf("%d\n", horizontal + vertical + diagonal) # Output: 18 + + return 0 diff --git a/examples/aoc2024/day04/part2.jou b/examples/aoc2024/day04/part2.jou new file mode 100644 index 00000000..1510c30c --- /dev/null +++ b/examples/aoc2024/day04/part2.jou @@ -0,0 +1,46 @@ +import "../grid.jou" +import "stdlib/io.jou" +import "stdlib/mem.jou" + + +# Count how many times template matches grid +# "." in template can be any character +def count_template(grid: Grid*, template: Grid*) -> int: + count = 0 + for ox = 0; ox <= grid->width - template->width; ox++: + for oy = 0; oy < grid->height - template->height; oy++: + all_match = True + for x = 0; x < template->width; x++: + for y = 0; y < template->height; y++: + grid_byte = grid->get([ox + x, oy + y]) + template_byte = template->get([x, y]) + if grid_byte != template_byte and template_byte != '.': + all_match = False + if all_match: + count += 1 + return count + + +def main() -> int: + templates: Grid[10] + num_templates = 0 + + f = fopen("part2_templates.txt", "r") + while feof(f) == 0: + assert num_templates < sizeof(templates)/sizeof(templates[0]) + templates[num_templates++] = read_grid_from_file(f) + fclose(f) + + f = fopen("input", "r") + grid = read_grid_from_file(f) + fclose(f) + + result = 0 + for i = 0; i < num_templates; i++: + result += count_template(&grid, &templates[i]) + printf("%d\n", result) + + for i = 0; i < num_templates; i++: + free(templates[i].data) + + return 0 diff --git a/examples/aoc2024/day04/part2_templates.txt b/examples/aoc2024/day04/part2_templates.txt new file mode 100644 index 00000000..538d3e6f --- /dev/null +++ b/examples/aoc2024/day04/part2_templates.txt @@ -0,0 +1,31 @@ +M.S +.A. +M.S + +S.S +.A. +M.M + +S.M +.A. +S.M + +M.M +.A. +S.S + +.M. +MAS +.S. + +.S. +MAS +.M. + +.M. +SAM +.S. + +.S. +SAM +.M. diff --git a/examples/aoc2024/day04/sampleinput.txt b/examples/aoc2024/day04/sampleinput.txt new file mode 100644 index 00000000..1f4eda20 --- /dev/null +++ b/examples/aoc2024/day04/sampleinput.txt @@ -0,0 +1,10 @@ +MMMSXXMASM +MSAMXMSMSA +AMXSXMAAMM +MSAMASMSMX +XMASAMXAMM +XXAMMXXAMA +SMSMSASXSS +SAXAMASAAA +MAMMMXMMMM +MXMXAXMASX diff --git a/examples/aoc2024/grid.jou b/examples/aoc2024/grid.jou new file mode 100644 index 00000000..045ab451 --- /dev/null +++ b/examples/aoc2024/grid.jou @@ -0,0 +1,112 @@ +# This file contains a utility class for AoC solutions. +# It is not in the standard library because it feels too AoC-specific to me. + +import "stdlib/ascii.jou" +import "stdlib/str.jou" +import "stdlib/mem.jou" +import "stdlib/io.jou" + + +class Grid: + width: int + height: int + data: byte* + + def is_in_bounds(self, point: int[2]) -> bool: + x = point[0] + y = point[1] + return 0 <= x and x < self->width and 0 <= y and y < self->height + + def get(self, point: int[2]) -> byte: + assert self->is_in_bounds(point) + x = point[0] + y = point[1] + return self->data[(self->width + 1)*y + x] + + def set(self, point: int[2], value: byte) -> None: + assert self->is_in_bounds(point) + x = point[0] + y = point[1] + self->data[(self->width + 1)*y + x] = value + + def swap(self, a: int[2], b: int[2]) -> None: + old_a = self->get(a) + self->set(a, self->get(b)) + self->set(b, old_a) + + def copy(self) -> Grid: + return Grid{width = self->width, height = self->height, data = strdup(self->data)} + + def transpose(self) -> None: + old = self->copy() + self->width = old.height + self->height = old.width + + self->data = realloc(self->data, (self->width + 1)*self->height + 1) + assert self->data != NULL + + for y = 0; y < self->height; y++: + for x = 0; x < self->width; x++: + self->set([x, y], old.get([y, x])) + self->data[(self->width + 1)*y + self->width] = '\n' + + free(old.data) + self->data[(self->width + 1)*self->height] = '\0' + + # returned array is terminated by [-1, -1] + def find_all(self, b: byte) -> int[2]*: + result: int[2]* = malloc(sizeof(result[0]) * (self->width * self->height + 1)) + result_len = 0 + + for y = 0; y < self->height; y++: + for x = 0; x < self->width; x++: + if self->get([x, y]) == b: + result[result_len++] = [x, y] + + result = realloc(result, sizeof(result[0]) * (result_len + 1)) + result[result_len] = [-1, -1] + return result + + def find_first(self, b: byte) -> int[2]: + for y = 0; y < self->height; y++: + for x = 0; x < self->width; x++: + if self->get([x, y]) == b: + return [x, y] + assert False + + def count(self, b: byte) -> int: + n = 0 + for y = 0; y < self->height; y++: + for x = 0; x < self->width; x++: + if self->get([x, y]) == b: + n++ + return n + + +# Reading stops on end of file or newline, so you can call this repeatedly +# to read multiple blank-line separated grids. +def read_grid_from_file(f: FILE*) -> Grid: + line: byte[5000] + max_size = 10000000 # 10 MB + + result = Grid{data = malloc(max_size)} + result.data[0] = '\0' + + while fgets(line, sizeof(line) as int, f) != NULL: + trim_ascii_whitespace(line) + if line[0] == '\0': + break + + if result.height == 0: # set width on first round + result.width = strlen(line) as int + assert result.width == strlen(line) + result.height++ + + assert result.width * result.height < max_size + strcat(result.data, line) + strcat(result.data, "\n") + + assert result.width != 0 and result.height != 0 + assert strlen(result.data) == (result.width + 1)*result.height + result.data = realloc(result.data, strlen(result.data) + 1) + return result From 329e1fd098b8217cf5b1251942646b05fcc516d3 Mon Sep 17 00:00:00 2001 From: Akuli Date: Thu, 5 Dec 2024 02:50:14 +0200 Subject: [PATCH 06/14] part 2 not working on real input --- examples/aoc2024/day04/part2.jou | 4 ++-- examples/aoc2024/day04/part2_templates.txt | 16 ---------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/examples/aoc2024/day04/part2.jou b/examples/aoc2024/day04/part2.jou index 1510c30c..0bd2d8b8 100644 --- a/examples/aoc2024/day04/part2.jou +++ b/examples/aoc2024/day04/part2.jou @@ -31,14 +31,14 @@ def main() -> int: templates[num_templates++] = read_grid_from_file(f) fclose(f) - f = fopen("input", "r") + f = fopen("sampleinput.txt", "r") grid = read_grid_from_file(f) fclose(f) result = 0 for i = 0; i < num_templates; i++: result += count_template(&grid, &templates[i]) - printf("%d\n", result) + printf("%d\n", result) # Output: 9 for i = 0; i < num_templates; i++: free(templates[i].data) diff --git a/examples/aoc2024/day04/part2_templates.txt b/examples/aoc2024/day04/part2_templates.txt index 538d3e6f..0d9a6fa0 100644 --- a/examples/aoc2024/day04/part2_templates.txt +++ b/examples/aoc2024/day04/part2_templates.txt @@ -13,19 +13,3 @@ S.M M.M .A. S.S - -.M. -MAS -.S. - -.S. -MAS -.M. - -.M. -SAM -.S. - -.S. -SAM -.M. From 7759ce90f530eb9cbbe8081d1bf267fa0f07f188 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 8 Dec 2024 00:45:35 +0200 Subject: [PATCH 07/14] fixed lol... omg --- examples/aoc2024/day04/part2.jou | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/aoc2024/day04/part2.jou b/examples/aoc2024/day04/part2.jou index 0bd2d8b8..50193dd6 100644 --- a/examples/aoc2024/day04/part2.jou +++ b/examples/aoc2024/day04/part2.jou @@ -8,7 +8,7 @@ import "stdlib/mem.jou" def count_template(grid: Grid*, template: Grid*) -> int: count = 0 for ox = 0; ox <= grid->width - template->width; ox++: - for oy = 0; oy < grid->height - template->height; oy++: + for oy = 0; oy <= grid->height - template->height; oy++: all_match = True for x = 0; x < template->width; x++: for y = 0; y < template->height; y++: From 3325dd4f6e9f695a81c62b897ade2b8495b67439 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 8 Dec 2024 01:27:37 +0200 Subject: [PATCH 08/14] day 5 --- examples/aoc2024/day05/part1.jou | 120 +++++++++++++++++++++++ examples/aoc2024/day05/part2.jou | 126 +++++++++++++++++++++++++ examples/aoc2024/day05/sampleinput.txt | 28 ++++++ 3 files changed, 274 insertions(+) create mode 100644 examples/aoc2024/day05/part1.jou create mode 100644 examples/aoc2024/day05/part2.jou create mode 100644 examples/aoc2024/day05/sampleinput.txt diff --git a/examples/aoc2024/day05/part1.jou b/examples/aoc2024/day05/part1.jou new file mode 100644 index 00000000..faa1f6da --- /dev/null +++ b/examples/aoc2024/day05/part1.jou @@ -0,0 +1,120 @@ +import "stdlib/io.jou" +import "stdlib/mem.jou" +import "stdlib/ascii.jou" +import "stdlib/str.jou" + + +def read_rules(file: FILE*, nrules: int*) -> int[2]*: + *nrules = 0 + + max_rules = 2000 + rules: int[2]* = malloc(sizeof(rules[0]) * max_rules) + assert rules != NULL + + line: byte[100] + while fgets(line, sizeof(line) as int, file) != NULL: + trim_ascii_whitespace(line) + if line[0] == '\0': + # This is the blank line that separates rules and jobs + return rules + + rule: int[2] + r = sscanf(line, "%d|%d", &rule[0], &rule[1]) + assert r == 2 + + assert *nrules < max_rules + rules[*nrules] = rule + ++*nrules + + return rules + + +# Each returned print job is terminated by -1 +def read_print_jobs(file: FILE*, njobs: int*) -> int[100]*: + *njobs = 0 + + max_jobs = 500 + jobs: int[100]* = malloc(sizeof(jobs[0]) * max_jobs) + assert jobs != NULL + + line: byte[100] + while fgets(line, sizeof(line) as int, file) != NULL: + trim_ascii_whitespace(line) + job: int[100] + num_pages = 0 + + p: byte* = line + while True: + assert num_pages < sizeof(job)/sizeof(job[0]) + job[num_pages++] = atoi(p) + p = strstr(p, ",") + if p == NULL: + break + p++ # skip comma + + assert num_pages < sizeof(job)/sizeof(job[0]) + job[num_pages] = -1 + + assert *njobs < max_jobs + jobs[(*njobs)++] = job + + return jobs + + +def find_page(job: int*, value: int) -> int: + for i = 0; job[i] != -1; i++: + if job[i] == value: + return i + return -1 + + +def job_is_valid(rules: int[2]*, nrules: int, job: int*) -> bool: + for i = 0; i < nrules; i++: + first_idx = find_page(job, rules[i][0]) + second_idx = find_page(job, rules[i][1]) + if first_idx != -1 and second_idx != -1 and first_idx >= second_idx: + return False + return True + + +def main() -> int: + f = fopen("sampleinput.txt", "r") + assert f != NULL + + nrules: int + rules = read_rules(f, &nrules) + + njobs: int + jobs = read_print_jobs(f, &njobs) + +# for i = 0; i < nrules; i++: +# printf("Rule %d: %d|%d\n", i, rules[i][0], rules[i][1]) +# +# for i = 0; i < njobs; i++: +# printf("Job %d", i) +# if job_is_valid(rules, nrules, jobs[i]): +# printf(" VALID") +# else: +# printf(" invalid") +# printf(": ") +# for k = 0; jobs[i][k] != -1; k++: +# if k != 0: +# printf(",") +# printf("%d", jobs[i][k]) +# printf("\n") + + midsum = 0L + for i = 0; i < njobs; i++: + job = jobs[i] + if job_is_valid(rules, nrules, job): + n = 0 + while job[n] != -1: + n++ + assert n % 2 == 1 + midsum += job[(n - 1) / 2] + + printf("%d\n", midsum) # Output: 143 + + free(rules) + free(jobs) + return 0 diff --git a/examples/aoc2024/day05/part2.jou b/examples/aoc2024/day05/part2.jou new file mode 100644 index 00000000..2b2f82c7 --- /dev/null +++ b/examples/aoc2024/day05/part2.jou @@ -0,0 +1,126 @@ +import "stdlib/io.jou" +import "stdlib/mem.jou" +import "stdlib/ascii.jou" +import "stdlib/str.jou" + + +def read_rules(file: FILE*, nrules: int*) -> int[2]*: + *nrules = 0 + + max_rules = 2000 + rules: int[2]* = malloc(sizeof(rules[0]) * max_rules) + assert rules != NULL + + line: byte[100] + while fgets(line, sizeof(line) as int, file) != NULL: + trim_ascii_whitespace(line) + if line[0] == '\0': + # This is the blank line that separates rules and jobs + return rules + + rule: int[2] + r = sscanf(line, "%d|%d", &rule[0], &rule[1]) + assert r == 2 + + assert *nrules < max_rules + rules[*nrules] = rule + ++*nrules + + return rules + + +# Each returned print job is terminated by -1 +def read_print_jobs(file: FILE*, njobs: int*) -> int[100]*: + *njobs = 0 + + max_jobs = 500 + jobs: int[100]* = malloc(sizeof(jobs[0]) * max_jobs) + assert jobs != NULL + + line: byte[100] + while fgets(line, sizeof(line) as int, file) != NULL: + trim_ascii_whitespace(line) + job: int[100] + num_pages = 0 + + p: byte* = line + while True: + assert num_pages < sizeof(job)/sizeof(job[0]) + job[num_pages++] = atoi(p) + p = strstr(p, ",") + if p == NULL: + break + p++ # skip comma + + assert num_pages < sizeof(job)/sizeof(job[0]) + job[num_pages] = -1 + + assert *njobs < max_jobs + jobs[(*njobs)++] = job + + return jobs + + +def find_page(job: int*, value: int) -> int: + for i = 0; job[i] != -1; i++: + if job[i] == value: + return i + return -1 + + +def job_is_valid(rules: int[2]*, nrules: int, job: int*) -> bool: + for i = 0; i < nrules; i++: + first_idx = find_page(job, rules[i][0]) + second_idx = find_page(job, rules[i][1]) + if first_idx != -1 and second_idx != -1 and first_idx >= second_idx: + return False + return True + + +def swap(a: int*, b: int*) -> None: + old_a = *a + *a = *b + *b = old_a + + +def fix_job(rules: int[2]*, nrules: int, job: int*) -> None: + length = 0 + while job[length] != -1: + length++ + + # super dumb, swap until it's ok + while not job_is_valid(rules, nrules, job): + for i = 0; i < nrules; i++: + rule = rules[i] + first_idx = find_page(job, rule[0]) + second_idx = find_page(job, rule[1]) + if first_idx != -1 and second_idx != -1 and first_idx >= second_idx: + swap(&job[first_idx], &job[second_idx]) + + +def main() -> int: + f = fopen("sampleinput.txt", "r") + assert f != NULL + + nrules: int + rules = read_rules(f, &nrules) + + njobs: int + jobs = read_print_jobs(f, &njobs) + + midsum = 0L + for i = 0; i < njobs; i++: + job = jobs[i] + if not job_is_valid(rules, nrules, job): + fix_job(rules, nrules, job) + n = 0 + while job[n] != -1: + n++ + assert n % 2 == 1 + midsum += job[(n - 1) / 2] + + printf("%d\n", midsum) # Output: 123 + + free(rules) + free(jobs) + return 0 diff --git a/examples/aoc2024/day05/sampleinput.txt b/examples/aoc2024/day05/sampleinput.txt new file mode 100644 index 00000000..9d146d67 --- /dev/null +++ b/examples/aoc2024/day05/sampleinput.txt @@ -0,0 +1,28 @@ +47|53 +97|13 +97|61 +97|47 +75|29 +61|13 +75|53 +29|13 +97|29 +53|29 +61|53 +97|53 +61|29 +47|13 +75|47 +97|75 +47|61 +75|61 +47|29 +75|13 +53|13 + +75,47,61,53,29 +97,61,53,29,13 +75,29,13 +75,97,47,61,53 +61,13,29 +97,13,75,29,47 From 298160d2632d26808ceb5cf49990f22ec0bdc4d5 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 8 Dec 2024 01:47:56 +0200 Subject: [PATCH 09/14] day6 --- examples/aoc2024/day06/part1.jou | 29 +++++++++++++ examples/aoc2024/day06/part2.jou | 56 ++++++++++++++++++++++++++ examples/aoc2024/day06/sampleinput.txt | 10 +++++ 3 files changed, 95 insertions(+) create mode 100644 examples/aoc2024/day06/part1.jou create mode 100644 examples/aoc2024/day06/part2.jou create mode 100644 examples/aoc2024/day06/sampleinput.txt diff --git a/examples/aoc2024/day06/part1.jou b/examples/aoc2024/day06/part1.jou new file mode 100644 index 00000000..a9ae56b8 --- /dev/null +++ b/examples/aoc2024/day06/part1.jou @@ -0,0 +1,29 @@ +import "../grid.jou" +import "stdlib/io.jou" +import "stdlib/mem.jou" + + +def main() -> int: + f = fopen("sampleinput.txt", "r") + grid = read_grid_from_file(f) + fclose(f) + + pos = grid.find_first('^') + movement = [0, -1] # up + + while True: + grid.set(pos, 'X') + + new_pos = [pos[0] + movement[0], pos[1] + movement[1]] + if not grid.is_in_bounds(new_pos): + break + elif grid.get(new_pos) == '#': + # turn right 90deg + movement = [-movement[1], movement[0]] + else: + pos = new_pos + + printf("%d\n", grid.count('X')) # Output: 41 + + free(grid.data) + return 0 diff --git a/examples/aoc2024/day06/part2.jou b/examples/aoc2024/day06/part2.jou new file mode 100644 index 00000000..eb6ee99e --- /dev/null +++ b/examples/aoc2024/day06/part2.jou @@ -0,0 +1,56 @@ +import "../grid.jou" +import "stdlib/io.jou" +import "stdlib/mem.jou" + + +def we_gonna_get_stuck(grid: Grid*) -> bool: + # Order: [up, right, down, left] (rotates clockwise) + dx = [0, 1, 0, -1] + dy = [-1, 0, 1, 0] + visited = [grid->copy(), grid->copy(), grid->copy(), grid->copy()] + + pos = grid->find_first('^') + movement_kind = 0 + got_stuck = False + + while True: + if visited[movement_kind].get(pos) == 'X': + # We saw the same exact move before. + got_stuck = True + break + visited[movement_kind].set(pos, 'X') + + new_pos = [pos[0] + dx[movement_kind], pos[1] + dy[movement_kind]] + if not grid->is_in_bounds(new_pos): + break + elif grid->get(new_pos) == '#': + # turn right 90deg + movement_kind = (movement_kind + 1) % 4 + else: + pos = new_pos + + free(visited[0].data) + free(visited[1].data) + free(visited[2].data) + free(visited[3].data) + return got_stuck + + +def main() -> int: + f = fopen("sampleinput.txt", "r") + grid = read_grid_from_file(f) + fclose(f) + + counter = 0 + for p = grid.data; *p != '\0'; p++: + if *p == '.': + # Place obstacle here + *p = '#' + if we_gonna_get_stuck(&grid): + counter++ + *p = '.' + + printf("%d\n", counter) # Output: 6 + + free(grid.data) + return 0 diff --git a/examples/aoc2024/day06/sampleinput.txt b/examples/aoc2024/day06/sampleinput.txt new file mode 100644 index 00000000..a4eb402c --- /dev/null +++ b/examples/aoc2024/day06/sampleinput.txt @@ -0,0 +1,10 @@ +....#..... +.........# +.......... +..#....... +.......#.. +.......... +.#..^..... +........#. +#......... +......#... From d0aab6b2bdcfa34d2b0fc9ac79f37cd72fb1cfc0 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 8 Dec 2024 01:48:17 +0200 Subject: [PATCH 10/14] fix whitespace --- examples/aoc2024/day06/part1.jou | 2 +- examples/aoc2024/day06/part2.jou | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/aoc2024/day06/part1.jou b/examples/aoc2024/day06/part1.jou index a9ae56b8..7fcc92e2 100644 --- a/examples/aoc2024/day06/part1.jou +++ b/examples/aoc2024/day06/part1.jou @@ -24,6 +24,6 @@ def main() -> int: pos = new_pos printf("%d\n", grid.count('X')) # Output: 41 - + free(grid.data) return 0 diff --git a/examples/aoc2024/day06/part2.jou b/examples/aoc2024/day06/part2.jou index eb6ee99e..72e98289 100644 --- a/examples/aoc2024/day06/part2.jou +++ b/examples/aoc2024/day06/part2.jou @@ -51,6 +51,6 @@ def main() -> int: *p = '.' printf("%d\n", counter) # Output: 6 - + free(grid.data) return 0 From fe677bcf0de398d18d2516b82a0781331c76f157 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 8 Dec 2024 02:28:14 +0200 Subject: [PATCH 11/14] day 7 --- examples/aoc2024/day07/part1.jou | 79 +++++++++++++++++++ examples/aoc2024/day07/part2.jou | 105 +++++++++++++++++++++++++ examples/aoc2024/day07/sampleinput.txt | 9 +++ 3 files changed, 193 insertions(+) create mode 100644 examples/aoc2024/day07/part1.jou create mode 100644 examples/aoc2024/day07/part2.jou create mode 100644 examples/aoc2024/day07/sampleinput.txt diff --git a/examples/aoc2024/day07/part1.jou b/examples/aoc2024/day07/part1.jou new file mode 100644 index 00000000..0326de65 --- /dev/null +++ b/examples/aoc2024/day07/part1.jou @@ -0,0 +1,79 @@ +import "stdlib/mem.jou" +import "stdlib/io.jou" +import "stdlib/str.jou" + + +class Equation: + expected_result: long + values: long[100] + nvalues: int + + def is_satisfiable(self) -> bool: + assert self->nvalues > 0 + results: long* = malloc(sizeof(results[0]) * 1) + assert results != NULL + results[0] = self->values[0] + nresults = 1 + + for value = &self->values[1]; value < &self->values[self->nvalues]; value++: + if nresults == 0: + break + + new_results: long* = malloc(sizeof(new_results[0]) * (nresults * 2)) + assert new_results != NULL + new_nresults = 0 + + # Let's try plus + for i = 0; i < nresults; i++: + r = results[i] + (*value) + assert r >= results[i] + # if too big already, no way it will be ok later + if r <= self->expected_result: + new_results[new_nresults++] = r + + # Let's try multiplying + for i = 0; i < nresults; i++: + r = results[i] * (*value) + assert r >= results[i] + # if too big already, no way it will be ok later + if r <= self->expected_result: + new_results[new_nresults++] = r + + free(results) + results = new_results + nresults = new_nresults + + found = False + for i = 0; i < nresults; i++: + if results[i] == self->expected_result: + found = True + break + + free(results) + return found + + +def main() -> int: + f = fopen("sampleinput.txt", "r") + assert f != NULL + + result = 0L + + line: byte[100] + while fgets(line, sizeof(line) as int, f) != NULL: + eq = Equation{expected_result = atoll(line)} + + # Remaining numbers are always after a space + p = &line[0] + while strstr(p, " ") != NULL: + p = strstr(p, " ") + p++ # skip space + assert eq.nvalues < sizeof(eq.values)/sizeof(eq.values[0]) + eq.values[eq.nvalues++] = atoll(p) + + if eq.is_satisfiable(): + result += eq.expected_result + + fclose(f) + printf("%lld\n", result) # Output: 3749 + return 0 diff --git a/examples/aoc2024/day07/part2.jou b/examples/aoc2024/day07/part2.jou new file mode 100644 index 00000000..42f35110 --- /dev/null +++ b/examples/aoc2024/day07/part2.jou @@ -0,0 +1,105 @@ +import "stdlib/mem.jou" +import "stdlib/io.jou" +import "stdlib/str.jou" + + +# Example: length_of_a_number(69420) == 5 +def length_of_a_number(x: long) -> int: + assert x > 0 + result = 0 + while x != 0: + x /= 10 + result++ + return result + + +# Example: concat(69, 420) == 69420 +def concat(a: long, b: long) -> long: + b_len = length_of_a_number(b) + while b_len --> 0: + a *= 10 + return a + b + + +class Equation: + expected_result: long + values: long[100] + nvalues: int + + def is_satisfiable(self) -> bool: + assert self->nvalues > 0 + results: long* = malloc(sizeof(results[0]) * 1) + assert results != NULL + results[0] = self->values[0] + nresults = 1 + + for value = &self->values[1]; value < &self->values[self->nvalues]; value++: + if nresults == 0: + break + + new_results: long* = malloc(sizeof(new_results[0]) * (nresults * 3)) + assert new_results != NULL + new_nresults = 0 + + # Let's try plus + for i = 0; i < nresults; i++: + r = results[i] + (*value) + assert r >= results[i] + # if too big already, no way it will be ok later + if r <= self->expected_result: + new_results[new_nresults++] = r + + # Let's try multiplying + for i = 0; i < nresults; i++: + r = results[i] * (*value) + assert r >= results[i] + # if too big already, no way it will be ok later + if r <= self->expected_result: + new_results[new_nresults++] = r + + # Let's try concatenating + for i = 0; i < nresults; i++: + r = concat(results[i], *value) + assert r >= results[i] + # if too big already, no way it will be ok later + if r <= self->expected_result: + new_results[new_nresults++] = r + + free(results) + results = new_results + nresults = new_nresults + + found = False + for i = 0; i < nresults; i++: + if results[i] == self->expected_result: + found = True + break + + free(results) + return found + + +def main() -> int: + f = fopen("sampleinput.txt", "r") + assert f != NULL + + result = 0L + + line: byte[100] + while fgets(line, sizeof(line) as int, f) != NULL: + eq = Equation{expected_result = atoll(line)} + + # Remaining numbers are always after a space + p = &line[0] + while strstr(p, " ") != NULL: + p = strstr(p, " ") + p++ # skip space + assert eq.nvalues < sizeof(eq.values)/sizeof(eq.values[0]) + eq.values[eq.nvalues++] = atoll(p) + + if eq.is_satisfiable(): + result += eq.expected_result + + fclose(f) + printf("%lld\n", result) # Output: 11387 + return 0 diff --git a/examples/aoc2024/day07/sampleinput.txt b/examples/aoc2024/day07/sampleinput.txt new file mode 100644 index 00000000..fc6e099d --- /dev/null +++ b/examples/aoc2024/day07/sampleinput.txt @@ -0,0 +1,9 @@ +190: 10 19 +3267: 81 40 27 +83: 17 5 +156: 15 6 +7290: 6 8 6 15 +161011: 16 10 13 +192: 17 8 14 +21037: 9 7 18 13 +292: 11 6 16 20 From 727c74c45ce00ab6b2723bc6ea43b94d40d4a029 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 8 Dec 2024 02:44:23 +0200 Subject: [PATCH 12/14] Update examples/aoc2024/day03/part2.jou --- examples/aoc2024/day03/part2.jou | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/aoc2024/day03/part2.jou b/examples/aoc2024/day03/part2.jou index ba2eec01..a889ae0f 100644 --- a/examples/aoc2024/day03/part2.jou +++ b/examples/aoc2024/day03/part2.jou @@ -48,7 +48,7 @@ def main() -> int: max_size = 100000 big_string: byte* = malloc(max_size) - f = fopen("sampleinput.txt", "r") + f = fopen("sampleinput2.txt", "r") assert f != NULL i = 0 From a2f7422a387f1006b889f6ad85b764884f9d44e1 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 8 Dec 2024 02:52:31 +0200 Subject: [PATCH 13/14] Local valgrind + review fixes --- examples/aoc2024/day03/part1.jou | 3 +++ examples/aoc2024/day03/part2.jou | 3 +++ examples/aoc2024/day04/part1.jou | 1 + examples/aoc2024/day04/part2.jou | 2 +- examples/aoc2024/day05/part1.jou | 17 +---------------- examples/aoc2024/day05/part2.jou | 3 ++- 6 files changed, 11 insertions(+), 18 deletions(-) diff --git a/examples/aoc2024/day03/part1.jou b/examples/aoc2024/day03/part1.jou index 4fe0abe3..218149da 100644 --- a/examples/aoc2024/day03/part1.jou +++ b/examples/aoc2024/day03/part1.jou @@ -44,6 +44,9 @@ def main() -> int: assert i < max_size big_string[i++] = c as byte + assert i < max_size + big_string[i] = '\0' + fclose(f) result = 0 as long diff --git a/examples/aoc2024/day03/part2.jou b/examples/aoc2024/day03/part2.jou index a889ae0f..8e94d93a 100644 --- a/examples/aoc2024/day03/part2.jou +++ b/examples/aoc2024/day03/part2.jou @@ -60,6 +60,9 @@ def main() -> int: assert i < max_size big_string[i++] = c as byte + assert i < max_size + big_string[i] = '\0' + fclose(f) remove_disabled_sections(big_string) diff --git a/examples/aoc2024/day04/part1.jou b/examples/aoc2024/day04/part1.jou index 7fc60c9a..77272720 100644 --- a/examples/aoc2024/day04/part1.jou +++ b/examples/aoc2024/day04/part1.jou @@ -53,4 +53,5 @@ def main() -> int: diagonal = count_diagonals(&grid) printf("%d\n", horizontal + vertical + diagonal) # Output: 18 + free(grid.data) return 0 diff --git a/examples/aoc2024/day04/part2.jou b/examples/aoc2024/day04/part2.jou index 50193dd6..5c2d1d47 100644 --- a/examples/aoc2024/day04/part2.jou +++ b/examples/aoc2024/day04/part2.jou @@ -42,5 +42,5 @@ def main() -> int: for i = 0; i < num_templates; i++: free(templates[i].data) - + free(grid.data) return 0 diff --git a/examples/aoc2024/day05/part1.jou b/examples/aoc2024/day05/part1.jou index faa1f6da..b9e8be3c 100644 --- a/examples/aoc2024/day05/part1.jou +++ b/examples/aoc2024/day05/part1.jou @@ -39,7 +39,6 @@ def read_print_jobs(file: FILE*, njobs: int*) -> int[100]*: line: byte[100] while fgets(line, sizeof(line) as int, file) != NULL: - trim_ascii_whitespace(line) job: int[100] num_pages = 0 @@ -87,21 +86,7 @@ def main() -> int: njobs: int jobs = read_print_jobs(f, &njobs) -# for i = 0; i < nrules; i++: -# printf("Rule %d: %d|%d\n", i, rules[i][0], rules[i][1]) -# -# for i = 0; i < njobs; i++: -# printf("Job %d", i) -# if job_is_valid(rules, nrules, jobs[i]): -# printf(" VALID") -# else: -# printf(" invalid") -# printf(": ") -# for k = 0; jobs[i][k] != -1; k++: -# if k != 0: -# printf(",") -# printf("%d", jobs[i][k]) -# printf("\n") + fclose(f) midsum = 0L for i = 0; i < njobs; i++: diff --git a/examples/aoc2024/day05/part2.jou b/examples/aoc2024/day05/part2.jou index 2b2f82c7..aa8efa9d 100644 --- a/examples/aoc2024/day05/part2.jou +++ b/examples/aoc2024/day05/part2.jou @@ -39,7 +39,6 @@ def read_print_jobs(file: FILE*, njobs: int*) -> int[100]*: line: byte[100] while fgets(line, sizeof(line) as int, file) != NULL: - trim_ascii_whitespace(line) job: int[100] num_pages = 0 @@ -108,6 +107,8 @@ def main() -> int: njobs: int jobs = read_print_jobs(f, &njobs) + fclose(f) + midsum = 0L for i = 0; i < njobs; i++: job = jobs[i] From f29485c2a4718159b625fcf93e505dca1df64bdc Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 8 Dec 2024 23:13:11 +0200 Subject: [PATCH 14/14] Delete duplicate grid.jou --- examples/aoc2024/day04/part1.jou | 2 +- examples/aoc2024/day04/part2.jou | 2 +- examples/aoc2024/day06/part1.jou | 2 +- examples/aoc2024/day06/part2.jou | 2 +- examples/aoc2024/grid.jou | 112 ------------------------------- 5 files changed, 4 insertions(+), 116 deletions(-) delete mode 100644 examples/aoc2024/grid.jou diff --git a/examples/aoc2024/day04/part1.jou b/examples/aoc2024/day04/part1.jou index 77272720..4243c0d3 100644 --- a/examples/aoc2024/day04/part1.jou +++ b/examples/aoc2024/day04/part1.jou @@ -1,4 +1,4 @@ -import "../grid.jou" +import "../../aoc2023/grid.jou" import "stdlib/str.jou" import "stdlib/mem.jou" import "stdlib/io.jou" diff --git a/examples/aoc2024/day04/part2.jou b/examples/aoc2024/day04/part2.jou index 5c2d1d47..9ff77eb3 100644 --- a/examples/aoc2024/day04/part2.jou +++ b/examples/aoc2024/day04/part2.jou @@ -1,4 +1,4 @@ -import "../grid.jou" +import "../../aoc2023/grid.jou" import "stdlib/io.jou" import "stdlib/mem.jou" diff --git a/examples/aoc2024/day06/part1.jou b/examples/aoc2024/day06/part1.jou index 7fcc92e2..e8c281be 100644 --- a/examples/aoc2024/day06/part1.jou +++ b/examples/aoc2024/day06/part1.jou @@ -1,4 +1,4 @@ -import "../grid.jou" +import "../../aoc2023/grid.jou" import "stdlib/io.jou" import "stdlib/mem.jou" diff --git a/examples/aoc2024/day06/part2.jou b/examples/aoc2024/day06/part2.jou index 72e98289..bebf84ba 100644 --- a/examples/aoc2024/day06/part2.jou +++ b/examples/aoc2024/day06/part2.jou @@ -1,4 +1,4 @@ -import "../grid.jou" +import "../../aoc2023/grid.jou" import "stdlib/io.jou" import "stdlib/mem.jou" diff --git a/examples/aoc2024/grid.jou b/examples/aoc2024/grid.jou deleted file mode 100644 index 045ab451..00000000 --- a/examples/aoc2024/grid.jou +++ /dev/null @@ -1,112 +0,0 @@ -# This file contains a utility class for AoC solutions. -# It is not in the standard library because it feels too AoC-specific to me. - -import "stdlib/ascii.jou" -import "stdlib/str.jou" -import "stdlib/mem.jou" -import "stdlib/io.jou" - - -class Grid: - width: int - height: int - data: byte* - - def is_in_bounds(self, point: int[2]) -> bool: - x = point[0] - y = point[1] - return 0 <= x and x < self->width and 0 <= y and y < self->height - - def get(self, point: int[2]) -> byte: - assert self->is_in_bounds(point) - x = point[0] - y = point[1] - return self->data[(self->width + 1)*y + x] - - def set(self, point: int[2], value: byte) -> None: - assert self->is_in_bounds(point) - x = point[0] - y = point[1] - self->data[(self->width + 1)*y + x] = value - - def swap(self, a: int[2], b: int[2]) -> None: - old_a = self->get(a) - self->set(a, self->get(b)) - self->set(b, old_a) - - def copy(self) -> Grid: - return Grid{width = self->width, height = self->height, data = strdup(self->data)} - - def transpose(self) -> None: - old = self->copy() - self->width = old.height - self->height = old.width - - self->data = realloc(self->data, (self->width + 1)*self->height + 1) - assert self->data != NULL - - for y = 0; y < self->height; y++: - for x = 0; x < self->width; x++: - self->set([x, y], old.get([y, x])) - self->data[(self->width + 1)*y + self->width] = '\n' - - free(old.data) - self->data[(self->width + 1)*self->height] = '\0' - - # returned array is terminated by [-1, -1] - def find_all(self, b: byte) -> int[2]*: - result: int[2]* = malloc(sizeof(result[0]) * (self->width * self->height + 1)) - result_len = 0 - - for y = 0; y < self->height; y++: - for x = 0; x < self->width; x++: - if self->get([x, y]) == b: - result[result_len++] = [x, y] - - result = realloc(result, sizeof(result[0]) * (result_len + 1)) - result[result_len] = [-1, -1] - return result - - def find_first(self, b: byte) -> int[2]: - for y = 0; y < self->height; y++: - for x = 0; x < self->width; x++: - if self->get([x, y]) == b: - return [x, y] - assert False - - def count(self, b: byte) -> int: - n = 0 - for y = 0; y < self->height; y++: - for x = 0; x < self->width; x++: - if self->get([x, y]) == b: - n++ - return n - - -# Reading stops on end of file or newline, so you can call this repeatedly -# to read multiple blank-line separated grids. -def read_grid_from_file(f: FILE*) -> Grid: - line: byte[5000] - max_size = 10000000 # 10 MB - - result = Grid{data = malloc(max_size)} - result.data[0] = '\0' - - while fgets(line, sizeof(line) as int, f) != NULL: - trim_ascii_whitespace(line) - if line[0] == '\0': - break - - if result.height == 0: # set width on first round - result.width = strlen(line) as int - assert result.width == strlen(line) - result.height++ - - assert result.width * result.height < max_size - strcat(result.data, line) - strcat(result.data, "\n") - - assert result.width != 0 and result.height != 0 - assert strlen(result.data) == (result.width + 1)*result.height - result.data = realloc(result.data, strlen(result.data) + 1) - return result