diff --git a/examples/aoc2024/day15/part1.jou b/examples/aoc2024/day15/part1.jou index f7fb4365..7af0f769 100644 --- a/examples/aoc2024/day15/part1.jou +++ b/examples/aoc2024/day15/part1.jou @@ -4,7 +4,7 @@ import "stdlib/str.jou" import "../../aoc2023/grid.jou" -def move_right(grid: Grid*, start: byte*) -> None: +def move_right(start: byte*) -> None: assert start != NULL assert *start == '@' @@ -36,19 +36,19 @@ def horizontal_mirror(grid: Grid*) -> None: def move(grid: Grid*, how: byte) -> None: if how == '>': - move_right(grid, strstr(grid->data, "@")) + move_right(strstr(grid->data, "@")) elif how == 'v': grid->transpose() - move_right(grid, strstr(grid->data, "@")) + move_right(strstr(grid->data, "@")) grid->transpose() elif how == '<': horizontal_mirror(grid) - move_right(grid, strstr(grid->data, "@")) + move_right(strstr(grid->data, "@")) horizontal_mirror(grid) elif how == '^': grid->transpose() horizontal_mirror(grid) - move_right(grid, strstr(grid->data, "@")) + move_right(strstr(grid->data, "@")) horizontal_mirror(grid) grid->transpose() else: @@ -56,7 +56,7 @@ def move(grid: Grid*, how: byte) -> None: def main() -> int: - f = fopen("sampleinput.txt", "r") + f = fopen("sampleinput1.txt", "r") assert f != NULL grid = read_grid_from_file(f) diff --git a/examples/aoc2024/day15/part2.jou b/examples/aoc2024/day15/part2.jou new file mode 100644 index 00000000..882f3d3b --- /dev/null +++ b/examples/aoc2024/day15/part2.jou @@ -0,0 +1,190 @@ +import "stdlib/io.jou" +import "stdlib/mem.jou" +import "stdlib/str.jou" +import "../../aoc2023/grid.jou" + + +def move_right(start: byte*) -> None: + assert start != NULL + assert *start == '@' + + relevant_length = strspn(start, "@.[]") + + first_blank = -1 + for i = 0; i < relevant_length; i++: + if start[i] == '.': + first_blank = i + break + + if first_blank == -1: + # no room to move, do nothing + return + + # shift boxes to the right + memmove(&start[2], &start[1], first_blank - 1) + start[0] = '.' + start[1] = '@' + + +# x_left and y specify the location of "[" part of box +def can_move_box_up(grid: Grid*, x: int, y: int) -> bool: + if grid->get([x, y]) == '[': + x_left = x + x_right = x+1 + elif grid->get([x, y]) == ']': + x_left = x-1 + x_right = x + else: + assert False + + if grid->get([x_left, y-1]) == '#' or grid->get([x_right, y-1]) == '#': + # bumping into wall + return False + + for x = x_left; x <= x_right; x++: + if strchr("[]", grid->get([x, y-1])) != NULL and not can_move_box_up(grid, x, y-1): + # Some kind of box (aligned or not) above, and it won't move. + return False + + return True + + +def move_box_up(grid: Grid*, x: int, y: int) -> None: + if grid->get([x, y]) == '[': + x_left = x + x_right = x+1 + elif grid->get([x, y]) == ']': + x_left = x-1 + x_right = x + else: + assert False + + for x = x_left; x <= x_right; x++: + if strchr("[]", grid->get([x, y-1])) != NULL: + move_box_up(grid, x, y-1) + + assert grid->get([x_left, y-1]) == '.' + assert grid->get([x_right, y-1]) == '.' + assert grid->get([x_left, y]) == '[' + assert grid->get([x_right, y]) == ']' + + grid->set([x_left, y-1], '[') + grid->set([x_right, y-1], ']') + grid->set([x_left, y], '.') + grid->set([x_right, y], '.') + + +def can_move_up(grid: Grid*) -> bool: + pos: int[2] = grid->find_first('@') + above = [pos[0], pos[1] - 1] + + return ( + grid->get(above) == '.' + or ( + strchr("[]", grid->get(above)) != NULL + and can_move_box_up(grid, above[0], above[1]) + ) + ) + + +def move_up(grid: Grid*) -> None: + pos: int[2] = grid->find_first('@') + above = [pos[0], pos[1] - 1] + + if strchr("[]", grid->get(above)) != NULL: + move_box_up(grid, above[0], above[1]) + + assert grid->get(above) == '.' + assert grid->get(pos) == '@' + + grid->set(above, '@') + grid->set(pos, '.') + + +def horizontal_mirror(grid: Grid*) -> None: + bytes_per_row = grid->width + 1 + for y = 0; y < grid->height; y++: + first = &grid->data[bytes_per_row * y] + last = &first[grid->width - 1] + while first < last: + memswap(first++, last--, 1) + + +def vertical_mirror(grid: Grid*) -> None: + bytes_per_row = grid->width + 1 + first = grid->data + last = &first[bytes_per_row*(grid->height - 1)] + + while first < last: + memswap(first, last, grid->width) + first = &first[bytes_per_row] + last = &last[-bytes_per_row] + + +def move(grid: Grid*, how: byte) -> None: + if how == '>': + move_right(strstr(grid->data, "@")) + elif how == '<': + horizontal_mirror(grid) + move_right(strstr(grid->data, "@")) + horizontal_mirror(grid) + elif how == '^': + if can_move_up(grid): + move_up(grid) + elif how == 'v': + vertical_mirror(grid) + if can_move_up(grid): + move_up(grid) + vertical_mirror(grid) + else: + assert False + + +def double_width(grid: Grid*) -> None: + new_grid = Grid{ + width = 2 * grid->width, + height = grid->height, + data = malloc((2*grid->width + 1)*grid->height + 1), + } + new_grid.data[0] = '\0' + for y = 0; y < grid->height; y++: + for x = 0; x < grid->width; x++: + if grid->get([x, y]) == 'O': + strcat(new_grid.data, "[]") + elif grid->get([x, y]) == '@': + strcat(new_grid.data, "@.") + else: + s = [grid->get([x, y]), grid->get([x, y]), '\0'] + strcat(new_grid.data, s) + strcat(new_grid.data, "\n") + + free(grid->data) + *grid = new_grid + + +def main() -> int: + f = fopen("sampleinput2.txt", "r") + assert f != NULL + grid = read_grid_from_file(f) + double_width(&grid) + + while True: + #getchar() + c = fgetc(f) + if c == -1: # TODO: EOF constant + break + if c == '\n': + continue + move(&grid, c as byte) + + fclose(f) + + result = 0 + for x = 0; x < grid.width; x++: + for y = 0; y < grid.height; y++: + if grid.get([x, y]) == '[': + result += 100*y + x + printf("%d\n", result) # Output: 9021 + + free(grid.data) + return 0 diff --git a/examples/aoc2024/day15/sampleinput.txt b/examples/aoc2024/day15/sampleinput1.txt similarity index 100% rename from examples/aoc2024/day15/sampleinput.txt rename to examples/aoc2024/day15/sampleinput1.txt diff --git a/examples/aoc2024/day15/sampleinput2-simple.txt b/examples/aoc2024/day15/sampleinput2-simple.txt new file mode 100644 index 00000000..6ee6098f --- /dev/null +++ b/examples/aoc2024/day15/sampleinput2-simple.txt @@ -0,0 +1,9 @@ +####### +#...#.# +#.....# +#..OO@# +#..O..# +#.....# +####### + +^v>^vv^v>v<>v^v<<><>>v^v^>^<<<><^ +vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<^<^^>>>^<>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^v^^<^^vv< +<>^^^^>>>v^<>vvv^>^^^vv^^>v<^^^^v<>^>vvvv><>>v^<<^^^^^ +^><^><>>><>^^<<^^v>>><^^>v>>>^v><>^v><<<>vvvv>^<><<>^>< +^>><>^v<><^vvv<^^<><^v<<<><<<^^<^>>^<<<^>>^v^>>^v>vv>^<<^v<>><<><<>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^ +<><^^>^^^<>^vv<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<> +^^>vv<^v^v^<>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<>< +v^^>>><<^^<>>^v^v^<<>^<^v^v><^<<<><<^vv>>v>v^<<^