Skip to content

Commit

Permalink
day19: tests
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-ong committed Dec 25, 2023
1 parent b7ba44c commit ce9c587
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 19 deletions.
42 changes: 24 additions & 18 deletions day19/day19.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
"""
parsing classes section
"""
INPUT = "day19/input.txt"
INPUT_SMALL = "day19/input-small.txt"


def get_input() -> tuple[list[Workflow], list[Part]]:
def get_input(path: str) -> tuple[list[Workflow], list[Part]]:
workflows: list[Workflow] = []
parts: list[Part] = []
with open("day19/input.txt", encoding="utf8") as file:
with open(path, encoding="utf8") as file:
for line in file:
if len(line.strip()) == 0:
break
Expand All @@ -24,20 +26,20 @@ def get_input() -> tuple[list[Workflow], list[Part]]:
return (workflows, parts)


def process_part(workflows: dict[str, Workflow], part: Part) -> bool:
def process_part(workflows: dict[str, Workflow], part: Part) -> int:
# ends are `A` and R
# start is `in`
workflow = workflows["in"]
while True:
workflow_name = workflow.process_part(part)
if workflow_name == "A":
return True
return part.rating
if workflow_name == "R":
return False
return 0
workflow = workflows[workflow_name]


def solve_part2(workflows: dict[str, Workflow]) -> None:
def solve_part2(workflows: dict[str, Workflow]) -> int:
min_xmas = Part(1, 1, 1, 1)
max_xmas = Part(4001, 4001, 4001, 4001)
part_range = PartRange(min_xmas, max_xmas)
Expand All @@ -57,23 +59,27 @@ def solve_part2(workflows: dict[str, Workflow]) -> None:
result += item.part_range.size()
elif item.destination != "R":
to_process.put(item)
print(result)
return result


def main() -> None:
# combined
workflows, parts = get_input()
def part1(workflows: list[Workflow], parts: list[Part]) -> int:
workflows_mapping: dict[str, Workflow] = {wf.name: wf for wf in workflows}
total = sum(process_part(workflows_mapping, part) for part in parts)

return total

# part 1
total = 0
for part in parts:
if process_part(workflows_mapping, part):
total += part.rating
print(total)

# part 2
solve_part2(workflows_mapping)
def part2(workflows: list[Workflow]) -> int:
workflows_mapping: dict[str, Workflow] = {wf.name: wf for wf in workflows}
return solve_part2(workflows_mapping)


def main() -> None:
# combined
workflows, parts = get_input(INPUT)

print(part1(workflows, parts))
print(part2(workflows))


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion day19/lib/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def process_part_range(
return None, fail


@dataclass
@dataclass(eq=True)
class Workflow:
name: str
rules: list[Rule]
Expand Down
8 changes: 8 additions & 0 deletions day19/tests/test_day19.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from day19.day19 import INPUT_SMALL, get_input, part1, part2


def test_day19() -> None:
workflows, parts = get_input(INPUT_SMALL)

assert part1(workflows, parts) == 19114
assert part2(workflows) == 167409079868000
65 changes: 65 additions & 0 deletions day19/tests/test_parsers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""parsers"""
from day19.lib.classes import Comparator, Component, Condition, Part, Rule, Workflow
from day19.lib.parsers import (
parse_condition_string,
parse_part_string,
parse_rule_string,
parse_workflow_string,
)


def test_parse_part_string() -> None:
part: Part = parse_part_string("{x=787,m=2655,a=1222,s=2876}\n")
assert part == Part(787, 2655, 1222, 2876)

part = parse_part_string("{x=1,m=2,a=3,s=4}\n")
assert part == Part(1, 2, 3, 4)


def test_parse_workflow_string() -> None:
"""
returns a workflow from a string representation
`px{a<2006:qkq,m>2090:A,rfg}\n`
"""
workflow: Workflow = parse_workflow_string("px{a<2006:qkq,m>2090:A,rfg}\n")
rules = [
Rule("qkq", Condition(Component.A, Comparator.LessThan, 2006)),
Rule("A", Condition(Component.M, Comparator.GreaterThan, 2090)),
Rule("rfg", None),
]
workflow2 = Workflow("px", rules)
assert workflow == workflow2 # confirm that workflow.eq works
assert workflow.name == workflow2.name
assert workflow.rules[0] == workflow2.rules[0]
assert workflow.rules[1] == workflow2.rules[1]
assert workflow.rules[2] == workflow2.rules[2]
assert workflow.rules == workflow2.rules


def test_parse_rule_string() -> None:
"""
`a<2006:qkq` or `rfg`
"""
rule: Rule = parse_rule_string("a<2006:qkq")
rule2: Rule = Rule("qkq", Condition(Component.A, Comparator.LessThan, 2006))

assert rule.destination == rule2.destination
assert rule.condition == rule2.condition
assert rule == rule2

rule = parse_rule_string("rfg")
rule2 = Rule("rfg")

assert rule.destination == rule2.destination
assert rule.condition == rule2.condition
assert rule == rule2


def test_parse_condition_string() -> None:
"""a<2006"""
condition: Condition = parse_condition_string("a<2006")
condition2: Condition = Condition(Component.A, Comparator.LessThan, 2006)
assert condition == condition2
assert condition.component == condition2.component
assert condition.sign == condition2.sign
assert condition.value == condition2.value

0 comments on commit ce9c587

Please sign in to comment.