-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path__init__.py
71 lines (52 loc) · 1.82 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import math
from typing import Tuple, List, Dict
from aocpy import BaseChallenge
Rule = Tuple[str, str]
Pairs = Dict[str, int]
def parse(instr: str) -> Tuple[str, List[Rule]]:
seq, rawRules = instr.strip().split("\n\n")
return seq, [tuple(x.split(" -> ")) for x in rawRules.splitlines()]
def make_pair_dict(seq: str) -> Pairs:
o = {}
for i in range(len(seq) - 1):
s = seq[i] + seq[i + 1]
o[s] = o.get(s, 0) + 1
return o
def apply_rules(pairs: Pairs, rules: List[Rule]) -> Pairs:
deltas = {}
for rule in rules:
rule_part_a = rule[0][0] + rule[1]
rule_part_b = rule[1] + rule[0][1]
if rule[0] in pairs:
count = pairs[rule[0]]
deltas[rule[0]] = deltas.get(rule[0], 0) - count
deltas[rule_part_a] = deltas.get(rule_part_a, 0) + count
deltas[rule_part_b] = deltas.get(rule_part_b, 0) + count
for key in deltas:
new = pairs.get(key, 0) + deltas[key]
pairs[key] = 0 if new < 0 else new
return pairs
def count_letters(pairs: Pairs) -> Dict[str, int]:
o = {}
for pair in pairs:
n = pairs[pair]
o[pair[0]] = o.get(pair[0], 0) + n
o[pair[1]] = o.get(pair[1], 0) + n
for key in o:
o[key] = math.ceil(o[key] / 2)
return o
class Challenge(BaseChallenge):
@staticmethod
def core(instr: str, n: int) -> int:
sequence, rules = parse(instr)
sequence_pairs = make_pair_dict(sequence)
for _ in range(n):
sequence_pairs = apply_rules(sequence_pairs, rules)
vals = count_letters(sequence_pairs).values()
return max(vals) - min(vals)
@staticmethod
def one(instr: str) -> int:
return Challenge.core(instr, 10)
@staticmethod
def two(instr: str) -> int:
return Challenge.core(instr, 40)