Skip to content

Instantly share code, notes, and snippets.

@StevenJL
Last active December 11, 2022 07:23
Show Gist options
  • Save StevenJL/4a4a7c1d2b321f1be3bbc518e7f00e1f to your computer and use it in GitHub Desktop.
Save StevenJL/4a4a7c1d2b321f1be3bbc518e7f00e1f to your computer and use it in GitHub Desktop.
aoc2022
# _____ _ _ _____ ______ ______ ______ ______ ______ ______ ______ _______
# / ____| | | |_ _| ____| ____| ____| ____| ____| ____| ____|__ __|
# | (___ | |__| | | | | |__ | |__ | |__ | |__ | |__ | |__ | |__ | |
# \___ \| __ | | | | __| | __| | __| | __| | __| | __| | __| | |
# ____) | | | |_| |_| |____| |____| |____| |____| |____| |____| |____ | |
# |_____/|_| |_|_____|______|______|______|______|______|______|______| |_|
######################## Day 1 ################################
with open('./input') as f:
lines = [line.rstrip() for line in f]
reduced = []
current_cal = 0
for line in lines:
if line == '':
reduced.append(current_cal)
current_cal = 0
else:
current_cal = current_cal + int(line)
length = len(reduced)
print(sorted(reduced)[length-3:length])
######################## Day 2 ################################
outcome_dict = { 'A X': 3, 'A Y': 6, 'A Z': 0, 'B X': 0, 'B Y': 3, 'B Z': 6, 'C X': 6, 'C Y': 0, 'C Z': 3}
shape_score = { 'X': 1, 'Y': 2, 'Z': 3}
score = 0
with open('./input') as f:
lines = [line.rstrip() for line in f]
for line in lines:
score = score + outcome_dict[line] + shape_score[line[2]]
print(score)
######################## Day 2 - pt 2 ################################
outcome_dict = { 'X': 0, 'Y': 3, 'Z': 6}
shape_dict = { 'A X': 3, 'A Y': 1, 'A Z': 2, 'B X': 1, 'B Y': 2, 'B Z': 3, 'C X': 2, 'C Y': 3, 'C Z': 1 }
score = 0
with open('./input') as f:
lines = [line.rstrip() for line in f]
for line in lines:
score = score + outcome_dict[line[2]] + shape_dict[line]
print(score)
######################## Day 3 ################################
with open('./input') as f:
lines = [line.rstrip() for line in f]
def messed_up_item(comp1, comp2):
for item in comp1:
if comp2.find(item) != -1:
return item
def priority(item):
# lower case
if ord(item) > 96:
return ord(item) - 96
else:
return ord(item) - 38
priority_sum = 0
for line in lines:
mp = int(len(line)/2)
comp1 = line[0:mp]
comp2 = line[mp:]
priority_sum = priority_sum + priority(messed_up_item(comp1, comp2))
print(priority_sum)
######################## Day 3 - pt 2 ################################
def priority(item):
# lower case
if ord(item) > 96:
return ord(item) - 96
else:
return ord(item) - 38
with open('./input') as f:
lines = [line.rstrip() for line in f]
lines_grouped_three = []
lines_len = len(lines)
for i in range(0, lines_len, 3):
lines_grouped_three.append(lines[i:i+3])
priority_sum = 0
for group in lines_grouped_three:
set_with_badge = set(group[0]) & set(group[1]) & set(group[2])
for badge in set_with_badge:
priority_sum = priority_sum + priority(badge)
print(priority_sum)
######################## Day 4 ################################
with open('./input') as f:
lines = [line.rstrip() for line in f]
fully_contained_count = 0
for line in lines:
parsed_line = list(map(lambda x: x.split('-'), line.split(',')))
ass1 = parsed_line[0]
ass2 = parsed_line[1]
if int(ass1[0]) == int(ass2[0]):
fully_contained_count = fully_contained_count + 1
elif int(ass1[1]) == int(ass2[1]):
fully_contained_count = fully_contained_count + 1
elif int(ass1[0]) < int(ass2[0]):
if int(ass1[1]) >= int(ass2[1]):
fully_contained_count = fully_contained_count + 1
else:
continue
else:
if int(ass1[1]) <= int(ass2[1]):
fully_contained_count = fully_contained_count + 1
else:
continue
print(fully_contained_count)
######################## Day 4 - part 2 ################################
with open('./input') as f:
lines = [line.rstrip() for line in f]
overlap_atall_count = 0
for line in lines:
parsed_line = list(map(lambda x: x.split('-'), line.split(',')))
ass1 = parsed_line[0]
ass2 = parsed_line[1]
if (int(ass1[1]) >= int(ass2[0])) and not (int(ass2[1]) <= int(ass1[0])):
overlap_atall_count = overlap_atall_count + 1 77 def knot_follow(follower, leader)
elif (int(ass2[1]) >= int(ass1[0])) and not (int(ass1[1]) <= int(ass2[0])):
overlap_atall_count = overlap_atall_count + 1
else:
continue
print(overlap_atall_count)
######################## Day 5 #############################
with open('initial_config') as f:
ic_lines = [line.rstrip() for line in f]
stack_indices = ic_lines.pop().split()
stack_indices_int = list(map(lambda x: int(x), stack_indices))
config_dict = { }
for si in stack_indices_int:
config_dict[si] = []
ic_lines.reverse()
for ic_line in ic_lines:
row = ic_line.replace('[','').replace(']','').split()
for si in stack_indices_int:
if row[si-1] == '*':
continue
else:
config_dict[si].append(row[si-1])
with open('steps') as f:
stp_lines = [line.rstrip() for line in f]
for sl in stp_lines:
sl_list = sl.split()
moves_count = int(sl_list[1])
stack_source = int(sl_list[3])
stack_target = int(sl_list[5])
for i in range(moves_count):
crate = config_dict[stack_source].pop()
config_dict[stack_target].append(crate)
######################## Day 5 - pt 2 #############################
with open('initial_config') as f:
ic_lines = [line.rstrip() for line in f]
stack_indices = ic_lines.pop().split()
stack_indices_int = list(map(lambda x: int(x), stack_indices))
config_dict = { }
for si in stack_indices_int:
config_dict[si] = []
ic_lines.reverse()
for ic_line in ic_lines:
row = ic_line.replace('[','').replace(']','').split()
for si in stack_indices_int:
if row[si-1] == '*':
continue
else:
config_dict[si].append(row[si-1])
with open('steps') as f:
stp_lines = [line.rstrip() for line in f]
for sl in stp_lines:
sl_list = sl.split()
moves_count = int(sl_list[1])
stack_source = int(sl_list[3])
stack_target = int(sl_list[5])
buffer = []
for i in range(moves_count):
buffer.append(config_dict[stack_source].pop())
buffer.reverse()
for crate in buffer :
config_dict[stack_target].append(crate)
######################## Day 6 #############################
with open('input') as f:
signal = [line.rstrip() for line in f][0]
signal_len = len(signal)
for i in range(signal_len):
j = i + 14
if len(set(signal[i:j])) == 14:
print(j)
break
###################### Day 7 ################################
# Don't know how regexes work in Python... didn't wanna learn it on the fly, so switched to Ruby
file_contents = open('./input') { |f| f.read }.split("\n")
directory_bytes = Hash.new(0)
directory_stack = ["root"]
file_contents[2..-1].each do |line|
if (mo = /^(\d+)\s.*/.match(line))
directory_stack.each_with_index do |_dir, indx|
full_path = directory_stack[0..indx].join("/")
directory_bytes[full_path] = directory_bytes[full_path] + mo[1].to_i
end
elsif line == "$ cd .."
directory_stack.pop
elsif (mo = /^\$\scd\s(.*)/.match(line))
directory_stack << mo[1]
end
end
# Part 1
puts directory_bytes.select { |k,v| v <= 100000 }.values.sum
# Part 2
current_unused_space = 70000000 - directory_bytes["root"]
delta = 30000000 - current_unused_space
puts directory_bytes.select { |k,v| v >= delta }.sort_by { |k, v| v }[0]
################# Day 8 - part 1 #################################
# Getting too hard, just gonna do em in Ruby going forward now lol
@trees = open('input') { |f| f.read }.split("\n").map { |row| row.split('') }
@i_last_index = @trees.count - 1
@j_last_index = @trees.first.count - 1
def is_visible?(coord)
is_visible_from_left?(coord[0], coord[1]) ||
is_visible_from_right?(coord[0], coord[1]) ||
is_visible_from_top?(coord[0], coord[1]) ||
is_visible_from_bottom?(coord[0], coord[1])
end
def is_visible_from_left?(i,j)
value = @trees[i][j].to_i
(0..(j -1)).each do |j_inner|
if @trees[i][j_inner].to_i >= value
return false
end
end
true
end
def is_visible_from_right?(i,j)
value = @trees[i][j].to_i
((j+1)..(@j_last_index)).each do |j_inner|
if @trees[i][j_inner].to_i >= value
return false
end
end
true
end
def is_visible_from_top?(i,j)
value = @trees[i][j].to_i
(0..(i-1)).each do |i_inner|
if @trees[i_inner][j].to_i >= value
return false
end
end
true
end
def is_visible_from_bottom?(i,j)
value = @trees[i][j].to_i
((i+1)..(@i_last_index)).each do |i_inner|
if @trees[i_inner][j].to_i >= value
return false
end
end
true
end
all_coords = []
(0..@i_last_index).each do |i|
(0..@j_last_index).each do |j|
all_coords << [i,j]
end
end
puts all_coords.select { |coord| is_visible?(coord) }.count
###################### Day 8 - part 2 ################
@trees = open('input') { |f| f.read }.split("\n").map { |row| row.split('') }
@i_last_index = @trees.count - 1
@j_last_index = @trees.first.count - 1
def is_visible?(coord)
is_visible_from_left?(coord[0], coord[1]) ||
is_visible_from_right?(coord[0], coord[1]) ||
is_visible_from_top?(coord[0], coord[1]) ||
is_visible_from_bottom?(coord[0], coord[1])
end
def is_visible_from_left?(i,j)
value = @trees[i][j].to_i
(0..(j -1)).each do |j_inner|
if @trees[i][j_inner].to_i >= value
return false
end
end
true
end
def is_visible_from_right?(i,j)
value = @trees[i][j].to_i
((j+1)..(@j_last_index)).each do |j_inner|
if @trees[i][j_inner].to_i >= value
return false
end
end
true
end
def is_visible_from_top?(i,j)
value = @trees[i][j].to_i
(0..(i-1)).each do |i_inner|
if @trees[i_inner][j].to_i >= value
return false
end
end
true
end
def is_visible_from_bottom?(i,j)
value = @trees[i][j].to_i
((i+1)..(@i_last_index)).each do |i_inner|
if @trees[i_inner][j].to_i >= value
return false
end
end
true
end
all_coords = []
(0..@i_last_index).each do |i|
(0..@j_last_index).each do |j|
all_coords << [i,j]
end
end
puts all_coords.select { |coord| is_visible?(coord) }.count
############################ Day 9 ################################
require "set"
file_contents = open('input.txt') { |f| f.read }.split("\n")
@tail_visited_coords = Set.new([0,0])
@tail_coord = [4,0]
@head_coord = [4,0]
def move_head(direction)
x,y = @head_coord
case direction
when "R"
@head_coord = [x, y + 1]
when "U"
@head_coord = [x - 1, y]
when "L"
@head_coord = [x, y - 1]
when "D"
@head_coord = [x + 1, y]
end
end
# https://en.wikipedia.org/wiki/Taxicab_geometry
def taxi_cab_dist
(@head_coord[0] - @tail_coord[0]).abs + (@head_coord[1] - @tail_coord[1]).abs
end
def adjacent?
return true if taxi_cab_dist <= 1
if taxi_cab_dist == 2
if @head_coord[0] == @tail_coord[0] || @head_coord[1] == @tail_coord[1]
# two steps away along same axis
false
else
# diagonal
true
end
end
end
def tail_follow
unless adjacent?
tx, ty = @tail_coord
hx, hy = @head_coord
if hx == tx && (ty - hy).abs == 2
@tail_coord = [tx, (ty + hy) / 2]
elsif ty == hy && (hx - tx).abs == 2
@tail_coord = [(tx + hx) / 2, ty]
else
if (hy - ty).abs == 2 && (hx - tx).abs == 1
@tail_coord = [hx, (hy + ty)/2]
elsif (hx - tx).abs == 2 && (hy - ty).abs == 1
@tail_coord = [(hx + tx)/2, hy]
else
raise "you dun' goofed, kid"
end
end
@tail_visited_coords.add(@tail_coord)
end
end
file_contents.each do |line|
puts line
mo = /^([A-Z])\s(\d+)/.match(line)
direction = mo[1]
steps = mo[2].to_i
steps.times do
move_head(direction)
tail_follow
end
end
############### Day 9 - pt 2 ###########################
require "set"
file_contents = open('test') { |f| f.read }.split("\n")
@tail_visited_coords = Set.new([0,0])
# Switched to Structs which are always pass-by-reference.
# Was worried (incorrectly) that arrays were pass-by-value in Ruby.
Coordinate = Struct.new(:x, :y, :name) do
def xy
[x,y]
end
end
@head_coord = Coordinate.new(40,40, 'H')
@one_coord = Coordinate.new(40,40, '1')
@two_coord = Coordinate.new(40,40, '2')
@three_coord = Coordinate.new(40,40, '3')
@four_coord = Coordinate.new(40,40, '4')
@five_coord = Coordinate.new(40,40, '5')
@six_coord = Coordinate.new(40,40, '6')
@seven_coord = Coordinate.new(40,40, '7')
@eight_coord = Coordinate.new(40,40, '8')
@nine_coord = Coordinate.new(40,40, '9')
@followers = [@one_coord, @two_coord, @three_coord, @four_coord, @five_coord, @six_coord, @seven_coord, @eight_coord, @nine_coord]
@leaders = [@head_coord, @one_coord, @two_coord, @three_coord, @four_coord, @five_coord, @six_coord, @seven_coord, @eight_coord]
def print_tail
world = []
80.times do
world << ('.' * 80).split('')
end
@tail_visited_coords.each do |coord|
world[coord[0]][coord[1]] = '#'
end
world.each do |line|
line.each do |c|
print(c)
end
print("\n")
end
end
def move_head(direction)
case direction
when "R"
@head_coord.y = @head_coord.y + 1
when "U"
@head_coord.x = @head_coord.x - 1
when "L"
@head_coord.y = @head_coord.y - 1
when "D"
@head_coord.x = @head_coord.x + 1
end
end
def taxi_cab_dist(coord1, coord2)
(coord1.x - coord2.x).abs + (coord1.y - coord2.y).abs
end
def adjacent?(coord1, coord2)
return true if taxi_cab_dist(coord1, coord2) <= 1
if taxi_cab_dist(coord1, coord2) == 2
if coord1.x == coord2.x || coord1.y == coord2.y
# two steps away along same axis
false
else
# diagonal
true
end
end
end
def knot_follow(follower, leader)
tx, ty = follower.xy
hx, hy = leader.xy
if hx == tx && (ty - hy).abs == 2
[tx, (ty + hy) / 2]
elsif ty == hy && (hx - tx).abs == 2
[(tx + hx) / 2, ty]
else
if (hy - ty).abs == 2 && (hx - tx).abs == 1
[hx, (hy + ty)/2]
elsif (hx - tx).abs == 2 && (hy - ty).abs == 1
[(hx + tx)/2, hy]
else
[(tx + hx)/2, (ty + hy)/2]
end
end
end
file_contents.each do |line|
mo = /^([A-Z])\s(\d+)/.match(line)
direction = mo[1]
steps = mo[2].to_i
steps.times do
move_head(direction)
@followers.each_with_index do |follower, index|
leader = @leaders[index]
unless adjacent?(follower, leader)
puts "MOVING #{follower.name}"
new_x, new_y = knot_follow(follower, leader)
follower.x = new_x
follower.y = new_y
tail_coordinates = [@nine_coord.x, @nine_coord.y]
@tail_visited_coords.add(tail_coordinates)
end
end
end
end
#################### Day 11 ##########################
Monkey = Struct.new(:times_inspected, :items, :worry_op, :test_div_num, :test_true_monkey, :test_false_monkey) do
def catch_item(item)
self.items.append(item)
end
def take_turn
tosses = []
items.each do |item|
new_worry = worry_op.call(item)
self.times_inspected = times_inspected + 1
new_worry = new_worry / 3
if new_worry % test_div_num == 0
tosses << [new_worry, test_true_monkey]
else
tosses << [new_worry, test_false_monkey]
end
end
self.items = []
tosses
end
end
# @param [String]
# Ex: "old * 11"
# Ex: "old + 4"
def lambdaize_worry(operation)
eval("-> (old) { #{operation} }")
end
@monkeys = []
open('input.txt') { |f| f.read }.split("\n\n").each do |monkey_serialized|
_monkey_number, starting_items, worry_operation, test_div, test_true, test_false = monkey_serialized.split("\n").map(&:strip)
starting_items_parsed = starting_items[15..-1].split(', ').map(&:to_i)
worry_operation_lambda = lambdaize_worry(worry_operation[17..-1])
test_div_num = test_div[19..-1].to_i
test_true_monkey = test_true[25..-1].to_i
test_false_monkey = test_false[26..-1].to_i
@monkeys << Monkey.new(0, starting_items_parsed, worry_operation_lambda, test_div_num, test_true_monkey, test_false_monkey)
end
def run_round
@monkeys.each do |monkey|
tosses = monkey.take_turn
tosses.each do |toss|
item, monkey_index = toss
target_monkey = @monkeys[monkey_index]
target_monkey.catch_item(item)
end
end
end
20.times do
run_round
end
max_times_counted = @monkeys.map { |monkey| monkey.times_inspected }.sort.reverse[0..1]
monkey_business = max_times_counted[0] * max_times_counted[1]
#################### Day 11 - part 2 ###########################
Monkey = Struct.new(:monkey_name, :times_inspected, :items, :worry_op, :test_div_num, :test_true_monkey, :test_false_monkey) do
def catch_item(item)
self.items.append(item)
end
def take_turn
tosses = []
items.each do |item|
self.times_inspected = times_inspected + 1
new_worry = worry_op.call(item)
new_worry_crted = new_worry % CRT_PRODUCT
if new_worry_crted % test_div_num == 0
tosses << [new_worry_crted, test_true_monkey]
else
tosses << [new_worry_crted, test_false_monkey]
end
end
self.items = []
tosses
end
end
# @param [String]
# Ex: "old * 11"
# Ex: "old + 4"
def lambdaize_worry(operation)
eval("-> (old) { #{operation} }")
end
@monkeys = []
# Product of all divisibility numbers, from Chinese Remainder Theorem
CRT_PRODUCT = 5 * 17 * 2 * 7 * 3 * 11 * 13 * 19
open('input.txt') { |f| f.read }.split("\n\n").each do |monkey_serialized|
monkey_number, starting_items, worry_operation, test_div, test_true, test_false = monkey_serialized.split("\n").map(&:strip)
starting_items_parsed = starting_items[15..-1].split(', ').map(&:to_i)
worry_operation_lambda = lambdaize_worry(worry_operation[17..-1])
test_div_num = test_div[19..-1].to_i
test_true_monkey = test_true[25..-1].to_i
test_false_monkey = test_false[26..-1].to_i
@monkeys << Monkey.new(monkey_number, 0, starting_items_parsed, worry_operation_lambda, test_div_num, test_true_monkey, test_false_monkey)
end
def run_round
@monkeys.each do |monkey|
tosses = monkey.take_turn
tosses.each do |toss|
item, monkey_index = toss
target_monkey = @monkeys[monkey_index]
target_monkey.catch_item(item)
end
end
end
10000.times do |indx|
puts "On Round #{indx + 1}"
run_round
end
max_times_counted = @monkeys.map { |monkey| monkey.times_inspected }.sort.reverse[0..1]
puts monkey_business = max_times_counted[0] * max_times_counted[1]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment