Commit shared files to aoc py meta repo.
This commit is contained in:
@@ -1,3 +1,8 @@
|
|||||||
|
My solutions to the Advent of Code 2023 programming challenges.
|
||||||
|
|
||||||
|
Thanks to Eric Wastl for creating this enjoyable event.
|
||||||
|
|
||||||
|
|
||||||
# Times
|
# Times
|
||||||
|
|
||||||
- Day 1: 40:00 (I don't know what I am doing.)
|
- Day 1: 40:00 (I don't know what I am doing.)
|
||||||
|
|||||||
30
dx.py
30
dx.py
@@ -1,30 +0,0 @@
|
|||||||
from lib import *
|
|
||||||
|
|
||||||
EXAMPLE = """
|
|
||||||
"""
|
|
||||||
|
|
||||||
def solve(i: Input, second=False):
|
|
||||||
res = 0
|
|
||||||
i.stats()
|
|
||||||
# g = i.grid2()
|
|
||||||
# ls = i.lines()
|
|
||||||
# ps = i.paras()
|
|
||||||
return res
|
|
||||||
|
|
||||||
def main():
|
|
||||||
DAY_INPUT = "ix.txt"
|
|
||||||
|
|
||||||
print("Example 1:", solve(Input(EXAMPLE)))
|
|
||||||
return
|
|
||||||
|
|
||||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
|
||||||
return
|
|
||||||
|
|
||||||
print("Example 2:", solve(Input(EXAMPLE), True))
|
|
||||||
return
|
|
||||||
|
|
||||||
print("Solution 2:", solve(Input(DAY_INPUT), True))
|
|
||||||
return
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
12
get.sh
12
get.sh
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ "$#" -ne 1 ]; then
|
|
||||||
echo "Usage: $0 <day>"
|
|
||||||
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"
|
|
||||||
235
lib.py
235
lib.py
@@ -1,235 +0,0 @@
|
|||||||
import re
|
|
||||||
import os
|
|
||||||
import string
|
|
||||||
import heapq
|
|
||||||
|
|
||||||
NUMBERS = string.digits
|
|
||||||
LETTERS_LOWER = string.ascii_lowercase
|
|
||||||
LETTERS_UPPER = string.ascii_uppercase
|
|
||||||
|
|
||||||
INF = float("inf")
|
|
||||||
fst = lambda l: l[0]
|
|
||||||
snd = lambda l: l[1]
|
|
||||||
|
|
||||||
def maps(f, xs):
|
|
||||||
if isinstance(xs, list):
|
|
||||||
return [maps(f, x) for x in xs]
|
|
||||||
return f(xs)
|
|
||||||
|
|
||||||
def mape(f, xs):
|
|
||||||
return list(map(f, xs))
|
|
||||||
|
|
||||||
def add2(a: tuple[int, int], b: tuple[int, int]) -> tuple[int, int]:
|
|
||||||
return (a[0] + b[0], a[1] + b[1])
|
|
||||||
|
|
||||||
class Grid2D:
|
|
||||||
N = (-1, 0)
|
|
||||||
E = (0, 1)
|
|
||||||
S = (1, 0)
|
|
||||||
W = (0, -1)
|
|
||||||
NW = (-1, -1)
|
|
||||||
NE = (-1, 1)
|
|
||||||
SE = (1, 1)
|
|
||||||
SW = (1, -1)
|
|
||||||
COORDS_ORTH = (N, E, S, W)
|
|
||||||
COORDS_DIAG = (NW, NE, SE, SW)
|
|
||||||
|
|
||||||
def __init__(self, text: str):
|
|
||||||
lines = [line for line in text.splitlines() if line.strip() != ""]
|
|
||||||
self.grid = list(map(list, lines))
|
|
||||||
self.n_rows = len(self.grid)
|
|
||||||
self.n_cols = len(self.grid[0])
|
|
||||||
|
|
||||||
def __getitem__(self, pos: tuple[int, int]):
|
|
||||||
row, col = pos
|
|
||||||
return self.grid[row][col]
|
|
||||||
|
|
||||||
def __setitem__(self, pos: tuple[int, int], val):
|
|
||||||
row, col = pos
|
|
||||||
self.grid[row][col] = val
|
|
||||||
|
|
||||||
def clone_with_val(self, val):
|
|
||||||
c = Grid2D("d\nd")
|
|
||||||
c.n_rows = self.n_rows
|
|
||||||
c.n_cols = self.n_cols
|
|
||||||
c.grid = [[val for _ in range(c.n_cols)]
|
|
||||||
for _ in range(self.n_rows)]
|
|
||||||
return c
|
|
||||||
|
|
||||||
def rows(self) -> list[list[str]]:
|
|
||||||
return [row for row in self.grid]
|
|
||||||
|
|
||||||
def cols(self) -> list[list[str]]:
|
|
||||||
rows = self.rows()
|
|
||||||
return [[row[col_i] for row in rows]
|
|
||||||
for col_i in range(self.n_cols)]
|
|
||||||
|
|
||||||
def find(self, chars: str) -> list[tuple[int, int]]:
|
|
||||||
return [c for c in self.all_coords() if self[c] in chars]
|
|
||||||
|
|
||||||
def find_not(self, chars: str) -> list[tuple[int, int]]:
|
|
||||||
return [c for c in self.all_coords() if self[c] not in chars]
|
|
||||||
|
|
||||||
def all_coords(self) -> list[tuple[int, int]]:
|
|
||||||
return [(row_i, col_i)
|
|
||||||
for row_i in range(self.n_rows)
|
|
||||||
for col_i in range(self.n_cols)]
|
|
||||||
|
|
||||||
def row_coords(self, row_i) -> list[tuple[int, int]]:
|
|
||||||
assert row_i < self.n_rows, f"{row_i=} must be smaller than {self.n_rows=}"
|
|
||||||
return [(col_i, row_i) for col_i in range(self.n_cols)]
|
|
||||||
|
|
||||||
def col_coords(self, col_i) -> list[tuple[int, int]]:
|
|
||||||
assert col_i < self.n_cols, f"{col_i=} must be smaller than {self.n_cols=}"
|
|
||||||
return [(col_i, row_i) for row_i in range(self.n_rows)]
|
|
||||||
|
|
||||||
def contains(self, pos: tuple[int, int]) -> bool:
|
|
||||||
row, col = pos
|
|
||||||
return row >= 0 and row < self.n_rows and col >= 0 and col < self.n_cols
|
|
||||||
|
|
||||||
def __contains__(self, pos: tuple[int, int]) -> bool:
|
|
||||||
return self.contains(pos)
|
|
||||||
|
|
||||||
def neighbors_ort(self, pos: tuple[int, int]) -> list[tuple[int, int]]:
|
|
||||||
return [add2(pos, off) for off in self.dirs_ort() if self.contains(add2(pos, off))]
|
|
||||||
|
|
||||||
def neighbors_vert(self, pos: tuple[int, int]) -> list[tuple[int, int]]:
|
|
||||||
return [add2(pos, off) for off in self.dirs_vert() if self.contains(add2(pos, off))]
|
|
||||||
|
|
||||||
def neighbors_adj(self, pos: tuple[int, int]) -> list[tuple[int, int]]:
|
|
||||||
return self.neighbors_ort(pos) + self.neighbors_vert(pos)
|
|
||||||
|
|
||||||
def flip_ort(self, pos: tuple[int, int]) -> tuple[int, int]:
|
|
||||||
return (-pos[0], -pos[1])
|
|
||||||
|
|
||||||
def dirs_ort(self) -> list[tuple[int, int]]:
|
|
||||||
return [self.N, self.E, self.S, self.W]
|
|
||||||
|
|
||||||
def dirs_vert(self) -> list[tuple[int, int]]:
|
|
||||||
return [self.NE, self.SE, self.SW, self.NW]
|
|
||||||
|
|
||||||
def print(self):
|
|
||||||
for r in self.rows():
|
|
||||||
print("".join(r))
|
|
||||||
|
|
||||||
def print_with_gaps(self):
|
|
||||||
for r in self.rows():
|
|
||||||
print(" ".join(map(str, r)))
|
|
||||||
|
|
||||||
class Input:
|
|
||||||
def __init__(self, text: str):
|
|
||||||
if os.path.isfile(text):
|
|
||||||
self.text = open(text).read()
|
|
||||||
else:
|
|
||||||
self.text = text
|
|
||||||
|
|
||||||
def stats(self):
|
|
||||||
print(f" size: {len(self.text)}")
|
|
||||||
print(f"lines: {len(self.text.splitlines())}")
|
|
||||||
ps = len(self.paras())
|
|
||||||
print(f"paras: {ps}")
|
|
||||||
|
|
||||||
def lines(self) -> list[str]:
|
|
||||||
return self.text.splitlines()
|
|
||||||
|
|
||||||
def paras(self) -> list[list[str]]:
|
|
||||||
return [p for p in self.text.split("\n\n")]
|
|
||||||
|
|
||||||
def grid2(self) -> Grid2D:
|
|
||||||
return Grid2D(self.text)
|
|
||||||
|
|
||||||
def prime_factors(n):
|
|
||||||
"""
|
|
||||||
Returns a list of prime factors for n.
|
|
||||||
|
|
||||||
:param n: number for which prime factors should be returned
|
|
||||||
"""
|
|
||||||
factors = []
|
|
||||||
rest = n
|
|
||||||
divisor = 2
|
|
||||||
while rest % divisor == 0:
|
|
||||||
factors.append(divisor)
|
|
||||||
rest //= divisor
|
|
||||||
divisor = 3
|
|
||||||
while divisor * divisor <= rest:
|
|
||||||
while rest % divisor == 0:
|
|
||||||
factors.append(divisor)
|
|
||||||
rest //= divisor
|
|
||||||
divisor += 2
|
|
||||||
if rest != 1:
|
|
||||||
factors.append(rest)
|
|
||||||
return factors
|
|
||||||
|
|
||||||
def lcm(numbers: list[int]) -> int:
|
|
||||||
fs = []
|
|
||||||
for n in numbers:
|
|
||||||
fs += prime_factors(n)
|
|
||||||
s = 1
|
|
||||||
fs = list(set(fs))
|
|
||||||
for f in fs:
|
|
||||||
s *= f
|
|
||||||
return s
|
|
||||||
|
|
||||||
def str_to_int(line: str) -> int:
|
|
||||||
line = line.replace(" ", "")
|
|
||||||
r = re.compile(r"-?\d+")
|
|
||||||
m = r.findall(line)
|
|
||||||
assert len(m) == 0, "str_to_int no int"
|
|
||||||
assert len(m) > 1, "str_to_int multiple ints"
|
|
||||||
return int(m[0])
|
|
||||||
|
|
||||||
def str_to_ints(line: str) -> list[int]:
|
|
||||||
r = re.compile(r"-?\d+")
|
|
||||||
return list(map(int, r.findall(line)))
|
|
||||||
|
|
||||||
def str_to_lines_no_empty(text: str) -> list[str]:
|
|
||||||
return list(filter(lambda l: l.strip() != "", text.splitlines()))
|
|
||||||
|
|
||||||
def str_to_lines(text: str) -> list[str]:
|
|
||||||
return list(text.splitlines())
|
|
||||||
|
|
||||||
def count_trailing_repeats(lst):
|
|
||||||
count = 0
|
|
||||||
for elem in reversed(lst):
|
|
||||||
if elem != lst[-1]:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
count += 1
|
|
||||||
return count
|
|
||||||
|
|
||||||
class A_Star(object):
|
|
||||||
def __init__(self, starts, is_goal, h, d, neighbors):
|
|
||||||
"""
|
|
||||||
:param h: heuristic function
|
|
||||||
:param d: cost from node to node function
|
|
||||||
:param neighbors: neighbors function
|
|
||||||
"""
|
|
||||||
open_set = []
|
|
||||||
g_score = {}
|
|
||||||
|
|
||||||
for start in starts:
|
|
||||||
heapq.heappush(open_set, (h(start), start))
|
|
||||||
g_score[start] = d(0, start)
|
|
||||||
|
|
||||||
while open_set:
|
|
||||||
current_f_score, current = heapq.heappop(open_set)
|
|
||||||
if is_goal(current):
|
|
||||||
self.cost = current_f_score
|
|
||||||
break
|
|
||||||
|
|
||||||
for neighbor in neighbors(current):
|
|
||||||
tentative_g_score = g_score[current] + d(current, neighbor)
|
|
||||||
if neighbor not in g_score or \
|
|
||||||
tentative_g_score < g_score[neighbor]:
|
|
||||||
g_score[neighbor] = tentative_g_score
|
|
||||||
f_score = g_score[neighbor] + h(neighbor)
|
|
||||||
heapq.heappush(open_set, (f_score, neighbor))
|
|
||||||
|
|
||||||
def shoelace_area(corners):
|
|
||||||
n = len(corners)
|
|
||||||
area = 0
|
|
||||||
for i in range(n):
|
|
||||||
x1, y1 = corners[i]
|
|
||||||
x2, y2 = corners[(i + 1) % n]
|
|
||||||
area += (x1 * y2) - (x2 * y1)
|
|
||||||
return abs(area) / 2.0
|
|
||||||
39
monitor.py
39
monitor.py
@@ -1,39 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import hashlib
|
|
||||||
import time
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def get_file_hash(filename):
|
|
||||||
hasher = hashlib.sha256()
|
|
||||||
with open(filename, 'rb') as f:
|
|
||||||
hasher.update(f.read())
|
|
||||||
return hasher.hexdigest()
|
|
||||||
|
|
||||||
|
|
||||||
def main(script_name, interval=1):
|
|
||||||
last_hash = None
|
|
||||||
process = None
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
current_hash = get_file_hash(script_name)
|
|
||||||
if current_hash != last_hash:
|
|
||||||
last_hash = current_hash
|
|
||||||
if process and process.poll() is None:
|
|
||||||
process.terminate()
|
|
||||||
print(f"Detected change in {script_name}, running script...")
|
|
||||||
process = subprocess.Popen(['pypy3', script_name], shell=False)
|
|
||||||
time.sleep(interval)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
if process:
|
|
||||||
process.terminate()
|
|
||||||
break
|
|
||||||
except FileNotFoundError:
|
|
||||||
print("The file was not found. Make sure the script name is correct.")
|
|
||||||
break
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main(sys.argv[1])
|
|
||||||
1
monitor.py
Symbolic link
1
monitor.py
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../aocpy/monitor.py
|
||||||
Reference in New Issue
Block a user