Compare commits
10 Commits
72e301c988
...
3375d25b92
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3375d25b92 | ||
![]() |
a0e96c2500 | ||
![]() |
8cd5c3d002 | ||
![]() |
4f7424b533 | ||
![]() |
822281aa4e | ||
![]() |
3da79d284e | ||
![]() |
54271e0a2c | ||
![]() |
ffa9ebcf53 | ||
![]() |
d8d7778cab | ||
![]() |
89af752a98 |
@@ -1,14 +0,0 @@
|
||||
from pathlib import Path
|
||||
|
||||
from puzzle import solve_pt_1, solve_pt_2
|
||||
|
||||
|
||||
def main():
|
||||
input = Path(__file__).parent.joinpath("schematic.txt").read_text().strip()
|
||||
print("Sum of Part Numbers:")
|
||||
print("Part 1 -", solve_pt_1(input))
|
||||
print("Part 2 -", solve_pt_2(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
35
03/puzzle.py
35
03/puzzle.py
@@ -1,35 +0,0 @@
|
||||
from schematic import Schematic, SchematicNumber, SchematicSymbol
|
||||
|
||||
|
||||
def solve_pt_1(input: str) -> int:
|
||||
schematic = Schematic.parse(input)
|
||||
|
||||
total = 0
|
||||
for part_number, _ in schematic.part_numbers():
|
||||
total += int(part_number.number)
|
||||
|
||||
return total
|
||||
|
||||
|
||||
def solve_pt_2(input: str) -> int:
|
||||
schematic = Schematic.parse(input)
|
||||
|
||||
part_groups: dict[SchematicSymbol, list[SchematicNumber]] = {}
|
||||
|
||||
for part_number, part_symbol in schematic.part_numbers():
|
||||
if part_symbol.symbol != "*":
|
||||
continue
|
||||
if part_symbol not in part_groups:
|
||||
part_groups[part_symbol] = []
|
||||
part_groups[part_symbol].append(part_number)
|
||||
|
||||
gears = [
|
||||
part_numbers for part_numbers in part_groups.values() if len(part_numbers) == 2
|
||||
]
|
||||
|
||||
total = 0
|
||||
for gear_1, gear_2 in gears:
|
||||
gear_ratio = int(gear_1.number) * int(gear_2.number)
|
||||
total += gear_ratio
|
||||
|
||||
return total
|
@@ -1,10 +0,0 @@
|
||||
from puzzle import solve_pt_1, solve_pt_2
|
||||
from schematic_test import mock_input
|
||||
|
||||
|
||||
def test_solve_pt_1():
|
||||
assert solve_pt_1(mock_input) == 4361
|
||||
|
||||
|
||||
def test_solve_pt_2():
|
||||
assert solve_pt_2(mock_input) == 467835
|
@@ -1,88 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class SchematicNumber(NamedTuple):
|
||||
number: str
|
||||
row: int
|
||||
col: int
|
||||
|
||||
def extend_digit(self, digit: str) -> SchematicNumber:
|
||||
return SchematicNumber(self.number + digit, self.row, self.col)
|
||||
|
||||
|
||||
class SchematicSymbol(NamedTuple):
|
||||
symbol: str
|
||||
row: int
|
||||
col: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class Schematic:
|
||||
numbers: list[SchematicNumber]
|
||||
symbols: list[SchematicSymbol]
|
||||
|
||||
@classmethod
|
||||
def parse(cls, input: str) -> Schematic:
|
||||
row = 0
|
||||
col = 0
|
||||
current_number: SchematicNumber | None = None
|
||||
numbers: list[SchematicNumber] = []
|
||||
symbols: list[SchematicSymbol] = []
|
||||
|
||||
for char in input:
|
||||
match char:
|
||||
# Digit
|
||||
case n if n in "0123456789":
|
||||
if not current_number:
|
||||
current_number = SchematicNumber("", row, col)
|
||||
current_number = current_number.extend_digit(char)
|
||||
col += 1
|
||||
|
||||
# Blank
|
||||
case ".":
|
||||
if current_number:
|
||||
numbers.append(current_number)
|
||||
current_number = None
|
||||
col += 1
|
||||
|
||||
# Newline
|
||||
case "\n":
|
||||
if current_number:
|
||||
numbers.append(current_number)
|
||||
current_number = None
|
||||
row += 1
|
||||
col = 0
|
||||
|
||||
# Schematic smybol
|
||||
case _:
|
||||
if current_number:
|
||||
numbers.append(current_number)
|
||||
current_number = None
|
||||
symbols.append(SchematicSymbol(char, row, col))
|
||||
col += 1
|
||||
|
||||
# Finalize a number at the end of the schematic
|
||||
if current_number:
|
||||
numbers.append(current_number)
|
||||
|
||||
return cls(numbers, symbols)
|
||||
|
||||
def part_numbers(self) -> list[tuple[SchematicNumber, SchematicSymbol]]:
|
||||
results = []
|
||||
|
||||
for number in self.numbers:
|
||||
for symbol in self.symbols:
|
||||
if (
|
||||
# Symbol within 1 row
|
||||
(number.row - 1 <= symbol.row <= number.row + 1)
|
||||
and
|
||||
# Symbol within 1 column
|
||||
(number.col - 1 <= symbol.col <= number.col + len(number.number))
|
||||
):
|
||||
results.append((number, symbol))
|
||||
break
|
||||
|
||||
return results
|
140
03/schematic.txt
140
03/schematic.txt
@@ -1,140 +0,0 @@
|
||||
...766.......821.547.....577......................................387.....................56..........446.793..........292..................
|
||||
...........................%...../.....981..........627..../..........-.....623......610..-..............*..................16......891.....
|
||||
...$...........716..&336.......470.325.................*.84........$..34....*.....+.....#.....*76....#.........303.433........-........&....
|
||||
.117../359.#...............595............129..963#..722..........128........192.313........31........887...............234.......-.........
|
||||
............298.....922...*.......482.......*..................*......./.........................395................264..../.......166......
|
||||
.732..................*..815..920*......113.827.........453.571.356..902......693...147............*.....128................................
|
||||
...*..........451-.442..................*...................................+....*....*.......918...680...........................529+......
|
||||
....844.587.....................347...425.....974......348.........$615....174.330..............*..................556.......972*...........
|
||||
..........&...676.........947..%.................*976.*.................45..........192........272.131..............-..977*......85.........
|
||||
.588..........*........$.$.......515...493.............73.....%...........*.....428.*....................*968..............964.......153*274
|
||||
....=..860...157....347............*..*......954.930.......472...618....899......%..726.330..44.......687........$..........................
|
||||
..........@..................+....465..47.......*......*............*........554............@...................485..320....................
|
||||
.....................%831.267.......................305.844.........413........*........741....-...692.948..........*..........650.......510
|
||||
....................................*212....419..............848............710.............670.....*......932...281......-.........398.....
|
||||
.......%....782.......187#..-....890...........@................*../...*531.....745................645......*........#..&..835......*.......
|
||||
.......180..=....153*......487........@322.........693.........805.687..............350.......259........626...849.221.833.......573....%674
|
||||
.....................821...........................*...988.............90..273...................*............*.............................
|
||||
.....65*845..346%..................*412...@.....901.............79.....*.....*..........169.764.14...3.....839...........559..=.............
|
||||
.....................553..798.............318.%..............29......772...................*......................511.........749...697.....
|
||||
.........@............*....*.........414.......13.517.......*...............597.....................28*366..........*......%.........*......
|
||||
......412...........724....973...&....*.............*..#......................%...910...........702......../......473.651...375.*347........
|
||||
.............*559................906..111........449....510......+342............*....797.262.............650............................175
|
||||
...........40.........793...................156......./.....643................577..........+.....................*304...711....437*368.....
|
||||
.........................*.............................843..*...........47..........406............=..../......761.......*...............851
|
||||
......309@......283...296......#.....322............./.....72.....729.....+...515......*..78......735..970.130..........16...../.&...426*...
|
||||
................................720.@......952....958.........672*..................239....*...............+................816..1..........
|
||||
............=..............259........494.+...........................+...447...........310............*...............%553.................
|
||||
....650....999..837*.......+.........*......%359..604.....577.........591.+.......................832.383........@252.........292...........
|
||||
....*...............677..........581.528...........*..=.....%.....................583.........................&........*354.................
|
||||
.................=.........470...*...........=...467...117........$736..3.........*...........................127...945.......808...&....785
|
||||
.747...658.....223...../........563.......466..........................#...652.841......417...........253.................906.*...984.......
|
||||
..........*106.......173....396.....................*106....645...426........*.......*......310.........%.....238*546.....*...442......$145.
|
||||
...618.........&203............*........988......833.................*......594.....837.....*...........................460.......671.......
|
||||
........................*...548.....704*......................274..985.575*...............122.....574......=391.............433%.-..........
|
||||
......871...747.......468................466*367..482....455....*..........53...................&.*.................507@....................
|
||||
........*..*..............597......................*...........855............................502.243.$484......446............-............
|
||||
.......51.............841...+...........7.565.....281.873*305........603................$..................#781...*.819.....591..104....675.
|
||||
............+..........*.......391-......*...........................-....658....515...861.......195/.......................................
|
||||
.............130.903...235..........757................&...765*237.........&....*...........215.......389%............*...269*812...........
|
||||
.526.919...........+.......-.......*........508*202...109............53.......899...........*....@..................55.94..............26...
|
||||
...*....................329........73...........................60=..+.....................10..152........674*993..........74..343..........
|
||||
......305......................902........349...542/.......................783..352...38.....................................=..*....507....
|
||||
.797.....+...............@.......=.......$.............303.348..408............*......-...729......=867.683..+.425*137.........698....&.....
|
||||
....*...........988.964.145.785.....916............*.....#.*...*.....535%.806.532.........*....@.........*..11..............................
|
||||
.684..834...473*.....*.......-.....*........892.372.448.....77.220........*............326..723.........836...........#503...994....*786....
|
||||
.........*..........863..483....773...........*.........101................121..535..................46......706..............*..334........
|
||||
.938*..304..../854......*...........267...462..367........#.......................*..%..............*........*...&...*......631.......384...
|
||||
....................................@.....*......................485..836...197..594..393....433..169.209..13....812..849..........=..../...
|
||||
.....................#.....132........172....419..380..245*860...........*...$.................=......@............................264......
|
||||
....52.555.........602...*........780*..........*...*............................398*245................................61.196.+............
|
||||
......*........@........624...823...............823..770.@....518......663.........................@972.....396*975.......*.....986.....*968
|
||||
.............694.308........................373...........578...#.........................959........................=250............461....
|
||||
..601...............#....719.-.......&.......................................757.............*.........344................660............699
|
||||
.....-.358..480*989...........261.....749......@......-689...209-.......826$...-..194........457..........*...473..........*.........893*...
|
||||
.339......%...........221..................643..564................................*.............443.....798.=.........668..69....@.........
|
||||
....*702..........&........145.734...........@..........$951...............325......439...........&.......................*....151.......436
|
||||
.........#......554.661....%......-....243.....................735.......-.....457.........769*........474*769............547........331....
|
||||
136.361..907.........*........../..........600.....-..739.769..#.........306.....*.............245..............*218..296......683...*......
|
||||
...*..................682...746.765..............681.....*...........511......704.........231................892..................*.715..728
|
||||
.......*415...................*........295..468.......................*.............35...*......./................665.985..&148.........&...
|
||||
....831.......510....444.......565.................3.....334......558..........626........342..532..426......709...#....*.......815.........
|
||||
..............*......*.............................*....*....*...*...............@.....................................418......*......%527.
|
||||
.280#...515..706..305........................344.623...957.803..2..............=...871.............243..989....+..............218...........
|
||||
.........*...............773...../...........@.......$................519/.88..249.+...........449*........#....86....454...2........$437...
|
||||
..........822...197.........*..717......./.......8....562.58*102.936@......*............187...........................@.........212.........
|
||||
..349.719.............728..623...........58.....*........................610....873........@...................................*............
|
||||
...*..*..................%.......423*214......259....426...101.....346............*.+.........359.....813.=...686.....$...639............140
|
||||
..839.768....464.........................../........*.....&...........@....367.951...741..........*....=..283...+..195.....%........632.*...
|
||||
...........#.......................821.893..539..287....................../.....................942...........................149.....*.925.
|
||||
......%....155..........*48.............*............143....../901.............844*368...=...................48....777.........*....246.....
|
||||
....79...............282.............437...............+...........561.....736............133.%.........+......*....*...257*....71..........
|
||||
.............655.131................................................*..........%..............154.......897..791.....29.....358.............
|
||||
...$...966.....*....*....864......892...........661..857=........=..259........645.................................$....630...........134...
|
||||
.806...=.....=....949...............*....#.......*..............531.................410.............................428..*..................
|
||||
..............225............941....570...705....705..36.86...........................%...972/...735....448/............528.................
|
||||
.....253................................................*...506.918.......390.478............................862............................
|
||||
.....*......137......................300..........607.....#....*......663................190................*.....869&..117$................
|
||||
.831.252.......+...%483..110.........*......299.........606..........&..................=................148...24..............147*748...851
|
||||
...........................-.......431.....%....820.........713.219....366.......704...........................*....%...&...............*...
|
||||
.......669.295.......*.................................155..*......#......*......=.....727........494...27...110...588..676..904...345...382
|
||||
......@...........987.829......732/......=.517*519.405.......897........115........716*...................*....................*......*.....
|
||||
..........................740..........713.........*.............978........*................+387.......=..885....-...+968......951....669..
|
||||
....105..............907.-.......105.......807..741.........*....*........627...882...=...........695..779.......248.......421..............
|
||||
...$................$.............*..907*.....*.....*....111.215.89...723........&....546.....849*....................119.....*......644*...
|
||||
.......62.....723......155.923...26......678.341.998.107...................=.........................=.........934.9....*...................
|
||||
....20*.................*...........251..............................470.46../........................31............*...406...441...........
|
||||
........$61......#...628......942......&......255/..926.......................520......47&...............240.......791.......*....875...424.
|
||||
.851.27.......700............*.....234..............-.......91.......=..729......................706...........458.....752...722.*......*...
|
||||
....*...............997....635...........920...*...........*.......266............2................*.............*......=................656
|
||||
.........=...................................57.115.773.944..107.........368...../..205.......971..829.728........566..........75....269....
|
||||
.......538...........646.......706#..762..............*........*.814=...................291..*..............30................*......&......
|
||||
..605*..............*...............*.......226.....709.8...671............159..974#...$.....427.......................645..587.............
|
||||
..........973.866..799......913...741...600*....705...............+........*.............................565..606.........*........654.778..
|
||||
......872....*.....................................#.873.....-225.499..546.847.......763..743@......113.....*.....=....380............*.....
|
||||
.........+......891.53.......206..........760..................................822.....-........136..%.....610.....20......85...............
|
||||
............200..+....*......*....236*511......849+.....672-.&................@..........591*.....*....292......%......176*.......571.......
|
||||
....#15......*......783....512..+....................*........914.86...-216........-574......381.658......*..201....17......758..*......$...
|
||||
..............560................725...628...+...646.432..867.....*.....................................734........*..........*.570....948..
|
||||
....417.....................................992....*............638......696..362...=.......40......................843.....722.............
|
||||
....*......*.................855.169...623......816..816...97.........*....*.....-..998..............................................3......
|
||||
...646..646.389..........................-..............*../.....990...972.92......................333....=..........185..261.400...*...#...
|
||||
.................966.&.............$.........#.....413.700........*...............................&....465...........*......=...+.621....452
|
||||
..873..247........*...212....290....429...551.....=............305....#...719.776....573#....657...............972..477.....................
|
||||
.....*...........725............*.........................405.........952..*.....$..........*.....856.......................295.............
|
||||
.....661.............919*92.....373.917*..794....#............12/..&.......468.......$....841.680.../..303..$..............*....653.197.=...
|
||||
..........730...........................9.#...#..166...206..........794.............891........*.............192.....300...329..+...*....884
|
||||
............/...........*189.....*..........677........+...%.............961.................819....294*............................242.....
|
||||
.....................139......607.41.923....................610..528......*...&455.....70.-.............215.......827&...256....124.........
|
||||
...............342..........................454.................*.......885.&...........*..396....69&....................*........%.........
|
||||
................&...........842...581..335.&.......672.......144.............852.......801...............&60..*............&..........802...
|
||||
..73.133.40....................+...*....%...........+...............248..........769.......511......707*......710..........228..........*...
|
||||
.....*...*.........984.....532....415..................................=.........*...151....*...........467........170..........#....913....
|
||||
..206.....147.....%....338....@..........394.........143%./......958..........749...*....569...................848...#.........268..........
|
||||
..............493......*.............*....................844....*................824...........=...553.......%...........894...............
|
||||
......................38..........796.852...=....955............674.974...................964..551.=............*259..-..*..................
|
||||
...596............857......941...............497...&.564.890.........*..311.905......382...../..........25...329.....241..174......873......
|
||||
...........907.......#........*741.....................*......180.808..*......*........*..........764..........................269*.........
|
||||
...308.......&.569......898........524...452...426..430....34.*.......937...231........752..........&.......111.......................93....
|
||||
....*..........&..............754...*.....*......................409............619................................610...............*......
|
||||
...20...886............788.......&..261.943.............#...#.....................*.../........@......+..137........*..460.205......760.71..
|
||||
........*.........+........837........................184..892...................811..161....648...643.....*........10.......*..............
|
||||
........309.....290..........*...../227.......331...........................659............................876..440.......891.........893...
|
||||
............*..........198...................*.............711*629.............*....837....538..-................*....335.....+.........=...
|
||||
..........923.............*281.330..423...726....530..*280....................990..*.............651..661......121......=.....236...344.....
|
||||
.....419...........$.............*...*..........*.............866..904............96..422.............@......%.....744.....$.......*........
|
||||
.......*..........770......../..843.794..42......201...........-..*.....................*........%.........905........&.....335..865...255..
|
||||
....164....95.814...........300.............*332...................180.....739...=..464.619....617......-.............................#.....
|
||||
.............*.........*.............304..81................../...........*....662...*................658...............368..%...........996
|
||||
.........755........738.329.&866...../.....................614...$.......851.......254......917.152............297..860*.....466...774......
|
||||
..........*................................467.....173.........$.684...........................*.......535.......$....................*.....
|
||||
..960..569.....888..=......................+........*........744.................................882........................975........841..
|
||||
...*..............*.700..........................458....*817......668..........882.710.............#.413%......@.............*..............
|
||||
..648............63...............803.237...341......229.............*..632....*......*910...405................625...........805...&...$...
|
||||
....................../...=............*.........984..........417...78.....*..141.+............*....46..839............786*88......454.289..
|
||||
.....145..=........502..63............111...826....*.../.........*......740.......153.432.....74......*....&.430..............594...........
|
||||
.......*...739..............599.&.............#...454.611........291........196......................172.......*.%434............*..........
|
||||
.........*..............671..&...266............/.......................928.-................................434......387/......16.699......
|
||||
......538.581........&....*............%......10.....168....537&....296..*......177...192................-.......470........................
|
||||
..................661......496.346*.....870............*................958....-......*......-....@......101.....+..........................
|
||||
..808..............................365..................195.........................90......482.837............................404.214......
|
@@ -1,87 +0,0 @@
|
||||
from schematic import Schematic, SchematicNumber, SchematicSymbol
|
||||
|
||||
mock_input = """
|
||||
467..114..
|
||||
...*......
|
||||
..35..633.
|
||||
......#...
|
||||
617*......
|
||||
.....+.58.
|
||||
..592.....
|
||||
......755.
|
||||
...$.*....
|
||||
.664.598..
|
||||
""".strip()
|
||||
|
||||
|
||||
def test_schematic_number_extend_digit():
|
||||
sn = SchematicNumber("", 1, 2)
|
||||
assert sn.number == ""
|
||||
sn = sn.extend_digit("3")
|
||||
assert sn.number == "3"
|
||||
sn = sn.extend_digit("5")
|
||||
assert sn.number == "35"
|
||||
sn = sn.extend_digit("1")
|
||||
assert sn.number == "351"
|
||||
|
||||
|
||||
def test_parse_schematic():
|
||||
assert Schematic.parse(mock_input) == Schematic(
|
||||
[
|
||||
SchematicNumber("467", 0, 0),
|
||||
SchematicNumber("114", 0, 5),
|
||||
SchematicNumber("35", 2, 2),
|
||||
SchematicNumber("633", 2, 6),
|
||||
SchematicNumber("617", 4, 0),
|
||||
SchematicNumber("58", 5, 7),
|
||||
SchematicNumber("592", 6, 2),
|
||||
SchematicNumber("755", 7, 6),
|
||||
SchematicNumber("664", 9, 1),
|
||||
SchematicNumber("598", 9, 5),
|
||||
],
|
||||
[
|
||||
SchematicSymbol("*", 1, 3),
|
||||
SchematicSymbol("#", 3, 6),
|
||||
SchematicSymbol("*", 4, 3),
|
||||
SchematicSymbol("+", 5, 5),
|
||||
SchematicSymbol("$", 8, 3),
|
||||
SchematicSymbol("*", 8, 5),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def test_schematic_part_numbers():
|
||||
assert Schematic.parse(mock_input).part_numbers() == [
|
||||
(
|
||||
SchematicNumber("467", 0, 0),
|
||||
SchematicSymbol("*", 1, 3),
|
||||
),
|
||||
(
|
||||
SchematicNumber("35", 2, 2),
|
||||
SchematicSymbol("*", 1, 3),
|
||||
),
|
||||
(
|
||||
SchematicNumber("633", 2, 6),
|
||||
SchematicSymbol("#", 3, 6),
|
||||
),
|
||||
(
|
||||
SchematicNumber("617", 4, 0),
|
||||
SchematicSymbol("*", 4, 3),
|
||||
),
|
||||
(
|
||||
SchematicNumber("592", 6, 2),
|
||||
SchematicSymbol("+", 5, 5),
|
||||
),
|
||||
(
|
||||
SchematicNumber("755", 7, 6),
|
||||
SchematicSymbol("*", 8, 5),
|
||||
),
|
||||
(
|
||||
SchematicNumber("664", 9, 1),
|
||||
SchematicSymbol("$", 8, 3),
|
||||
),
|
||||
(
|
||||
SchematicNumber("598", 9, 5),
|
||||
SchematicSymbol("*", 8, 5),
|
||||
),
|
||||
]
|
@@ -1,13 +0,0 @@
|
||||
from pathlib import Path
|
||||
|
||||
from puzzle import solve_pt_1, solve_pt_2
|
||||
|
||||
|
||||
def main():
|
||||
input = Path(__file__).parent.joinpath("cards.txt").read_text().strip().split("\n")
|
||||
print("Total Points of Scratchcards -", solve_pt_1(input))
|
||||
print("Total Scratchcard Copies -", solve_pt_2(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
35
04/card.py
35
04/card.py
@@ -1,35 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
|
||||
|
||||
@dataclass
|
||||
class Card:
|
||||
winning_numbers: set[int]
|
||||
your_numbers: set[int]
|
||||
|
||||
@classmethod
|
||||
def parse(cls, desc: str) -> Card:
|
||||
try:
|
||||
_, numbers_segment = desc.split(":")
|
||||
winning_numbers_segment, your_numbers_segment = numbers_segment.split("|")
|
||||
winning_numbers = {
|
||||
int(n) for n in winning_numbers_segment.strip().split(" ") if n != ""
|
||||
}
|
||||
your_numbers = {
|
||||
int(n) for n in your_numbers_segment.strip().split(" ") if n != ""
|
||||
}
|
||||
except:
|
||||
raise ValueError("Card description is invalid.")
|
||||
|
||||
return Card(winning_numbers, your_numbers)
|
||||
|
||||
@cached_property
|
||||
def match_count(self):
|
||||
matching_numbers = self.winning_numbers.intersection(self.your_numbers)
|
||||
return len(matching_numbers)
|
||||
|
||||
@cached_property
|
||||
def points(self):
|
||||
return 2 ** (self.match_count - 1) if self.match_count > 0 else 0
|
@@ -1,25 +0,0 @@
|
||||
from card import Card
|
||||
|
||||
mock_input = [
|
||||
"Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53",
|
||||
"Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19",
|
||||
"Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1",
|
||||
"Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83",
|
||||
"Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36",
|
||||
"Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11",
|
||||
]
|
||||
|
||||
|
||||
def test_parse():
|
||||
assert Card.parse(mock_input[0]) == Card(
|
||||
{41, 48, 83, 86, 17},
|
||||
{83, 86, 6, 31, 17, 9, 48, 53},
|
||||
)
|
||||
|
||||
|
||||
def test_match_count():
|
||||
assert [Card.parse(desc).match_count for desc in mock_input] == [4, 2, 2, 1, 0, 0]
|
||||
|
||||
|
||||
def test_points():
|
||||
assert [Card.parse(desc).points for desc in mock_input] == [8, 2, 2, 1, 0, 0]
|
196
04/cards.txt
196
04/cards.txt
@@ -1,196 +0,0 @@
|
||||
Card 1: 61 73 92 28 96 76 32 62 44 53 | 61 17 26 13 92 5 73 29 53 42 62 46 96 32 21 97 99 28 12 4 7 44 19 71 76
|
||||
Card 2: 3 88 36 12 2 9 15 55 21 89 | 23 39 98 36 2 24 9 3 78 95 55 37 12 61 38 88 85 89 13 15 96 45 21 25 30
|
||||
Card 3: 96 44 52 56 82 89 73 50 9 68 | 39 71 64 32 13 57 56 67 34 84 51 53 41 16 38 63 5 80 70 75 7 76 85 83 18
|
||||
Card 4: 54 84 76 44 38 33 12 17 93 94 | 18 21 53 11 7 98 78 92 9 32 29 50 86 23 95 77 22 79 71 80 60 35 54 36 91
|
||||
Card 5: 8 11 33 98 37 80 39 76 53 91 | 82 35 27 29 50 73 24 4 5 53 93 65 45 69 74 54 59 44 43 87 58 38 28 16 98
|
||||
Card 6: 10 58 39 28 35 79 14 73 64 96 | 90 86 38 93 74 29 21 14 33 16 85 9 2 1 3 71 5 76 50 73 19 47 34 58 69
|
||||
Card 7: 1 96 73 38 64 87 45 25 99 10 | 11 30 96 43 17 72 24 55 79 64 98 46 25 38 45 73 99 1 91 87 90 10 18 75 85
|
||||
Card 8: 24 3 23 50 58 35 57 51 22 2 | 95 50 22 75 27 57 72 25 12 61 82 16 76 23 51 24 52 11 81 63 58 65 3 35 2
|
||||
Card 9: 98 59 30 22 10 69 68 17 48 8 | 22 75 34 63 7 72 30 73 19 13 35 80 58 84 98 59 77 57 55 46 6 52 25 48 42
|
||||
Card 10: 82 32 48 60 17 85 97 22 26 87 | 33 49 81 29 70 8 74 45 97 68 36 78 83 11 14 90 93 99 1 59 95 30 4 26 2
|
||||
Card 11: 73 71 18 75 29 87 36 98 72 33 | 56 48 1 32 81 10 64 41 21 93 6 88 30 4 14 51 96 39 37 42 59 69 36 5 66
|
||||
Card 12: 1 67 47 54 45 75 73 64 6 26 | 10 53 5 50 57 27 95 54 64 2 61 89 73 84 70 69 93 85 49 92 1 19 21 76 13
|
||||
Card 13: 65 19 2 74 3 20 83 11 82 78 | 70 19 55 87 90 50 79 59 77 52 62 85 22 75 96 73 6 65 25 74 63 10 11 20 44
|
||||
Card 14: 44 8 3 31 57 91 39 25 43 80 | 75 51 1 56 39 97 13 11 10 78 53 22 9 8 23 66 38 90 14 50 26 16 74 83 6
|
||||
Card 15: 78 34 48 33 74 12 44 98 17 8 | 52 19 81 77 63 72 49 8 90 84 87 96 76 57 62 11 20 74 95 12 91 5 89 44 25
|
||||
Card 16: 28 90 29 51 63 42 3 65 37 5 | 83 68 61 66 81 53 82 14 4 47 87 77 62 18 85 16 10 94 86 33 55 1 20 15 21
|
||||
Card 17: 77 11 72 70 34 74 14 89 57 42 | 7 28 30 57 35 65 96 90 12 64 85 25 99 41 80 68 39 84 83 56 70 13 73 93 50
|
||||
Card 18: 45 11 62 99 34 19 82 13 71 31 | 6 8 63 66 86 35 69 75 53 97 7 68 78 72 64 42 95 51 94 24 98 14 55 76 80
|
||||
Card 19: 42 30 59 65 19 41 49 12 13 55 | 57 16 31 26 39 51 25 28 56 3 34 85 46 80 52 5 8 89 37 95 6 98 69 63 64
|
||||
Card 20: 7 9 84 17 12 49 45 83 74 63 | 82 46 66 59 14 21 29 35 33 76 6 67 81 41 1 89 13 40 5 52 62 27 50 37 4
|
||||
Card 21: 31 81 25 28 33 95 71 30 84 23 | 30 29 21 84 31 95 23 33 92 71 27 86 52 87 5 44 81 28 13 6 9 45 1 25 93
|
||||
Card 22: 78 21 36 3 39 38 11 97 54 6 | 42 2 78 32 27 39 6 13 4 86 88 44 3 54 38 43 36 82 97 21 66 69 11 65 72
|
||||
Card 23: 37 19 7 49 52 67 17 53 16 75 | 52 91 13 75 35 3 25 14 78 33 17 49 83 56 16 81 62 53 19 37 73 67 7 71 28
|
||||
Card 24: 44 19 43 15 81 1 50 29 31 94 | 68 43 66 75 61 50 29 44 31 85 19 83 49 77 15 72 24 60 69 1 17 52 94 90 81
|
||||
Card 25: 3 45 5 83 72 12 61 24 48 13 | 5 52 3 45 32 13 65 55 72 57 15 1 79 19 82 75 12 56 85 2 14 54 16 8 86
|
||||
Card 26: 98 86 62 91 5 69 34 66 88 87 | 86 95 30 52 38 62 87 98 46 88 31 53 34 59 22 5 54 29 91 56 66 25 69 32 3
|
||||
Card 27: 91 85 44 3 59 83 79 90 23 48 | 3 53 12 62 28 90 93 15 71 65 17 4 84 63 48 30 44 85 23 59 83 91 79 35 77
|
||||
Card 28: 49 30 6 43 64 92 32 90 74 83 | 31 90 59 83 17 34 3 67 94 58 75 18 52 74 89 60 53 32 42 33 1 28 7 46 41
|
||||
Card 29: 98 15 24 47 48 26 7 43 52 75 | 48 1 39 27 25 22 15 65 57 87 74 45 76 63 35 26 47 81 80 99 17 88 7 9 18
|
||||
Card 30: 52 48 96 80 81 12 86 26 29 21 | 6 88 14 5 91 59 37 25 35 16 15 43 60 50 73 46 12 75 10 78 30 9 68 65 33
|
||||
Card 31: 94 2 68 75 65 99 48 71 80 50 | 2 65 5 99 75 94 77 26 68 80 57 15 40 41 79 90 82 71 36 56 59 16 78 50 48
|
||||
Card 32: 47 14 55 1 62 99 93 18 17 91 | 7 89 17 20 91 55 29 19 99 41 14 47 77 36 1 73 35 93 48 18 45 57 60 62 92
|
||||
Card 33: 27 61 63 74 43 25 65 98 48 76 | 64 66 4 40 82 6 21 54 95 8 97 77 83 76 26 39 70 34 73 69 88 79 19 52 60
|
||||
Card 34: 71 86 21 59 81 44 45 40 54 77 | 46 51 80 7 36 48 37 95 70 63 88 49 90 9 24 62 66 79 71 59 29 4 40 20 22
|
||||
Card 35: 6 14 46 53 85 20 43 59 96 94 | 42 39 84 54 65 48 85 64 86 37 47 88 8 38 49 79 30 71 96 56 89 98 20 60 11
|
||||
Card 36: 30 13 45 1 15 29 95 83 20 90 | 26 95 93 80 29 38 15 1 96 79 41 67 9 43 50 86 30 11 55 90 34 56 88 7 65
|
||||
Card 37: 8 92 23 52 43 16 87 81 6 89 | 92 31 3 54 60 56 52 8 27 88 39 25 5 94 28 29 74 82 91 81 43 47 87 59 70
|
||||
Card 38: 32 68 11 96 7 85 70 39 8 90 | 10 40 8 82 35 22 85 96 97 78 83 88 68 20 62 12 43 33 63 13 75 72 64 36 93
|
||||
Card 39: 83 73 64 34 69 85 7 89 42 94 | 94 16 38 37 61 89 98 73 95 66 45 13 58 5 65 79 48 68 3 27 52 87 25 39 35
|
||||
Card 40: 24 42 57 48 56 94 95 62 12 71 | 95 17 56 43 72 18 29 63 16 41 75 39 12 48 69 47 81 10 87 49 36 9 31 8 32
|
||||
Card 41: 4 96 99 82 62 50 28 41 55 3 | 84 19 14 15 37 39 88 59 35 89 22 68 1 33 49 67 29 61 17 18 75 8 96 25 63
|
||||
Card 42: 72 13 34 70 16 49 54 77 9 92 | 99 90 96 36 30 24 61 3 6 26 67 80 17 70 65 10 87 53 21 63 64 93 14 1 45
|
||||
Card 43: 58 71 95 47 2 41 83 46 87 13 | 17 63 25 84 80 39 68 40 77 73 61 51 6 2 69 78 9 24 19 65 43 92 67 44 75
|
||||
Card 44: 54 40 57 13 50 88 48 74 32 66 | 99 14 56 63 27 1 20 47 62 25 83 49 43 23 16 96 33 61 80 79 69 60 92 6 55
|
||||
Card 45: 96 55 3 60 45 5 90 99 69 6 | 75 68 14 41 89 80 51 99 5 13 50 36 25 67 72 95 65 59 34 83 82 8 45 35 33
|
||||
Card 46: 47 82 88 72 33 48 24 41 91 9 | 91 19 94 84 20 98 48 64 21 22 14 5 35 36 27 40 43 67 56 6 17 32 11 99 88
|
||||
Card 47: 36 28 57 22 38 45 43 17 88 76 | 18 34 56 75 21 26 7 74 98 28 4 12 92 65 16 15 25 46 99 87 49 85 33 29 37
|
||||
Card 48: 16 2 25 26 61 44 88 73 8 74 | 10 16 12 99 45 70 15 2 85 47 17 62 77 44 21 73 26 92 31 8 88 7 61 69 64
|
||||
Card 49: 69 57 49 52 17 37 77 20 65 3 | 16 37 45 69 38 8 14 81 91 77 65 89 5 78 13 17 3 39 73 52 70 49 20 58 55
|
||||
Card 50: 9 89 58 46 41 77 93 16 90 63 | 71 96 90 52 27 29 14 22 3 20 63 18 88 42 30 24 70 38 15 75 81 40 99 26 16
|
||||
Card 51: 79 57 28 98 59 96 81 44 14 30 | 31 70 16 99 52 32 22 21 66 25 40 94 82 26 35 64 54 80 38 95 53 65 20 42 55
|
||||
Card 52: 60 40 5 65 35 82 9 78 64 31 | 34 73 74 60 40 77 19 30 52 98 55 64 20 8 90 31 33 39 28 85 63 50 48 32 61
|
||||
Card 53: 40 46 51 28 33 23 36 21 27 97 | 25 75 24 41 47 1 64 52 56 62 5 79 58 23 72 39 36 83 44 80 32 13 14 69 37
|
||||
Card 54: 57 84 68 8 12 65 69 32 38 40 | 98 75 19 43 28 31 32 20 60 53 94 71 38 59 61 97 4 79 15 93 1 2 18 13 21
|
||||
Card 55: 20 79 29 40 74 41 43 99 24 2 | 26 22 56 33 6 11 14 10 3 62 30 61 94 98 52 71 39 4 12 2 21 36 41 95 77
|
||||
Card 56: 93 5 57 26 77 84 35 71 96 16 | 74 98 15 17 68 88 2 65 52 23 64 59 7 93 82 31 75 87 69 49 9 35 24 91 55
|
||||
Card 57: 14 89 2 15 28 69 72 68 70 25 | 54 88 32 20 89 90 80 62 97 4 94 46 77 76 74 10 85 11 81 61 53 23 7 39 78
|
||||
Card 58: 39 52 81 1 47 28 99 14 9 26 | 14 93 89 19 64 72 25 12 71 42 60 15 96 83 34 32 95 54 29 10 55 43 73 80 74
|
||||
Card 59: 22 36 98 99 92 50 47 69 76 33 | 90 28 51 31 10 67 77 24 82 4 6 62 25 43 95 80 70 64 40 89 55 96 73 45 19
|
||||
Card 60: 84 44 70 51 79 23 93 62 48 61 | 91 80 72 9 3 64 87 16 36 81 34 8 12 24 10 22 35 40 11 94 65 77 28 82 26
|
||||
Card 61: 65 69 68 94 84 63 62 49 6 2 | 74 31 54 81 59 24 92 6 9 62 49 68 2 77 67 69 4 84 65 46 94 63 40 34 38
|
||||
Card 62: 78 62 31 91 13 35 56 87 43 67 | 31 9 78 91 23 16 62 58 13 83 63 4 71 75 84 8 30 68 60 12 35 7 22 64 56
|
||||
Card 63: 57 52 91 29 54 13 44 74 65 77 | 80 63 12 65 47 54 24 74 51 29 44 16 91 68 62 96 77 28 34 13 39 64 57 67 52
|
||||
Card 64: 20 35 98 46 26 84 83 21 86 18 | 11 99 21 78 18 14 92 66 28 37 31 83 36 46 68 26 84 35 67 98 86 20 91 52 55
|
||||
Card 65: 34 90 57 66 36 3 13 30 64 62 | 62 90 3 75 81 54 17 70 57 13 69 35 30 20 8 92 66 67 34 60 87 36 14 64 91
|
||||
Card 66: 29 91 56 4 85 41 58 36 48 10 | 33 78 54 58 16 56 41 27 4 7 9 71 98 51 3 91 10 48 90 11 85 29 14 36 76
|
||||
Card 67: 13 45 37 99 81 93 75 65 83 36 | 39 86 49 32 83 64 71 13 65 56 34 38 21 93 97 36 69 22 45 75 59 37 29 98 62
|
||||
Card 68: 81 18 38 50 13 86 22 85 52 1 | 31 1 92 11 64 81 85 86 45 54 37 13 66 15 22 69 52 50 40 58 38 18 99 84 93
|
||||
Card 69: 91 12 81 2 99 22 52 35 95 28 | 10 28 44 12 95 39 67 81 54 69 92 91 36 19 75 51 96 22 52 29 2 99 42 25 35
|
||||
Card 70: 16 48 63 76 2 60 61 58 12 99 | 54 99 16 83 66 59 58 6 63 70 60 61 77 8 51 86 3 20 98 90 5 30 52 64 1
|
||||
Card 71: 86 25 4 2 62 42 19 80 11 5 | 10 51 82 90 55 99 97 85 24 91 53 31 38 72 67 4 21 29 42 84 39 98 71 33 43
|
||||
Card 72: 72 86 57 48 85 93 46 39 12 40 | 46 8 86 68 83 48 36 77 61 97 39 96 3 53 67 26 43 56 60 12 85 52 31 22 63
|
||||
Card 73: 38 88 23 78 90 55 30 14 69 2 | 66 42 23 37 1 40 84 16 13 17 31 19 58 38 7 90 32 30 43 69 89 76 78 12 55
|
||||
Card 74: 21 38 35 8 27 70 69 42 5 13 | 51 75 17 31 96 15 95 41 97 93 88 76 55 89 26 44 77 58 71 19 61 73 21 43 84
|
||||
Card 75: 69 16 13 98 88 97 34 26 39 95 | 19 39 53 30 98 65 83 40 93 88 16 35 2 60 84 75 94 13 82 6 52 12 25 92 69
|
||||
Card 76: 80 8 99 74 25 52 26 30 57 83 | 63 20 9 76 87 38 6 75 31 27 90 46 60 14 64 3 55 84 13 32 89 23 28 86 10
|
||||
Card 77: 57 86 8 94 89 40 42 3 18 98 | 88 73 66 11 79 72 95 39 45 30 60 40 68 97 43 5 3 19 44 86 77 4 23 76 32
|
||||
Card 78: 66 86 28 15 14 9 23 81 36 58 | 5 12 98 27 77 41 15 43 46 55 91 7 36 32 21 16 85 59 61 1 96 13 40 14 34
|
||||
Card 79: 40 68 52 33 63 89 15 64 28 70 | 7 2 77 48 36 82 50 5 98 70 93 94 21 80 22 69 10 73 39 49 71 51 74 30 1
|
||||
Card 80: 92 81 37 5 63 66 38 68 49 20 | 18 62 36 52 65 17 19 26 91 23 6 58 45 54 75 90 79 72 7 24 2 74 14 10 56
|
||||
Card 81: 57 72 41 25 90 47 19 93 96 64 | 32 61 7 74 59 37 56 68 27 52 10 4 99 8 44 47 94 29 16 5 23 65 28 66 84
|
||||
Card 82: 62 65 45 19 57 20 87 53 50 69 | 52 36 28 17 93 81 48 14 4 72 67 27 91 47 58 95 90 49 55 35 12 11 75 15 25
|
||||
Card 83: 73 24 22 75 33 43 30 57 59 7 | 8 73 2 71 20 17 22 67 30 43 75 84 85 92 33 24 70 59 45 95 56 31 34 11 5
|
||||
Card 84: 83 44 39 27 17 93 67 31 23 40 | 44 83 27 95 17 66 58 22 67 35 93 39 41 10 20 18 92 40 24 34 86 64 23 71 31
|
||||
Card 85: 39 22 33 35 71 13 86 41 73 99 | 47 95 98 50 14 78 23 80 24 97 99 43 68 30 6 56 34 42 52 91 32 44 66 89 37
|
||||
Card 86: 97 93 8 54 40 11 29 55 10 36 | 7 64 58 70 55 9 34 97 31 17 8 62 49 87 90 15 93 56 43 98 78 54 38 13 22
|
||||
Card 87: 41 96 97 46 80 59 78 89 8 34 | 56 40 6 46 23 80 92 60 85 78 26 9 30 39 41 44 59 36 38 65 43 96 17 63 97
|
||||
Card 88: 32 55 91 50 95 29 92 90 73 68 | 36 12 93 90 82 20 87 73 85 31 54 59 96 99 56 8 32 22 55 50 91 14 27 6 46
|
||||
Card 89: 87 77 82 74 14 92 21 15 68 93 | 68 19 61 25 94 33 12 84 44 20 91 16 23 36 93 72 47 17 8 53 18 14 83 24 57
|
||||
Card 90: 34 85 33 44 96 68 89 15 2 36 | 65 55 98 15 8 91 21 9 17 16 30 62 46 90 45 82 36 33 47 6 74 43 72 34 31
|
||||
Card 91: 89 66 32 11 12 37 63 31 86 49 | 7 97 93 98 18 81 1 85 31 49 69 27 56 83 89 37 11 96 12 72 14 64 16 59 35
|
||||
Card 92: 43 54 57 20 8 78 1 17 79 5 | 51 58 96 67 28 33 20 7 5 55 79 27 70 52 89 40 69 4 36 76 54 9 11 59 95
|
||||
Card 93: 39 4 47 22 60 62 50 27 6 13 | 89 63 40 16 38 45 92 86 14 3 97 21 49 47 76 4 78 52 37 43 75 27 36 1 51
|
||||
Card 94: 29 14 53 32 98 9 70 97 88 86 | 11 49 41 15 8 42 52 2 66 4 78 74 51 67 38 13 24 97 45 20 40 64 29 59 56
|
||||
Card 95: 85 51 50 20 18 76 48 26 41 23 | 14 45 51 34 49 94 83 25 56 43 71 35 33 74 66 40 48 37 65 62 68 9 99 80 95
|
||||
Card 96: 8 5 12 7 68 18 37 29 1 13 | 52 36 67 62 94 99 24 65 22 83 97 63 16 69 12 15 91 85 71 39 9 34 29 50 26
|
||||
Card 97: 40 67 12 93 11 68 16 2 56 34 | 76 27 31 45 19 44 8 30 42 75 9 72 97 62 58 60 47 91 18 70 71 89 40 59 84
|
||||
Card 98: 63 26 80 84 53 17 65 70 88 22 | 51 61 69 27 29 37 85 82 42 72 2 38 89 24 7 68 64 90 21 31 75 87 5 79 66
|
||||
Card 99: 15 94 55 20 7 10 72 48 17 61 | 78 45 17 10 72 7 69 55 66 20 68 24 14 94 82 2 22 50 48 15 13 73 61 44 11
|
||||
Card 100: 31 61 23 89 70 81 9 12 64 4 | 23 81 61 12 75 7 70 4 59 98 3 6 50 37 99 16 9 36 39 35 31 64 40 13 89
|
||||
Card 101: 27 12 95 46 25 67 91 54 52 94 | 81 70 28 27 56 65 30 41 57 94 67 60 53 91 10 16 12 71 46 95 52 36 42 25 54
|
||||
Card 102: 98 88 23 70 93 71 40 33 75 28 | 28 93 75 71 10 77 92 60 90 98 35 81 61 38 26 32 41 63 3 54 46 14 62 53 67
|
||||
Card 103: 26 24 33 49 77 39 85 93 97 76 | 86 26 17 76 95 69 40 50 9 27 12 44 13 49 25 94 77 21 35 22 85 93 16 8 47
|
||||
Card 104: 51 13 73 86 94 23 14 24 30 32 | 73 93 18 41 70 23 24 89 71 96 62 14 48 27 31 84 81 94 30 13 32 29 52 46 51
|
||||
Card 105: 98 77 75 41 62 76 45 72 88 27 | 94 1 60 22 84 26 65 52 10 43 27 67 82 61 75 95 46 34 45 11 39 85 63 48 93
|
||||
Card 106: 90 79 89 17 36 96 95 60 50 23 | 69 84 89 10 12 63 27 21 72 15 43 5 55 48 24 74 26 85 90 65 42 81 99 36 44
|
||||
Card 107: 49 10 63 60 37 96 16 98 24 46 | 63 75 1 55 3 33 68 49 76 17 97 31 64 45 2 82 70 30 41 12 14 9 87 54 13
|
||||
Card 108: 54 27 21 4 99 32 83 97 42 8 | 51 81 8 55 62 16 60 54 72 94 42 7 82 18 3 65 80 59 66 46 57 86 61 50 32
|
||||
Card 109: 69 61 5 73 87 89 25 34 42 54 | 35 74 64 71 93 11 66 61 19 45 3 62 10 44 9 6 27 65 94 76 79 63 26 36 70
|
||||
Card 110: 26 95 86 2 94 62 14 5 20 18 | 61 1 99 5 65 13 56 71 2 91 32 98 18 97 3 20 92 59 28 93 4 39 17 9 15
|
||||
Card 111: 62 15 25 50 92 45 77 1 16 39 | 62 28 48 70 31 69 3 75 44 38 59 4 41 53 32 19 82 36 39 95 88 56 35 91 43
|
||||
Card 112: 39 35 48 73 34 30 57 94 42 62 | 85 49 82 69 16 23 60 88 10 70 15 14 77 27 45 62 65 87 52 79 4 30 93 33 22
|
||||
Card 113: 79 75 72 54 98 74 57 15 77 64 | 21 89 24 65 53 29 60 19 14 11 46 1 90 86 79 17 68 34 39 35 44 8 52 66 62
|
||||
Card 114: 84 35 28 72 9 38 79 13 77 76 | 86 64 50 17 82 23 80 43 91 63 73 98 15 90 70 54 2 1 67 66 25 11 41 7 42
|
||||
Card 115: 31 14 86 27 8 75 25 72 50 9 | 80 43 69 49 2 60 85 5 51 46 70 57 93 55 6 84 87 66 53 74 32 29 13 63 41
|
||||
Card 116: 49 81 23 62 61 31 87 76 39 98 | 3 15 32 52 24 56 7 62 18 79 27 98 31 99 71 39 34 58 87 76 81 91 33 61 49
|
||||
Card 117: 36 60 14 13 15 72 45 66 52 23 | 50 4 26 19 37 41 13 59 52 92 60 45 23 20 36 16 94 14 61 89 93 51 76 83 91
|
||||
Card 118: 31 21 57 69 84 86 25 63 19 87 | 34 86 13 29 2 73 69 38 99 63 87 79 25 35 68 19 89 91 88 57 53 84 31 21 72
|
||||
Card 119: 20 38 40 82 72 46 95 26 1 77 | 63 40 65 2 62 47 82 95 1 53 41 56 19 77 81 33 93 61 55 20 72 38 52 26 46
|
||||
Card 120: 55 61 86 89 74 3 91 67 36 92 | 34 59 77 72 91 98 39 54 36 11 21 1 79 95 7 17 3 4 67 12 89 69 96 85 19
|
||||
Card 121: 63 75 79 88 35 4 99 65 45 58 | 65 35 92 15 98 99 25 83 45 14 79 17 28 58 75 89 52 88 40 2 33 12 95 4 63
|
||||
Card 122: 2 12 7 28 20 92 21 59 10 88 | 10 45 20 68 17 2 39 56 7 44 34 48 21 62 88 43 16 77 57 59 92 28 12 76 47
|
||||
Card 123: 33 8 23 28 15 54 20 76 97 38 | 51 96 38 28 84 19 57 69 45 85 97 26 12 20 39 17 54 76 74 8 33 34 80 91 23
|
||||
Card 124: 50 5 79 61 40 55 8 51 71 28 | 2 79 15 28 90 50 62 73 83 20 31 40 94 11 5 8 3 56 55 51 61 97 80 71 76
|
||||
Card 125: 16 30 10 62 2 66 83 67 85 89 | 92 67 38 41 18 3 45 63 25 64 68 17 57 71 70 83 59 39 48 31 5 61 49 11 77
|
||||
Card 126: 52 24 61 2 15 38 9 75 30 18 | 5 9 77 52 38 75 16 99 78 87 61 31 50 73 18 49 30 28 43 60 2 15 24 92 47
|
||||
Card 127: 79 8 57 33 7 18 35 59 50 25 | 72 63 31 64 7 22 75 96 80 79 50 84 59 57 30 55 34 43 15 8 88 21 28 5 98
|
||||
Card 128: 71 72 12 56 36 1 75 81 60 4 | 6 34 75 72 94 20 12 59 19 71 81 80 97 3 60 30 37 93 1 31 4 36 56 22 62
|
||||
Card 129: 78 55 42 31 73 35 5 82 12 66 | 51 28 81 97 50 2 71 83 39 19 14 64 38 22 69 8 57 54 89 27 34 44 67 91 29
|
||||
Card 130: 74 89 1 92 27 55 16 46 33 2 | 92 89 1 84 19 21 46 13 99 16 7 55 78 32 2 42 33 74 35 47 22 41 27 69 85
|
||||
Card 131: 58 59 85 45 83 53 44 41 93 68 | 7 68 18 13 37 15 31 78 96 82 70 60 99 21 2 17 46 77 88 76 41 75 90 61 89
|
||||
Card 132: 30 71 18 67 50 28 47 86 90 66 | 20 97 50 51 54 3 84 93 1 73 11 86 27 99 9 26 55 12 59 28 18 47 77 71 61
|
||||
Card 133: 46 58 72 54 34 57 8 89 98 20 | 99 65 58 16 81 91 34 5 23 92 72 29 41 98 59 27 13 54 57 62 88 19 75 89 2
|
||||
Card 134: 13 37 20 77 43 65 94 30 73 23 | 19 66 5 63 57 72 65 93 68 62 14 48 85 12 52 25 64 54 2 31 24 3 39 1 32
|
||||
Card 135: 79 42 76 64 68 91 22 66 25 63 | 94 41 51 87 57 80 68 60 95 93 30 8 44 24 26 76 98 42 71 12 58 85 13 27 4
|
||||
Card 136: 74 45 81 24 85 3 28 75 53 48 | 84 10 30 86 66 59 52 12 81 11 3 54 88 94 48 96 28 47 61 34 9 7 58 27 93
|
||||
Card 137: 16 42 55 80 99 39 2 91 59 37 | 49 97 63 50 76 20 35 92 8 82 99 48 56 87 32 53 33 60 13 96 22 71 43 23 91
|
||||
Card 138: 41 7 81 54 30 72 43 59 4 48 | 11 79 16 19 7 21 72 83 94 35 17 33 6 18 64 91 10 88 9 2 32 67 27 12 89
|
||||
Card 139: 43 31 83 44 89 66 53 2 91 40 | 49 48 58 20 33 32 97 68 29 62 22 81 65 9 4 55 26 57 99 66 60 10 16 42 7
|
||||
Card 140: 80 51 96 20 95 17 13 35 30 40 | 22 27 88 12 97 44 56 49 57 71 47 37 8 84 81 45 2 14 78 41 55 10 26 43 16
|
||||
Card 141: 35 10 16 92 60 88 59 84 8 14 | 38 92 16 66 52 31 60 10 84 64 32 45 88 39 54 8 59 69 35 20 49 29 14 50 42
|
||||
Card 142: 51 69 72 40 58 52 65 1 68 18 | 48 52 1 69 68 95 88 91 38 99 55 58 40 5 51 72 94 65 31 82 35 36 18 86 87
|
||||
Card 143: 81 76 34 56 32 90 30 25 26 83 | 67 32 9 34 56 30 76 88 28 81 74 65 52 25 54 26 66 11 33 35 21 63 90 53 83
|
||||
Card 144: 52 49 10 63 93 88 17 16 34 28 | 98 29 92 82 69 42 36 93 67 28 61 35 7 68 12 91 44 65 58 1 26 22 46 32 56
|
||||
Card 145: 58 89 39 7 46 50 52 54 49 21 | 17 6 52 94 12 92 49 16 77 89 46 50 37 70 58 7 54 3 64 33 59 21 22 71 39
|
||||
Card 146: 92 83 29 3 48 38 12 86 42 50 | 86 52 67 15 99 54 12 50 10 66 36 44 55 48 89 83 38 19 70 29 46 92 76 42 3
|
||||
Card 147: 4 54 34 78 89 32 69 15 33 16 | 63 57 62 84 87 20 50 41 67 71 45 79 70 60 42 98 48 1 92 77 3 85 88 52 86
|
||||
Card 148: 61 21 36 94 45 60 28 76 38 10 | 79 96 94 23 56 59 24 38 63 95 68 15 41 89 75 69 48 18 33 45 10 21 90 36 91
|
||||
Card 149: 60 44 45 84 13 2 12 64 1 30 | 94 76 43 34 54 80 90 2 37 14 84 20 88 57 12 63 6 74 9 18 78 41 23 13 42
|
||||
Card 150: 28 29 65 50 89 17 96 83 2 15 | 74 48 40 62 53 93 84 77 8 21 46 83 92 1 34 59 33 18 61 79 13 76 26 87 60
|
||||
Card 151: 96 5 61 3 68 42 67 12 97 69 | 62 14 80 82 74 69 30 92 59 3 28 89 73 31 48 97 24 11 1 18 37 66 70 58 94
|
||||
Card 152: 61 71 13 45 27 35 16 79 10 49 | 12 42 82 97 94 78 92 23 33 88 98 96 90 89 67 99 58 57 79 25 75 10 87 93 76
|
||||
Card 153: 72 17 8 50 35 13 63 41 75 49 | 46 33 90 18 36 71 1 70 56 9 59 53 52 12 92 49 79 95 80 78 27 73 22 91 19
|
||||
Card 154: 3 98 54 80 45 92 2 57 22 64 | 3 39 30 10 67 86 79 95 85 15 97 82 63 49 42 68 31 78 94 46 14 76 4 73 33
|
||||
Card 155: 65 11 46 89 47 90 34 9 55 27 | 56 77 79 9 67 42 58 16 37 60 21 96 57 30 97 98 78 82 41 13 70 2 17 44 29
|
||||
Card 156: 23 88 83 72 55 85 3 5 20 80 | 99 64 35 40 33 69 32 42 15 14 21 97 11 43 70 4 62 53 60 77 82 7 9 93 31
|
||||
Card 157: 62 26 48 49 19 10 75 88 43 52 | 87 57 3 59 26 4 80 39 21 96 99 64 5 24 41 22 72 53 68 43 34 28 50 90 86
|
||||
Card 158: 30 72 87 43 18 16 6 83 58 13 | 32 74 25 81 15 54 17 19 5 75 9 49 27 89 77 8 61 12 52 39 87 90 24 60 62
|
||||
Card 159: 78 32 66 92 1 84 5 88 80 55 | 97 38 37 98 30 28 50 16 94 90 45 7 89 44 36 96 13 62 82 11 68 34 95 91 8
|
||||
Card 160: 29 67 83 32 9 18 24 38 69 35 | 21 59 48 61 4 50 43 72 53 76 65 97 42 20 39 92 94 26 98 3 99 77 95 60 80
|
||||
Card 161: 61 84 65 10 15 13 53 86 81 54 | 50 44 92 14 47 5 75 39 19 81 71 34 4 25 73 43 82 49 86 65 97 62 87 59 8
|
||||
Card 162: 5 62 96 14 8 44 82 41 71 89 | 86 73 60 5 14 71 51 26 8 21 17 41 89 83 13 33 96 18 82 44 92 95 90 50 62
|
||||
Card 163: 15 16 3 68 25 36 12 43 53 20 | 90 18 17 51 91 66 29 21 98 63 69 14 27 33 5 54 64 31 80 60 45 7 82 47 88
|
||||
Card 164: 56 57 88 81 91 95 48 96 68 76 | 44 48 9 78 45 10 13 6 28 33 92 15 69 57 70 39 86 79 40 81 66 71 18 80 2
|
||||
Card 165: 68 29 98 52 89 81 88 54 24 40 | 89 88 40 34 49 19 57 54 80 72 81 67 10 98 82 69 18 73 62 16 68 24 52 85 29
|
||||
Card 166: 13 28 96 87 62 37 44 64 68 51 | 57 9 21 73 83 47 89 46 55 6 93 97 26 15 7 80 84 14 23 3 8 20 98 69 34
|
||||
Card 167: 39 28 37 40 9 4 91 8 87 14 | 64 35 79 28 32 39 1 9 77 91 14 25 17 40 7 11 2 69 8 37 24 88 36 44 87
|
||||
Card 168: 55 89 98 63 34 22 17 43 86 59 | 32 86 62 63 84 68 31 9 87 61 48 59 55 20 7 30 89 43 17 2 34 4 35 98 54
|
||||
Card 169: 21 79 83 32 14 9 92 98 16 53 | 80 21 78 97 22 15 86 48 88 90 47 50 99 75 55 60 17 12 82 25 89 66 11 94 6
|
||||
Card 170: 22 82 43 80 90 78 73 70 14 97 | 28 68 7 90 80 99 22 98 73 5 41 87 74 43 14 56 84 36 20 3 6 75 97 88 49
|
||||
Card 171: 47 57 71 68 44 78 93 25 28 9 | 78 71 24 96 48 82 33 68 22 9 59 47 57 46 13 27 61 38 6 4 20 14 93 56 32
|
||||
Card 172: 19 98 50 38 96 60 27 31 55 22 | 88 33 52 68 36 28 67 23 31 98 61 40 48 41 78 25 12 20 91 21 58 74 73 37 49
|
||||
Card 173: 86 15 81 5 9 12 14 21 47 74 | 49 19 83 40 67 2 93 36 56 7 65 58 33 64 87 11 32 43 52 28 92 59 6 73 41
|
||||
Card 174: 54 21 9 89 1 91 97 51 36 7 | 81 74 63 12 80 50 56 45 34 36 65 1 77 52 66 97 60 31 62 9 72 99 24 39 90
|
||||
Card 175: 10 71 36 13 20 86 34 65 35 1 | 32 4 84 72 58 7 62 70 95 43 8 20 11 87 99 30 16 25 85 73 86 1 17 15 67
|
||||
Card 176: 91 98 51 9 65 97 41 86 17 93 | 44 6 16 60 25 43 73 35 53 85 88 99 14 51 57 67 70 82 87 46 40 45 28 62 15
|
||||
Card 177: 87 29 80 11 88 92 50 39 12 5 | 44 64 81 40 33 41 78 32 97 9 37 69 98 21 18 4 59 20 49 13 65 96 82 85 66
|
||||
Card 178: 77 66 84 13 74 81 3 21 42 94 | 88 31 26 97 15 1 93 54 2 4 14 56 72 39 47 27 62 6 37 55 49 87 75 44 58
|
||||
Card 179: 6 71 23 79 42 39 85 93 28 88 | 48 72 46 71 28 82 42 39 16 50 88 18 23 93 56 97 51 8 67 36 30 79 85 6 11
|
||||
Card 180: 24 64 83 1 75 14 99 85 73 55 | 86 55 73 75 61 47 7 1 24 65 85 77 36 3 91 9 6 82 72 89 99 64 25 59 14
|
||||
Card 181: 22 79 46 27 71 9 57 60 94 42 | 16 56 41 96 30 72 18 38 23 44 13 79 35 87 6 68 15 46 33 11 28 80 5 77 20
|
||||
Card 182: 9 35 53 73 7 64 66 58 40 13 | 58 38 49 64 85 4 13 50 77 66 9 37 40 35 84 72 36 53 28 8 92 21 56 59 27
|
||||
Card 183: 79 96 64 80 95 29 81 34 92 44 | 50 21 95 92 28 43 76 79 22 2 44 63 40 4 24 86 81 9 96 80 25 64 98 11 34
|
||||
Card 184: 50 66 2 93 84 95 54 96 86 25 | 71 96 64 92 49 86 20 93 32 50 25 54 65 28 66 44 36 95 79 2 84 68 39 37 41
|
||||
Card 185: 27 20 84 49 72 71 41 1 93 13 | 27 84 85 49 60 47 67 15 80 13 19 41 34 57 2 82 18 66 44 58 78 93 71 92 65
|
||||
Card 186: 64 46 63 4 9 59 85 52 34 49 | 7 50 74 34 93 84 59 63 2 16 77 96 32 49 85 46 39 12 33 8 52 38 9 57 54
|
||||
Card 187: 27 94 63 35 23 88 22 80 91 33 | 43 18 23 80 48 40 2 94 59 26 91 32 35 64 45 63 62 51 33 88 73 10 78 66 27
|
||||
Card 188: 34 43 79 99 72 74 96 51 71 54 | 98 9 38 61 10 86 95 41 94 18 44 24 83 13 56 46 37 76 17 62 87 5 72 80 90
|
||||
Card 189: 25 7 41 55 23 56 71 1 2 14 | 80 71 39 13 93 69 1 54 83 70 50 48 63 85 19 51 95 56 61 44 34 52 17 59 33
|
||||
Card 190: 12 7 69 90 34 39 11 77 18 5 | 17 8 4 20 13 95 43 69 91 77 41 66 54 48 15 71 34 68 90 80 76 1 59 55 3
|
||||
Card 191: 46 90 41 96 23 63 67 61 75 12 | 24 97 94 93 17 10 86 76 59 75 41 38 67 47 7 92 81 96 29 77 20 61 74 73 78
|
||||
Card 192: 96 46 86 58 16 99 98 38 27 25 | 76 57 79 74 94 84 4 91 89 25 6 96 99 75 41 18 81 88 26 19 98 3 43 51 14
|
||||
Card 193: 92 52 87 63 59 77 79 38 8 96 | 70 72 26 8 49 51 39 53 94 42 55 44 65 78 34 66 41 11 82 56 12 88 33 23 95
|
||||
Card 194: 49 19 18 28 94 70 6 34 24 43 | 98 91 99 46 66 20 31 80 88 61 90 56 8 73 92 51 45 9 63 67 86 3 55 78 40
|
||||
Card 195: 26 99 10 13 62 14 91 77 31 44 | 22 54 60 70 27 52 58 62 55 97 90 76 96 63 72 48 86 11 80 88 30 33 45 67 74
|
||||
Card 196: 2 29 23 92 61 87 75 63 50 55 | 83 7 74 69 16 4 72 62 51 37 22 10 84 28 94 24 89 5 53 88 33 14 99 41 35
|
30
04/puzzle.py
30
04/puzzle.py
@@ -1,30 +0,0 @@
|
||||
from card import Card
|
||||
|
||||
|
||||
def solve_pt_1(input: list[str]):
|
||||
total = 0
|
||||
|
||||
for card_desc in input:
|
||||
card = Card.parse(card_desc)
|
||||
total += card.points
|
||||
|
||||
return total
|
||||
|
||||
|
||||
def solve_pt_2(input: list[str]):
|
||||
cards = [Card.parse(card_desc) for card_desc in input]
|
||||
copies = _resolve_copies(cards)
|
||||
|
||||
total = 0
|
||||
for copy in copies:
|
||||
total += copy
|
||||
|
||||
return total
|
||||
|
||||
|
||||
def _resolve_copies(cards: list[Card]) -> list[int]:
|
||||
copies = [1] * len(cards)
|
||||
for i in range(len(cards)):
|
||||
for j in range(cards[i].match_count):
|
||||
copies[i + j + 1] += copies[i]
|
||||
return copies
|
@@ -1,16 +0,0 @@
|
||||
from card import Card
|
||||
from card_test import mock_input
|
||||
from puzzle import _resolve_copies, solve_pt_1, solve_pt_2
|
||||
|
||||
|
||||
def test_solve_pt_1():
|
||||
assert solve_pt_1(mock_input) == 13
|
||||
|
||||
|
||||
def test_solve_pt_2():
|
||||
assert solve_pt_2(mock_input) == 30
|
||||
|
||||
|
||||
def test_resolve_copies():
|
||||
copies = _resolve_copies([Card.parse(card_desc) for card_desc in mock_input])
|
||||
assert copies == [1, 2, 4, 8, 14, 1]
|
@@ -1,5 +1,10 @@
|
||||
from puzzle import (RangeConversion, resolve_destination, resolve_source,
|
||||
solve_pt_1, solve_pt_2)
|
||||
from puzzle import (
|
||||
RangeConversion,
|
||||
resolve_destination,
|
||||
resolve_source,
|
||||
solve_pt_1,
|
||||
solve_pt_2,
|
||||
)
|
||||
|
||||
mock_seeds = [79, 14, 55, 13]
|
||||
mock_destinations = [81, 14, 57, 13]
|
||||
|
@@ -4,14 +4,17 @@ __author__ = "Nettika <nettika@leaf.ninja>"
|
||||
__version__ = "1.0.0"
|
||||
|
||||
from typing import Callable
|
||||
from advent_of_code.trebuchet import (
|
||||
recover_calibration_digits_and_words,
|
||||
recover_calibration_digits_only,
|
||||
)
|
||||
|
||||
Solver = Callable[[str], str]
|
||||
from advent_of_code import cubes, gears, network, oasis, scratchcards, trebuchet
|
||||
|
||||
Solver = Callable[[str], int]
|
||||
|
||||
|
||||
solvers: dict[int, tuple[Solver, Solver]] = {
|
||||
1: (recover_calibration_digits_only, recover_calibration_digits_and_words),
|
||||
1: (trebuchet.solve_part_1, trebuchet.solve_part_2),
|
||||
2: (cubes.solve_part_1, cubes.solve_part_2),
|
||||
3: (gears.solve_part_1, gears.solve_part_2),
|
||||
4: (scratchcards.solve_part_1, scratchcards.solve_part_2),
|
||||
8: (network.solve_part_1, network.solve_part_2),
|
||||
9: (oasis.solve_part_1, oasis.solve_part_2),
|
||||
}
|
||||
|
90
advent_of_code/cubes.py
Normal file
90
advent_of_code/cubes.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"Day 2: Cube Conundrum"
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from collections import UserDict
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Configuration(UserDict[str, int]):
|
||||
color_yield_pattern: ClassVar[re.Pattern] = re.compile(r"(\d+) (\w+)")
|
||||
|
||||
@staticmethod
|
||||
def _parse_color_yield(yield_desc: str) -> tuple[str, int]:
|
||||
yield_match = Configuration.color_yield_pattern.match(yield_desc.strip())
|
||||
if not yield_match:
|
||||
raise ValueError(f"Color yield is invalid: {yield_desc}")
|
||||
amount = int(yield_match.group(1))
|
||||
color = yield_match.group(2)
|
||||
return (color, amount)
|
||||
|
||||
@classmethod
|
||||
def parse(cls, desc: str) -> Configuration:
|
||||
return cls(
|
||||
cls._parse_color_yield(yield_desc)
|
||||
for yield_desc in desc.split(",")
|
||||
if len(yield_desc)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def parse_sequence(cls, desc: str) -> list[Configuration]:
|
||||
return [cls.parse(draw_desc) for draw_desc in desc.split(";") if len(draw_desc)]
|
||||
|
||||
def power(self) -> int:
|
||||
return self.get("blue", 0) * self.get("green", 0) * self.get("red", 0)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Game:
|
||||
id: int
|
||||
draws: list[Configuration]
|
||||
|
||||
id_pattern: ClassVar[re.Pattern] = re.compile(r"Game (\d+)$")
|
||||
|
||||
@classmethod
|
||||
def parse_table(cls, table: str) -> list[Game]:
|
||||
return [cls.parse(line) for line in table.split("\n")]
|
||||
|
||||
@classmethod
|
||||
def parse(cls, desc: str) -> Game:
|
||||
id_segment, _, draws_segment = desc.partition(":")
|
||||
return cls(
|
||||
cls._parse_id(id_segment),
|
||||
Configuration.parse_sequence(draws_segment),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _parse_id(desc: str) -> int:
|
||||
id_match = Game.id_pattern.match(desc)
|
||||
if not id_match:
|
||||
raise ValueError("Game ID is invalid.")
|
||||
return int(id_match.group(1))
|
||||
|
||||
def meets_configuration(self, configuration: Configuration) -> bool:
|
||||
for draw in self.draws:
|
||||
for name, quantity in draw.items():
|
||||
if quantity > configuration.get(name, 0):
|
||||
return False
|
||||
return True
|
||||
|
||||
def minimum_configuration(self) -> Configuration:
|
||||
config = Configuration()
|
||||
for draw in self.draws:
|
||||
for name, quantity in draw.items():
|
||||
config[name] = max(quantity, config.get(name, 0))
|
||||
return config
|
||||
|
||||
|
||||
def solve_part_1(input: str) -> int:
|
||||
actual_bag = Configuration(red=12, green=13, blue=14)
|
||||
return sum(
|
||||
game.id
|
||||
for game in Game.parse_table(input)
|
||||
if game.meets_configuration(actual_bag)
|
||||
)
|
||||
|
||||
|
||||
def solve_part_2(input: str) -> int:
|
||||
return sum(game.minimum_configuration().power() for game in Game.parse_table(input))
|
122
advent_of_code/gears.py
Normal file
122
advent_of_code/gears.py
Normal file
@@ -0,0 +1,122 @@
|
||||
"Day 3: Gear Ratios"
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from collections import UserDict
|
||||
from dataclasses import dataclass
|
||||
from functools import reduce
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class Symbol(NamedTuple):
|
||||
value: str
|
||||
row: int
|
||||
col: int
|
||||
|
||||
|
||||
class Number(NamedTuple):
|
||||
value: str
|
||||
row: int
|
||||
col: int
|
||||
anchor: Symbol | None = None
|
||||
|
||||
def extend_digit(self, digit: str) -> Number:
|
||||
return self._replace(value=self.value + digit)
|
||||
|
||||
|
||||
class Part(NamedTuple):
|
||||
number: Number
|
||||
symbol: Symbol
|
||||
|
||||
|
||||
@dataclass
|
||||
class Schematic:
|
||||
numbers: list[Number]
|
||||
symbols: list[Symbol]
|
||||
|
||||
@classmethod
|
||||
def parse(cls, input: str) -> Schematic:
|
||||
row = 0
|
||||
col = 0
|
||||
current_number: Number | None = None
|
||||
numbers: list[Number] = []
|
||||
symbols: list[Symbol] = []
|
||||
|
||||
for char in input:
|
||||
match char:
|
||||
# Digit
|
||||
case n if n in "0123456789":
|
||||
if not current_number:
|
||||
current_number = Number("", row, col)
|
||||
current_number = current_number.extend_digit(char)
|
||||
col += 1
|
||||
|
||||
# Blank
|
||||
case ".":
|
||||
if current_number:
|
||||
numbers.append(current_number)
|
||||
current_number = None
|
||||
col += 1
|
||||
|
||||
# Newline
|
||||
case "\n":
|
||||
if current_number:
|
||||
numbers.append(current_number)
|
||||
current_number = None
|
||||
row += 1
|
||||
col = 0
|
||||
|
||||
# Schematic smybol
|
||||
case _:
|
||||
if current_number:
|
||||
numbers.append(current_number)
|
||||
current_number = None
|
||||
symbols.append(Symbol(char, row, col))
|
||||
col += 1
|
||||
|
||||
# Finalize a number at the end of the schematic
|
||||
if current_number:
|
||||
numbers.append(current_number)
|
||||
|
||||
return cls(numbers, symbols)
|
||||
|
||||
def parts(self) -> set[Part]:
|
||||
return {
|
||||
Part(number, symbol)
|
||||
for number in self.numbers
|
||||
for symbol in self.symbols
|
||||
if (
|
||||
# Symbol within 1 row
|
||||
(number.row - 1 <= symbol.row <= number.row + 1)
|
||||
and
|
||||
# Symbol within 1 column
|
||||
(number.col - 1 <= symbol.col <= number.col + len(number.value))
|
||||
)
|
||||
}
|
||||
|
||||
def part_groups(self) -> dict[Symbol, set[Part]]:
|
||||
groups: dict[Symbol, set[Part]] = {}
|
||||
for part in self.parts():
|
||||
if part.symbol not in groups:
|
||||
groups[part.symbol] = set()
|
||||
groups[part.symbol].add(part)
|
||||
return groups
|
||||
|
||||
|
||||
def solve_part_1(input: str) -> int:
|
||||
schematic = Schematic.parse(input)
|
||||
return sum(int(part.number.value) for part in schematic.parts())
|
||||
|
||||
|
||||
def solve_part_2(input: str) -> int:
|
||||
schematic = Schematic.parse(input)
|
||||
return sum(
|
||||
reduce(
|
||||
lambda x, y: x * y,
|
||||
(int(part.number.value) for part in parts),
|
||||
)
|
||||
for symbol, parts in schematic.part_groups().items()
|
||||
if symbol.value == "*"
|
||||
if len(parts) == 2
|
||||
)
|
103
advent_of_code/network.py
Normal file
103
advent_of_code/network.py
Normal file
@@ -0,0 +1,103 @@
|
||||
"Day 8: Haunted Wasteland"
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from functools import cache
|
||||
from math import lcm
|
||||
from typing import ClassVar, NamedTuple
|
||||
|
||||
from frozendict import frozendict
|
||||
|
||||
|
||||
class Instruction(Enum):
|
||||
Left = "L"
|
||||
Right = "R"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Network:
|
||||
instructions: tuple[Instruction, ...]
|
||||
nodes: frozendict[str, tuple[str, str]]
|
||||
|
||||
node_pattern: ClassVar[re.Pattern] = re.compile(
|
||||
r"([0-9A-Z]{3}) = \(([0-9A-Z]{3}), ([0-9A-Z]{3})\)$"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _parse_instructions(instructions_segment: str) -> tuple[Instruction, ...]:
|
||||
try:
|
||||
return tuple(Instruction(symbol) for symbol in instructions_segment)
|
||||
except:
|
||||
raise ValueError("Network instructions are invalid")
|
||||
|
||||
@staticmethod
|
||||
def _parse_node(node_desc) -> tuple[str, tuple[str, str]]:
|
||||
node_match = Network.node_pattern.match(node_desc)
|
||||
if not node_match:
|
||||
raise ValueError("Network node description is invalid")
|
||||
return (
|
||||
node_match.group(1),
|
||||
(
|
||||
node_match.group(2),
|
||||
node_match.group(3),
|
||||
),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def parse(cls, network_desc: str) -> Network:
|
||||
instructions_segment, _, node_desc_segment = network_desc.partition("\n\n")
|
||||
|
||||
instructions = cls._parse_instructions(instructions_segment)
|
||||
nodes = frozendict(
|
||||
cls._parse_node(node_desc)
|
||||
for node_desc in node_desc_segment.split("\n")
|
||||
if node_desc != ""
|
||||
)
|
||||
|
||||
return Network(instructions, nodes)
|
||||
|
||||
@cache
|
||||
def traverse(self, start_node: str) -> str:
|
||||
cursor = start_node
|
||||
for instruction in self.instructions:
|
||||
if cursor not in self.nodes:
|
||||
raise Exception(f"Dead end: node {cursor} not found")
|
||||
left, right = self.nodes[cursor]
|
||||
match instruction:
|
||||
case Instruction.Left:
|
||||
cursor = left
|
||||
case Instruction.Right:
|
||||
cursor = right
|
||||
return cursor
|
||||
|
||||
@cache
|
||||
def distance(self, start_node: str, stop_flag: str) -> int:
|
||||
cursor = start_node
|
||||
cycles = 0
|
||||
while not cursor.endswith(stop_flag):
|
||||
cursor = self.traverse(cursor)
|
||||
cycles += 1
|
||||
return cycles * len(self.instructions)
|
||||
|
||||
@cache
|
||||
def linked_distance(self, start_flag: str, stop_flag: str) -> int:
|
||||
return lcm(
|
||||
*(
|
||||
self.distance(node, stop_flag)
|
||||
for node in self.nodes.keys()
|
||||
if node.endswith(start_flag)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def solve_part_1(input: str) -> int:
|
||||
network = Network.parse(input)
|
||||
return network.distance("AAA", "ZZZ")
|
||||
|
||||
|
||||
def solve_part_2(input: str) -> int:
|
||||
network = Network.parse(input)
|
||||
return network.linked_distance("A", "Z")
|
28
advent_of_code/oasis.py
Normal file
28
advent_of_code/oasis.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"Day 9: Mirage Maintenance"
|
||||
|
||||
Sequence = tuple[int, ...]
|
||||
|
||||
|
||||
def parse_sequence(desc: str) -> Sequence:
|
||||
return tuple(int(num) for num in desc.split(" "))
|
||||
|
||||
|
||||
def extrapolate_sequence(sequence: tuple[int, ...]) -> int:
|
||||
if any(sequence):
|
||||
difference_sequence = tuple(
|
||||
right - left for left, right in zip(sequence, sequence[1:])
|
||||
)
|
||||
next_difference = extrapolate_sequence(difference_sequence)
|
||||
return sequence[-1] + next_difference
|
||||
return 0
|
||||
|
||||
|
||||
def solve_part_1(input: str) -> int:
|
||||
sequences = (parse_sequence(desc) for desc in input.split("\n"))
|
||||
return sum(extrapolate_sequence(sequence) for sequence in sequences)
|
||||
|
||||
|
||||
def solve_part_2(input: str) -> int:
|
||||
sequences = (parse_sequence(desc) for desc in input.split("\n"))
|
||||
reversed_sequences = (tuple(reversed(sequence)) for sequence in sequences)
|
||||
return sum(extrapolate_sequence(sequence) for sequence in reversed_sequences)
|
69
advent_of_code/scratchcards.py
Normal file
69
advent_of_code/scratchcards.py
Normal file
@@ -0,0 +1,69 @@
|
||||
"Day 4: Scratchcards"
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
|
||||
|
||||
@dataclass
|
||||
class Scratchcard:
|
||||
id: int
|
||||
winning_numbers: set[int]
|
||||
your_numbers: set[int]
|
||||
|
||||
id_pattern = re.compile("Card +([1-9][0-9]*)")
|
||||
|
||||
@staticmethod
|
||||
def _parse_id(id_segment: str) -> int:
|
||||
id_match = Scratchcard.id_pattern.match(id_segment)
|
||||
if not id_match:
|
||||
raise ValueError("Scratchcard ID is invalid")
|
||||
return int(id_match.group(1))
|
||||
|
||||
@staticmethod
|
||||
def _parse_numbers(segment: str) -> set[int]:
|
||||
try:
|
||||
return {int(n) for n in segment.strip().split(" ") if n != ""}
|
||||
except:
|
||||
raise ValueError("Scratchcard number sequence is invalid.")
|
||||
|
||||
@classmethod
|
||||
def parse(cls, desc: str) -> Scratchcard:
|
||||
id_segment, _, numbers_segment = desc.partition(":")
|
||||
# fmt: off
|
||||
winning_numbers_segment, _, your_numbers_segment = numbers_segment.partition("|")
|
||||
|
||||
id = cls._parse_id(id_segment)
|
||||
winning_numbers = cls._parse_numbers(winning_numbers_segment)
|
||||
your_numbers = cls._parse_numbers(your_numbers_segment)
|
||||
|
||||
return Scratchcard(id, winning_numbers, your_numbers)
|
||||
|
||||
@staticmethod
|
||||
def resolve_copies(cards: list[Scratchcard]) -> list[int]:
|
||||
copies = [1] * len(cards)
|
||||
for i in range(len(cards)):
|
||||
for j in range(cards[i].match_count):
|
||||
copies[i + j + 1] += copies[i]
|
||||
return copies
|
||||
|
||||
@cached_property
|
||||
def match_count(self):
|
||||
matching_numbers = self.winning_numbers.intersection(self.your_numbers)
|
||||
return len(matching_numbers)
|
||||
|
||||
@cached_property
|
||||
def points(self):
|
||||
return 2 ** (self.match_count - 1) if self.match_count > 0 else 0
|
||||
|
||||
|
||||
def solve_part_1(input: str) -> int:
|
||||
return sum(Scratchcard.parse(card_desc).points for card_desc in input.split("\n"))
|
||||
|
||||
|
||||
def solve_part_2(input: str) -> int:
|
||||
cards = [Scratchcard.parse(card_desc) for card_desc in input.split("\n")]
|
||||
copies = Scratchcard.resolve_copies(cards)
|
||||
return sum(copies)
|
@@ -1,5 +1,6 @@
|
||||
import re
|
||||
"Day 1: Trebuchet?!"
|
||||
|
||||
import re
|
||||
|
||||
number_word_map = {
|
||||
"one": "1",
|
||||
@@ -61,23 +62,19 @@ def _recover_all_calibration_values(
|
||||
)
|
||||
|
||||
|
||||
def recover_calibration_digits_only(input: str) -> str:
|
||||
return str(
|
||||
_recover_all_calibration_values(
|
||||
input,
|
||||
decimal_only_pattern,
|
||||
decimal_only_pattern,
|
||||
{},
|
||||
)
|
||||
def solve_part_1(input: str) -> int:
|
||||
return _recover_all_calibration_values(
|
||||
input,
|
||||
decimal_only_pattern,
|
||||
decimal_only_pattern,
|
||||
{},
|
||||
)
|
||||
|
||||
|
||||
def recover_calibration_digits_and_words(input: str) -> str:
|
||||
return str(
|
||||
_recover_all_calibration_values(
|
||||
input,
|
||||
left_decimal_and_words_pattern,
|
||||
right_decimal_and_words_pattern,
|
||||
number_word_map,
|
||||
)
|
||||
def solve_part_2(input: str) -> int:
|
||||
return _recover_all_calibration_values(
|
||||
input,
|
||||
left_decimal_and_words_pattern,
|
||||
right_decimal_and_words_pattern,
|
||||
number_word_map,
|
||||
)
|
||||
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
||||
[project]
|
||||
name = "advent_of_code"
|
||||
version = "0.1.0"
|
||||
dependencies = ["requests"]
|
||||
dependencies = ["requests", "frozendict"]
|
||||
|
||||
[project.optional-dependencies]
|
||||
test = ["pytest", "pytest-cov", "types-requests"]
|
||||
@@ -15,3 +15,13 @@ advent-of-code-2023 = "advent_of_code.__main__:main"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
|
||||
[tool.coverage.run]
|
||||
source = ["advent_of_code"]
|
||||
omit = ["advent_of_code/__main__.py"]
|
||||
|
||||
[tool.coverage.report]
|
||||
show_missing = true
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
|
114
tests/cubes_test.py
Normal file
114
tests/cubes_test.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import pytest
|
||||
|
||||
from advent_of_code.cubes import Configuration, Game, solve_part_1, solve_part_2
|
||||
|
||||
|
||||
def test_configuration_parse():
|
||||
assert Configuration.parse("1 red") == Configuration(red=1)
|
||||
assert Configuration.parse(" 2 blue, 4 green,") == Configuration(green=4, blue=2)
|
||||
assert Configuration.parse("") == Configuration()
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
Configuration.parse("invalid")
|
||||
|
||||
|
||||
def test_configuration_parse_sequence():
|
||||
assert Configuration.parse_sequence("1 red; 2 blue, 4 green;") == [
|
||||
Configuration(red=1),
|
||||
Configuration(green=4, blue=2),
|
||||
]
|
||||
assert Configuration.parse_sequence("") == []
|
||||
|
||||
|
||||
def test_configuration_power():
|
||||
assert Configuration(red=2, blue=3, green=5).power() == 30
|
||||
|
||||
|
||||
def test_game_parse_table():
|
||||
assert list(Game.parse_table("Game 1: 1 red\nGame 2: 1 blue")) == [
|
||||
Game(1, [{"red": 1}]),
|
||||
Game(2, [{"blue": 1}]),
|
||||
]
|
||||
|
||||
|
||||
def test_game_parse():
|
||||
assert Game.parse("Game 3: 1 green") == Game(3, [Configuration(green=1)])
|
||||
assert Game.parse(
|
||||
"Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green",
|
||||
) == Game(
|
||||
1,
|
||||
[
|
||||
Configuration(blue=3, red=4),
|
||||
Configuration(red=1, green=2, blue=6),
|
||||
Configuration(green=2),
|
||||
],
|
||||
)
|
||||
assert Game.parse("Game 4:") == Game(4, [])
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
assert Game.parse("invalid")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
assert Game.parse(":")
|
||||
|
||||
|
||||
def test_game_meets_configuration():
|
||||
bag = Configuration(red=5, green=5, blue=5)
|
||||
|
||||
assert Game(
|
||||
1,
|
||||
[
|
||||
Configuration(red=3, blue=5),
|
||||
Configuration(green=2, blue=3),
|
||||
Configuration(red=4),
|
||||
],
|
||||
).meets_configuration(bag)
|
||||
assert Game(3, []).meets_configuration(bag)
|
||||
assert not Game(
|
||||
2,
|
||||
[
|
||||
Configuration(green=3),
|
||||
Configuration(red=6, blue=2),
|
||||
Configuration(blue=2),
|
||||
],
|
||||
).meets_configuration(bag)
|
||||
assert not Game(3, [Configuration(orange=1)]).meets_configuration(bag)
|
||||
|
||||
|
||||
def test_game_minimum_configuration():
|
||||
assert Game(
|
||||
1,
|
||||
[
|
||||
Configuration(red=3, blue=5),
|
||||
Configuration(green=2, blue=3),
|
||||
Configuration(red=4),
|
||||
],
|
||||
).minimum_configuration() == Configuration(red=4, blue=5, green=2)
|
||||
|
||||
assert Game(
|
||||
2,
|
||||
[
|
||||
Configuration(red=1),
|
||||
Configuration(blue=1),
|
||||
Configuration(green=1),
|
||||
],
|
||||
).minimum_configuration() == Configuration(red=1, blue=1, green=1)
|
||||
|
||||
|
||||
mock_input = "\n".join(
|
||||
[
|
||||
"Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green",
|
||||
"Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue",
|
||||
"Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red",
|
||||
"Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red",
|
||||
"Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_solve_pt_1():
|
||||
assert solve_part_1(mock_input) == 8
|
||||
|
||||
|
||||
def test_solve_pt_2():
|
||||
assert solve_part_2(mock_input) == 2286
|
99
tests/gears_test.py
Normal file
99
tests/gears_test.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from advent_of_code.gears import (
|
||||
Number,
|
||||
Part,
|
||||
Schematic,
|
||||
Symbol,
|
||||
solve_part_1,
|
||||
solve_part_2,
|
||||
)
|
||||
|
||||
mock_input = """
|
||||
467..114..
|
||||
...*......
|
||||
..35..633.
|
||||
......#...
|
||||
617*......
|
||||
.....+..58
|
||||
..592.....
|
||||
......755.
|
||||
...$.*....
|
||||
.664.598.3
|
||||
""".strip()
|
||||
|
||||
|
||||
def test_schematic_number_extend_digit():
|
||||
assert Number("", 1, 2).extend_digit("3") == Number("3", 1, 2)
|
||||
assert (Number("5", 3, 5).extend_digit("0").extend_digit("4")) == Number(
|
||||
"504", 3, 5
|
||||
)
|
||||
|
||||
|
||||
def test_parse_schematic():
|
||||
assert Schematic.parse(mock_input) == Schematic(
|
||||
[
|
||||
Number("467", 0, 0),
|
||||
Number("114", 0, 5),
|
||||
Number("35", 2, 2),
|
||||
Number("633", 2, 6),
|
||||
Number("617", 4, 0),
|
||||
Number("58", 5, 8),
|
||||
Number("592", 6, 2),
|
||||
Number("755", 7, 6),
|
||||
Number("664", 9, 1),
|
||||
Number("598", 9, 5),
|
||||
Number("3", 9, 9),
|
||||
],
|
||||
[
|
||||
Symbol("*", 1, 3),
|
||||
Symbol("#", 3, 6),
|
||||
Symbol("*", 4, 3),
|
||||
Symbol("+", 5, 5),
|
||||
Symbol("$", 8, 3),
|
||||
Symbol("*", 8, 5),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def test_schematic_part_numbers():
|
||||
assert Schematic.parse(mock_input).parts() == {
|
||||
Part(
|
||||
Number("467", 0, 0),
|
||||
Symbol("*", 1, 3),
|
||||
),
|
||||
Part(
|
||||
Number("35", 2, 2),
|
||||
Symbol("*", 1, 3),
|
||||
),
|
||||
Part(
|
||||
Number("633", 2, 6),
|
||||
Symbol("#", 3, 6),
|
||||
),
|
||||
Part(
|
||||
Number("617", 4, 0),
|
||||
Symbol("*", 4, 3),
|
||||
),
|
||||
Part(
|
||||
Number("592", 6, 2),
|
||||
Symbol("+", 5, 5),
|
||||
),
|
||||
Part(
|
||||
Number("755", 7, 6),
|
||||
Symbol("*", 8, 5),
|
||||
),
|
||||
Part(
|
||||
Number("664", 9, 1),
|
||||
Symbol("$", 8, 3),
|
||||
),
|
||||
Part(
|
||||
Number("598", 9, 5),
|
||||
Symbol("*", 8, 5),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def test_solve_part_1():
|
||||
assert solve_part_1(mock_input) == 4361
|
||||
|
||||
|
||||
def test_solve_part_2():
|
||||
assert solve_part_2(mock_input) == 467835
|
99
tests/network_test.py
Normal file
99
tests/network_test.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
from frozendict import frozendict
|
||||
|
||||
from advent_of_code.network import Instruction, Network, solve_part_1, solve_part_2
|
||||
|
||||
mock_network = Network(
|
||||
(
|
||||
Instruction.Left,
|
||||
Instruction.Left,
|
||||
Instruction.Right,
|
||||
),
|
||||
frozendict(
|
||||
{
|
||||
"AAA": ("BBB", "BBB"),
|
||||
"BBB": ("AAA", "ZZZ"),
|
||||
"ZZZ": ("ZZZ", "ZZZ"),
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_network_parse():
|
||||
mock_input = dedent(
|
||||
"""\
|
||||
LLR
|
||||
|
||||
AAA = (BBB, BBB)
|
||||
BBB = (AAA, ZZZ)
|
||||
ZZZ = (ZZZ, ZZZ)
|
||||
"""
|
||||
)
|
||||
assert Network.parse(mock_input) == mock_network
|
||||
|
||||
assert Network.parse("LR") == Network((Instruction.Left, Instruction.Right), {})
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
Network.parse("invalid\nAAA = (BBB, CCC)")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
Network.parse("LR\n\ninvalid")
|
||||
|
||||
|
||||
def test_network_traverse():
|
||||
assert mock_network.traverse("AAA") == "BBB"
|
||||
assert mock_network.traverse("BBB") == "ZZZ"
|
||||
|
||||
with pytest.raises(Exception):
|
||||
network = Network(
|
||||
(Instruction.Left, Instruction.Left),
|
||||
frozendict({"AAA": ("BBB", "BBB")}),
|
||||
)
|
||||
network.traverse("AAA")
|
||||
|
||||
|
||||
def test_network_distance():
|
||||
assert mock_network.distance("AAA", "ZZZ") == 6
|
||||
|
||||
|
||||
def test_solve_part_1():
|
||||
assert (
|
||||
solve_part_1(
|
||||
dedent(
|
||||
"""\
|
||||
RL
|
||||
|
||||
AAA = (BBB, AAA)
|
||||
BBB = (CCC, BBB)
|
||||
CCC = (DDD, CCC)
|
||||
DDD = (ZZZ, DDD)
|
||||
ZZZ = (ZZZ, ZZZ)
|
||||
"""
|
||||
)
|
||||
)
|
||||
== 8
|
||||
)
|
||||
|
||||
|
||||
def test_solve_part_2():
|
||||
assert (
|
||||
solve_part_2(
|
||||
dedent(
|
||||
"""\
|
||||
LR
|
||||
|
||||
11A = (11B, XXX)
|
||||
11B = (XXX, 11Z)
|
||||
11Z = (11B, XXX)
|
||||
22A = (22B, XXX)
|
||||
22B = (22C, 22C)
|
||||
22C = (22Z, 22Z)
|
||||
22Z = (22B, 22B)
|
||||
XXX = (XXX, XXX)
|
||||
"""
|
||||
)
|
||||
)
|
||||
== 6
|
||||
)
|
46
tests/oasis_test.py
Normal file
46
tests/oasis_test.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from advent_of_code.oasis import (
|
||||
extrapolate_sequence,
|
||||
parse_sequence,
|
||||
solve_part_1,
|
||||
solve_part_2,
|
||||
)
|
||||
|
||||
|
||||
def test_parse_sequencce():
|
||||
assert parse_sequence("1 2 3") == (1, 2, 3)
|
||||
|
||||
|
||||
def test_extrapolate_sequence():
|
||||
assert extrapolate_sequence((0, 3, 6, 9, 12, 15)) == 18
|
||||
assert extrapolate_sequence((1, 3, 6, 10, 15, 21)) == 28
|
||||
assert extrapolate_sequence((10, 13, 16, 21, 30, 45)) == 68
|
||||
|
||||
|
||||
def test_solve_part_1():
|
||||
assert (
|
||||
solve_part_1(
|
||||
"\n".join(
|
||||
[
|
||||
"0 3 6 9 12 15",
|
||||
"1 3 6 10 15 21",
|
||||
"10 13 16 21 30 45",
|
||||
]
|
||||
)
|
||||
)
|
||||
== 114
|
||||
)
|
||||
|
||||
|
||||
def test_solve_part_2():
|
||||
assert (
|
||||
solve_part_2(
|
||||
"\n".join(
|
||||
[
|
||||
"0 3 6 9 12 15",
|
||||
"1 3 6 10 15 21",
|
||||
"10 13 16 21 30 45",
|
||||
]
|
||||
)
|
||||
)
|
||||
== 2
|
||||
)
|
53
tests/scratchcards_test.py
Normal file
53
tests/scratchcards_test.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import pytest
|
||||
|
||||
from advent_of_code.scratchcards import Scratchcard, solve_part_1, solve_part_2
|
||||
|
||||
mock_inputs = [
|
||||
"Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53",
|
||||
"Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19",
|
||||
"Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1",
|
||||
"Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83",
|
||||
"Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36",
|
||||
"Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11",
|
||||
]
|
||||
|
||||
|
||||
def test_scratchcard_parse():
|
||||
assert Scratchcard.parse(mock_inputs[0]) == Scratchcard(
|
||||
1,
|
||||
{41, 48, 83, 86, 17},
|
||||
{83, 86, 6, 31, 17, 9, 48, 53},
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
Scratchcard.parse("invalid")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
Scratchcard.parse("Card 4: invalid | invalid")
|
||||
|
||||
assert Scratchcard.parse("Card 5:") == Scratchcard(5, set(), set())
|
||||
assert Scratchcard.parse("Card 6: | ") == Scratchcard(6, set(), set())
|
||||
|
||||
|
||||
def test_scratchcard_match_count():
|
||||
assert Scratchcard(1, {1, 2}, {3, 4}).match_count == 0
|
||||
assert Scratchcard(1, {1, 2}, {2, 3}).match_count == 1
|
||||
assert Scratchcard(1, set(), set()).match_count == 0
|
||||
|
||||
|
||||
def test_scratchcard_points():
|
||||
card = Scratchcard(1, {41, 48, 83, 86, 17}, {83, 86, 6, 31, 17, 9, 48, 53})
|
||||
assert card.points == 8
|
||||
|
||||
|
||||
def test_scratchcard_resolve_copies():
|
||||
cards = [Scratchcard.parse(mock_input) for mock_input in mock_inputs]
|
||||
assert Scratchcard.resolve_copies(cards) == [1, 2, 4, 8, 14, 1]
|
||||
|
||||
|
||||
def test_solve_pt_1():
|
||||
assert solve_part_1("\n".join(mock_inputs)) == 13
|
||||
|
||||
|
||||
def test_solve_pt_2():
|
||||
assert solve_part_2("\n".join(mock_inputs)) == 30
|
@@ -1,9 +1,12 @@
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from advent_of_code.trebuchet import (
|
||||
recover_calibration_digits_and_words,
|
||||
recover_calibration_digits_only,
|
||||
_recover_all_calibration_values,
|
||||
_recover_calibration_value,
|
||||
solve_part_1,
|
||||
solve_part_2,
|
||||
)
|
||||
|
||||
|
||||
@@ -18,6 +21,14 @@ def test_recover_calibration_value():
|
||||
== 12
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
_recover_calibration_value(
|
||||
".",
|
||||
re.compile("ab"),
|
||||
re.compile("ba"),
|
||||
{},
|
||||
)
|
||||
|
||||
|
||||
def test_recover_all_calibration_values():
|
||||
assert (
|
||||
@@ -31,9 +42,9 @@ def test_recover_all_calibration_values():
|
||||
)
|
||||
|
||||
|
||||
def test_recover_calibration_digits_only():
|
||||
def test_solve_part_1():
|
||||
assert (
|
||||
recover_calibration_digits_only(
|
||||
solve_part_1(
|
||||
"\n".join(
|
||||
[
|
||||
"1abc2",
|
||||
@@ -43,13 +54,13 @@ def test_recover_calibration_digits_only():
|
||||
]
|
||||
)
|
||||
)
|
||||
== "142"
|
||||
== 142
|
||||
)
|
||||
|
||||
|
||||
def test_recover_calibration_digits_and_words():
|
||||
def test_solve_part_2():
|
||||
assert (
|
||||
recover_calibration_digits_and_words(
|
||||
solve_part_2(
|
||||
"\n".join(
|
||||
[
|
||||
"two1nine",
|
||||
@@ -62,5 +73,5 @@ def test_recover_calibration_digits_and_words():
|
||||
]
|
||||
)
|
||||
)
|
||||
== "281"
|
||||
== 281
|
||||
)
|
||||
|
Reference in New Issue
Block a user