[py] Port 2017_07
This commit is contained in:
parent
dc35256b28
commit
988c2098e6
4 changed files with 114 additions and 130 deletions
|
|
@ -1,116 +0,0 @@
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# PART 1
|
|
||||||
|
|
||||||
def any_key(d):
|
|
||||||
return list(d)[0]
|
|
||||||
|
|
||||||
class Tower:
|
|
||||||
PROG_RE = r"(\S+) \((\d+)\)( -> (.*))?\n"
|
|
||||||
|
|
||||||
def __init__(self, weight_of, children_of, parent_of):
|
|
||||||
self.wo = weight_of
|
|
||||||
self.co = children_of
|
|
||||||
self.po = parent_of
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_file(cls, filename):
|
|
||||||
weight_of = {} # name -> weight
|
|
||||||
children_of = {} # name -> children
|
|
||||||
parent_of = {} # name -> parent
|
|
||||||
|
|
||||||
with open(filename, "r") as f:
|
|
||||||
for line in f:
|
|
||||||
match = re.fullmatch(cls.PROG_RE, line)
|
|
||||||
|
|
||||||
name = match.group(1)
|
|
||||||
weight = int(match.group(2))
|
|
||||||
if match.group(4):
|
|
||||||
children = match.group(4).split(", ")
|
|
||||||
else:
|
|
||||||
children = []
|
|
||||||
|
|
||||||
weight_of[name] = weight
|
|
||||||
children_of[name] = children
|
|
||||||
for child in children:
|
|
||||||
parent_of[child] = name
|
|
||||||
|
|
||||||
return cls(weight_of, children_of, parent_of)
|
|
||||||
|
|
||||||
def find_root(self):
|
|
||||||
program = any_key(self.po)
|
|
||||||
while program in self.po:
|
|
||||||
program = self.po[program]
|
|
||||||
return program
|
|
||||||
|
|
||||||
# PART 2
|
|
||||||
|
|
||||||
# This part is implemented really shitty. It makes a lot of assumptions and
|
|
||||||
# will probably break the second the input changes or you're just unlucky.
|
|
||||||
# For my particular input, it worked though.
|
|
||||||
#
|
|
||||||
# The basic idea of the algorithm is:
|
|
||||||
#
|
|
||||||
# 1. Find the plate where one branch has a different weight from all the others
|
|
||||||
# 2. Find out which branch weight is wrong and whic weights are correct
|
|
||||||
# 3. Fix the branch's root program's weight
|
|
||||||
|
|
||||||
def weight(self, name):
|
|
||||||
return self.wo[name] + sum(self.weight(c) for c in self.co[name])
|
|
||||||
|
|
||||||
def balanced(self, name):
|
|
||||||
cs = self.co[name]
|
|
||||||
ws = [self.weight(c) for c in cs]
|
|
||||||
return min(ws) == max(ws)
|
|
||||||
|
|
||||||
def unbalanced_child(self, name):
|
|
||||||
for c in self.co[name]:
|
|
||||||
if not self.balanced(c):
|
|
||||||
return c
|
|
||||||
|
|
||||||
def find_imbalance(self, name):
|
|
||||||
c = self.unbalanced_child(name)
|
|
||||||
if c is None:
|
|
||||||
weights = [(c, self.weight(c)) for c in self.co[name]]
|
|
||||||
return weights
|
|
||||||
else:
|
|
||||||
return self.find_imbalance(c)
|
|
||||||
|
|
||||||
def fix_imbalance(self, weights):
|
|
||||||
# Which weight do we need to correct?
|
|
||||||
ws = [weight for (c, weight) in weights]
|
|
||||||
if ws.count(max(ws)) < ws.count(min(ws)):
|
|
||||||
weight = max(ws)
|
|
||||||
other = min(ws)
|
|
||||||
else:
|
|
||||||
weight = min(ws)
|
|
||||||
other = max(ws)
|
|
||||||
|
|
||||||
# Wich program has that weight?
|
|
||||||
prog = None
|
|
||||||
for (p, w) in weights:
|
|
||||||
if w == weight:
|
|
||||||
prog = p
|
|
||||||
break
|
|
||||||
|
|
||||||
# w_prog_soll - w_prog = w_soll - w_branch
|
|
||||||
# w_prog_soll = w_soll - w_branch + w_prog
|
|
||||||
# w_prog_soll = w_soll - (w_branch - w_prog)
|
|
||||||
w_prog = self.wo[prog]
|
|
||||||
w_soll = other
|
|
||||||
w_branch = self.weight(prog)
|
|
||||||
return w_soll - (w_branch - w_prog)
|
|
||||||
|
|
||||||
def main(filename):
|
|
||||||
print(f"Solutions for {filename}")
|
|
||||||
tower = Tower.from_file(filename)
|
|
||||||
root = tower.find_root()
|
|
||||||
print(f"Part 1: {root}")
|
|
||||||
weights = tower.find_imbalance(root)
|
|
||||||
fixed = tower.fix_imbalance(weights)
|
|
||||||
print(f"Part 2: {fixed}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
for filename in sys.argv[1:]:
|
|
||||||
main(filename)
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
pbga (66)
|
|
||||||
xhth (57)
|
|
||||||
ebii (61)
|
|
||||||
havc (66)
|
|
||||||
ktlj (57)
|
|
||||||
fwft (72) -> ktlj, cntj, xhth
|
|
||||||
qoyq (66)
|
|
||||||
padx (45) -> pbga, havc, qoyq
|
|
||||||
tknk (41) -> ugml, padx, fwft
|
|
||||||
jptl (61)
|
|
||||||
ugml (68) -> gyxo, ebii, jptl
|
|
||||||
gyxo (61)
|
|
||||||
cntj (57)
|
|
||||||
|
|
@ -2,7 +2,7 @@ import sys
|
||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from .y2017 import d01, d02, d03, d04, d05, d06
|
from .y2017 import d01, d02, d03, d04, d05, d06, d07
|
||||||
from .y2018 import d01, d02, d03, d04, d05, d06, d07, d08, d09, d10, d11
|
from .y2018 import d01, d02, d03, d04, d05, d06, d07, d08, d09, d10, d11
|
||||||
from .y2020 import d10
|
from .y2020 import d10
|
||||||
from .y2021 import d14
|
from .y2021 import d14
|
||||||
|
|
@ -15,6 +15,7 @@ DAYS = {
|
||||||
"2017_04": y2017.d04.solve,
|
"2017_04": y2017.d04.solve,
|
||||||
"2017_05": y2017.d05.solve,
|
"2017_05": y2017.d05.solve,
|
||||||
"2017_06": y2017.d06.solve,
|
"2017_06": y2017.d06.solve,
|
||||||
|
"2017_07": y2017.d07.solve,
|
||||||
"2018_01": y2018.d01.solve,
|
"2018_01": y2018.d01.solve,
|
||||||
"2018_02": y2018.d02.solve,
|
"2018_02": y2018.d02.solve,
|
||||||
"2018_03": y2018.d03.solve,
|
"2018_03": y2018.d03.solve,
|
||||||
|
|
|
||||||
112
py/aoc/y2017/d07.py
Normal file
112
py/aoc/y2017/d07.py
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
# PART 1
|
||||||
|
|
||||||
|
|
||||||
|
def any_key(d):
|
||||||
|
return list(d)[0]
|
||||||
|
|
||||||
|
|
||||||
|
class Tower:
|
||||||
|
PROG_RE = r"(\S+) \((\d+)\)( -> (.*))?"
|
||||||
|
|
||||||
|
def __init__(self, weight_of, children_of, parent_of):
|
||||||
|
self.wo = weight_of
|
||||||
|
self.co = children_of
|
||||||
|
self.po = parent_of
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_str(cls, s):
|
||||||
|
weight_of = {} # name -> weight
|
||||||
|
children_of = {} # name -> children
|
||||||
|
parent_of = {} # name -> parent
|
||||||
|
|
||||||
|
for line in s.splitlines():
|
||||||
|
match = re.fullmatch(cls.PROG_RE, line)
|
||||||
|
|
||||||
|
name = match.group(1)
|
||||||
|
weight = int(match.group(2))
|
||||||
|
if match.group(4):
|
||||||
|
children = match.group(4).split(", ")
|
||||||
|
else:
|
||||||
|
children = []
|
||||||
|
|
||||||
|
weight_of[name] = weight
|
||||||
|
children_of[name] = children
|
||||||
|
for child in children:
|
||||||
|
parent_of[child] = name
|
||||||
|
|
||||||
|
return cls(weight_of, children_of, parent_of)
|
||||||
|
|
||||||
|
def find_root(self):
|
||||||
|
program = any_key(self.po)
|
||||||
|
while program in self.po:
|
||||||
|
program = self.po[program]
|
||||||
|
return program
|
||||||
|
|
||||||
|
# PART 2
|
||||||
|
|
||||||
|
# This part is implemented really shitty. It makes a lot of assumptions and
|
||||||
|
# will probably break the second the input changes or you're just unlucky.
|
||||||
|
# For my particular input, it worked though.
|
||||||
|
#
|
||||||
|
# The basic idea of the algorithm is:
|
||||||
|
#
|
||||||
|
# 1. Find the plate where one branch has a different weight from all the others
|
||||||
|
# 2. Find out which branch weight is wrong and whic weights are correct
|
||||||
|
# 3. Fix the branch's root program's weight
|
||||||
|
|
||||||
|
def weight(self, name):
|
||||||
|
return self.wo[name] + sum(self.weight(c) for c in self.co[name])
|
||||||
|
|
||||||
|
def balanced(self, name):
|
||||||
|
cs = self.co[name]
|
||||||
|
ws = [self.weight(c) for c in cs]
|
||||||
|
return min(ws) == max(ws)
|
||||||
|
|
||||||
|
def unbalanced_child(self, name):
|
||||||
|
for c in self.co[name]:
|
||||||
|
if not self.balanced(c):
|
||||||
|
return c
|
||||||
|
|
||||||
|
def find_imbalance(self, name):
|
||||||
|
c = self.unbalanced_child(name)
|
||||||
|
if c is None:
|
||||||
|
weights = [(c, self.weight(c)) for c in self.co[name]]
|
||||||
|
return weights
|
||||||
|
else:
|
||||||
|
return self.find_imbalance(c)
|
||||||
|
|
||||||
|
def fix_imbalance(self, weights):
|
||||||
|
# Which weight do we need to correct?
|
||||||
|
ws = [weight for (c, weight) in weights]
|
||||||
|
if ws.count(max(ws)) < ws.count(min(ws)):
|
||||||
|
weight = max(ws)
|
||||||
|
other = min(ws)
|
||||||
|
else:
|
||||||
|
weight = min(ws)
|
||||||
|
other = max(ws)
|
||||||
|
|
||||||
|
# Wich program has that weight?
|
||||||
|
prog = None
|
||||||
|
for (p, w) in weights:
|
||||||
|
if w == weight:
|
||||||
|
prog = p
|
||||||
|
break
|
||||||
|
|
||||||
|
# w_prog_soll - w_prog = w_soll - w_branch
|
||||||
|
# w_prog_soll = w_soll - w_branch + w_prog
|
||||||
|
# w_prog_soll = w_soll - (w_branch - w_prog)
|
||||||
|
w_prog = self.wo[prog]
|
||||||
|
w_soll = other
|
||||||
|
w_branch = self.weight(prog)
|
||||||
|
return w_soll - (w_branch - w_prog)
|
||||||
|
|
||||||
|
|
||||||
|
def solve(inputstr):
|
||||||
|
tower = Tower.from_str(inputstr)
|
||||||
|
root = tower.find_root()
|
||||||
|
print(f"Part 1: {root}")
|
||||||
|
weights = tower.find_imbalance(root)
|
||||||
|
fixed = tower.fix_imbalance(weights)
|
||||||
|
print(f"Part 2: {fixed}")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue