Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b5dbf5b
Create module for `Stack` class
katzuv Dec 10, 2022
2cbd6b0
Create `Stack` class
katzuv Dec 10, 2022
6dcc6f0
Create `Stack` class constructor
katzuv Dec 10, 2022
c21a7c3
Add method that removes crates from a `Stack` and returns them
katzuv Dec 10, 2022
ae52255
Add `property` of the top crate to `Stack`
katzuv Dec 10, 2022
9e676ad
Add method that adds crates to a `Stack`
katzuv Dec 13, 2022
342a108
Create solution file for part 1
katzuv Dec 13, 2022
b68cebd
Add constants module
katzuv Dec 13, 2022
3a62548
Add constant for the input parts splitter
katzuv Dec 13, 2022
81b3612
Add constant for the number of the line containing the amount of stacks
katzuv Dec 13, 2022
994b638
Add constant for the index of the stacks amount in the line
katzuv Dec 13, 2022
4917b66
Add constant for the index of the first crate in the line
katzuv Dec 13, 2022
3924e37
Add constant for the step between crates in a line
katzuv Dec 13, 2022
1e590a3
Add `__str__` magic method to `Stack`
katzuv Dec 13, 2022
6e59ac1
Create module for input parsing functions
katzuv Dec 13, 2022
216abe8
Add a function that parses starting stacks from the input text
katzuv Dec 13, 2022
0bfbe02
Create module for `Step` class
katzuv Dec 13, 2022
6cebd33
Create `Step` class
katzuv Dec 13, 2022
14b54da
Add "amount" field to `Step` class
katzuv Dec 13, 2022
8b26dd5
Add "source" field to `Step` class
katzuv Dec 13, 2022
35c6dc8
Add "destination" field to `Step` class
katzuv Dec 13, 2022
c792ca8
Add a function that parses procedure steps from the input text
katzuv Dec 13, 2022
fde19c5
Add function that executes a crates transfer step
katzuv Dec 13, 2022
988800d
Add function that returns the tops of stacks after transfers finish
katzuv Dec 13, 2022
b049594
Move crates order reversing from crates "add" method to "remove" method
katzuv Dec 13, 2022
88e7a5c
Create solution file for part 2
katzuv Dec 13, 2022
5b91508
Add function that executes a crates transfer step
katzuv Dec 13, 2022
9fb4ddc
Add function that returns the tops of stacks after transfers finish
katzuv Dec 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions puzzles/solutions/2022/d05/consts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
INPUT_PARTS_SPLITTER = "\n\n"
AMOUNT_LINE_NUMBER = -1
AMOUNT_INDEX_IN_LINE = -2
FIRST_CRATE_INDEX = 1
STEP_BETWEEN_CRATES = 4
52 changes: 52 additions & 0 deletions puzzles/solutions/2022/d05/input_parsing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import re

import consts
from stack import Stack
from step import Step


def get_starting_stacks(stacks_input: str) -> tuple[Stack]:
"""
:param stacks_input: stacks part of the puzzle input
:return: tuple of `Stack`s parsed from the input
"""
lines = stacks_input.splitlines()
stacks_amount = int(lines[consts.AMOUNT_LINE_NUMBER][consts.AMOUNT_INDEX_IN_LINE])

stacks = tuple(Stack(()) for _ in range(stacks_amount))
stacks_lines = reversed(
lines[: consts.AMOUNT_LINE_NUMBER] # Start building stacks from the bottom up.
)

for line in stacks_lines:
for index, stack_number in zip(
range(
consts.FIRST_CRATE_INDEX,
consts.FIRST_CRATE_INDEX + consts.STEP_BETWEEN_CRATES * stacks_amount,
consts.STEP_BETWEEN_CRATES,
),
range(stacks_amount),
):
character = line[index]
if (
character.isalpha()
): # Crates are represented by letters. The other character is a space,
# which means that no crate is in this line on that stack.
stacks[stack_number].add_crates(character)

return stacks


def get_procedure_steps(procedure_input: str) -> tuple[Step]:
"""
:param procedure_input: procedure steps part of the puzzle input
:return: tuple of `Step`s parsed from the input
"""
steps = []
for line in procedure_input.splitlines():
values = re.match(
r"move (?P<amount>\d+) from (?P<src>\d+) to (?P<dst>\d+)", line
).groupdict()
values = {field: int(value) for field, value in values.items()}
steps.append(Step(**values))
return tuple(steps)
34 changes: 34 additions & 0 deletions puzzles/solutions/2022/d05/p1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import sys
from typing import Sequence

import consts
import input_parsing
from stack import Stack
from step import Step


def execute_transfer_step(stacks: Sequence[Stack], step: Step):
"""
Process a transferring of crates between stacks.
:param stacks: sequence of `Stack`s
:param step: step to execute
"""
crates = stacks[step.src - 1].remove_crates(step.amount)
stacks[step.dst - 1].add_crates(crates)


def get_answer(input_text: str):
"""Return the crates that end up on top of each stack after the rearrangement procedure completes."""
starting_stacks, steps = input_text.split(consts.INPUT_PARTS_SPLITTER)
stacks = input_parsing.get_starting_stacks(starting_stacks)
steps = input_parsing.get_procedure_steps(steps)
for step in steps:
execute_transfer_step(stacks, step)
return "".join(stack.top for stack in stacks)


if __name__ == "__main__":
try:
print(get_answer(sys.argv[1]))
except IndexError:
pass # Don't crash if no input was passed through command line arguments.
39 changes: 39 additions & 0 deletions puzzles/solutions/2022/d05/p2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import sys
from typing import Sequence

import consts
import input_parsing
from stack import Stack
from step import Step


def execute_transfer_step(stacks: Sequence[Stack], step: Step):
"""
Process a transferring of crates between stacks.
:param stacks: sequence of `Stack`s
:param step: step to execute
"""
crates = stacks[step.src - 1].remove_crates(step.amount)
stacks[step.dst - 1].add_crates(
reversed(tuple(crates))
) # Reverse the crates because now they now retain their order when transferred.


def get_answer(input_text: str):
"""
Return the crates that end up on top of each stack after the rearrangement procedure completes,
now when crates retain their order.
"""
starting_stacks, steps = input_text.split(consts.INPUT_PARTS_SPLITTER)
stacks = input_parsing.get_starting_stacks(starting_stacks)
steps = input_parsing.get_procedure_steps(steps)
for step in steps:
execute_transfer_step(stacks, step)
return "".join(stack.top for stack in stacks)


if __name__ == "__main__":
try:
print(get_answer(sys.argv[1]))
except IndexError:
pass # Don't crash if no input was passed through command line arguments.
42 changes: 42 additions & 0 deletions puzzles/solutions/2022/d05/stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from typing import Sequence, Iterable


class Stack:
"""Class representing a stack of crates."""

def __init__(self, initial_crates: Sequence[str]):
"""
Instantiate a stack.
:param initial_crates: initial crates in the stack
"""
self._crates = list(initial_crates)

def __str__(self) -> str:
"""
:return: a string representation of the crates in the stack
"""
return " ".join(self._crates)

def remove_crates(self, amount: int) -> Iterable[str]:
"""
Remove crates from the top of the stack and return a list of them.
:param amount: amount of crates to remove
:return: removed crates
"""
removed = self._crates[-amount:]
self._crates = self._crates[:-amount]
return reversed(removed)

def add_crates(self, crates: Iterable[str]):
"""
Add crates to the stack.
:param crates: crates to add to the stack
"""
self._crates.extend(crates)

@property
def top(self) -> str:
"""
:return: crate at the top of the stack
"""
return self._crates[-1]
10 changes: 10 additions & 0 deletions puzzles/solutions/2022/d05/step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import dataclasses


@dataclasses.dataclass
class Step:
"""A step of moving crates between stacks."""

amount: int
src: int
dst: int