예제 #1
0
 def Movement(self):
     if self == Direction.NORTH:
         return linalg.Point(row=-1, col=0)
     elif self == Direction.EAST:
         return linalg.Point(row=0, col=1)
     elif self == Direction.SOUTH:
         return linalg.Point(row=1, col=0)
     elif self == Direction.WEST:
         return linalg.Point(row=0, col=-1)
     else:
         raise ValueError(f"Invalid direction {self}")
 def test_Part2(self):
     state = problem12.WaypointShip()
     state = state.ApplyInputs(EXAMPLE_1.splitlines())
     self.assertEqual(
         state,
         problem12.WaypointShip(
             position=linalg.Point(row=72, col=214),
             waypoint=linalg.Point(row=10, col=4),
         ),
     )
     self.assertEqual(
         abs(state.position.row) + abs(state.position.col), 286)
예제 #3
0
 def __str__(self):
     output = ""
     for row in range(0, self.height + 1):
         for col in range(0, self.width + 1):
             output += self.data.get(linalg.Point(row=row, col=col), " ")
         output += "\n"
     return output
예제 #4
0
class WaypointShip(object):
    waypoint: linalg.Point = linalg.Point(row=-1, col=10)
    position: linalg.Point = linalg.Point(0, 0)

    def TranslateWaypoint(self, pt: linalg.Point) -> WaypointShip:
        return WaypointShip(
            waypoint=self.waypoint + pt,
            position=self.position,
        )

    def Command(self, c: str) -> WaypointShip:
        match = INPUT_REGEX.match(c.strip())
        if not match:
            raise ValueError("Could not parse")
        command = match.group("command")
        value = int(match.group("value"))
        if command == "N":
            return self.TranslateWaypoint(Direction.NORTH.Movement() * value)
        elif command == "E":
            return self.TranslateWaypoint(Direction.EAST.Movement() * value)
        elif command == "S":
            return self.TranslateWaypoint(Direction.SOUTH.Movement() * value)
        elif command == "W":
            return self.TranslateWaypoint(Direction.WEST.Movement() * value)
        elif command == "L":
            return WaypointShip(
                position=self.position,
                waypoint=self.waypoint.RotateClockwise(-value),
            )
        elif command == "R":
            return WaypointShip(
                position=self.position,
                waypoint=self.waypoint.RotateClockwise(value),
            )
        elif command == "F":
            return WaypointShip(
                waypoint=self.waypoint,
                position=self.position + self.waypoint * value,
            )
        else:
            raise ValueError(f"Invalid command: {command}, {value}")

    def ApplyInputs(self, inputs: Iterable[str]) -> WaypointShip:
        state = self
        for line in inputs:
            state = state.Command(line.strip())
        return state
예제 #5
0
def CountTrees(hill: grid.Grid, slope: linalg.Slope) -> int:
    trees_hit = 0
    pt = linalg.Point(0, 0)
    while pt.row < hill.rows:
        if hill.Get(pt) == grid.Tile.TREE:
            trees_hit += 1
        pt += slope
    return trees_hit
 def test_Part1(self):
     state = problem12.Ship()
     state = state.ApplyInputs(EXAMPLE_1.splitlines())
     self.assertEqual(
         state,
         problem12.Ship(
             position=linalg.Point(row=8, col=17),
             direction=problem12.Direction.SOUTH,
         ),
     )
     self.assertEqual(abs(state.position.row) + abs(state.position.col), 25)
예제 #7
0
 def FromString(
     cls,
     inp: str,
     bounds: Mapping[Tuple[Axis, Direction], BoundaryBehavior] = {},
 ) -> Grid:
     data = dict()
     for row_idx, line in enumerate(inp.splitlines()):
         for col_idx, char in enumerate(line):
             pt = linalg.Point(row=row_idx, col=col_idx)
             data[pt] = Tile.FromChar(char)
     return cls(tiles=data, boundary_behaviors=bounds)
예제 #8
0
def Neighbors(pt: linalg.Point) -> Iterator[linalg.Point]:
    yield pt + linalg.Point(row=0, col=1)
    yield pt + linalg.Point(row=0, col=-1)
    yield pt + linalg.Point(row=1, col=0)
    yield pt + linalg.Point(row=1, col=-1)
    yield pt + linalg.Point(row=-1, col=1)
    yield pt + linalg.Point(row=-1, col=0)
예제 #9
0
class Ship(object):
    direction: Direction = Direction.EAST
    position: linalg.Point = linalg.Point(0, 0)

    def Translate(self, pt: linalg.Point) -> Ship:
        return Ship(
            direction=self.direction,
            position=self.position + pt,
        )

    def Command(self, c: str) -> Ship:
        match = INPUT_REGEX.match(c.strip())
        if not match:
            raise ValueError("Could not parse")
        command = match.group("command")
        value = int(match.group("value"))
        if command == "N":
            return self.Translate(Direction.NORTH.Movement() * value)
        elif command == "E":
            return self.Translate(Direction.EAST.Movement() * value)
        elif command == "S":
            return self.Translate(Direction.SOUTH.Movement() * value)
        elif command == "W":
            return self.Translate(Direction.WEST.Movement() * value)
        elif command == "L":
            state = self
            for _ in range(0, value, 90):
                state = Ship(
                    direction=state.direction.Left(),
                    position=state.position,
                )
            return state
        elif command == "R":
            state = self
            for _ in range(0, value, 90):
                state = Ship(
                    direction=state.direction.Right(),
                    position=state.position,
                )
            return state
        elif command == "F":
            return self.Translate(self.direction.Movement() * value)
        raise ValueError(f"Invalid command: {command}, {value}")

    def ApplyInputs(self, inputs: Iterable[str]) -> Ship:
        state = self
        for line in inputs:
            state = state.Command(line)
        return state
예제 #10
0
def Movement(instructions: str) -> linalg.Point:
    match = _MOVE_RE.fullmatch(instructions.strip())
    position = linalg.Point(0, 0)
    for move in match.captures("move"):
        if move == "e":
            position += linalg.Point(row=0, col=1)
        elif move == "w":
            position += linalg.Point(row=0, col=-1)
        elif move == "se":
            position += linalg.Point(row=1, col=0)
        elif move == "sw":
            position += linalg.Point(row=1, col=-1)
        elif move == "ne":
            position += linalg.Point(row=-1, col=1)
        elif move == "nw":
            position += linalg.Point(row=-1, col=0)
    return position
예제 #11
0
                return nextgrid
            else:
                g = nextgrid

    def Visible(self, pt: linalg.Point,
                direction: linalg.Point) -> Optional[str]:
        next_point = pt
        while True:
            next_point += direction
            next_cell = self.data.get(next_point)
            if next_cell != ".":
                return next_cell


_DIRECTIONS = [
    linalg.Point(0, 1),
    linalg.Point(0, -1),
    linalg.Point(1, 1),
    linalg.Point(1, 0),
    linalg.Point(1, -1),
    linalg.Point(-1, 1),
    linalg.Point(-1, 0),
    linalg.Point(-1, -1),
]


def ParseInput(inp: str) -> Grid:
    result = {}
    for row_idx, row in enumerate(inp.splitlines()):
        for col_idx, char in enumerate(row.strip()):
            result[linalg.Point(row=row_idx, col=col_idx)] = char
예제 #12
0
 def test_multiplication(self):
     self.assertEqual(linalg.Point(1, 2) * 2, linalg.Point(2, 4))
     self.assertEqual(linalg.Point(1, 2) * -2, linalg.Point(-2, -4))
예제 #13
0
 def test_subtraction(self):
     self.assertEqual(
         linalg.Point(1, 2) - linalg.Point(3, 4), linalg.Point(-2, -2))
     self.assertEqual(
         linalg.Point(5, 10) - linalg.Point(3, 2), linalg.Point(2, 8))
예제 #14
0
 def Get(self, coord: linalg.Point) -> Tile:
     normalized = linalg.Point(
         row=self._Normalize(Axis.ROW, coord.row),
         col=self._Normalize(Axis.COL, coord.col),
     )
     return self.tiles[normalized]
예제 #15
0
 def test_Rotate(self):
     self.assertEqual(
         linalg.Point(1, 2).RotateClockwise(90), linalg.Point(2, -1))
     self.assertEqual(
         linalg.Point(1, 2).RotateClockwise(-90), linalg.Point(-2, 1))
예제 #16
0
 def test_CanAddToPoint(self):
     self.assertEqual(
         linalg.Point(row=1, col=2) + linalg.Slope(over=10, down=30),
         linalg.Point(row=31, col=12),
     )
예제 #17
0
 def test_addition(self):
     self.assertEqual(
         linalg.Point(1, 2) + linalg.Point(3, 4), linalg.Point(4, 6))
예제 #18
0
def ParseInput(inp: str) -> Grid:
    result = {}
    for row_idx, row in enumerate(inp.splitlines()):
        for col_idx, char in enumerate(row.strip()):
            result[linalg.Point(row=row_idx, col=col_idx)] = char
    return Grid(result)