Cleanup whoops
This commit is contained in:
parent
1d827b517b
commit
d2405f75d8
@ -1,13 +0,0 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
|
||||
[dev-packages]
|
||||
mypy = ""
|
||||
pytest = ""
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
156
aoc2020/py/Pipfile.lock
generated
156
aoc2020/py/Pipfile.lock
generated
@ -1,156 +0,0 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "ed02d1728cc686824535903ae2f5f3956ba104434c4c6e532237df55bcd69a12"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.9"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {},
|
||||
"develop": {
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",
|
||||
"sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==20.3.0"
|
||||
},
|
||||
"iniconfig": {
|
||||
"hashes": [
|
||||
"sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
|
||||
"sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"
|
||||
],
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"mypy": {
|
||||
"hashes": [
|
||||
"sha256:0a0d102247c16ce93c97066443d11e2d36e6cc2a32d8ccc1f705268970479324",
|
||||
"sha256:0d34d6b122597d48a36d6c59e35341f410d4abfa771d96d04ae2c468dd201abc",
|
||||
"sha256:2170492030f6faa537647d29945786d297e4862765f0b4ac5930ff62e300d802",
|
||||
"sha256:2842d4fbd1b12ab422346376aad03ff5d0805b706102e475e962370f874a5122",
|
||||
"sha256:2b21ba45ad9ef2e2eb88ce4aeadd0112d0f5026418324176fd494a6824b74975",
|
||||
"sha256:72060bf64f290fb629bd4a67c707a66fd88ca26e413a91384b18db3876e57ed7",
|
||||
"sha256:af4e9ff1834e565f1baa74ccf7ae2564ae38c8df2a85b057af1dbbc958eb6666",
|
||||
"sha256:bd03b3cf666bff8d710d633d1c56ab7facbdc204d567715cb3b9f85c6e94f669",
|
||||
"sha256:c614194e01c85bb2e551c421397e49afb2872c88b5830e3554f0519f9fb1c178",
|
||||
"sha256:cf4e7bf7f1214826cf7333627cb2547c0db7e3078723227820d0a2490f117a01",
|
||||
"sha256:da56dedcd7cd502ccd3c5dddc656cb36113dd793ad466e894574125945653cea",
|
||||
"sha256:e86bdace26c5fe9cf8cb735e7cedfe7850ad92b327ac5d797c656717d2ca66de",
|
||||
"sha256:e97e9c13d67fbe524be17e4d8025d51a7dca38f90de2e462243ab8ed8a9178d1",
|
||||
"sha256:eea260feb1830a627fb526d22fbb426b750d9f5a47b624e8d5e7e004359b219c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.790"
|
||||
},
|
||||
"mypy-extensions": {
|
||||
"hashes": [
|
||||
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
|
||||
"sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
|
||||
],
|
||||
"version": "==0.4.3"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858",
|
||||
"sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==20.8"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
|
||||
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.13.1"
|
||||
},
|
||||
"py": {
|
||||
"hashes": [
|
||||
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
|
||||
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.10.0"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8",
|
||||
"sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==6.2.1"
|
||||
},
|
||||
"toml": {
|
||||
"hashes": [
|
||||
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
|
||||
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.2"
|
||||
},
|
||||
"typed-ast": {
|
||||
"hashes": [
|
||||
"sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1",
|
||||
"sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d",
|
||||
"sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6",
|
||||
"sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd",
|
||||
"sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37",
|
||||
"sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151",
|
||||
"sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07",
|
||||
"sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440",
|
||||
"sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70",
|
||||
"sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496",
|
||||
"sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea",
|
||||
"sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400",
|
||||
"sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc",
|
||||
"sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606",
|
||||
"sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc",
|
||||
"sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581",
|
||||
"sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412",
|
||||
"sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a",
|
||||
"sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2",
|
||||
"sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787",
|
||||
"sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f",
|
||||
"sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937",
|
||||
"sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64",
|
||||
"sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487",
|
||||
"sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b",
|
||||
"sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41",
|
||||
"sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a",
|
||||
"sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3",
|
||||
"sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166",
|
||||
"sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"
|
||||
],
|
||||
"version": "==1.4.2"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918",
|
||||
"sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c",
|
||||
"sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"
|
||||
],
|
||||
"version": "==3.7.4.3"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
import sys
|
||||
import typing
|
||||
|
||||
|
||||
def main() -> int:
|
||||
inputs = [int(s) for s in sys.stdin.read().split()]
|
||||
for i, j in _find_2020_pairs(inputs):
|
||||
print(f"pair: {i} * {j} == {i * j}")
|
||||
|
||||
for i, j, k in _find_2020_triplets(inputs):
|
||||
print(f"triplet: {i} * {j} * {k} == {i * j * k}")
|
||||
return 0
|
||||
|
||||
|
||||
def _find_2020_pairs(
|
||||
inputs: typing.List[int],
|
||||
) -> typing.Generator[typing.Tuple[int, ...], None, None]:
|
||||
found = []
|
||||
|
||||
for i, in0 in enumerate(inputs):
|
||||
for j, in1 in enumerate(inputs):
|
||||
if i == j:
|
||||
continue
|
||||
if in0 + in1 == 2020:
|
||||
to_yield = tuple(sorted([in0, in1]))
|
||||
if to_yield not in found:
|
||||
yield to_yield
|
||||
found.append(to_yield)
|
||||
|
||||
|
||||
def _find_2020_triplets(
|
||||
inputs: typing.List[int],
|
||||
) -> typing.Generator[typing.Tuple[int, ...], None, None]:
|
||||
found = []
|
||||
|
||||
for i, in0 in enumerate(inputs):
|
||||
for j, in1 in enumerate(inputs):
|
||||
for k, in2 in enumerate(inputs):
|
||||
if i == j or i == k:
|
||||
continue
|
||||
if in0 + in1 + in2 == 2020:
|
||||
to_yield = tuple(sorted([in0, in1, in2]))
|
||||
if to_yield not in found:
|
||||
yield to_yield
|
||||
found.append(to_yield)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -1,53 +0,0 @@
|
||||
import sys
|
||||
|
||||
|
||||
def main() -> int:
|
||||
n_valid = 0
|
||||
total = 0
|
||||
|
||||
for pol_pas in [PolicyPassword.fromstring(s) for s in sys.stdin.readlines(False)]:
|
||||
if pol_pas.is_valid():
|
||||
n_valid += 1
|
||||
total += 1
|
||||
|
||||
print(f"{n_valid}/{total} valid")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
class Policy:
|
||||
def __init__(self, char: str, pos1: int, pos2: int):
|
||||
self.char = char
|
||||
self.pos1 = pos1
|
||||
self.pos2 = pos2
|
||||
|
||||
@classmethod
|
||||
def fromstring(cls, input_string) -> "Policy":
|
||||
parts = [s.strip() for s in input_string.split(" ")][:2]
|
||||
pos = [int(s) for s in parts[0].split("-")][:2]
|
||||
return cls(parts[1], pos[0], pos[1])
|
||||
|
||||
def is_valid(self, password: str) -> bool:
|
||||
matches = 0
|
||||
for pos in (self.pos1 - 1, self.pos2 - 1):
|
||||
if password[pos] == self.char:
|
||||
matches += 1
|
||||
return matches == 1
|
||||
|
||||
|
||||
class PolicyPassword:
|
||||
def __init__(self, policy: "Policy", password: str):
|
||||
self.policy = policy
|
||||
self.password = password
|
||||
|
||||
@classmethod
|
||||
def fromstring(cls, input_string: str) -> "PolicyPassword":
|
||||
parts = [s.strip() for s in input_string.split(":")][:2]
|
||||
return cls(Policy.fromstring(parts[0]), parts[1])
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
return self.policy.is_valid(self.password)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -1,52 +0,0 @@
|
||||
import functools
|
||||
import sys
|
||||
import typing
|
||||
|
||||
|
||||
class Loc(typing.NamedTuple):
|
||||
x: int
|
||||
y: int
|
||||
|
||||
|
||||
def main() -> int:
|
||||
forest_frame = [list(line.strip()) for line in sys.stdin.readlines()]
|
||||
frame_width = len(forest_frame[0])
|
||||
frame_height = len(forest_frame)
|
||||
|
||||
all_trees_encountered = []
|
||||
|
||||
for slope in [
|
||||
Loc(x=1, y=1),
|
||||
Loc(x=3, y=1),
|
||||
Loc(x=5, y=1),
|
||||
Loc(x=7, y=1),
|
||||
Loc(x=1, y=2),
|
||||
]:
|
||||
loc = Loc(x=0, y=0)
|
||||
|
||||
trees_encountered = 0
|
||||
|
||||
while loc.y <= (frame_height - 1):
|
||||
at_loc = forest_frame[loc.y][loc.x]
|
||||
if at_loc == "#":
|
||||
trees_encountered += 1
|
||||
|
||||
next_x = (loc.x + slope.x) % frame_width
|
||||
next_y = loc.y + slope.y
|
||||
next_loc = Loc(x=next_x, y=next_y)
|
||||
loc = next_loc
|
||||
|
||||
print(
|
||||
f"(slope right={slope.x} down={slope.y}) trees encountered: {trees_encountered}"
|
||||
)
|
||||
all_trees_encountered.append(trees_encountered)
|
||||
|
||||
trees_encountered_product = functools.reduce(
|
||||
lambda x, y: x * y, all_trees_encountered
|
||||
)
|
||||
print(f"trees encountered product: {trees_encountered_product}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -1,115 +0,0 @@
|
||||
import sys
|
||||
import typing
|
||||
|
||||
|
||||
def main() -> int:
|
||||
checked = []
|
||||
for passport in _read_passports(sys.stdin):
|
||||
if passport is None:
|
||||
checked.append(False)
|
||||
continue
|
||||
checked.append(passport.is_valid())
|
||||
|
||||
print(f"total={len(checked)} valid={checked.count(True)}")
|
||||
return 0
|
||||
|
||||
|
||||
NoneString = typing.Optional[str]
|
||||
|
||||
VALID_EYE_COLORS = ("amb", "blu", "brn", "gry", "grn", "hzl", "oth")
|
||||
|
||||
|
||||
class Passport:
|
||||
byr: NoneString = None
|
||||
cid: NoneString = None
|
||||
ecl: NoneString = None
|
||||
eyr: NoneString = None
|
||||
hcl: NoneString = None
|
||||
hgt: NoneString = None
|
||||
iyr: NoneString = None
|
||||
pid: NoneString = None
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
return (
|
||||
self._is_year_in_range(self.byr, range(1920, 2003))
|
||||
and self._is_year_in_range(self.iyr, range(2010, 2021))
|
||||
and self._is_year_in_range(self.eyr, range(2020, 2031))
|
||||
and self._has_valid_height()
|
||||
and self._has_valid_hair_color()
|
||||
and self.ecl in VALID_EYE_COLORS
|
||||
and self._has_valid_passport_id()
|
||||
)
|
||||
|
||||
def _has_valid_height(self) -> bool:
|
||||
if self.hgt is None:
|
||||
return False
|
||||
|
||||
height_value = 0
|
||||
|
||||
height_value_string = self.hgt.replace("cm", "").replace("in", "")
|
||||
if not height_value_string.isdigit():
|
||||
return False
|
||||
|
||||
height = int(height_value_string)
|
||||
|
||||
if self.hgt.endswith("cm") and height in range(150, 194):
|
||||
return True
|
||||
elif self.hgt.endswith("in") and height in range(59, 77):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _has_valid_hair_color(self) -> bool:
|
||||
if self.hcl is None:
|
||||
return False
|
||||
|
||||
if not self.hcl.startswith("#"):
|
||||
return False
|
||||
|
||||
hair_value = self.hcl.replace("#", "")
|
||||
if len(hair_value) != 6:
|
||||
return False
|
||||
|
||||
try:
|
||||
_ = int(hair_value, 16)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def _has_valid_passport_id(self) -> bool:
|
||||
return (
|
||||
self.pid is not None
|
||||
and len(self.pid) == 9
|
||||
and all([s.isdigit() for s in list(self.pid)])
|
||||
)
|
||||
|
||||
def _is_year_in_range(self, value: NoneString, yr_range: range) -> bool:
|
||||
if value is None:
|
||||
return False
|
||||
if len(value) != 4:
|
||||
return False
|
||||
if not value.isdigit():
|
||||
return False
|
||||
return int(value) in yr_range
|
||||
|
||||
|
||||
def _read_passports(
|
||||
instream: typing.TextIO,
|
||||
) -> typing.Generator[typing.Optional[Passport], None, None]:
|
||||
cur = Passport()
|
||||
|
||||
for i, line in enumerate(instream):
|
||||
line = line.strip()
|
||||
if line == "":
|
||||
yield cur
|
||||
cur = Passport()
|
||||
|
||||
for pair in line.split():
|
||||
attr, value = pair.split(":", 1)
|
||||
setattr(cur, attr, value)
|
||||
|
||||
yield cur
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -1,77 +0,0 @@
|
||||
import sys
|
||||
import typing
|
||||
|
||||
|
||||
def main() -> int:
|
||||
highest_seat = 0
|
||||
|
||||
taken_seats = set()
|
||||
|
||||
for line in sys.stdin:
|
||||
line = line.strip()
|
||||
if line == "":
|
||||
continue
|
||||
|
||||
seat = _locate_seat(line)
|
||||
|
||||
if seat.number > highest_seat:
|
||||
highest_seat = seat.number
|
||||
|
||||
taken_seats.add(seat.number)
|
||||
|
||||
print(f"bp={line} row={seat.row} column={seat.col} seat={seat.number}")
|
||||
|
||||
seat_number: typing.Optional[int] = None
|
||||
n_found = 0
|
||||
|
||||
for candidate_seat in range(0, (127 * 8) + 1):
|
||||
if candidate_seat in taken_seats:
|
||||
continue
|
||||
|
||||
if (candidate_seat - 1) in taken_seats and (candidate_seat + 1) in taken_seats:
|
||||
seat_number = candidate_seat
|
||||
n_found += 1
|
||||
|
||||
print(f"highest_seat={highest_seat} seat_number={seat_number} n_found={n_found}")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
class Seat:
|
||||
row: int
|
||||
column: int
|
||||
|
||||
def __init__(self, row: int = 0, col: int = 0):
|
||||
self.row = row
|
||||
self.col = col
|
||||
|
||||
@property
|
||||
def number(self) -> int:
|
||||
return (self.row * 8) + self.col
|
||||
|
||||
|
||||
def _locate_seat(bp: str) -> Seat:
|
||||
rows = list(range(0, 128))
|
||||
cols = list(range(0, 8))
|
||||
|
||||
row_part = list(bp[:7])
|
||||
col_part = list(bp[7:])
|
||||
|
||||
return Seat(
|
||||
row=_bisect(rows, [{"F": 0, "B": 1}[s] for s in row_part]),
|
||||
col=_bisect(cols, [{"L": 0, "R": 1}[s] for s in col_part]),
|
||||
)
|
||||
|
||||
|
||||
def _bisect(initial_selection: typing.List[int], bisections: typing.List[int]) -> int:
|
||||
selection = initial_selection[:]
|
||||
|
||||
for bisection in bisections:
|
||||
halfway = int(len(selection) / 2)
|
||||
selection = [selection[:halfway], selection[halfway:]][bisection]
|
||||
|
||||
return selection[0]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -1,3 +0,0 @@
|
||||
BFFFBBFRRR
|
||||
FFFBBBFRRR
|
||||
BBFFBBFRLL
|
@ -1,3 +0,0 @@
|
||||
bp=BFFFBBFRRR row=70 column=7 seat=567
|
||||
bp=FFFBBBFRRR row=14 column=7 seat=119
|
||||
bp=BBFFBBFRLL row=102 column=4 seat=820
|
@ -1,21 +0,0 @@
|
||||
import sys
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from solution import main
|
||||
|
||||
|
||||
HERE = Path(__file__).absolute().parent
|
||||
|
||||
|
||||
def test_solution(capsys):
|
||||
with (HERE / "test-input").open() as infile:
|
||||
sys.stdin = infile
|
||||
main()
|
||||
|
||||
expected_output = (HERE / "test-output").read_text().splitlines()
|
||||
assert expected_output == [
|
||||
l for l in capsys.readouterr().out.splitlines() if l.startswith("counts_sum=")
|
||||
]
|
@ -1,42 +0,0 @@
|
||||
import sys
|
||||
import typing
|
||||
|
||||
|
||||
def main() -> int:
|
||||
counts_sum = sum([c for c in _iter_group_counts(sys.stdin)])
|
||||
print(f"counts_sum={counts_sum}")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def _iter_group_counts(instream: typing.TextIO) -> typing.Generator[int, None, None]:
|
||||
for i, group in enumerate(_iter_groups(instream)):
|
||||
answers = set(list(group[0]))
|
||||
print(f"i={i} initial={answers}")
|
||||
|
||||
for answers_text in group[1:]:
|
||||
to_add = set(list(answers_text))
|
||||
answers = answers.intersection(set(list(answers_text)))
|
||||
print(f"i={i} added={to_add} result={answers}")
|
||||
|
||||
print(f"i={i} final={answers} n={len(answers)}")
|
||||
yield len(answers)
|
||||
|
||||
|
||||
def _iter_groups(instream):
|
||||
cur_group = []
|
||||
|
||||
for line in instream:
|
||||
line = line.strip()
|
||||
if line == "":
|
||||
yield cur_group
|
||||
cur_group = []
|
||||
continue
|
||||
|
||||
cur_group.append(line)
|
||||
|
||||
yield cur_group
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -1,15 +0,0 @@
|
||||
abc
|
||||
|
||||
a
|
||||
b
|
||||
c
|
||||
|
||||
ab
|
||||
ac
|
||||
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
|
||||
b
|
@ -1 +0,0 @@
|
||||
counts_sum=6
|
@ -1,21 +0,0 @@
|
||||
import sys
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from solution import main
|
||||
|
||||
|
||||
HERE = Path(__file__).absolute().parent
|
||||
|
||||
|
||||
def test_solution(capsys):
|
||||
with (HERE / "test-input").open() as infile:
|
||||
sys.stdin = infile
|
||||
main()
|
||||
|
||||
expected_output = (HERE / "test-output").read_text().splitlines()
|
||||
assert expected_output == [
|
||||
l for l in capsys.readouterr().out.splitlines() if l.startswith("counts_sum")
|
||||
]
|
Loading…
Reference in New Issue
Block a user