Day 22 (Python)
This commit is contained in:
parent
c2a6a2fe3b
commit
aba7285d84
7 changed files with 259 additions and 1 deletions
2
.github/README.md
vendored
2
.github/README.md
vendored
|
@ -37,7 +37,7 @@ Puzzle inputs and descriptions are not included in this repository. You'll have
|
|||
| [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](/21-allergenAmusement) | ![Partially complete][partial] | [Link](/21-allergenAmusement/python) | | |
|
||||
| 22 | ![Not yet attempted][pending] | | | |
|
||||
| [22](/22-crabCombat) | ![Partially complete][partial] | [Link](/22-crabCombat/python) | | |
|
||||
| 23 | | | | |
|
||||
| 24 | | | | |
|
||||
| 25 | | | | |
|
||||
|
|
19
22-crabCombat/README.md
Normal file
19
22-crabCombat/README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# [Day 22: Crab Combat](https://adventofcode.com/2020/day/22)
|
||||
|
||||
<details><summary>Script output</summary>
|
||||
|
||||
```
|
||||
❯ python .\python\
|
||||
AoC 2020: day 22 - Crab Combat
|
||||
Python 3.8.5
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 35397
|
||||
Part 2: 31120 in 18.785030126571655 seconds
|
||||
```
|
||||
|
||||
</details>
|
19
22-crabCombat/info.json
Normal file
19
22-crabCombat/info.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"year": "2020",
|
||||
"day": "22",
|
||||
"title": "Crab Combat",
|
||||
"testCases": {
|
||||
"one": [
|
||||
{
|
||||
"input": "Player 1:\n9\n2\n6\n3\n1\n\nPlayer 2:\n5\n8\n4\n7\n10\n",
|
||||
"expected": 306
|
||||
}
|
||||
],
|
||||
"two": [
|
||||
{
|
||||
"input": "Player 1:\n9\n2\n6\n3\n1\n\nPlayer 2:\n5\n8\n4\n7\n10\n",
|
||||
"expected": 291
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
110
22-crabCombat/python/__main__.py
Normal file
110
22-crabCombat/python/__main__.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
import json
|
||||
import platform
|
||||
import sys
|
||||
import time
|
||||
|
||||
from rich import print
|
||||
|
||||
from partOne import partOne
|
||||
from partTwo import partTwo
|
||||
|
||||
|
||||
def run_and_time(f):
|
||||
st = time.time()
|
||||
x = f()
|
||||
et = time.time()
|
||||
return x, et-st
|
||||
|
||||
|
||||
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):
|
||||
readable_test_num = f"{n}.{i+1}"
|
||||
print(f"Running {readable_test_num}...", end="\r")
|
||||
|
||||
expectedInt = tc["expected"]
|
||||
|
||||
result, t = run_and_time(lambda: f(str(tc["input"])))
|
||||
|
||||
output_string = f"{readable_test_num} "
|
||||
|
||||
if result == expectedInt:
|
||||
output_string += "[green]pass[/green]"
|
||||
else:
|
||||
output_string += f"[red]fail[/red] (got {result}, expected {expectedInt})"
|
||||
|
||||
if t > 15:
|
||||
output_string += f" in {t} seconds"
|
||||
|
||||
print(output_string + " "*12)
|
||||
|
||||
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("Running part 1...", end="\r")
|
||||
output_string = "Part 1: "
|
||||
x, t = run_and_time(lambda: partOne(challenge_input))
|
||||
output_string += str(x)
|
||||
if t > 15:
|
||||
output_string += f" in {t} seconds"
|
||||
print(output_string + " "*12)
|
||||
|
||||
print("Running part 2...", end="\r")
|
||||
output_string = "Part 2: "
|
||||
x, t = run_and_time(lambda: partTwo(challenge_input))
|
||||
output_string += str(x)
|
||||
if t > 15:
|
||||
output_string += f" in {t} seconds"
|
||||
print(output_string + " "*12)
|
21
22-crabCombat/python/common.py
Normal file
21
22-crabCombat/python/common.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from typing import List, Tuple
|
||||
|
||||
|
||||
def parse(instr: str) -> Tuple[List[int], List[int]]:
|
||||
|
||||
deck_one_str, deck_two_str = instr.strip().split("\n\n")
|
||||
|
||||
deck_one = [int(x) for x in deck_one_str.split("\n")[1:]]
|
||||
deck_two = [int(x) for x in deck_two_str.split("\n")[1:]]
|
||||
|
||||
return deck_one, deck_two
|
||||
|
||||
|
||||
def calc_score(deck: List[int]) -> int:
|
||||
score = 0
|
||||
|
||||
deck_len = len(deck)
|
||||
for i, v in enumerate(deck):
|
||||
score += v * (deck_len - i)
|
||||
|
||||
return score
|
23
22-crabCombat/python/partOne.py
Normal file
23
22-crabCombat/python/partOne.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from common import *
|
||||
import time
|
||||
|
||||
def play_round(deck_one: List[int], deck_two: List[int]) -> None:
|
||||
|
||||
top_one = deck_one.pop(0)
|
||||
top_two = deck_two.pop(0)
|
||||
|
||||
if top_one > top_two:
|
||||
deck_one.append(top_one)
|
||||
deck_one.append(top_two)
|
||||
elif top_two > top_one:
|
||||
deck_two.append(top_two)
|
||||
deck_two.append(top_one)
|
||||
|
||||
|
||||
def partOne(instr: str) -> int:
|
||||
deck_one, deck_two = parse(instr)
|
||||
|
||||
while len(deck_one) > 0 and len(deck_two) > 0:
|
||||
play_round(deck_one, deck_two)
|
||||
|
||||
return calc_score(deck_one if len(deck_one) != 0 else deck_two)
|
66
22-crabCombat/python/partTwo.py
Normal file
66
22-crabCombat/python/partTwo.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
from common import *
|
||||
import copy
|
||||
|
||||
|
||||
def play_round(deck_one: List[int], deck_two: List[int]) -> Tuple[int, Tuple[List[int], List[int]]]:
|
||||
# returns winner number and decks in their new state
|
||||
|
||||
# print("new round")
|
||||
|
||||
seen_configurations = []
|
||||
|
||||
while len(deck_one) > 0 and len(deck_two) > 0:
|
||||
if (deck_one, deck_two) in seen_configurations:
|
||||
# print("Seen this config before")
|
||||
return 1, (deck_one, deck_two)
|
||||
else:
|
||||
seen_configurations.append((copy.deepcopy(deck_one), copy.deepcopy(deck_two)))
|
||||
|
||||
# do gameplay shenanigans
|
||||
top_one = deck_one.pop(0)
|
||||
top_two = deck_two.pop(0)
|
||||
|
||||
winner = 0
|
||||
if len(deck_one) >= top_one and len(deck_two) >= top_two:
|
||||
# recurse! 🦀
|
||||
# print("recursing 🦀")
|
||||
|
||||
new_deck_one = deck_one[:top_one]
|
||||
new_deck_two = deck_two[:top_two]
|
||||
|
||||
winner, _ = play_round(new_deck_one, new_deck_two)
|
||||
else:
|
||||
# play as usual
|
||||
if top_one > top_two:
|
||||
winner = 1
|
||||
elif top_two > top_one:
|
||||
winner = 2
|
||||
|
||||
# print(winner, "wins")
|
||||
|
||||
# do things based on the winner
|
||||
if winner == 1:
|
||||
deck_one.append(top_one)
|
||||
deck_one.append(top_two)
|
||||
elif winner == 2:
|
||||
deck_two.append(top_two)
|
||||
deck_two.append(top_one)
|
||||
else:
|
||||
raise Exception("SDFGKSHDFGKSHDFGAAAAAAAA!!!") # yes
|
||||
|
||||
# print("finished this round")
|
||||
|
||||
return 1 if len(deck_one) != 0 else 2, (deck_one, deck_two)
|
||||
|
||||
|
||||
def partTwo(instr: str) -> int:
|
||||
deck_one, deck_two = parse(instr)
|
||||
|
||||
winner, (deck_one, deck_two) = play_round(copy.deepcopy(deck_one), copy.deepcopy(deck_two))
|
||||
|
||||
if winner == 1:
|
||||
return calc_score(deck_one)
|
||||
elif winner == 2:
|
||||
return calc_score(deck_two)
|
||||
|
||||
return 0
|
Loading…
Add table
Add a link
Reference in a new issue