Skip to content

Commit

Permalink
Solution and tests for day 14
Browse files Browse the repository at this point in the history
  • Loading branch information
Sara Veldhoen committed Dec 16, 2021
1 parent 38150b0 commit 3c1af9a
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 0 deletions.
172 changes: 172 additions & 0 deletions aoc_14.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import pathlib
import aocd
from collections import Counter
import sys


def parse(puzzle_input):
lines = puzzle_input.splitlines()
template = lines[0]
rules = {line.split(' -> ')[0]:line.split(' -> ')[1] for line in lines[2:]}
return template, rules
"""Parse input"""

def compute_score_counter(counter):
c = counter.most_common()
return c[0][1] - c[-1][1]

def apply_steps_for_pairs(template,cat_rules, n):
cnt = Counter(template)
polymer = ''
for i in range(len(template) - 1):
polymer += template[i]
c, s = apply_steps_pair(template[i:i+2],cat_rules, n)
cnt += c
polymer += s
polymer += template[-1]
return cnt, polymer


def expand(parents, rules, n):
# we know that every right branch will always expend the same, so focus on the left expansions only
child = rules[parents]
if n>1:
left = parents[0]+child
if left == parents:
True# don't go into this again, we're already working this out for one level higher
else:
expand(left, rules, n-1)
right = child+parents[1]
if right == parents:
True
# don't go into this again, we're already working this out for one level higher
else:
expand(right,rules,n-1)




def apply_steps_pair(parents, cat_rules, n):
polymer = ''
case = 'left' if parents in cat_rules['left'] else 'right' if parents in cat_rules['right'] else 'other'
#breakpoint()
if parents in cat_rules['left']:
child = cat_rules['left'][parents]
descendants = Counter({child:n})
polymer+= n*child
if n>1:
c, s = apply_steps_pair(child+parents[1], cat_rules,n-1)
descendants += c
polymer += s
elif parents in cat_rules['right']:
child = cat_rules['right'][parents]
descendants = Counter({child: n})
if n>1:
c, s = apply_steps_pair(parents[0]+child,cat_rules,n-1)
descendants +=c
polymer += s
polymer += n * child
else:
child = cat_rules['other'][parents]
descendants = Counter({child:1})
if n>1:
c, s = apply_steps_pair(parents[0] + child, cat_rules, n - 1)
descendants += c
polymer += s
polymer += child
c, s = apply_steps_pair(child + parents[1], cat_rules, n - 1)
descendants += c
polymer += s
else:
polymer += child
return descendants, polymer


def null_expansions(rules):
return {0:{key: key[0]+value+key[1] for key, value in rules.items}}




def apply_step(template, rules):
polymer = ''
for i in range(len(template)-1):
polymer+=template[i] + rules[template[i:i+2]]
polymer += template[i+1]
return polymer

def apply_steps(polymer, rules, n):
for i in range(n):
polymer = apply_step(polymer,rules)
return polymer


def pair_counts(pair, rules, known_counts, depth):
if depth not in known_counts:
known_counts[depth]={}
if depth-1 not in known_counts:
known_counts[depth-1] = {}
if depth > 0:
child = rules[pair]
left = pair[0]+child
if left not in known_counts[depth-1]:
known_counts = pair_counts(left, rules, known_counts, depth-1)
assert left in known_counts[depth-1]
right = child+pair[1]
if right not in known_counts[depth - 1]:
known_counts = pair_counts(right, rules, known_counts, depth-1)
assert right in known_counts[depth - 1]
known_counts[depth][pair] = known_counts[depth-1][left]+known_counts[depth-1][right]
known_counts[depth][pair][child] -= 1 # ugly way to make sure child is only counted once
else:
if pair not in known_counts[depth]:
known_counts[depth][pair] = Counter(pair)
return known_counts

def all_pair_counts(rules, to_depth):
counts = {0:{pair:Counter(pair) for pair in rules.keys()}}
for pair in rules.keys():
counts = pair_counts(pair,rules,counts,to_depth)
return counts

def count_based_on_counts(template, rules, depth):
counts = all_pair_counts(rules, depth)
score = Counter()
for i in range(len(template) - 1):
score += counts[depth][template[i:i + 2]]
score[template[i + 1]] -= 1
score[template[-1]] += 1
return score


def compute_score_polymer(polymer):
c = Counter(polymer).most_common()
return c[0][1] - c[-1][1]

def part1(data):
template, rules = parse(data)
#return compute_score_polymer(apply_steps(template,rules,10))
#return compute_score_counter(apply_steps_for_pairs(template, rules, 10))
return compute_score_counter(count_based_on_counts(template, rules, 10))

"""Solve part 1"""



def part2(data):
template, rules = parse(data)

return compute_score_counter(count_based_on_counts(template, rules, 40))


"""Solve part 2"""

def solve(day=14):

"""Solve the puzzle for the given input"""

data = aocd.get_data(day=day)

print('Part one:', part1(data))
print('Part two:', part2(data))

29 changes: 29 additions & 0 deletions aoc_16.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import pathlib
import aocd

import sys


def parse(puzzle_input):

"""Parse input"""


def part1(data):

"""Solve part 1"""


def part2(data):

"""Solve part 2"""


def solve(day=-1):

"""Solve the puzzle for the given input"""

data = aocd.get_data(day=day)

print('Part one:', part1(data))
print('Part two:', part2(data))
114 changes: 114 additions & 0 deletions test_aoc_14.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import collections

import aoc_14 as target


def test_parse():
template, rules = target.parse(example_data)
assert template == example_template
assert rules == example_rules


def test_apply_step():
step_1 = target.apply_step(example_template, example_rules)
assert step_1 == example_step_1
step_2 = target.apply_step(step_1, example_rules)
assert step_2 == example_step_2
step_3 = target.apply_step(step_2, example_rules)
assert step_3 == example_step_3
step_4 = target.apply_step(step_3, example_rules)
assert step_4 == example_step_4


def test_apply_steps():
step_4 = target.apply_steps(example_template, example_rules, 4)
assert step_4 == example_step_4


def test_compute_score():
step_10 = target.apply_steps(example_template, example_rules, 10)
assert target.compute_score(step_10) == 1588


def test_part1():
assert False


def test_part2():
assert False


example_data = """NNCB
CH -> B
HH -> N
CB -> H
NH -> C
HB -> C
HC -> B
HN -> C
NN -> C
BH -> H
NC -> B
NB -> B
BN -> B
BB -> N
BC -> B
CC -> N
CN -> C"""

example_rules = {'CH': 'B', 'HH': 'N', 'CB': 'H', 'NH': 'C', 'HB': 'C', 'HC': 'B', 'HN': 'C', 'NN': 'C', 'BH': 'H',
'NC': 'B', 'NB': 'B', 'BN': 'B', 'BB': 'N', 'BC': 'B', 'CC': 'N', 'CN': 'C'}

example_template = """NNCB"""
example_step_1 = "NCNBCHB"
example_step_2 = "NBCCNBBBCBHCB"
example_step_3 = "NBBBCNCCNBBNBNBBCHBHHBCHB"
example_step_4 = "NBBNBNBBCCNBCNCCNBBNBBNBBBNBBNBBCBHCBHHNHCBBCBHCB"

example_counter_10 = collections.Counter({'B': 1749, 'C': 298, 'H': 161, 'N': 865})


def test_compute_score_counter():
assert target.compute_score_counter(example_counter_10) == 1588


def test_apply_steps_for_pairs():
cat_rules = target.categorize_rules(example_rules)
example_steps = [example_step_1, example_step_2, example_step_3, example_step_4]
# for i, example in enumerate(example_steps):
# c, s = target.apply_steps_for_pairs(example_template, cat_rules, i+1)
# assert s == example
# assert c == collections.Counter(example)

c, s = target.apply_steps_for_pairs(example_steps[0], cat_rules, 3)
assert s == example_steps[3]
assert c == collections.Counter(example_steps[3])


def test_apply_steps_pair():
cat_rules = target.categorize_rules(example_rules)
parents = 'CN'
depth, expansion = 3, 'CCNBCNCCN'
# depth, expansion = 2, 'CNCCN'

# parents = 'CC'
# depth, expansion = 1, 'CNC'
c, s = target.apply_steps_pair(parents, cat_rules, depth)
assert parents[0] + s + parents[1] == expansion
assert c + collections.Counter(parents) == collections.Counter(expansion)


def test_all_pair_counts():
example_steps = [example_template,example_step_1, example_step_2, example_step_3, example_step_4]
for depth, example in enumerate(example_steps):
counts = target.all_pair_counts(example_rules, depth)
score = collections.Counter()
for i in range(len(example_template)-1):
score += counts[depth][example_template[i:i+2]]
score[example_template[i+1]]-=1
score[example_template[-1]]+=1
assert score==collections.Counter(example)



2 changes: 2 additions & 0 deletions test_aoc_16.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def test_read_packet():
assert False

0 comments on commit 3c1af9a

Please sign in to comment.