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/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 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 diff --git a/examples/aoc2024/day03/part1.jou b/examples/aoc2024/day03/part1.jou new file mode 100644 index 00000000..218149da --- /dev/null +++ b/examples/aoc2024/day03/part1.jou @@ -0,0 +1,59 @@ +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("sampleinput1.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 + + assert i < max_size + big_string[i] = '\0' + + 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/part2.jou b/examples/aoc2024/day03/part2.jou new file mode 100644 index 00000000..8e94d93a --- /dev/null +++ b/examples/aoc2024/day03/part2.jou @@ -0,0 +1,77 @@ +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("sampleinput2.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 + + assert i < max_size + big_string[i] = '\0' + + 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/sampleinput1.txt b/examples/aoc2024/day03/sampleinput1.txt new file mode 100644 index 00000000..f274bdae --- /dev/null +++ b/examples/aoc2024/day03/sampleinput1.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)) 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..4243c0d3 --- /dev/null +++ b/examples/aoc2024/day04/part1.jou @@ -0,0 +1,57 @@ +import "../../aoc2023/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 + + free(grid.data) + return 0 diff --git a/examples/aoc2024/day04/part2.jou b/examples/aoc2024/day04/part2.jou new file mode 100644 index 00000000..9ff77eb3 --- /dev/null +++ b/examples/aoc2024/day04/part2.jou @@ -0,0 +1,46 @@ +import "../../aoc2023/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("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) # Output: 9 + + for i = 0; i < num_templates; i++: + free(templates[i].data) + free(grid.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..0d9a6fa0 --- /dev/null +++ b/examples/aoc2024/day04/part2_templates.txt @@ -0,0 +1,15 @@ +M.S +.A. +M.S + +S.S +.A. +M.M + +S.M +.A. +S.M + +M.M +.A. +S.S 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/day05/part1.jou b/examples/aoc2024/day05/part1.jou new file mode 100644 index 00000000..b9e8be3c --- /dev/null +++ b/examples/aoc2024/day05/part1.jou @@ -0,0 +1,105 @@ +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: + 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) + + fclose(f) + + 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..aa8efa9d --- /dev/null +++ b/examples/aoc2024/day05/part2.jou @@ -0,0 +1,127 @@ +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: + 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) + + fclose(f) + + 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 diff --git a/examples/aoc2024/day06/part1.jou b/examples/aoc2024/day06/part1.jou new file mode 100644 index 00000000..e8c281be --- /dev/null +++ b/examples/aoc2024/day06/part1.jou @@ -0,0 +1,29 @@ +import "../../aoc2023/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..bebf84ba --- /dev/null +++ b/examples/aoc2024/day06/part2.jou @@ -0,0 +1,56 @@ +import "../../aoc2023/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 @@ +....#..... +.........# +.......... +..#....... +.......#.. +.......... +.#..^..... +........#. +#......... +......#... 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