Day 13 (Python)
This commit is contained in:
parent
d25b1f6625
commit
9cd865e194
7 changed files with 239 additions and 27 deletions
54
.github/README.md
vendored
54
.github/README.md
vendored
|
@ -14,33 +14,33 @@ Puzzle inputs and descriptions are not included in this repository. You'll have
|
||||||
|
|
||||||
<!-- PARSE START -->
|
<!-- PARSE START -->
|
||||||
|
|
||||||
| Day | | Python | Go |
|
| Day | | Python | Go |
|
||||||
| --------------------------- | ----------------------------- | ------------------------------------- | --------------------------------- |
|
| --------------------------- | ------------------------------ | ------------------------------------- | --------------------------------- |
|
||||||
| [1](/01-reportRepair) | ![Completed][check] | [Link](/01-reportRepair/python) | [Link](/01-reportRepair/go) |
|
| [1](/01-reportRepair) | ![Completed][check] | [Link](/01-reportRepair/python) | [Link](/01-reportRepair/go) |
|
||||||
| [2](/02-passwordPhilosophy) | ![Completed][check] | [Link](/02-passwordPhilosophy/python) | [Link](/02-passwordPhilosophy/go) |
|
| [2](/02-passwordPhilosophy) | ![Completed][check] | [Link](/02-passwordPhilosophy/python) | [Link](/02-passwordPhilosophy/go) |
|
||||||
| [3](/03-tobogganTrajectory) | ![Completed][check] | [Link](/03-tobogganTrajectory/python) | [Link](/03-tobogganTrajectory/go) |
|
| [3](/03-tobogganTrajectory) | ![Completed][check] | [Link](/03-tobogganTrajectory/python) | [Link](/03-tobogganTrajectory/go) |
|
||||||
| [4](/04-passportProcessing) | ![Completed][check] | [Link](/04-passportProcessing/python) | [Link](/04-passportProcessing/go) |
|
| [4](/04-passportProcessing) | ![Completed][check] | [Link](/04-passportProcessing/python) | [Link](/04-passportProcessing/go) |
|
||||||
| [5](/05-binaryBoarding) | ![Completed][check] | [Link](/05-binaryBoarding/python) | [Link](/05-binaryBoarding/go) |
|
| [5](/05-binaryBoarding) | ![Completed][check] | [Link](/05-binaryBoarding/python) | [Link](/05-binaryBoarding/go) |
|
||||||
| [6](/06-customCustoms) | ![Completed][check] | [Link](/06-customCustoms/python) | [Link](/06-customCustoms/go) |
|
| [6](/06-customCustoms) | ![Completed][check] | [Link](/06-customCustoms/python) | [Link](/06-customCustoms/go) |
|
||||||
| [7](/07-handyHaversacks) | ![Completed][check] | [Link](/07-handyHaversacks/python) | [Link](/07-handyHaversacks/go) |
|
| [7](/07-handyHaversacks) | ![Completed][check] | [Link](/07-handyHaversacks/python) | [Link](/07-handyHaversacks/go) |
|
||||||
| [8](/08-handheldHalting) | ![Completed][check] | [Link](/08-handheldHalting/python) | [Link](/08-handheldHalting/go) |
|
| [8](/08-handheldHalting) | ![Completed][check] | [Link](/08-handheldHalting/python) | [Link](/08-handheldHalting/go) |
|
||||||
| [9](/09-encodingError) | ![Completed][check] | [Link](/09-encodingError/python) | [Link](/09-encodingError/go) |
|
| [9](/09-encodingError) | ![Completed][check] | [Link](/09-encodingError/python) | [Link](/09-encodingError/go) |
|
||||||
| [10](/10-adapterArray) | ![Completed][check] | [Link](/10-adapterArray/python) | [Link](/10-adapterArray/go) |
|
| [10](/10-adapterArray) | ![Completed][check] | [Link](/10-adapterArray/python) | [Link](/10-adapterArray/go) |
|
||||||
| [11](/11-seatingSystem) \* | ![Completed][check] | [Link](/11-seatingSystem/python) | [Link](/11-seatingSystem/python) |
|
| [11](/11-seatingSystem) \* | ![Completed][check] | [Link](/11-seatingSystem/python) | [Link](/11-seatingSystem/python) |
|
||||||
| [12](/12-rainRisk) \* | ![Completed][check] | [Link](/12-rainRisk/python) | [Link](/12-rainRisk/go) |
|
| [12](/12-rainRisk) \* | ![Completed][check] | [Link](/12-rainRisk/python) | [Link](/12-rainRisk/go) |
|
||||||
| 13 | ![Not yet attempted][pending] | | |
|
| [13](/13-shuttleSearch) | ![Partially complete][partial] | [Link](/13-shuttleSearch/python) | |
|
||||||
| 14 | | | |
|
| 14 | | | |
|
||||||
| 15 | | | |
|
| 15 | | | |
|
||||||
| 16 | | | |
|
| 16 | | | |
|
||||||
| 17 | | | |
|
| 17 | | | |
|
||||||
| 18 | | | |
|
| 18 | | | |
|
||||||
| 19 | | | |
|
| 19 | | | |
|
||||||
| 20 | | | |
|
| 20 | | | |
|
||||||
| 21 | | | |
|
| 21 | | | |
|
||||||
| 22 | | | |
|
| 22 | | | |
|
||||||
| 23 | | | |
|
| 23 | | | |
|
||||||
| 24 | | | |
|
| 24 | | | |
|
||||||
| 25 | | | |
|
| 25 | | | |
|
||||||
|
|
||||||
<!-- PARSE END -->
|
<!-- PARSE END -->
|
||||||
|
|
||||||
|
|
35
13-shuttleSearch/README.md
Normal file
35
13-shuttleSearch/README.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# [Day 13: Shuttle Search](https://adventofcode.com/2020/day/13)
|
||||||
|
|
||||||
|
No, I don't really know why the maths works, but it works!
|
||||||
|
|
||||||
|
Here are the notes I made for part two to work this out for a test case before implementing it for the first time to make sure that my method worked.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Related
|
||||||
|
|
||||||
|
* [Maths with Jay - Chinese remainder theorem](https://www.youtube.com/watch?v=zIFehsBHB8o)
|
||||||
|
* [StackOverflow - Modular multiplicative inverse function in Python](https://stackoverflow.com/a/9758173)
|
||||||
|
|
||||||
|
<details><summary>Script output</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
❯ python .\python\
|
||||||
|
AoC 2020: day 13 - Shuttle Search
|
||||||
|
Python 3.8.5
|
||||||
|
|
||||||
|
Test cases
|
||||||
|
1.1 pass
|
||||||
|
2.1 pass
|
||||||
|
2.2 pass
|
||||||
|
2.3 pass
|
||||||
|
2.4 pass
|
||||||
|
2.5 pass
|
||||||
|
2.6 pass
|
||||||
|
|
||||||
|
Answers
|
||||||
|
Part 1: 4782
|
||||||
|
Part 2: 1118684865113056
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
39
13-shuttleSearch/info.json
Normal file
39
13-shuttleSearch/info.json
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{
|
||||||
|
"year": "2020",
|
||||||
|
"day": "13",
|
||||||
|
"title": "Shuttle Search",
|
||||||
|
"testCases": {
|
||||||
|
"one": [
|
||||||
|
{
|
||||||
|
"input": "939\n7,13,x,x,59,x,31,19",
|
||||||
|
"expected": 295
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"two": [
|
||||||
|
{
|
||||||
|
"input": "939\n7,13,x,x,59,x,31,19",
|
||||||
|
"expected": 1068781
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1\n17,x,13,19",
|
||||||
|
"expected": 3417
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1\n67,7,59,61",
|
||||||
|
"expected": 754018
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1\n67,x,7,59,61",
|
||||||
|
"expected": 779210
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1\n67,7,x,59,61",
|
||||||
|
"expected": 1261476
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1\n1789,37,47,1889",
|
||||||
|
"expected": 1202161486
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
77
13-shuttleSearch/python/__main__.py
Normal file
77
13-shuttleSearch/python/__main__.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
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:", partOne(challenge_input))
|
||||||
|
print("Part 2:", partTwo(challenge_input))
|
29
13-shuttleSearch/python/partOne.py
Normal file
29
13-shuttleSearch/python/partOne.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
class Timetable:
|
||||||
|
earliest_departure: int
|
||||||
|
services: List[int]
|
||||||
|
|
||||||
|
def __init__(self, earliest_departure: int, services: str):
|
||||||
|
self.earliest_departure = earliest_departure
|
||||||
|
self.services = [int(s) for s in services.split(",") if s != "x"]
|
||||||
|
|
||||||
|
|
||||||
|
def parse(instr: str) -> Timetable:
|
||||||
|
instr = instr.strip().split("\n")
|
||||||
|
return Timetable(int(instr[0]), instr[1])
|
||||||
|
|
||||||
|
|
||||||
|
def partOne(instr: str) -> int:
|
||||||
|
timetable = parse(instr)
|
||||||
|
|
||||||
|
earliest_times = []
|
||||||
|
for service in timetable.services:
|
||||||
|
earliest_times.append(
|
||||||
|
(service, (int(timetable.earliest_departure / service) + 1) * service)
|
||||||
|
)
|
||||||
|
|
||||||
|
route, earliest_departure = min(earliest_times, key=lambda x: x[1])
|
||||||
|
|
||||||
|
return route * (earliest_departure - timetable.earliest_departure)
|
32
13-shuttleSearch/python/partTwo.py
Normal file
32
13-shuttleSearch/python/partTwo.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
def partTwo(instr: str) -> int:
|
||||||
|
# This is the parsing section
|
||||||
|
service_list = instr.strip().split("\n")[-1].split(",")
|
||||||
|
|
||||||
|
eqns = []
|
||||||
|
for i, svc in enumerate(service_list):
|
||||||
|
if svc == "x":
|
||||||
|
continue
|
||||||
|
svc = int(svc)
|
||||||
|
|
||||||
|
v = 0
|
||||||
|
if i != 0:
|
||||||
|
v = svc - i # This is the only maths stuff in the parsing
|
||||||
|
|
||||||
|
eqns.append((v, svc))
|
||||||
|
|
||||||
|
# This is the maths section
|
||||||
|
|
||||||
|
n = 1
|
||||||
|
for (_, v) in eqns:
|
||||||
|
n *= v
|
||||||
|
|
||||||
|
sigma_x = 0
|
||||||
|
for (bi, ni) in eqns:
|
||||||
|
# this type cast could potentially cause a problem.
|
||||||
|
# int required for pow function and the division *should* produce a whole number anyway
|
||||||
|
Ni = int(n / ni)
|
||||||
|
yi = pow(Ni, -1, ni) # https://stackoverflow.com/a/9758173
|
||||||
|
print(Ni, ni, yi)
|
||||||
|
sigma_x += bi * Ni * yi
|
||||||
|
|
||||||
|
return sigma_x % n
|
BIN
13-shuttleSearch/working.jpg
Normal file
BIN
13-shuttleSearch/working.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 312 KiB |
Loading…
Add table
Add a link
Reference in a new issue