Skip to content

Instantly share code, notes, and snippets.

@pjhoberman
Last active December 7, 2021 15:37
Show Gist options
  • Save pjhoberman/76ed9487660af8ab0c62739a065c2fd7 to your computer and use it in GitHub Desktop.
Save pjhoberman/76ed9487660af8ab0c62739a065c2fd7 to your computer and use it in GitHub Desktop.
Advent of Code 2021
inp = """199
200
208
210
200
207
240
269
260
263"""
inp = [int(val) for val in inp.split()]
prev = inp[0]
counter = 0
for val in inp[1:]:
if val > prev:
counter += 1
prev = val
# counter --> 7
# replace inp with actual input
from more_itertools import triplewise # this is cheating, but here we are
inp = """199
200
208
210
200
207
240
269
260
263"""
inp = [int(val) for val in inp.split()]
c = 0
first = True
for trip in triplewise(inp):
if first:
prev = sum(trip)
first = False
continue
else:
if sum(trip) > prev:
c += 1
prev = sum(trip)
# counter --> 5
# replace inp with actual input
# day 2.1
inp = """forward 5
down 5
forward 8
up 3
down 8
forward 2"""
inp = [line.split() for line in inp.split("\n")]
x = 0
y = 0
for instr in inp:
direction, value = instr
value = int(value)
if direction == "forward":
x += value
elif direction == "down":
y += value
elif direction == "up":
y -= value
else:
print(f"bad instruction: {instr}")
print(x,y)
print(x*y)
## day2.2
inp = """forward 5
down 5
forward 8
up 3
down 8
forward 2"""
inp = [line.split() for line in inp.split("\n")]
x = 0
y = 0
aim = 0
for instr in inp:
direction, value = instr
value = int(value)
if direction == "forward":
x += value
y += aim * value
elif direction == "down":
# y += value
aim += value
elif direction == "up":
# y -= value
aim -= value
else:
print(f"bad instruction: {instr}")
print(x*y)
# day 3.1
inp = """00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010"""
from collections import Counter, defaultdict
inp = inp.split("\n")
bit_counter = defaultdict(Counter)
for line in inp:
for pos, val in enumerate(line):
bit_counter[pos].update([val])
gamma = ""
epsilon = ""
for pos, res in bit_counter.items():
most_common = res.most_common(1)[0][0]
gamma += most_common
epsilon += "0" if most_common == "1" else "1"
gamma = int(gamma, 2)
epsilon = int(epsilon, 2)
answer = gamma * epsilon
# part 2
o2_inp = inp.copy()
co2_inp = inp.copy()
i = 0
while len(o2_inp) > 1 and i < len(o2_inp[0]):
# calc most common for i
c = Counter()
for line in o2_inp:
c.update([line[i]])
# check for ties
if c['1'] == c['0']:
most_common = '1'
else:
most_common = c.most_common(1)[0][0]
o2_inp = filter(lambda item: item[i] == most_common, o2_inp)
o2_inp = list(o2_inp)
i += 1
i = 0
while len(co2_inp) > 1 and i < len(co2_inp[0]):
# calc most common for i
c = Counter()
for line in co2_inp:
c.update([line[i]])
# check for ties
if c['1'] == c['0']:
least_common = '0'
else:
least_common = c.most_common(2)[1][0]
co2_inp = filter(lambda item: item[i] == least_common, co2_inp)
co2_inp = list(co2_inp)
i += 1
answer = int(o2_inp[0], 2) * int(co2_inp[0], 2)
draws = (7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1)
boards = """
22 13 17 11 0
8 2 23 4 24
21 9 14 16 7
6 10 3 18 5
1 12 20 15 19
3 15 0 2 22
9 18 13 17 5
19 8 7 25 23
20 11 10 24 4
14 21 16 12 6
14 21 17 24 4
10 16 15 9 19
18 8 23 26 20
22 11 13 6 5
2 0 12 3 7
"""
class Puzzle:
def __init__(self, board):
self.score = None
self.board_input = board
self.rows = None
self.cols = None
self.build_board()
def build_board(self):
self.rows = [row.split() for row in self.board_input.split("\n") if row]
col_length = len(self.rows[0])
self.cols = [[] for i in range(col_length)]
for row in self.rows:
for i, val in enumerate(row):
self.cols[i].append(val)
def calculate_unmarked(self):
total = 0
for row in self.rows:
for val in row:
if val != "x":
total += int(val)
return total
def mark_board(self, n):
for row in self.rows:
for i, val in enumerate(row):
if val == n:
row[i] = "x"
for col in self.cols:
for i, val in enumerate(col):
if val == n:
col[i] = "x"
if self.check_cols() or self.check_rows():
self.score = self.calculate_unmarked() * int(n)
return self.calculate_unmarked() * int(n)
return False
def check_rows(self):
for row in self.rows:
if all([val == "x" for val in row]):
return True
return False
def check_cols(self):
for col in self.cols:
if all([val == "x" for val in col]):
return True
return False
puzzles = [Puzzle(board) for board in boards.split("\n\n")]
bingo = False
for draw in draws:
for puzzle in puzzles:
bingo = puzzle.mark_board(str(draw))
if bingo:
print(bingo)
break
if bingo:
break
# part 2
puzzles = [Puzzle(board) for board in boards.split("\n\n")]
winning_boards = []
for draw in draws:
for puzzle in puzzles:
if puzzle in winning_boards:
continue
bingo = puzzle.mark_board(str(draw))
if bingo:
winning_boards.append(puzzle)
print(bingo)
"""
This is only part 2. Part 1, just put a `pass` on the diagonal else around line 60
"""
data = """0,9 -> 5,9
8,0 -> 0,8
9,4 -> 3,4
2,2 -> 2,1
7,0 -> 7,4
6,4 -> 2,0
0,9 -> 2,9
3,4 -> 1,4
0,0 -> 8,8
5,5 -> 8,2"""
data = data.split("\n")
class Line:
def __init__(self, data):
self.data = data
self.x_start = None
self.x_end = None
self.y_start = None
self.y_end = None
self.points = []
self.parse_data()
self.all_points()
def parse_data(self):
start, end = self.data.split(" -> ")
self.x_start, self.y_start = [int(x) for x in start.split(",")]
self.x_end, self.y_end = [int(x) for x in end.split(",")]
@property
def coords(self):
return {
"x_start": self.x_start,
"x_end": self.x_end,
"y_start": self.y_start,
"y_end": self.y_end,
}
def all_points(self):
if self.x_start == self.x_end:
if self.y_start < self.y_end:
for i in range(self.y_start, self.y_end + 1):
self.points.append((self.x_start, i))
else:
for i in range(self.y_end, self.y_start + 1):
self.points.append((self.x_start, i))
elif self.y_start == self.y_end:
if self.x_start < self.x_end:
for i in range(self.x_start, self.x_end + 1):
self.points.append((i, self.y_start))
else:
for i in range(self.x_end, self.x_start + 1):
self.points.append((i, self.y_start))
else:
# diagonal, added for part 2
x_step = 1 if self.x_start < self.x_end else -1
x = range(self.x_start, self.x_end + x_step, x_step)
y_step = 1 if self.y_start < self.y_end else -1
y = range(self.y_start, self.y_end + y_step, y_step)
self.points += list(zip(list(x),list(y)))
# parse lines and find shape
lines = []
max_x = 1
max_y = 1
for line in data:
_line = Line(line)
lines.append(_line)
if max(_line.x_start, _line.x_end) > max_x:
max_x = max(_line.x_start, _line.x_end)
if max(_line.y_start, _line.y_end) > max_y:
max_y = max(_line.y_start, _line.y_end)
# build shape
class Grid:
def __init__(self, x, y):
self.max_x = x
self.max_y = y
self.rows = []
self.build_grid()
def build_grid(self):
for i in range(self.max_x+1):
self.rows.append([])
for j in range(self.max_y+1):
self.rows[i].append(0)
def update_point(self, x, y):
self.rows[y][x] += 1
def get_dangerous_points(self, danger=2):
dangerous_points = 0
for row in self.rows:
for cell in row:
if cell >= danger:
dangerous_points += 1
return dangerous_points
def __repr__(self):
return "\n".join([" ".join([str(cell) for cell in row]) for row in self.rows])
grid = Grid(max_x, max_y)
for line in lines:
points = line.points
for point in points:
grid.update_point(*point)
# actual answer toward the bottom
# this works for part 1 but very slowly, part 2 chokes
def make_more_fish(days=18, starting_fish=None):
schedule = defaultdict(int)
fish = starting_fish.copy() if starting_fish is not None else [3,4,3,1,2]
for f in fish:
schedule[f] += 1
for day in range(days):
new_fish = 0
for i, f in enumerate(fish):
if fish[i] == 0:
fish[i] = 6
new_fish += 1
else:
fish[i] -= 1
fish += [8]*new_fish
return len(fish)
# Better and actually works for part 2
from collections import defaultdict
def make_more_fish(days=18, starting_fish=None):
fish = starting_fish.copy() if starting_fish is not None else [3,4,3,1,2]
_fish = defaultdict(int)
for f in fish:
_fish[f] += 1
for day in range(days):
new_fish = defaultdict(int)
for _day, count in _fish.items():
if _day == 0:
new_fish[8] += count
new_fish[6] += count
else:
new_fish[_day-1] += count
_fish = new_fish.copy()
return sum(_fish.values())
# day 7
import statistics
data = [16,1,2,0,4,2,7,1,2,14]
# part 1
median = statistics.median(data)
gas = 0
for d in data:
gas += abs(d-median)
assert gas == 37
# part 2
gas = 0
# rounding down worked on this for actual input... but not round. Round worked for the test data (which rounded up)
mean = round(statistics.mean(data))
for d in data:
gas += sum(range(abs(d-mean)+1))
assert gas == 168
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment