summaryrefslogtreecommitdiffstats
path: root/16/solution.py
diff options
context:
space:
mode:
Diffstat (limited to '16/solution.py')
-rw-r--r--16/solution.py77
1 files changed, 77 insertions, 0 deletions
diff --git a/16/solution.py b/16/solution.py
new file mode 100644
index 0000000..b7ebc5c
--- /dev/null
+++ b/16/solution.py
@@ -0,0 +1,77 @@
+from dataclasses import dataclass
+
+@dataclass
+class SueQuality:
+ quality: int | None = None
+
+ def __eq__(self, other):
+ return self.quality is None or other.quality is None or self.quality == other.quality
+
+ def __gt__(self, other):
+ return self.quality is None or other.quality is None or self.quality > other.quality
+ def __lt__(self, other):
+ return self.quality is None or other.quality is None or self.quality < other.quality
+
+@dataclass
+class Sue:
+ children: SueQuality = SueQuality()
+ cats: SueQuality = SueQuality()
+ samoyeds: SueQuality = SueQuality()
+ pomeranians: SueQuality = SueQuality()
+ akitas: SueQuality = SueQuality()
+ vizslas: SueQuality = SueQuality()
+ goldfish: SueQuality = SueQuality()
+ trees: SueQuality = SueQuality()
+ cars: SueQuality = SueQuality()
+ perfumes: SueQuality = SueQuality()
+
+ def cmp(self, other: 'Sue') -> bool:
+ for attr in self.__dict__:
+ if getattr(self, attr) != getattr(other, attr):
+ return False
+ return True
+
+ def cmp2(self, other: 'Sue') -> bool:
+ return (
+ self.children == other.children and
+ self.cats > other.cats and
+ self.samoyeds == other.samoyeds and
+ self.pomeranians < other.pomeranians and
+ self.akitas == other.akitas and
+ self.vizslas == other.vizslas and
+ self.goldfish < other.goldfish and
+ self.trees > other.trees and
+ self.cars == other.cars and
+ self.perfumes == other.perfumes
+ )
+
+ @staticmethod
+ def from_string(s: str) -> tuple[int, 'Sue']:
+ number, rest = s.split(': ', 1)
+ number = int(number.split(' ')[1])
+ properties = {p[0]: SueQuality(int(p[1])) for p in (prop.split(': ') for prop in rest.split(', '))}
+ return number, Sue(**properties)
+
+def part1(sues: list[Sue]) -> int:
+ desired = Sue(
+ children=SueQuality(3), cats=SueQuality(7), samoyeds=SueQuality(2),
+ pomeranians=SueQuality(3), akitas=SueQuality(0), vizslas=SueQuality(0),
+ goldfish=SueQuality(5), trees=SueQuality(3), cars=SueQuality(2),
+ perfumes=SueQuality(1)
+ )
+ return next(number for number, sue in sues.items() if sue.cmp(desired))
+
+def part2(sues: list[Sue]) -> int:
+ desired = Sue(
+ children=SueQuality(3), cats=SueQuality(7), samoyeds=SueQuality(2),
+ pomeranians=SueQuality(3), akitas=SueQuality(0), vizslas=SueQuality(0),
+ goldfish=SueQuality(5), trees=SueQuality(3), cars=SueQuality(2),
+ perfumes=SueQuality(1)
+ )
+ return next(number for number, sue in sues.items() if sue.cmp2(desired))
+
+if __name__ == '__main__':
+ with open('input') as f:
+ sues = {number: sue for number, sue in (Sue.from_string(line) for line in f)}
+ print(part1(sues))
+ print(part2(sues))