2023 #1

Merged
tyrel merged 5 commits from 2023 into main 2023-12-03 04:14:17 +00:00
12 changed files with 1937 additions and 0 deletions

1000
2023/full/day01.txt Normal file

File diff suppressed because it is too large Load Diff

100
2023/full/day02.txt Normal file
View File

@ -0,0 +1,100 @@
Game 1: 5 red, 1 green; 6 red, 3 blue; 9 red; 1 blue, 1 green, 4 red; 1 green, 2 blue; 2 blue, 1 red
Game 2: 12 red, 2 green, 9 blue; 8 red, 12 blue; 9 red, 1 blue, 2 green; 12 blue, 8 red, 2 green; 4 red, 5 blue; 1 green, 9 blue, 10 red
Game 3: 2 red, 8 blue, 5 green; 10 red, 10 green, 7 blue; 9 green, 13 red, 5 blue
Game 4: 3 red; 1 blue, 3 green, 3 red; 3 blue, 8 green, 5 red; 8 green, 2 blue
Game 5: 8 blue, 1 red, 1 green; 1 blue, 1 red, 7 green; 7 green, 5 blue
Game 6: 2 red, 8 blue; 5 blue, 4 green; 5 blue, 4 red, 3 green; 3 red, 9 blue; 5 green, 9 blue, 7 red; 6 red, 9 blue, 5 green
Game 7: 3 green, 4 blue; 7 green, 3 red, 3 blue; 7 red, 4 green, 6 blue; 4 blue, 1 green, 5 red; 6 blue, 2 red, 7 green; 1 green, 4 blue, 4 red
Game 8: 2 blue, 12 red; 1 green, 2 blue, 10 red; 12 red, 10 blue; 5 red, 1 green, 2 blue; 13 red, 16 blue, 1 green; 2 blue, 18 red
Game 9: 5 green, 2 red, 13 blue; 5 green, 1 red; 7 green, 8 blue, 1 red; 16 blue; 5 blue, 2 green, 3 red
Game 10: 5 blue, 2 red; 13 blue, 3 red, 5 green; 2 red, 3 blue; 6 red, 9 blue, 5 green; 9 blue, 3 green, 3 red
Game 11: 9 red, 4 green, 3 blue; 8 blue, 8 red; 1 green, 13 blue; 11 blue, 8 red, 4 green
Game 12: 1 green; 1 blue, 4 red, 6 green; 1 red, 8 green; 7 red, 1 blue, 3 green; 8 green, 1 blue, 8 red
Game 13: 5 blue, 14 red, 1 green; 10 red, 4 blue, 1 green; 6 red, 1 green, 3 blue; 7 blue, 4 red; 14 red, 2 blue, 1 green
Game 14: 9 green, 1 blue; 6 red, 9 green; 7 green, 3 blue
Game 15: 1 green, 4 blue, 2 red; 8 red, 3 blue; 1 red, 3 blue
Game 16: 6 blue, 10 green, 5 red; 11 blue, 1 red; 3 red, 2 green, 3 blue; 1 green, 4 red, 6 blue; 11 blue, 2 red, 11 green
Game 17: 4 green, 5 blue, 8 red; 6 green, 7 red; 3 green, 8 red, 5 blue; 4 green, 8 red; 5 green, 11 blue, 3 red; 5 green, 15 blue, 1 red
Game 18: 7 green, 17 blue, 14 red; 4 green, 11 red, 7 blue; 13 blue, 8 green; 3 red, 7 green, 11 blue
Game 19: 13 red, 13 blue, 1 green; 7 blue, 1 red, 5 green; 18 blue, 1 green, 11 red; 4 blue, 13 red, 6 green
Game 20: 1 blue, 6 green, 7 red; 5 green, 4 red, 1 blue; 1 blue, 1 red, 4 green
Game 21: 3 red, 5 green, 7 blue; 6 green, 10 blue, 5 red; 9 red, 1 blue; 5 green, 8 blue, 9 red; 2 red, 11 green, 4 blue; 5 red, 6 blue
Game 22: 8 blue, 1 red, 1 green; 10 blue; 13 blue, 1 green, 4 red; 1 green, 8 blue, 4 red; 3 blue, 1 red
Game 23: 2 blue; 3 blue, 5 green; 6 blue, 5 green, 2 red; 1 green
Game 24: 1 red, 13 green, 4 blue; 16 green, 4 blue; 4 red, 5 blue, 11 green; 15 green, 5 red, 10 blue; 16 green, 1 red; 5 red, 3 blue, 10 green
Game 25: 12 red, 7 green, 6 blue; 5 blue, 5 red, 12 green; 12 green, 3 red; 5 green, 5 red, 3 blue
Game 26: 2 green, 11 blue; 5 red, 3 blue; 5 red, 12 blue, 3 green
Game 27: 3 green, 5 red, 12 blue; 3 red, 11 blue, 1 green; 3 red, 4 blue, 3 green; 3 red, 9 green, 9 blue; 14 blue, 1 green, 12 red
Game 28: 8 green, 9 blue; 6 green, 8 red, 1 blue; 7 red, 6 green; 12 red, 2 blue, 2 green
Game 29: 16 red, 4 green, 1 blue; 10 red, 7 green, 2 blue; 3 green, 8 red; 2 blue, 1 red, 4 green; 2 blue, 10 red, 9 green; 7 green, 1 blue, 18 red
Game 30: 13 red, 3 blue; 3 blue, 1 green, 10 red; 15 red, 3 blue; 1 green, 1 red, 1 blue; 16 red, 1 green, 3 blue
Game 31: 5 red, 8 blue, 3 green; 5 green, 7 blue, 13 red; 9 red, 3 green, 10 blue; 15 red, 1 green, 7 blue; 5 green, 12 blue, 2 red; 6 blue, 13 red
Game 32: 2 blue, 8 red, 1 green; 3 green, 2 blue, 11 red; 2 green, 6 red; 13 red, 3 green, 2 blue; 6 red
Game 33: 5 blue, 5 red; 8 red, 1 green, 7 blue; 1 green, 6 red
Game 34: 3 blue; 3 green, 2 blue, 2 red; 3 green, 1 blue, 3 red; 3 blue
Game 35: 4 red, 2 blue, 6 green; 4 blue, 9 red, 10 green; 3 blue, 8 green, 1 red; 3 red, 1 green, 4 blue; 4 green, 7 blue; 8 red, 8 green, 2 blue
Game 36: 1 red, 3 blue, 12 green; 16 green, 7 blue, 1 red; 1 blue, 1 red, 9 green; 2 blue, 2 green; 8 green, 2 red
Game 37: 2 green, 8 red; 3 blue, 1 red, 2 green; 15 red, 7 blue; 1 green, 16 red, 15 blue; 13 red, 9 blue
Game 38: 9 red, 9 blue, 5 green; 3 red, 19 blue, 8 green; 15 blue, 11 red, 6 green; 10 red, 19 blue, 5 green; 8 blue, 7 green, 6 red; 7 red, 6 green, 10 blue
Game 39: 8 blue, 13 green, 2 red; 16 blue, 9 green; 19 blue, 1 green; 1 red, 3 blue, 9 green; 1 green, 18 blue
Game 40: 6 red, 5 blue; 11 green, 15 blue, 7 red; 10 blue, 5 green, 10 red; 13 blue, 9 red, 11 green; 2 green, 14 blue, 12 red; 6 red, 6 green
Game 41: 10 green, 1 red, 1 blue; 1 red, 9 green; 1 green; 6 green, 1 blue, 2 red; 1 blue, 8 green, 1 red; 9 green
Game 42: 13 green, 2 blue; 10 blue, 1 red; 10 red, 10 green, 8 blue; 16 green, 8 blue, 6 red; 9 red, 18 green; 10 red, 15 blue, 1 green
Game 43: 3 red, 16 blue, 6 green; 1 red, 17 blue, 12 green; 19 blue, 2 red, 16 green; 12 green, 7 blue, 1 red; 8 green, 7 blue, 2 red; 12 green, 9 blue
Game 44: 4 red, 3 green, 2 blue; 18 blue, 3 green; 7 red, 7 blue, 4 green
Game 45: 1 green, 3 blue, 7 red; 9 green, 8 red, 2 blue; 5 green, 3 blue, 6 red
Game 46: 18 blue; 4 blue, 1 red, 5 green; 2 red, 15 blue, 7 green
Game 47: 17 red, 4 green, 12 blue; 6 green, 1 red, 2 blue; 3 blue, 13 green, 4 red
Game 48: 11 red, 2 green; 8 red, 3 green; 2 green, 5 blue, 9 red; 3 green, 2 blue, 5 red
Game 49: 2 green, 12 blue, 9 red; 1 green, 12 red; 1 green, 2 blue, 18 red; 8 blue, 19 red; 1 green, 5 blue; 3 blue, 10 red, 1 green
Game 50: 5 green, 1 red; 7 red, 3 blue, 9 green; 15 blue, 4 green, 4 red
Game 51: 12 green, 14 blue; 2 red, 5 green, 16 blue; 4 red, 17 blue, 16 green; 6 blue, 16 green, 2 red; 17 blue, 13 green, 5 red
Game 52: 7 green, 10 red, 2 blue; 6 green, 12 red, 3 blue; 10 red, 3 blue, 8 green; 3 blue, 1 green, 8 red; 6 green, 5 blue, 3 red
Game 53: 8 blue, 3 green; 7 green, 11 blue, 1 red; 1 red, 7 blue, 9 green; 1 blue, 1 green; 4 green, 1 red; 1 red, 8 blue
Game 54: 1 blue, 1 green, 4 red; 1 red, 1 blue, 13 green; 11 red, 11 green, 1 blue
Game 55: 5 blue, 4 red, 11 green; 13 green, 9 blue, 3 red; 3 red, 7 green, 8 blue; 2 red, 20 blue, 2 green; 3 red, 10 blue, 1 green; 12 green, 5 red, 8 blue
Game 56: 17 red, 2 green, 1 blue; 13 blue, 8 green, 6 red; 1 green, 9 blue, 6 red; 2 blue
Game 57: 9 green, 1 red, 9 blue; 15 green, 10 blue, 1 red; 5 blue, 3 red, 10 green
Game 58: 14 red, 2 blue, 14 green; 17 red, 7 blue, 10 green; 4 green, 13 red, 11 blue; 3 green, 13 red, 5 blue; 13 red, 6 blue; 1 red, 7 green, 2 blue
Game 59: 16 blue, 7 red, 2 green; 7 green, 10 red, 12 blue; 4 red, 9 green, 14 blue; 8 blue, 11 green, 1 red; 3 blue, 5 red, 11 green
Game 60: 1 blue; 9 red, 4 green; 3 green, 3 blue, 1 red; 3 red, 1 blue
Game 61: 2 green, 15 red, 12 blue; 9 green, 1 blue, 10 red; 14 blue, 17 red, 2 green; 12 red, 6 blue, 3 green; 8 green, 10 blue, 10 red; 2 green, 10 red, 2 blue
Game 62: 12 red, 6 blue, 1 green; 2 red, 1 green, 4 blue; 10 blue, 12 red, 4 green; 5 green, 8 red, 8 blue
Game 63: 3 green, 3 red; 7 red; 2 green, 1 blue, 7 red; 5 red, 1 green
Game 64: 5 green, 11 red; 4 green, 2 blue, 7 red; 7 red, 11 blue, 3 green; 8 blue, 5 green, 5 red; 8 red, 4 blue
Game 65: 5 red, 5 blue; 15 green, 3 blue; 3 blue, 3 red, 8 green; 1 blue, 3 red, 5 green
Game 66: 8 green, 5 blue, 12 red; 10 red, 5 blue, 11 green; 12 red, 3 blue, 2 green; 5 green, 1 blue, 10 red; 15 red, 5 green, 3 blue; 2 red, 8 blue
Game 67: 12 blue, 3 red; 4 blue, 4 red, 1 green; 9 green, 14 blue, 3 red; 2 red, 13 blue, 6 green; 17 blue, 5 green
Game 68: 1 blue, 4 red, 11 green; 11 green, 4 red, 7 blue; 11 green, 7 blue; 14 green, 2 blue, 1 red; 2 blue, 4 red
Game 69: 4 red, 1 green; 5 red, 2 green, 3 blue; 1 red, 7 blue; 8 red, 6 blue, 1 green; 2 green, 6 red, 1 blue; 6 red, 8 blue, 2 green
Game 70: 6 blue, 2 green, 4 red; 1 green, 5 blue; 1 blue, 3 red; 2 red; 2 red, 17 blue
Game 71: 9 blue, 2 green, 1 red; 7 blue, 2 green, 3 red; 12 red, 13 blue; 15 blue, 1 green, 1 red
Game 72: 15 blue, 16 red, 18 green; 16 red, 12 blue, 14 green; 3 blue, 12 red, 4 green; 8 green, 17 blue, 15 red; 15 blue, 18 green, 4 red; 5 blue, 3 red, 10 green
Game 73: 17 blue, 3 red, 19 green; 10 blue, 15 green, 18 red; 4 green, 15 red; 1 green, 17 blue, 14 red; 16 red, 1 green, 4 blue
Game 74: 6 green, 2 blue, 5 red; 1 blue, 9 green; 5 red, 1 blue, 10 green; 4 green, 11 red, 1 blue
Game 75: 4 blue; 4 green, 6 blue; 2 green, 2 blue, 4 red
Game 76: 5 blue; 5 green, 5 red; 9 red, 1 blue, 1 green; 5 green; 3 green, 6 red, 1 blue
Game 77: 2 red, 10 blue, 6 green; 1 red, 6 blue, 6 green; 9 blue, 2 green, 8 red; 12 blue, 7 green, 18 red
Game 78: 2 red, 5 blue, 2 green; 2 blue, 4 green, 6 red; 4 blue, 4 green, 3 red; 3 red, 5 green; 2 red, 4 green, 4 blue
Game 79: 14 red, 6 blue, 1 green; 6 blue, 18 red, 2 green; 1 green; 8 red, 5 green; 1 blue, 7 red, 6 green; 11 red, 1 blue
Game 80: 5 blue, 4 red; 19 blue, 7 red; 6 red, 1 green, 12 blue; 1 green, 8 red
Game 81: 7 green, 6 red, 9 blue; 14 blue, 8 green; 15 green, 6 red, 4 blue; 1 red, 7 blue, 19 green
Game 82: 1 red, 4 blue; 3 blue, 1 red, 5 green; 3 blue, 5 green, 12 red; 17 red, 2 blue; 4 blue, 1 red
Game 83: 6 blue, 11 green, 18 red; 11 red, 7 blue, 2 green; 13 red, 14 blue, 14 green; 1 red, 3 blue, 16 green
Game 84: 2 red, 5 blue, 3 green; 9 red, 7 blue, 2 green; 4 green, 9 red, 3 blue; 1 blue, 1 green, 5 red
Game 85: 1 red, 10 green, 15 blue; 9 green, 1 red; 1 red, 2 green, 12 blue
Game 86: 1 green, 5 blue, 8 red; 10 green, 8 red, 9 blue; 6 green, 3 red, 8 blue; 9 red, 3 green, 8 blue; 2 red, 6 blue, 1 green
Game 87: 13 red, 12 green; 6 blue, 5 green, 3 red; 10 green, 1 blue, 17 red; 9 green, 6 blue, 2 red; 1 blue, 9 green, 14 red
Game 88: 4 green, 1 blue, 7 red; 6 green, 2 red, 1 blue; 13 red, 7 green
Game 89: 2 blue, 7 green, 10 red; 6 green, 5 blue; 12 red, 4 blue, 5 green; 15 red, 8 blue; 6 blue, 8 red, 3 green; 14 red, 11 green, 16 blue
Game 90: 8 green, 8 red; 5 green, 1 blue, 13 red; 3 blue, 1 green, 3 red; 11 red, 2 green; 9 red, 7 green, 1 blue
Game 91: 4 green, 13 red, 10 blue; 11 blue, 4 red; 10 blue, 9 green; 9 green, 4 blue, 12 red; 7 green, 4 red, 1 blue
Game 92: 6 blue; 10 green, 1 red, 11 blue; 5 blue, 5 green; 6 green, 1 red; 1 red, 6 green
Game 93: 2 red, 15 blue, 4 green; 13 red, 11 green; 6 green, 1 blue, 6 red; 6 red, 5 blue, 10 green; 2 blue, 11 green, 18 red
Game 94: 2 red, 13 blue, 3 green; 15 blue, 4 red, 2 green; 4 green, 9 blue, 7 red; 12 blue, 6 red, 11 green; 20 blue, 13 red, 11 green
Game 95: 6 blue, 1 red, 10 green; 10 red, 5 blue, 7 green; 9 red, 13 green, 10 blue; 11 blue, 9 red, 8 green
Game 96: 2 red, 7 green, 16 blue; 20 green, 2 red, 14 blue; 5 red, 15 green, 15 blue; 4 blue, 6 red, 15 green; 6 green, 6 red, 10 blue
Game 97: 1 red, 1 blue, 14 green; 10 green, 12 red, 1 blue; 10 red, 2 green, 1 blue; 1 blue, 3 green, 14 red; 3 red, 2 blue, 13 green; 1 blue, 3 green, 13 red
Game 98: 13 blue, 1 green; 18 green, 6 red, 3 blue; 11 blue, 7 red, 9 green; 4 red, 6 green, 11 blue; 12 blue, 6 red, 8 green
Game 99: 4 blue; 1 red, 2 green, 11 blue; 12 blue, 1 green, 1 red; 11 blue, 6 green; 1 red, 7 green, 8 blue
Game 100: 10 blue, 5 green; 4 green, 3 red, 6 blue; 2 green, 4 red, 1 blue

22
2023/justfile Normal file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env -S just --justfile
DAY := `date +%d`
new:
cp python/_sample.py python/day{{ DAY }}.py
touch full/day{{ DAY }}.txt
touch samples/day{{ DAY }}.txt
full:
/usr/bin/env python3 python/day{{ DAY }}.py
sample:
/usr/bin/env python3 python/day{{ DAY }}.py --sample
ws:
watch /usr/bin/env python3 python/day{{ DAY }}.py --sample
watch:
watch /usr/bin/env python3 python/day{{ DAY }}.py

29
2023/python/_sample.py Normal file
View File

@ -0,0 +1,29 @@
import matrix
import shared
import itertools
import functools
# @shared.profile
def part1(rows):
pass
# @shared.profile
def part2(rows):
pass
def main():
rows = [row for row in shared.load_rows(15)]
with shared.elapsed_timer() as elapsed:
part1(rows)
print("🕒", elapsed())
rows = [row for row in shared.load_rows(1,True)]
with shared.elapsed_timer() as elapsed:
part2(rows)
print("🕒", elapsed())
if __name__ == "__main__":
main()

45
2023/python/anim.py Normal file
View File

@ -0,0 +1,45 @@
from matrix import get_size, pmx
import imageio
import matplotlib.pyplot as plt
import numpy as np
class Animate:
def __init__(self, mx, day="CHANGEME"):
self.mx = mx
self.day = day
_size = get_size(mx)
self.height = _size[0]
self.width = _size[1]
self.f_count = -1
def add_frame(self, frame):
self.f_count += 1
self.write_frame(frame)
def write_frame(self, frame):
current = np.zeros_like(self.mx)
for y, row in enumerate(frame):
for x, col in enumerate(row):
current[y][x] = frame[y][x]
fig, ax = plt.subplots()
ax.imshow(current, cmap=plt.cm.gray)
ax.axis("off")
_figpath = f"gif-{self.day}/{self.f_count:05}.png"
plt.savefig(_figpath)
plt.close()
def animate(self, frameskip=1):
with imageio.get_writer(
f"gif-{self.day}/day{self.day}.gif", mode="I"
) as writer:
names = [
f"gif-{self.day}/{x:05}.png" for x in range(0, self.f_count, frameskip)
]
print(names)
for filename in names:
try:
image = imageio.imread(filename)
writer.append_data(image)
except FileNotFoundError:
pass

67
2023/python/day01.py Normal file
View File

@ -0,0 +1,67 @@
import matrix
import shared
import itertools
import functools
NUMS = {
"one": 1,
"two": 2,
"six": 6,
"four": 4,
"five": 5,
"nine": 9,
"seven": 7,
"eight": 8,
"three": 3,
}
# @shared.profile
def part1(rows):
total = 0
for row in rows:
numbers = ''.join(filter(str.isdigit, row))
total += get_total(numbers)
print(total)
def get_total(numbers):
tens, ones= int(numbers[0]),int(numbers[-1])
return (tens * 10) + ones
def loop_row(row):
digits = []
for idx, _ in enumerate(row):
if str.isdigit(row[idx]):
digits.append(row[idx])
continue
for x in [3,4,5]:
next = row[idx:idx+x]
if next in NUMS.keys():
digits.append(str(NUMS[next]))
break
return "".join(digits)
# @shared.profile
def part2(rows):
total = 0
for row in rows:
nums = loop_row(row)
total += get_total(nums)
print(total)
def main():
rows = [row for row in shared.load_rows(1)]
with shared.elapsed_timer() as elapsed:
part1(rows)
print("🕒", elapsed())
rows = [row for row in shared.load_rows(1, True)]
with shared.elapsed_timer() as elapsed:
part2(rows)
print("🕒", elapsed())
if __name__ == "__main__":
main()

65
2023/python/day02.py Normal file
View File

@ -0,0 +1,65 @@
import shared
from collections import defaultdict
def split_games(row):
game, draws = row.split(":")
game = int(game.split(" ")[-1])
colors = defaultdict(list)
for draw in draws.split(";"):
for cube in draw.split(","):
cube = cube.split()
count, color = cube
colors[color].append(int(count))
return game,colors
MAXES = {
"red": 12,
"green":13,
"blue": 14,
}
# @shared.profile
def part1(rows):
applicable = []
for row in rows:
ok = True
game, colors = split_games(row)
for color, _max in MAXES.items():
bag_max = max(colors[color])
if bag_max > _max:
ok = False
break
if ok:
applicable.append(game)
print(sum(applicable))
# @shared.profile
def part2(rows):
total = 0
for row in rows:
_, colors = split_games(row)
power=1
for vals in colors.values():
power *= max(vals)
total += power
print(total)
def main():
rows = [row for row in shared.load_rows(2)]
with shared.elapsed_timer() as elapsed:
part1(rows)
print("🕒", elapsed())
rows = [row for row in shared.load_rows(2, True)]
with shared.elapsed_timer() as elapsed:
part2(rows)
print("🕒", elapsed())
if __name__ == "__main__":
main()

425
2023/python/matrix.py Normal file
View File

@ -0,0 +1,425 @@
from copy import deepcopy
from collections import defaultdict
import math
from typing import List, Dict, Tuple
split_word_to_chr_list = lambda y: [w for w in y]
split_word_to_int_list = lambda y: [int(w) for w in y]
split_line_to_int_list = lambda y: [int(w) for w in y.split(" ") if w]
def split_x_out(l):
return [x for _, x in l]
def split_y_out(l):
return [y for y, _ in l]
class colors:
# HEADER = '\033[95m'
BLUE = "\033[94m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
RED = "\033[91m"
ENDC = "\033[0m"
BLINK = "\033[5m"
def apply_to_all(mx, func):
for row_num, row in enumerate(mx):
for col_num, val in enumerate(row):
mx[row_num][col_num] = func(val)
def rotate(m, right=True): # -90
"""
Takes a matrix, and rotates all of the values 90 degrees to the left
"""
x = list(zip(*m[::-1]))
if right:
return x
return [list(reversed(y)) for y in x]
def load_matrix_file(name, func=None):
"""
Open a file and split all space separated word lists to integers as a matrix
"""
with open(name, "r") as f:
my_file = []
for line in f:
my_file.append(line.rstrip())
if func:
return [func(x) for x in my_file]
return [split_word_to_int_list(x) for x in my_file]
def find_in_matrix(mx, what, one=True):
coords = []
for row_num, row in enumerate(mx):
for col_num, val in enumerate(row):
if val == what:
coord = (row_num, col_num)
if one is True:
return coord
else:
coords.append(coord)
return coords
def get_neighbors(matrix, x, y, _dict=False):
neighbors = []
# left
try:
if x - 1 >= 0:
if _dict:
neighbors.append({"x": x - 1, "y": y, "value": matrix[y][x - 1]})
else:
neighbors.append([(x - 1, y), matrix[y][x - 1]])
except IndexError:
pass
# right
try:
if _dict:
neighbors.append({"x": x + 1, "y": y, "value": matrix[y][x + 1]})
else:
neighbors.append([(x + 1, y), matrix[y][x + 1]])
except IndexError:
pass
# up
try:
if y - 1 >= 0:
if _dict:
neighbors.append({"x": x, "y": y - 1, "value": matrix[y - 1][x]})
else:
neighbors.append([(x, y - 1), matrix[y - 1][x]])
except IndexError:
pass
# down
try:
if _dict:
neighbors.append({"x": x, "y": y + 1, "value": matrix[y + 1][x]})
else:
neighbors.append([(x, y + 1), matrix[y + 1][x]])
except IndexError:
pass
return neighbors
def valid_neighbors(matrix, x, y, criteria=None):
if criteria is None:
raise Exception("Please pass in a lambda for criteria")
cur = matrix[y][x]
neighbors = get_neighbors(matrix, x, y, _dict=True)
valid = []
for neighbor in neighbors:
if criteria(cur, neighbor["value"]):
valid.append(neighbor)
return valid
def sum_matrix(mtx):
total = 0
for row in mtx:
total += sum(row)
return total
M_UL, M_U, M_UR = (-1, -1), (0, -1), (1, -1)
M_L, M_R = (-1, 0), (1, 0)
M_DL, M_D, M_DR = (-1, 1), (0, 1), (1, 1)
def get_neighbor_coords(matrix, c, r, diagonals=True):
height = len(matrix)
width = len(matrix[0])
if diagonals:
coords = (M_UL, M_U, M_UR, M_L, M_R, M_DL, M_D, M_DR)
else:
coords = (M_U, M_L, M_R, M_D)
neighbors = []
for _c, _r in coords:
try:
value = matrix[r + _r][c + _c] # Try to get a value error
if r + _r >= 0 and c + _c >= 0:
neighbors.append(
[{"c": c + _c, "r": r + _r}, value]
) # woo, no error, this coord is valid
except IndexError:
pass # okay we out of bounds boizzzz
return neighbors
def line_of_sight_coords(
matrix, row, col, distance=None
) -> Dict[str, List[Tuple[int, int]]]:
"""
Takes a matrix, a row, and a column
calculates the coordinates to the edge for all four cardinal directions
returns a dict with a list of tuple coordes TRAVELING AWAY from the
requested coordinate
"""
height, width = get_size(matrix)
col_ids = list(range(0, height))
row_ids = list(range(0, width))
if distance:
up_ids, down_ids = (
list(reversed(col_ids[:col])),
col_ids[col + 1 : col + distance + 1],
)
left_ids, right_ids = (
list(reversed(row_ids[:row])),
row_ids[row + 1 : row + distance + 1],
)
else:
up_ids, down_ids = list(reversed(col_ids[:col])), col_ids[col + 1 :]
left_ids, right_ids = list(reversed(row_ids[:row])), row_ids[row + 1 :]
left = [(r, col) for r in left_ids]
right = [(r, col) for r in right_ids]
up = [(row, c) for c in up_ids]
down = [(row, c) for c in down_ids]
return {
"U": up,
"L": left,
"D": down,
"R": right,
}
def line_of_sight(mx, row, col, distance=None):
"""
renders a line of sight coord calculation, into the values
"""
coords = line_of_sight_coords(mx, row, col, distance)
los = defaultdict(list)
for k, ids in coords.items():
for _row, _col in ids:
los[k].append(mx[_row][_col])
return los
def coords_between_points(point1, point2):
y1, x1 = point1
y2, x2 = point2
coords = []
x = 0
y = 0
if x2 < x1:
y = point1[0]
for _x in range(x2, x1 + 1):
coords.append((y, _x))
elif x1 < x2:
y = point1[0]
for _x in range(x1, x2 + 1):
coords.append((y, _x))
elif y2 < y1:
x = point1[1]
for _y in range(y2, y1 + 1):
coords.append((_y, x))
elif y1 < y2:
x = point1[1]
for _y in range(y1, y2 + 1):
coords.append((_y, x))
return coords
def get_size(matrix):
height = len(matrix)
width = len(matrix[0])
return height, width
def row_col_from_int(matrix, x):
h, w = get_size(matrix)
col = x % w
row = x // h
return row, col
def matrix_of_size(width, height, default=0):
return [[default] * width for x in range(height)]
def set_matrix_dict(m):
for x in range(len(m)):
for y in range(len(m[x])):
m[x][y] = {}
return m
def pmx(*matrices, pad=True, space=True):
"""
print a matrix of integers, zero turns to `.` for clarity
"""
if len(matrices) > 1:
matrices = list(zip(*matrices))
for row in matrices:
r = []
for col in row:
r.append("".join([f"{int(x)or '.'}".rjust(3) for x in col]))
print(" ".join(r))
else:
for row in matrices:
for c in row:
if pad:
f = lambda x: f"{int(x)or '.'}".rjust(2)
if space:
f = lambda x: f"{int(x)or '.'}".rjust(3)
else:
f = lambda x: f"{int(x)or '.'}"
if space:
f = lambda x: f"{int(x)or '.'} "
print("".join([f(x) for x in c]))
def ppmx(*matrices, pad=True, space=True, zero="."):
"""
print a matrix of anything, Falsy values turns to `.` for clarity
"""
out = []
if len(matrices) > 1:
matrices = list(zip(*matrices))
for row in matrices:
r = []
for col in row:
r.append("".join([f"{x or zero}".rjust(3) for x in col]))
out.append(" ".join(r))
else:
for row in matrices:
for c in row:
if pad:
f = lambda x: f"{x or zero}".rjust(2)
if space:
f = lambda x: f"{x or zero}".rjust(3)
else:
f = lambda x: f"{x or zero}"
if space:
f = lambda x: f"{x or zero} "
out.append("".join([f(x) for x in c]))
return "\n".join(out)
def view_matrix(matrix, y1, x1, y2, x2):
lines = ppmx(matrix, pad=0, space=0).split("\n")
for line in lines[y1 : y2 + 1]:
print(line[x1:x2])
def highlight(matrix, red=[], green=[], blue=[], blink_green=[]):
"""
print a matrix of anything, Falsy values turns to `.` for clarity
"""
mx = deepcopy(matrix)
for (y, x) in red:
if (y, x) in blue or (y, x) in green or (y, x) in blink_green:
continue
new = f"{colors.RED}{mx[y][x]}{colors.ENDC}"
mx[y][x] = new
for (y, x) in green:
if (y, x) in blue or (y, x) in blink_green:
continue
new = f"{colors.GREEN}{mx[y][x]}{colors.ENDC}"
mx[y][x] = new
for (y, x) in blue:
if (y, x) in blink_green:
continue
new = f"{colors.BLUE}{mx[y][x]}{colors.ENDC}"
mx[y][x] = new
for (y, x) in blink_green:
new = f"{colors.BLINK}{colors.GREEN}{mx[y][x]}{colors.ENDC}"
mx[y][x] = new
print(ppmx(mx, pad=False, space=True, zero="0"))
def draw_shape_at(mx, row, col, shape=None, value=1):
if shape is None:
raise Exception("Please provide a list of coordinate offsets from Y,X to draw")
for y,x in shape:
mx[row+y][col+x] = value
def collision_at(mx, row, col, shape=None):
if shape is None:
raise Exception("Please provide a list of coordinate offsets from Y,X to draw")
for y,x in shape:
if mx[row+y][col+x] != 0:
return True
return False
def out_of_bounds(mx, row, col, shape=None):
if shape is None:
raise Exception("Please provide a list of coordinate offsets from Y,X to draw")
height, width = get_size(mx)
for y,x in shape:
if row+y > height-1:
return True
if col+x >= width:
return True
if col+x < 0:
return True
return False
def spiral_generator(width, height):
k = 0
l = 0
m = height
n = width
''' k - starting row index
m - ending row index
l - starting column index
n - ending column index
i - iterator '''
while (k < m and l < n):
# Print the first row from
# the remaining rows
for i in range(l, n):
yield (i,k)
#print(a[k][i], end=" ")
k += 1
# Print the last column from
# the remaining columns
for i in range(k, m):
yield (n-1,i)
#print(a[i][n - 1], end=" ")
n -= 1
# Print the last row from
# the remaining rows
if (k < m):
for i in range(n - 1, (l - 1), -1):
#print(a[m - 1][i], end=" ")
yield (i, m-1)
m -= 1
# Print the first column from
# the remaining columns
if (l < n):
for i in range(m - 1, k - 1, -1):
#print(a[i][l], end=" ")
yield (l,i)
l += 1

168
2023/python/shared.py Normal file
View File

@ -0,0 +1,168 @@
from contextlib import contextmanager
from timeit import default_timer
from pathlib import Path
import cProfile
import functools
import pstats
def profile(func):
@functools.wraps(func)
def inner(*args, **kwargs):
profiler = cProfile.Profile()
profiler.enable()
try:
retval = func(*args, **kwargs)
finally:
profiler.disable()
with open("profile.out", "w") as profile_file:
stats = pstats.Stats(profiler, stream=profile_file)
stats.print_stats()
return retval
return inner
spl = lambda y: [int(w) for w in y]
def minmax(l):
return min(l), max(l)
def load_rows(day, part2=False):
return [row for row in load(day,part2)]
def load(day, part2=False):
if part2:
path = Path(get_fname(day)+".part2")
try:
return path.read_text().rstrip().split("\n")
except FileNotFoundError:
# No part 2 file, use first file
pass
path = Path(get_fname(day))
return path.read_text().rstrip().split("\n")
def get_fname(day: int) -> str:
import sys
if sys.argv[-1] == "--sample":
return f"samples/day{day:02}.txt"
else:
return f"full/day{day:02}.txt"
#############
def load_char_matrix(f):
my_file = []
for line in f:
my_file.append(line.rstrip())
return [list(x) for x in my_file]
def load_file_char_matrix(name):
with open(name, "r") as f:
return load_char_matrix(f)
def load_int_matrix(f):
my_file = []
for line in f:
my_file.append(line.rstrip())
return [list(map(int, x)) for x in my_file]
def load_file_int_matrix(name):
with open(name, "r") as f:
return load_int_matrix(f)
def load_word_matrix(f):
my_file = []
for line in f:
my_file.append(line.rstrip())
return [x.split(" ") for x in my_file]
def load_file_word_matrix(name):
with open(name, "r") as f:
return load_word_matrix(f)
#############
def rotate(WHAT, times=1):
what = WHAT
for x in range(times):
what = list(zip(*what[::-1]))
return what
@contextmanager
def elapsed_timer():
start = default_timer()
elapser = lambda: default_timer() - start
yield lambda: elapser()
end = default_timer()
elapser = lambda: end - start
def render_cubes(maxX,maxY,maxZ, my_cubes):
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
def cuboid_data(o, size=(1,1,1)):
X = [[[0, 1, 0], [0, 0, 0], [1, 0, 0], [1, 1, 0]],
[[0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0]],
[[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]],
[[0, 0, 1], [0, 0, 0], [0, 1, 0], [0, 1, 1]],
[[0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 1, 0]],
[[0, 1, 1], [0, 0, 1], [1, 0, 1], [1, 1, 1]]]
X = np.array(X).astype(float)
for i in range(3):
X[:,:,i] *= size[i]
X += np.array(o)
return X
def plotCubeAt(positions,sizes=None,colors=None, **kwargs):
if not isinstance(colors,(list,np.ndarray)): colors=["C0"]*len(positions)
if not isinstance(sizes,(list,np.ndarray)): sizes=[(1,1,1)]*len(positions)
g = []
for p,s,c in zip(positions,sizes,colors):
g.append( cuboid_data(p, size=s) )
return Poly3DCollection(np.concatenate(g),
facecolors=np.repeat(colors,6, axis=0), **kwargs)
N1 = maxX
N2 = maxY
N3 = maxZ
ma = np.random.choice([0,1], size=(N1,N2,N3), p=[0.99, 0.01])
x,y,z = np.indices((N1,N2,N3))-.5
#positions = np.c_[x[ma==1],y[ma==1],z[ma==1]]
positions = np.c_[my_cubes]
colors= np.random.rand(len(positions),3)
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.set_aspect('equal')
pc = plotCubeAt(positions, colors=colors,edgecolor="k")
ax.add_collection3d(pc)
ax.set_xlim([0,maxX])
ax.set_ylim([0,maxY])
ax.set_zlim([0,maxZ])
#plotMatrix(ax, ma)
#ax.voxels(ma, edgecolor="k")
plt.show()

4
2023/samples/day01.txt Normal file
View File

@ -0,0 +1,4 @@
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet

View File

@ -0,0 +1,7 @@
two1nine
eightwothree
abcone2threexyz
xtwone3four
4nineeightseven2
zoneight234
7pqrstsixteen

5
2023/samples/day02.txt Normal file
View File

@ -0,0 +1,5 @@
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