formatting and cosmetic updates to 2020.
This commit is contained in:
parent
84c4cf9991
commit
cd75e58f77
28 changed files with 320 additions and 287 deletions
|
|
@ -2,41 +2,43 @@
|
|||
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
def parse(puzzle_input):
|
||||
"""Parse input"""
|
||||
return [int(string) for string in puzzle_input.splitlines()]
|
||||
|
||||
def part1(data:list[int]):
|
||||
|
||||
def part1(data: list[int]):
|
||||
"""Solve part 1"""
|
||||
data.sort()
|
||||
while True:
|
||||
if len(data)<2:
|
||||
raise ValueError('no match found')
|
||||
s = data[0]+data[-1]
|
||||
if s>2020:
|
||||
if len(data) < 2:
|
||||
raise ValueError("no match found")
|
||||
s = data[0] + data[-1]
|
||||
if s > 2020:
|
||||
data.pop(-1)
|
||||
elif s<2020:
|
||||
elif s < 2020:
|
||||
data.pop(0)
|
||||
else:
|
||||
return data[0]*data[-1]
|
||||
return data[0] * data[-1]
|
||||
|
||||
|
||||
def part2(data):
|
||||
"""Solve part 2"""
|
||||
data.sort()
|
||||
while True:
|
||||
if len(data)<3:
|
||||
raise ValueError('no match found')
|
||||
if data[0]+data[1]+data[-1]>2020:
|
||||
if len(data) < 3:
|
||||
raise ValueError("no match found")
|
||||
if data[0] + data[1] + data[-1] > 2020:
|
||||
data.pop(-1)
|
||||
elif data[0]+data[-1]+data[-2]<2020:
|
||||
elif data[0] + data[-1] + data[-2] < 2020:
|
||||
data.pop(0)
|
||||
elif data[0]+data[1]+data[-1]==2020:
|
||||
return data[0]*data[1]*data[-1]
|
||||
elif data[0] + data[1] + data[-1] == 2020:
|
||||
return data[0] * data[1] * data[-1]
|
||||
else:
|
||||
return data[0]*data[-1]*data[-2]
|
||||
return data[0] * data[-1] * data[-2]
|
||||
|
||||
|
||||
def solve(puzzle_input):
|
||||
"""Solve the puzzle for the given input"""
|
||||
|
|
@ -46,6 +48,7 @@ def solve(puzzle_input):
|
|||
|
||||
return solution1, solution2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for path in sys.argv[1:]:
|
||||
print(f"{path}:")
|
||||
|
|
|
|||
|
|
@ -6,28 +6,24 @@ import day1 as aoc
|
|||
|
||||
PUZZLE_DIR = pathlib.Path(__file__).parent
|
||||
|
||||
#these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
|
||||
# these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
@pytest.fixture
|
||||
def example1():
|
||||
puzzle_input = (PUZZLE_DIR / "example1").read_text().strip()
|
||||
def example():
|
||||
puzzle_input = (PUZZLE_DIR / "example").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
@pytest.fixture
|
||||
def example2():
|
||||
puzzle_input = (PUZZLE_DIR / "example2").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_parse_example1(example1):
|
||||
def test_parse(example):
|
||||
"""Test that input is parsed properly"""
|
||||
assert example1 == [1721, 979, 366, 299, 675, 1456]
|
||||
assert example == [1721, 979, 366, 299, 675, 1456]
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part1_example1(example1):
|
||||
|
||||
def test_part1(example):
|
||||
"""Test part 1 on example input"""
|
||||
assert aoc.part1(example1) == 514579
|
||||
assert aoc.part1(example) == 514579
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part2_example2(example1):
|
||||
|
||||
def test_part2(example):
|
||||
"""Test part 2 on example input"""
|
||||
assert aoc.part2(example1) == 241861950
|
||||
assert aoc.part2(example) == 241861950
|
||||
|
|
|
|||
|
|
@ -1,40 +1,52 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class PasswordSpec:
|
||||
first:int
|
||||
second:int
|
||||
letter:str
|
||||
password:str
|
||||
first: int
|
||||
second: int
|
||||
letter: str
|
||||
password: str
|
||||
|
||||
|
||||
def parse(puzzle_input: str):
|
||||
"""Parse input"""
|
||||
regex = re.compile(r'^(\d+)-(\d+) (\w): (\w+)$')
|
||||
toInt = lambda x: PasswordSpec(int(x[0]), int(x[1]), x[2], x[3])
|
||||
regex = re.compile(r"^(\d+)-(\d+) (\w): (\w+)$")
|
||||
|
||||
def toInt(x):
|
||||
return PasswordSpec(int(x[0]), int(x[1]), x[2], x[3])
|
||||
|
||||
return [toInt(regex.match(i).groups()) for i in puzzle_input.splitlines()]
|
||||
|
||||
|
||||
def part1(data):
|
||||
"""Solve part 1"""
|
||||
test = lambda x: x.first<=x.password.count(x.letter)<=x.second
|
||||
|
||||
def test(x):
|
||||
return x.first <= x.password.count(x.letter) <= x.second
|
||||
|
||||
# these two lines are equivilant.
|
||||
# return sum(1 for p in data if test(p))
|
||||
return len([1 for p in data if test(p)])
|
||||
|
||||
|
||||
def test_password(passwordSpec: PasswordSpec):
|
||||
if passwordSpec.password[passwordSpec.first-1]==passwordSpec.letter:
|
||||
return passwordSpec.password[passwordSpec.second-1]!=passwordSpec.letter
|
||||
if passwordSpec.password[passwordSpec.first - 1] == passwordSpec.letter:
|
||||
return passwordSpec.password[passwordSpec.second - 1] != passwordSpec.letter
|
||||
else:
|
||||
return passwordSpec.password[passwordSpec.second-1]==passwordSpec.letter
|
||||
return passwordSpec.password[passwordSpec.second - 1] == passwordSpec.letter
|
||||
|
||||
|
||||
def part2(data):
|
||||
"""Solve part 2"""
|
||||
return sum(1 for p in data if test_password(p))
|
||||
|
||||
|
||||
def solve(puzzle_input):
|
||||
"""Solve the puzzle for the given input"""
|
||||
data = parse(puzzle_input)
|
||||
|
|
@ -43,6 +55,7 @@ def solve(puzzle_input):
|
|||
|
||||
return solution1, solution2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for path in sys.argv[1:]:
|
||||
print(f"{path}:")
|
||||
|
|
|
|||
|
|
@ -6,32 +6,28 @@ import day2 as aoc
|
|||
|
||||
PUZZLE_DIR = pathlib.Path(__file__).parent
|
||||
|
||||
#these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
|
||||
# these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
@pytest.fixture
|
||||
def example1():
|
||||
puzzle_input = (PUZZLE_DIR / "example1").read_text().strip()
|
||||
def example():
|
||||
puzzle_input = (PUZZLE_DIR / "example").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
@pytest.fixture
|
||||
def example2():
|
||||
puzzle_input = (PUZZLE_DIR / "example2").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_parse_example1(example1):
|
||||
def test_parse(example):
|
||||
"""Test that input is parsed properly"""
|
||||
assert example1 == [
|
||||
aoc.PasswordSpec(first=1, second=3, letter='a', password='abcde'),
|
||||
aoc.PasswordSpec(first=1, second=3, letter='b', password='cdefg'),
|
||||
aoc.PasswordSpec(first=2, second=9, letter='c', password='ccccccccc')
|
||||
]
|
||||
assert example == [
|
||||
aoc.PasswordSpec(first=1, second=3, letter="a", password="abcde"),
|
||||
aoc.PasswordSpec(first=1, second=3, letter="b", password="cdefg"),
|
||||
aoc.PasswordSpec(first=2, second=9, letter="c", password="ccccccccc"),
|
||||
]
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part1_example1(example1):
|
||||
|
||||
def test_part1(example):
|
||||
"""Test part 1 on example input"""
|
||||
assert aoc.part1(example1) == 2
|
||||
assert aoc.part1(example) == 2
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part2_example2(example1):
|
||||
|
||||
def test_part2(example):
|
||||
"""Test part 2 on example input"""
|
||||
assert aoc.part2(example1) == 1
|
||||
assert aoc.part2(example) == 1
|
||||
|
|
|
|||
|
|
@ -2,25 +2,35 @@
|
|||
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from pprint import pprint
|
||||
|
||||
|
||||
def parse(puzzle_input: str):
|
||||
"""Parse input"""
|
||||
# returns a 2 dimentional array where true means there is a tree there.
|
||||
return [[i=='#' for i in j] for j in puzzle_input.splitlines()]
|
||||
return [[i == "#" for i in j] for j in puzzle_input.splitlines()]
|
||||
|
||||
|
||||
def part1(data):
|
||||
"""Solve part 1"""
|
||||
return solveForSlope(data, 3, 1)
|
||||
|
||||
|
||||
def solveForSlope(data, right: int, down: int):
|
||||
return sum(1 for index, row in enumerate(data[::down]) if row[(right*index)%len(row)])
|
||||
return sum(
|
||||
1 for index, row in enumerate(data[::down]) if row[(right * index) % len(row)]
|
||||
)
|
||||
|
||||
|
||||
def part2(data):
|
||||
"""Solve part 2"""
|
||||
return solveForSlope(data,1,1)*solveForSlope(data,3,1)*solveForSlope(data,5,1)*solveForSlope(data,7,1)*solveForSlope(data,1,2)
|
||||
return (
|
||||
solveForSlope(data, 1, 1)
|
||||
* solveForSlope(data, 3, 1)
|
||||
* solveForSlope(data, 5, 1)
|
||||
* solveForSlope(data, 7, 1)
|
||||
* solveForSlope(data, 1, 2)
|
||||
)
|
||||
|
||||
|
||||
def solve(puzzle_input):
|
||||
"""Solve the puzzle for the given input"""
|
||||
|
|
@ -30,6 +40,7 @@ def solve(puzzle_input):
|
|||
|
||||
return solution1, solution2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for path in sys.argv[1:]:
|
||||
print(f"{path}:")
|
||||
|
|
|
|||
|
|
@ -6,38 +6,38 @@ import day3 as aoc
|
|||
|
||||
PUZZLE_DIR = pathlib.Path(__file__).parent
|
||||
|
||||
#these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
|
||||
# these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
@pytest.fixture
|
||||
def example1():
|
||||
puzzle_input = (PUZZLE_DIR / "example1").read_text().strip()
|
||||
def example():
|
||||
puzzle_input = (PUZZLE_DIR / "example.txt").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
@pytest.fixture
|
||||
def example2():
|
||||
puzzle_input = (PUZZLE_DIR / "example1").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_parse_example1(example1):
|
||||
def test_parse(example):
|
||||
"""Test that input is parsed properly"""
|
||||
assert example1 == [[False, False, True, True, False, False, False, False, False, False, False],
|
||||
[True, False, False, False, True, False, False, False, True, False, False],
|
||||
[False, True, False, False, False, False, True, False, False, True, False],
|
||||
[False, False, True, False, True, False, False, False, True, False, True],
|
||||
[False, True, False, False, False, True, True, False, False, True, False],
|
||||
[False, False, True, False, True, True, False, False, False, False, False],
|
||||
[False, True, False, True, False, True, False, False, False, False, True],
|
||||
[False, True, False, False, False, False, False, False, False, False, True],
|
||||
[True, False, True, True, False, False, False, True, False, False, False],
|
||||
[True, False, False, False, True, True, False, False, False, False, True],
|
||||
[False, True, False, False, True, False, False, False, True, False, True]]
|
||||
assert example == [
|
||||
[False, False, True, True, False, False, False, False, False, False, False],
|
||||
[True, False, False, False, True, False, False, False, True, False, False],
|
||||
[False, True, False, False, False, False, True, False, False, True, False],
|
||||
[False, False, True, False, True, False, False, False, True, False, True],
|
||||
[False, True, False, False, False, True, True, False, False, True, False],
|
||||
[False, False, True, False, True, True, False, False, False, False, False],
|
||||
[False, True, False, True, False, True, False, False, False, False, True],
|
||||
[False, True, False, False, False, False, False, False, False, False, True],
|
||||
[True, False, True, True, False, False, False, True, False, False, False],
|
||||
[True, False, False, False, True, True, False, False, False, False, True],
|
||||
[False, True, False, False, True, False, False, False, True, False, True],
|
||||
]
|
||||
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part1_example1(example1):
|
||||
def test_part1(example):
|
||||
"""Test part 1 on example input"""
|
||||
assert aoc.part1(example1) == 7
|
||||
assert aoc.part1(example) == 7
|
||||
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part2_example2(example2):
|
||||
def test_part2(example):
|
||||
"""Test part 2 on example input"""
|
||||
assert aoc.part2(example2) == 336
|
||||
assert aoc.part2(example) == 336
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pprint import pprint
|
||||
|
||||
|
||||
@dataclass
|
||||
class Passport:
|
||||
|
|
@ -17,105 +17,131 @@ class Passport:
|
|||
passportId: str | None
|
||||
countryId: str | None
|
||||
|
||||
def regexUnwrap(match, group:int)->str | None:
|
||||
|
||||
def regexUnwrap(match, group: int) -> str | None:
|
||||
return match[group] if match is not None else None
|
||||
|
||||
def parse(puzzle_input: str)->list[Passport]:
|
||||
|
||||
def parse(puzzle_input: str) -> list[Passport]:
|
||||
"""Parse input"""
|
||||
rawRecords = [i.replace('\n', ' ') for i in puzzle_input.split('\n\n')]
|
||||
rawRecords = [i.replace("\n", " ") for i in puzzle_input.split("\n\n")]
|
||||
records = []
|
||||
for rawRecord in rawRecords:
|
||||
birthYear=re.search(r'byr:(\S+)', rawRecord)
|
||||
issueYear=re.search(r'iyr:(\S+)', rawRecord)
|
||||
expirationYear=re.search(r'eyr:(\S+)', rawRecord)
|
||||
height=re.search(r'hgt:(\S+)', rawRecord)
|
||||
hairColor=re.search(r'hcl:(\S+)', rawRecord)
|
||||
eyeColor=re.search(r'ecl:(\S+)', rawRecord)
|
||||
passportId=re.search(r'pid:(\S+)', rawRecord)
|
||||
countryId=re.search(r'cid:(\S+)', rawRecord)
|
||||
records.append(Passport(
|
||||
int(birthYear[1]) if birthYear is not None else None,
|
||||
int(issueYear[1]) if issueYear is not None else None,
|
||||
int(expirationYear[1]) if expirationYear is not None else None,
|
||||
regexUnwrap(height,1),
|
||||
regexUnwrap(hairColor,1),
|
||||
regexUnwrap(eyeColor,1),
|
||||
regexUnwrap(passportId,1),
|
||||
regexUnwrap(countryId,1),
|
||||
))
|
||||
birthYear = re.search(r"byr:(\S+)", rawRecord)
|
||||
issueYear = re.search(r"iyr:(\S+)", rawRecord)
|
||||
expirationYear = re.search(r"eyr:(\S+)", rawRecord)
|
||||
height = re.search(r"hgt:(\S+)", rawRecord)
|
||||
hairColor = re.search(r"hcl:(\S+)", rawRecord)
|
||||
eyeColor = re.search(r"ecl:(\S+)", rawRecord)
|
||||
passportId = re.search(r"pid:(\S+)", rawRecord)
|
||||
countryId = re.search(r"cid:(\S+)", rawRecord)
|
||||
records.append(
|
||||
Passport(
|
||||
int(birthYear[1]) if birthYear is not None else None,
|
||||
int(issueYear[1]) if issueYear is not None else None,
|
||||
int(expirationYear[1]) if expirationYear is not None else None,
|
||||
regexUnwrap(height, 1),
|
||||
regexUnwrap(hairColor, 1),
|
||||
regexUnwrap(eyeColor, 1),
|
||||
regexUnwrap(passportId, 1),
|
||||
regexUnwrap(countryId, 1),
|
||||
)
|
||||
)
|
||||
return records
|
||||
|
||||
def lazyCheckPassport(passport: Passport)->bool:
|
||||
|
||||
def lazyCheckPassport(passport: Passport) -> bool:
|
||||
return (
|
||||
passport.birthYear is not None
|
||||
and passport.issueYear is not None
|
||||
and passport.expirationYear is not None
|
||||
and passport.height is not None
|
||||
and passport.hairColor is not None
|
||||
and passport.eyeColor is not None
|
||||
and passport.passportId is not None
|
||||
)
|
||||
passport.birthYear is not None
|
||||
and passport.issueYear is not None
|
||||
and passport.expirationYear is not None
|
||||
and passport.height is not None
|
||||
and passport.hairColor is not None
|
||||
and passport.eyeColor is not None
|
||||
and passport.passportId is not None
|
||||
)
|
||||
|
||||
|
||||
def part1(data):
|
||||
"""Solve part 1"""
|
||||
return sum(1 for record in data if lazyCheckPassport(record))
|
||||
|
||||
def checkBirthYear(passport: Passport)->bool:
|
||||
if passport.birthYear is None: return False
|
||||
return (1920<=passport.birthYear<=2002)
|
||||
|
||||
def checkIssueYear(passport: Passport)->bool:
|
||||
if passport.issueYear is None: return False
|
||||
return (2010<=passport.issueYear<=2020)
|
||||
def checkBirthYear(passport: Passport) -> bool:
|
||||
if passport.birthYear is None:
|
||||
return False
|
||||
return 1920 <= passport.birthYear <= 2002
|
||||
|
||||
def checkExpirationYear(passport: Passport)->bool:
|
||||
if passport.expirationYear is None: return False
|
||||
return (2020<=passport.expirationYear<=2030)
|
||||
|
||||
def checkHeight(passport: Passport)->bool:
|
||||
if passport.height is None: return False
|
||||
rematch = re.match(r'(\d+)((?:in)|(?:cm))', passport.height)
|
||||
if rematch is None: return False
|
||||
def checkIssueYear(passport: Passport) -> bool:
|
||||
if passport.issueYear is None:
|
||||
return False
|
||||
return 2010 <= passport.issueYear <= 2020
|
||||
|
||||
|
||||
def checkExpirationYear(passport: Passport) -> bool:
|
||||
if passport.expirationYear is None:
|
||||
return False
|
||||
return 2020 <= passport.expirationYear <= 2030
|
||||
|
||||
|
||||
def checkHeight(passport: Passport) -> bool:
|
||||
if passport.height is None:
|
||||
return False
|
||||
rematch = re.match(r"(\d+)((?:in)|(?:cm))", passport.height)
|
||||
if rematch is None:
|
||||
return False
|
||||
number = int(rematch.group(1))
|
||||
unit = rematch.group(2)
|
||||
if unit == 'in':
|
||||
return (59<=number<=76)
|
||||
if unit == "in":
|
||||
return 59 <= number <= 76
|
||||
else:
|
||||
return (150<=number<=193)
|
||||
return 150 <= number <= 193
|
||||
|
||||
def checkHairColour(passport: Passport)->bool:
|
||||
if passport.hairColor is None: return False
|
||||
return (re.match(r'#[0123456789abcdef]{6}$', passport.hairColor) is not None)
|
||||
|
||||
def checkEyeColour(passport: Passport)->bool:
|
||||
if passport.eyeColor is None: return False
|
||||
return (passport.eyeColor == 'amb'
|
||||
or passport.eyeColor == 'blu'
|
||||
or passport.eyeColor == 'brn'
|
||||
or passport.eyeColor == 'gry'
|
||||
or passport.eyeColor == 'grn'
|
||||
or passport.eyeColor == 'hzl'
|
||||
or passport.eyeColor == 'oth'
|
||||
)
|
||||
def checkHairColour(passport: Passport) -> bool:
|
||||
if passport.hairColor is None:
|
||||
return False
|
||||
return re.match(r"#[0123456789abcdef]{6}$", passport.hairColor) is not None
|
||||
|
||||
def checkPassportId(passport: Passport)->bool:
|
||||
if passport.passportId is None: return False
|
||||
return (re.match(r'[0-9]{9}$', passport.passportId) is not None)
|
||||
|
||||
def checkPassport(passport: Passport)->bool:
|
||||
return (checkBirthYear(passport)
|
||||
and checkIssueYear(passport)
|
||||
and checkExpirationYear(passport)
|
||||
and checkHeight(passport)
|
||||
and checkHairColour(passport)
|
||||
and checkEyeColour(passport)
|
||||
and checkPassportId(passport)
|
||||
)
|
||||
def checkEyeColour(passport: Passport) -> bool:
|
||||
if passport.eyeColor is None:
|
||||
return False
|
||||
return (
|
||||
passport.eyeColor == "amb"
|
||||
or passport.eyeColor == "blu"
|
||||
or passport.eyeColor == "brn"
|
||||
or passport.eyeColor == "gry"
|
||||
or passport.eyeColor == "grn"
|
||||
or passport.eyeColor == "hzl"
|
||||
or passport.eyeColor == "oth"
|
||||
)
|
||||
|
||||
|
||||
def checkPassportId(passport: Passport) -> bool:
|
||||
if passport.passportId is None:
|
||||
return False
|
||||
return re.match(r"[0-9]{9}$", passport.passportId) is not None
|
||||
|
||||
|
||||
def checkPassport(passport: Passport) -> bool:
|
||||
return (
|
||||
checkBirthYear(passport)
|
||||
and checkIssueYear(passport)
|
||||
and checkExpirationYear(passport)
|
||||
and checkHeight(passport)
|
||||
and checkHairColour(passport)
|
||||
and checkEyeColour(passport)
|
||||
and checkPassportId(passport)
|
||||
)
|
||||
|
||||
|
||||
def part2(data):
|
||||
"""Solve part 2"""
|
||||
return sum(1 for record in data if checkPassport(record))
|
||||
|
||||
|
||||
def solve(puzzle_input):
|
||||
"""Solve the puzzle for the given input"""
|
||||
data = parse(puzzle_input)
|
||||
|
|
@ -124,6 +150,7 @@ def solve(puzzle_input):
|
|||
|
||||
return solution1, solution2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for path in sys.argv[1:]:
|
||||
print(f"{path}:")
|
||||
|
|
|
|||
|
|
@ -7,59 +7,67 @@ from day4 import Passport
|
|||
|
||||
PUZZLE_DIR = pathlib.Path(__file__).parent
|
||||
|
||||
#these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
|
||||
# these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
@pytest.fixture
|
||||
def example1():
|
||||
puzzle_input = (PUZZLE_DIR / "example1").read_text().strip()
|
||||
def example():
|
||||
puzzle_input = (PUZZLE_DIR / "example.txt").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
@pytest.fixture
|
||||
def example2():
|
||||
puzzle_input = (PUZZLE_DIR / "example2").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_parse_example1(example1):
|
||||
def test_parse(example):
|
||||
"""Test that input is parsed properly"""
|
||||
assert example1 == [Passport(birthYear=1937,
|
||||
issueYear=2017,
|
||||
expirationYear=2020,
|
||||
height='183cm',
|
||||
hairColor='#fffffd',
|
||||
eyeColor='gry',
|
||||
passportId='860033327',
|
||||
countryId='147'),
|
||||
Passport(birthYear=1929,
|
||||
assert example == [
|
||||
Passport(
|
||||
birthYear=1937,
|
||||
issueYear=2017,
|
||||
expirationYear=2020,
|
||||
height="183cm",
|
||||
hairColor="#fffffd",
|
||||
eyeColor="gry",
|
||||
passportId="860033327",
|
||||
countryId="147",
|
||||
),
|
||||
Passport(
|
||||
birthYear=1929,
|
||||
issueYear=2013,
|
||||
expirationYear=2023,
|
||||
height=None,
|
||||
hairColor='#cfa07d',
|
||||
eyeColor='amb',
|
||||
passportId='028048884',
|
||||
countryId='350'),
|
||||
Passport(birthYear=1931,
|
||||
hairColor="#cfa07d",
|
||||
eyeColor="amb",
|
||||
passportId="028048884",
|
||||
countryId="350",
|
||||
),
|
||||
Passport(
|
||||
birthYear=1931,
|
||||
issueYear=2013,
|
||||
expirationYear=2024,
|
||||
height='179cm',
|
||||
hairColor='#ae17e1',
|
||||
eyeColor='brn',
|
||||
passportId='760753108',
|
||||
countryId=None),
|
||||
Passport(birthYear=None,
|
||||
height="179cm",
|
||||
hairColor="#ae17e1",
|
||||
eyeColor="brn",
|
||||
passportId="760753108",
|
||||
countryId=None,
|
||||
),
|
||||
Passport(
|
||||
birthYear=None,
|
||||
issueYear=2011,
|
||||
expirationYear=2025,
|
||||
height='59in',
|
||||
hairColor='#cfa07d',
|
||||
eyeColor='brn',
|
||||
passportId='166559648',
|
||||
countryId=None)]
|
||||
height="59in",
|
||||
hairColor="#cfa07d",
|
||||
eyeColor="brn",
|
||||
passportId="166559648",
|
||||
countryId=None,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part1_example1(example1):
|
||||
def test_part1(example):
|
||||
"""Test part 1 on example input"""
|
||||
assert aoc.part1(example1) == 2
|
||||
assert aoc.part1(example) == 2
|
||||
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part2_example2(example1):
|
||||
def test_part2(example):
|
||||
"""Test part 2 on example input"""
|
||||
assert aoc.part2(example1) == 2
|
||||
assert aoc.part2(example) == 2
|
||||
|
|
|
|||
|
|
@ -2,34 +2,39 @@
|
|||
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from pprint import pprint
|
||||
|
||||
def row_to_int(string: str)->int:
|
||||
return int(string.replace('F','0').replace('B','1'),2)
|
||||
|
||||
def col_to_int(string: str)->int:
|
||||
return int(string.replace('L','0').replace('R','1'),2)
|
||||
def row_to_int(string: str) -> int:
|
||||
return int(string.replace("F", "0").replace("B", "1"), 2)
|
||||
|
||||
|
||||
def col_to_int(string: str) -> int:
|
||||
return int(string.replace("L", "0").replace("R", "1"), 2)
|
||||
|
||||
|
||||
def parse(puzzle_input: str):
|
||||
"""Parse input"""
|
||||
rows_and_cols = [(row_to_int(x[:7]),col_to_int(x[7:])) for x in puzzle_input.splitlines()]
|
||||
return set([x[0]*8+x[1] for x in rows_and_cols])
|
||||
rows_and_cols = [
|
||||
(row_to_int(x[:7]), col_to_int(x[7:])) for x in puzzle_input.splitlines()
|
||||
]
|
||||
return set([x[0] * 8 + x[1] for x in rows_and_cols])
|
||||
|
||||
|
||||
def part1(data):
|
||||
"""Solve part 1"""
|
||||
return max(data)
|
||||
|
||||
|
||||
def part2(data):
|
||||
"""Solve part 2"""
|
||||
for row in range(128):
|
||||
for col in range(8):
|
||||
potentialID=row*8+col
|
||||
potentialID = row * 8 + col
|
||||
if potentialID not in data:
|
||||
if (potentialID+1 in data) and (potentialID-1 in data):
|
||||
if (potentialID + 1 in data) and (potentialID - 1 in data):
|
||||
return potentialID
|
||||
|
||||
|
||||
def solve(puzzle_input):
|
||||
"""Solve the puzzle for the given input"""
|
||||
data = parse(puzzle_input)
|
||||
|
|
@ -38,6 +43,7 @@ def solve(puzzle_input):
|
|||
|
||||
return solution1, solution2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for path in sys.argv[1:]:
|
||||
print(f"{path}:")
|
||||
|
|
|
|||
|
|
@ -6,28 +6,24 @@ import day5 as aoc
|
|||
|
||||
PUZZLE_DIR = pathlib.Path(__file__).parent
|
||||
|
||||
#these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
|
||||
# these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
@pytest.fixture
|
||||
def example1():
|
||||
puzzle_input = (PUZZLE_DIR / "example1").read_text().strip()
|
||||
def example():
|
||||
puzzle_input = (PUZZLE_DIR / "example.txt").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
@pytest.fixture
|
||||
def example2():
|
||||
puzzle_input = (PUZZLE_DIR / "input").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_parse_example1(example1):
|
||||
def test_parse(example):
|
||||
"""Test that input is parsed properly"""
|
||||
assert example1 == {119, 357, 567, 820}
|
||||
assert example == {119, 357, 567, 820}
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part1_example1(example1):
|
||||
|
||||
def test_part1(example):
|
||||
"""Test part 1 on example input"""
|
||||
assert aoc.part1(example1) == 820
|
||||
assert aoc.part1(example) == 820
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part2_example2(example2):
|
||||
|
||||
def test_part2(example):
|
||||
"""Test part 2 on example input"""
|
||||
assert aoc.part2(example2) == 640
|
||||
assert aoc.part2(example) == 640
|
||||
|
|
|
|||
|
|
@ -2,15 +2,14 @@
|
|||
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from pprint import pprint
|
||||
|
||||
|
||||
def parse(puzzle_input: str):
|
||||
"""Parse input"""
|
||||
records = [[list(y) for y in x.splitlines()] for x in puzzle_input.split('\n\n')]
|
||||
records = [[list(y) for y in x.splitlines()] for x in puzzle_input.split("\n\n")]
|
||||
return records
|
||||
|
||||
|
||||
def part1(data):
|
||||
"""Solve part 1"""
|
||||
results = []
|
||||
|
|
@ -21,6 +20,7 @@ def part1(data):
|
|||
results.append(len(result))
|
||||
return sum(results)
|
||||
|
||||
|
||||
def part2(data):
|
||||
"""Solve part 2"""
|
||||
results = []
|
||||
|
|
@ -31,6 +31,7 @@ def part2(data):
|
|||
results.append(len(result))
|
||||
return sum(results)
|
||||
|
||||
|
||||
def solve(puzzle_input):
|
||||
"""Solve the puzzle for the given input"""
|
||||
data = parse(puzzle_input)
|
||||
|
|
@ -39,6 +40,7 @@ def solve(puzzle_input):
|
|||
|
||||
return solution1, solution2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for path in sys.argv[1:]:
|
||||
print(f"{path}:")
|
||||
|
|
|
|||
|
|
@ -6,50 +6,33 @@ import day6 as aoc
|
|||
|
||||
PUZZLE_DIR = pathlib.Path(__file__).parent
|
||||
|
||||
#these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
|
||||
# these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
@pytest.fixture
|
||||
def example1():
|
||||
puzzle_input = (PUZZLE_DIR / "example1").read_text().strip()
|
||||
def example():
|
||||
puzzle_input = (PUZZLE_DIR / "example.txt").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
@pytest.fixture
|
||||
def example2():
|
||||
puzzle_input = (PUZZLE_DIR / "example2").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_parse_example1(example1):
|
||||
def test_parse(example):
|
||||
"""Test that input is parsed properly"""
|
||||
assert example1 == [
|
||||
[
|
||||
['a', 'b', 'c']
|
||||
],
|
||||
[
|
||||
['a'],
|
||||
['b'],
|
||||
['c']
|
||||
],
|
||||
[
|
||||
['a', 'b'],
|
||||
['a', 'c']
|
||||
],
|
||||
[
|
||||
['a'],
|
||||
['a'],
|
||||
['a'],
|
||||
['a']
|
||||
],
|
||||
[
|
||||
['b']
|
||||
]
|
||||
]
|
||||
assert example == [
|
||||
[["a", "b", "c"]],
|
||||
[["a"], ["b"], ["c"]],
|
||||
[["a", "b"], ["a", "c"]],
|
||||
[["a"], ["a"], ["a"], ["a"]],
|
||||
[["b"]],
|
||||
]
|
||||
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part1_example1(example1):
|
||||
def test_part1(example):
|
||||
"""Test part 1 on example input"""
|
||||
assert aoc.part1(example1) == 11
|
||||
assert aoc.part1(example) == 11
|
||||
|
||||
|
||||
# @pytest.mark.skip(reason="Not implemented")
|
||||
def test_part2_example2(example1):
|
||||
def test_part2(example):
|
||||
"""Test part 2 on example input"""
|
||||
assert aoc.part2(example1) == 6
|
||||
assert aoc.part2(example) == 6
|
||||
|
|
|
|||
0
2020/template/example.txt
Normal file
0
2020/template/example.txt
Normal file
0
2020/template/input.txt
Normal file
0
2020/template/input.txt
Normal file
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from pprint import pprint
|
||||
|
||||
def parse(puzzle_input: str):
|
||||
"""Parse input"""
|
||||
|
|
@ -2,32 +2,27 @@
|
|||
|
||||
import pathlib
|
||||
import pytest
|
||||
import template as aoc
|
||||
import temp as aoc
|
||||
|
||||
PUZZLE_DIR = pathlib.Path(__file__).parent
|
||||
|
||||
#these test fixtures setup the test, mainly by reading the filename into a string in this simple case.
|
||||
@pytest.fixture
|
||||
def example1():
|
||||
puzzle_input = (PUZZLE_DIR / "example1").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
@pytest.fixture
|
||||
def example2():
|
||||
puzzle_input = (PUZZLE_DIR / "example2").read_text().strip()
|
||||
def example():
|
||||
puzzle_input = (PUZZLE_DIR / "example.txt").read_text().strip()
|
||||
return aoc.parse(puzzle_input)
|
||||
|
||||
@pytest.mark.skip(reason="Not implemented")
|
||||
def test_parse_example1(example1):
|
||||
def test_parse_example(example):
|
||||
"""Test that input is parsed properly"""
|
||||
assert example1 == ...
|
||||
assert example == ...
|
||||
|
||||
@pytest.mark.skip(reason="Not implemented")
|
||||
def test_part1_example1(example1):
|
||||
def test_part1_example(example):
|
||||
"""Test part 1 on example input"""
|
||||
assert aoc.part1(example1) == ...
|
||||
assert aoc.part1(example) == ...
|
||||
|
||||
@pytest.mark.skip(reason="Not implemented")
|
||||
def test_part2_example2(example2):
|
||||
def test_part2_example(example):
|
||||
"""Test part 2 on example input"""
|
||||
assert aoc.part2(example2) == ...
|
||||
assert aoc.part2(example) == ...
|
||||
Loading…
Add table
Add a link
Reference in a new issue