Day 21 (Python)
This commit is contained in:
parent
5a5b902009
commit
93082b4cd9
7 changed files with 225 additions and 1 deletions
2
.github/README.md
vendored
2
.github/README.md
vendored
|
@ -36,7 +36,7 @@ Puzzle inputs and descriptions are not included in this repository. You'll have
|
|||
| [18](/18-operationOrder) | ![Partially complete][partial] | [Link](/18-operationOrder/python) | | |
|
||||
| [19](/19-monsterMessages) | ![Completed][check] | [Link](/19-monsterMessages/python) | [Link](/19-monsterMessages/go) | |
|
||||
| [20](/20-jurassicJigsaw) | ![Partially complete][partial] | [Link](/20-jurassicJigsaw/python) | | Only part one solved |
|
||||
| 21 | ![Not yet attempted][pending] | | | |
|
||||
| [21](/21-allergenAmusement) | ![Partially complete][partial] | [Link](/21-allergenAmusement/python) | | |
|
||||
| 22 | | | | |
|
||||
| 23 | | | | |
|
||||
| 24 | | | | |
|
||||
|
|
23
21-allergenAmusement/README.md
Normal file
23
21-allergenAmusement/README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# [Day 21: Allergen Amusement](https://adventofcode.com/2020/day/21)
|
||||
|
||||
This one isn't going to be translated to go because **a)** Go has no sets and **b)** Go is statically typed and I cannot be bothered to try and tweak the return type for part two.
|
||||
|
||||
*I made the assumption we'd only ever have numeric solutions when I built the boilerplate, goddamnit!*
|
||||
|
||||
<details><summary>Script output</summary>
|
||||
|
||||
```
|
||||
❯ python .\python\
|
||||
AoC 2020: day 21 - Allergen Amusement
|
||||
Python 3.8.5
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 2307
|
||||
Part 2: cljf,frtfg,vvfjj,qmrps,hvnkk,qnvx,cpxmpc,qsjszn
|
||||
```
|
||||
|
||||
</details>
|
19
21-allergenAmusement/info.json
Normal file
19
21-allergenAmusement/info.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"year": "2020",
|
||||
"day": "21",
|
||||
"title": "Allergen Amusement",
|
||||
"testCases": {
|
||||
"one": [
|
||||
{
|
||||
"input": "mxmxvkd kfcds sqjhc nhms (contains dairy, fish)\ntrh fvjkl sbzzf mxmxvkd (contains dairy)\nsqjhc fvjkl (contains soy)\nsqjhc mxmxvkd sbzzf (contains fish)\n",
|
||||
"expected": 5
|
||||
}
|
||||
],
|
||||
"two": [
|
||||
{
|
||||
"input": "mxmxvkd kfcds sqjhc nhms (contains dairy, fish)\ntrh fvjkl sbzzf mxmxvkd (contains dairy)\nsqjhc fvjkl (contains soy)\nsqjhc mxmxvkd sbzzf (contains fish)\n",
|
||||
"expected": "mxmxvkd,sqjhc,fvjkl"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
79
21-allergenAmusement/python/__main__.py
Normal file
79
21-allergenAmusement/python/__main__.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
import json
|
||||
import platform
|
||||
import sys
|
||||
|
||||
from rich import print
|
||||
|
||||
from partOne import partOne
|
||||
from partTwo import partTwo
|
||||
|
||||
|
||||
def run_tests(test_cases):
|
||||
do_tests = True
|
||||
if len(test_cases) == 0:
|
||||
do_tests = False
|
||||
elif len(test_cases["one"]) == 0 and len(test_cases["two"]) == 0:
|
||||
do_tests = False
|
||||
|
||||
if not do_tests:
|
||||
print("Info: no test cases specified. Skipping tests\n")
|
||||
return
|
||||
|
||||
print("Test cases")
|
||||
|
||||
def rt(tcs, f, n):
|
||||
for i, tc in enumerate(tcs):
|
||||
print(f"{n}.{i+1} ", end="")
|
||||
expectedInt = tc["expected"]
|
||||
result = f(str(tc["input"]))
|
||||
if result == expectedInt:
|
||||
print("[green]pass[/green]")
|
||||
else:
|
||||
print(f"[red]fail[/red] (got {result}, expected {expectedInt})")
|
||||
|
||||
rt(test_cases["one"], partOne, 1)
|
||||
rt(test_cases["two"], partTwo, 2)
|
||||
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
info = open("info.json").read()
|
||||
except FileNotFoundError:
|
||||
print("Error: could not open info.json")
|
||||
sys.exit(-1)
|
||||
|
||||
info = json.loads(info)
|
||||
|
||||
year = info["year"]
|
||||
day = info["day"]
|
||||
title = info["title"]
|
||||
|
||||
print(f"[yellow]AoC {year}[/yellow]: day {day} - {title}")
|
||||
print(f"Python {platform.python_version()}\n")
|
||||
|
||||
try:
|
||||
challenge_input = open("input.txt").read()
|
||||
except FileNotFoundError:
|
||||
print("Error: could not open input.txt")
|
||||
sys.exit(-1)
|
||||
|
||||
if "vis" in sys.argv:
|
||||
import visualise
|
||||
|
||||
print("[green]Running visualisation....[/green]")
|
||||
|
||||
visualise.visualise(challenge_input)
|
||||
sys.exit()
|
||||
|
||||
run_tests(info["testCases"])
|
||||
|
||||
if "debug" in sys.argv:
|
||||
sys.exit()
|
||||
|
||||
print("Answers")
|
||||
print("Part 1: ", end="")
|
||||
print(partOne(challenge_input))
|
||||
print("Part 2: ", end="")
|
||||
print(partTwo(challenge_input))
|
46
21-allergenAmusement/python/common.py
Normal file
46
21-allergenAmusement/python/common.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
from typing import List, Set, Tuple, Dict
|
||||
import re
|
||||
|
||||
|
||||
class Food:
|
||||
ingredients: List[str]
|
||||
known_allergens: Set[str]
|
||||
|
||||
def __init__(self, ingredients: List[str], known_allergens: Set[str]) -> None:
|
||||
self.ingredients = ingredients
|
||||
self.known_allergens = known_allergens
|
||||
|
||||
|
||||
def parse(instr: str) -> Tuple[List[Food], Set[str]]:
|
||||
|
||||
foods = []
|
||||
all_allergens = set()
|
||||
|
||||
for x in instr.strip().split("\n"):
|
||||
|
||||
m = re.match(r"(.+) \(contains (.+)\)", x)
|
||||
if m is None:
|
||||
raise ValueError("input string does not match required format")
|
||||
|
||||
ingredients = m.group(1).split(" ")
|
||||
allergens = set(m.group(2).split(", "))
|
||||
all_allergens = all_allergens.union(allergens)
|
||||
|
||||
foods.append(Food(ingredients, allergens))
|
||||
|
||||
return foods, all_allergens
|
||||
|
||||
|
||||
def get_possibilities(foods: List[Food], allergens: Set[str]) -> Dict[str, Set[str]]:
|
||||
possibilities = {n: set() for n in allergens}
|
||||
|
||||
for food in foods:
|
||||
for known_allergen in food.known_allergens:
|
||||
if len(possibilities[known_allergen]) == 0:
|
||||
possibilities[known_allergen] = set(food.ingredients)
|
||||
else:
|
||||
possibilities[known_allergen] = (
|
||||
set(food.ingredients) & possibilities[known_allergen]
|
||||
)
|
||||
|
||||
return possibilities
|
18
21-allergenAmusement/python/partOne.py
Normal file
18
21-allergenAmusement/python/partOne.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
from common import *
|
||||
|
||||
|
||||
def partOne(instr: str) -> int:
|
||||
foods, allergens = parse(instr)
|
||||
possibilities = get_possibilities(foods, allergens)
|
||||
|
||||
bad_ingredients = set()
|
||||
for x in possibilities:
|
||||
bad_ingredients.update(possibilities[x])
|
||||
|
||||
count = 0
|
||||
for food in foods:
|
||||
for ingredient in food.ingredients:
|
||||
if ingredient not in bad_ingredients:
|
||||
count += 1
|
||||
|
||||
return count
|
39
21-allergenAmusement/python/partTwo.py
Normal file
39
21-allergenAmusement/python/partTwo.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from common import *
|
||||
|
||||
|
||||
def partTwo(instr: str) -> None:
|
||||
foods, allergens = parse(instr)
|
||||
possibilities = get_possibilities(foods, allergens)
|
||||
|
||||
definites = {} # ingredients that definitely contain allergens
|
||||
|
||||
# remove known things
|
||||
for possibility in possibilities:
|
||||
if len(possibilities[possibility]) == 1:
|
||||
definites[possibility] = possibilities[possibility].pop()
|
||||
|
||||
for definite in definites:
|
||||
del possibilities[definite]
|
||||
|
||||
while True:
|
||||
definite_set = set([definites[x] for x in definites])
|
||||
if len(possibilities) == 0:
|
||||
break
|
||||
|
||||
to_del = []
|
||||
for possibility in possibilities:
|
||||
possibilities[possibility] = possibilities[possibility] - definite_set
|
||||
if len(possibilities[possibility]) == 0:
|
||||
to_del.append(possibility)
|
||||
elif len(possibilities[possibility]) == 1:
|
||||
definites[possibility] = possibilities[possibility].pop()
|
||||
|
||||
for td in to_del:
|
||||
del possibilities[td]
|
||||
|
||||
return ",".join(
|
||||
[
|
||||
x[1]
|
||||
for x in sorted([(x, definites[x]) for x in definites], key=lambda x: x[0])
|
||||
]
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue