diff --git a/.gitignore b/.gitignore index bee8a64..50c1b40 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ __pycache__ +*.txt diff --git a/README.md b/README.md index b239c3c..ee20252 100644 --- a/README.md +++ b/README.md @@ -7,5 +7,8 @@ - Day 5: 1st 25:00, 2nd 1:55:00; Required patience and accuracy - Day 6: 13:54; I was slow because I thought it is much harder? - Day 7: 75:00; leaderboard 16:00... that was just bad; no excuse -- Day 8: 57:00; my input parse function did not consider negative values... -- Day 9: +- Day 8: 25:00; I was doing pretty decent here. +- Day 9: 57:00; my input parse function did not consider negative values... +- Day 10: 180:00; this one was hard for me. +- Day 11: 68:00; okay but not elegant and way too slow ofc. +- Day 12: diff --git a/d10.py b/d10.py new file mode 100644 index 0000000..f06a062 --- /dev/null +++ b/d10.py @@ -0,0 +1,218 @@ +import lib + +EXAMPLE = """ +..F7. +.FJ|. +SJ.L7 +|F--J +LJ... +""" + +EXAMPLE2 = """ +........... +.S-------7. +.|F-----7|. +.||.....||. +.||.....||. +.|L-7.F-J|. +.|..|.|..|. +.L--J.L--J. +........... +""" + +EXAMPLE3 = """ +.......... +.S------7. +.|F----7|. +.||OOOO||. +.||OOOO||. +.|L-7F-J|. +.|II||II|. +.L--JL--J. +.......... +""" + +EXAMPLE4 = """ +FF7FSF7F7F7F7F7F---7 +L|LJ||||||||||||F--J +FL-7LJLJ||||||LJL-77 +F--JF--7||LJLJIF7FJ- +L---JF-JLJIIIIFJLJJ7 +|F|F-JF---7IIIL7L|7| +|FFJF7L7F-JF7IIL---7 +7-L-JL7||F7|L7F-7F7| +L.L7LFJ|||||FJL7||LJ +L7JLJL-JLJLJL--JLJ.L +""" + + +# | is a vertical pipe connecting north and south. +# - is a horizontal pipe connecting east and west. +# L is a 90-degree bend connecting north and east. +# J is a 90-degree bend connecting north and west. +# 7 is a 90-degree bend connecting south and west. +# F is a 90-degree bend connecting south and east. +# . is ground; there is no pipe in this tile. +# S is the starting position of the animal; there is a pipe on this tile, but your sketch doesn't show what shape the pipe has. + +# Mapping of in-direction to out-direction for each piece. +DIRS = { + '|': { + (1, 0): (1, 0), + (-1, 0): (-1, 0), + }, + '-': { + (0, -1): (0, -1), + (0, 1): (0, 1), + }, + 'L': { + (1, 0): (0, 1), + (0, -1): (-1, 0), + }, + 'J': { + (0, 1): (-1, 0), + (1, 0): (0, -1), + }, + '7': { + (0, 1): (1, 0), + (-1, 0): (0, -1), + }, + 'F': { + (-1, 0): (0, 1), + (0, -1): (1, 0), + } +} + +RIGHTS = { + '|': { + (1, 0): [(0, -1)], + (-1, 0): [(0, 1)], + }, + '-': { + (0, -1): [(-1, 0)], + (0, 1): [(1, 0)], + }, + 'L': { + (1, 0): [(0, -1), (1, 0)], + (0, -1): [(-1, 1)], + }, + 'J': { + (0, 1): [(1, 0), (0, 1)], + (1, 0): [(-1, -1)], + }, + '7': { + (0, 1): [(1, -1)], + (-1, 0): [(0, 1), (-1, 0)], + }, + 'F': { + (-1, 0): [(1, 1)], + (0, -1): [(-1, 0), (0, -1)], + } +} + +def solve(lines: list[str], return_path=False): + res = 0 + maze = [] + start = () + max_path, max_right = [], [] + maze = list(map(list, lines)) + for i, row in enumerate(maze): + for j, col in enumerate(row): + if col == "S": + start = (i , j) + row_max, col_max = len(maze), len(maze[0]) + + for current_dir in [(0, 1), (0, -1), (1, 0), (-1, 0)]: + current_field = start + steps = 0 + path = [] + right = [] + # print(f"START: {start} {current_dir=}") + while True: + path.append(current_field) + next_field = (current_field[0] + current_dir[0], current_field[1] + current_dir[1]) + if next_field == start: + break + + if next_field[0] < 0 or next_field[1] < 0 or next_field[0] >= row_max or next_field[1] >= col_max: + # print(f"BREAK: Cannot go to {next_field=}!") + break + + prev_dir = current_dir + next_char = maze[next_field[0]][next_field[1]] + try: + current_dir = DIRS[next_char][current_dir] + except KeyError: + # print(f"BREAK: Cannot go from {current_field=} with {current_dir=} to {next_field=} ({next_char})!") + break + + for rights in RIGHTS[next_char][prev_dir]: + rf = (next_field[0] + rights[0], next_field[1] + rights[1]) + right.append(rf) + + current_field = next_field + steps += 1 + res = max(res, (steps + 1) // 2) + if len(path) > len(max_path): + max_path = path + max_right = right + + if return_path: + return res, max_path, max_right + else: + return res + +def solve2(lines: list[str]): + row_max = len(lines) + col_max = len(lines[0]) + length, path, right = solve(lines, True) + + def clean(fields): + fields = list(set(fields)) + cleaned = [] + for f in fields: + if f in path: + continue + if f[0] < 0 or f[1] < 0 or f[0] >= row_max or f[1] >= col_max: + continue + cleaned.append(f) + return cleaned + + right = clean(right) + visited = set() + to_visit = list(right) + while to_visit: + current = to_visit.pop() + for nb in [(0, 1), (0, -1), (1, 0), (-1, 0)]: + f = (current[0] + nb[0], current[1] + nb[1]) + if f[0] < 0 or f[1] < 0 or f[0] >= row_max or f[1] >= col_max: + continue + + if f not in visited and f not in path: + right.append(f) + to_visit.append(f) + visited.add(f) + + right = clean(right) + + n_all = row_max * col_max + n_right = len(right) + n_left = n_all - n_right - len(path) + + return min(n_left, n_right) + +def main(): + lines = lib.str_to_lines_no_empty(EXAMPLE) + print("Example 1:", solve(lines)) + + lines = lib.str_to_lines_no_empty(open("i10.txt").read()) + print("Solution 1:", solve(lines)) + + lines = lib.str_to_lines_no_empty(EXAMPLE4) + print("Example 2:", solve2(lines)) + + lines = lib.str_to_lines_no_empty(open("i10.txt").read()) + print("Solution 2:", solve2(lines)) + +if __name__ == "__main__": + main() diff --git a/d11.py b/d11.py new file mode 100644 index 0000000..b53a743 --- /dev/null +++ b/d11.py @@ -0,0 +1,111 @@ +import lib + +EXAMPLE = """ +...#...... +.......#.. +#......... +.......... +......#... +.#........ +.........# +.......... +.......#.. +#...#..... +""" + +def mdist(a, b): + return abs(a[0] - b[0]) + abs(a[1] - b[1]) + +def solve(lines: list[str]): + res = 0 + + g = list(map(list, lines)) + + er = [] + for (i, r) in enumerate(g): + if "#" not in r: + er.append(i) + + ec = [] + for j in range(len(g[0])): + for row in g: + if "#" == row[j]: + break + else: + ec.append(j) + + for r in reversed(er): + g.insert(r, ["." for _ in range(len(g[0]))]) + + for row in g: + for c in reversed(ec): + row.insert(c, ".") + + # for row in g: + # print("".join(row)) + + gxs = [] + for (row, line) in enumerate(g): + for (col, c) in enumerate(line): + if c == '#': + gxs.append((row, col)) + + for i in range(len(gxs)): + for j in range(i, len(gxs)): + a, b = gxs[i], gxs[j] + d = mdist(a, b) + # print(a, b, d) + res += d + # 16:00 + return res + +def solve2(lines: list[str], factor): + res = 0 + g = list(map(list, lines)) + gxs = [] + for (row, line) in enumerate(g): + for (col, c) in enumerate(line): + if c == '#': + gxs.append((row, col, row, col)) + + for (row_i, row) in enumerate(g): + if "#" not in row: + for i in range(len(gxs)): + row, col, orig_row, orig_col = gxs[i] + if orig_row > row_i: + gxs[i] = (row + factor, col, orig_row, orig_col) + + for col_j in range(len(g[0])): + for row in g: + if "#" == row[col_j]: + break + else: + for i in range(len(gxs)): + row, col, orig_row, orig_col = gxs[i] + if orig_col > col_j: + gxs[i] = (row, col + factor, orig_row, orig_col) + + for i in range(len(gxs)): + for j in range(i, len(gxs)): + a, b = gxs[i], gxs[j] + d = mdist(a, b) + # print(a, b, d) + res += d + # 16:00 + return res + +def main(): + lines = lib.str_to_lines_no_empty(EXAMPLE) + print("Example 1:", solve(lines)) + + lines = lib.str_to_lines_no_empty(open("i11.txt").read()) + print("Solution 1:", solve(lines)) + + lines = lib.str_to_lines_no_empty(EXAMPLE) + print("Example 2:", solve2(lines, 99)) + + lines = lib.str_to_lines_no_empty(open("i11.txt").read()) + print("Solution 2:", solve2(lines, 10**6 - 1)) + +if __name__ == "__main__": + main() diff --git a/d12.py b/d12.py new file mode 100644 index 0000000..2a533a0 --- /dev/null +++ b/d12.py @@ -0,0 +1,43 @@ +import lib + +EXAMPLE = """ +""" + +def solve(lines: list[str]): + res = 0 + + # g = list(map(list, lines)) + # for (ri, r) in enumerate(g): + # for (ci, c) in enumerate(r): + # pass + + for (i, line) in enumerate(lines): + print(i, line) + # digits = lib.str_to_int_list(line) + # digit = lib.str_to_single_int(line) + return res + +def solve2(lines: list[str]): + res = 0 + for (i, line) in enumerate(lines): + print(i, line) + return res + +def main(): + lines = lib.str_to_lines_no_empty(EXAMPLE) + print("Example 1:", solve(lines)) + return + + lines = lib.str_to_lines_no_empty(open("i12.txt").read()) + print("Solution 1:", solve(lines)) + return + + lines = lib.str_to_lines_no_empty(EXAMPLE) + print("Example 2:", solve2(lines)) + return + + lines = lib.str_to_lines_no_empty(open("i12.txt").read()) + print("Solution 2:", solve2(lines)) + +if __name__ == "__main__": + main() diff --git a/dx.py b/dx.py index 61e8a65..cee3769 100644 --- a/dx.py +++ b/dx.py @@ -5,6 +5,12 @@ EXAMPLE = """ def solve(lines: list[str]): res = 0 + + # g = list(map(list, lines)) + # for (ri, r) in enumerate(g): + # for (ci, c) in enumerate(r): + # pass + for (i, line) in enumerate(lines): print(i, line) # digits = lib.str_to_int_list(line) diff --git a/get.sh b/get.sh new file mode 100755 index 0000000..4c55d39 --- /dev/null +++ b/get.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi +DAY=$1 + +SESSION_COOKIE=$(keyring get aoc-session-cookie felixm) +echo $SESSION_COOKIE + +curl "https://adventofcode.com/2023/day/$DAY/input" --cookie "session=$SESSION_COOKIE" > "i$DAY.txt"