コード例 #1
0
def getCompletedPuzzleCleanedImage(imagePuzzle: Puzzle) -> Grid:
    # Removing puzzle piece borders
    cleanedPiecesData = {}
    for p in imagePuzzle.pieces.values():
        cleanedPiecesData[p.id] = [[
            p.grid.data[y][x] for x in range(1, p.grid.width - 1)
        ] for y in range(1, p.grid.height - 1)]

    # Each pieces have same dimensions
    piecesWidth = Grid(next(iter(cleanedPiecesData.values()))).width
    piecesHeight = Grid(next(iter(cleanedPiecesData.values()))).height

    # Puzzle dimensions
    puzzleWidth = max([p.x
                       for p in imagePuzzle.matchedPiecePositions.keys()]) + 1
    puzzleHeight = max([p.y
                        for p in imagePuzzle.matchedPiecePositions.keys()]) + 1

    # Joining pieces together
    fullImage = [[SYMBOL.SEA.value for x in range(piecesWidth * puzzleWidth)]
                 for y in range(piecesHeight * puzzleHeight)]
    for py in range(puzzleHeight):
        for px in range(puzzleWidth):
            puzzlePieceId = imagePuzzle.matchedPiecePositions[Coordinate(
                px, py)].id
            for y in range(piecesHeight):
                for x in range(piecesWidth):
                    fullImage[py * piecesHeight +
                              y][px * piecesWidth +
                                 x] = cleanedPiecesData[puzzlePieceId][y][x]

    return Grid(fullImage)
コード例 #2
0
def remapSeatsNeighbors(grid: Grid, seatsGrid: dict) -> None:
    directions = [Coordinate(*d) for d in getAdjacentDirections(dimensions=2)]

    # Map seat grid neighbors with new rules
    for p, seat in seatsGrid.items():
        visibleAdjacentSeats = []

        for d in directions:
            position = Coordinate(p.x, p.y)
            while utils.inbetween(0, position.x, grid.width-1) and utils.inbetween(0, position.y, grid.height-1):
                position = Coordinate(position.x + d.x, position.y + d.y)
                if position in seatsGrid:
                    visibleAdjacentSeats.append(seatsGrid[position])
                    break

        seat.adjacentSeats = visibleAdjacentSeats
コード例 #3
0
def mapSeats(grid: Grid) -> dict:
    seatsGrid = {}

    # Map seat grid
    for y in range(0, grid.height):
        for x in range(0, grid.width):
            s = SYMBOL(grid.data[y][x])
            if s != SYMBOL.FLOOR:
                p = Coordinate(x, y)
                seatsGrid[p] = Seat(p, s)

    return seatsGrid
コード例 #4
0
def moveShipWithWaypoint(instructions: list, shipPosition: Coordinate, wayPointPosition: Coordinate) -> (Coordinate, Coordinate, ACTION):
    currentShipPosition = Coordinate(shipPosition.x, shipPosition.y)
    currentWaypointPosition = Coordinate(wayPointPosition.x, wayPointPosition.y)

    for action, value in instructions:
        if action in DIRECTION:
            # Move waypoint only
            d = DIRECTION[action]
            currentWaypointPosition = Coordinate(currentWaypointPosition.x + value * d.x, currentWaypointPosition.y + value * d.y)
        elif action in ROTATION:
            # Move waypoint only
            for _ in range(getNbTurns(value)):
                currentWaypointPosition = rotatePosition(currentWaypointPosition, action)
        elif action == ACTION.FORWARD:
            # Move ship towards waypoint (movement amplified by waypoint)
            currentShipPosition = Coordinate(currentShipPosition.x + value * currentWaypointPosition.x, currentShipPosition.y + value * currentWaypointPosition.y)
        else:
            print(action)
            raise Exception('Unknown action !')

    return (currentShipPosition, currentWaypointPosition, direction)
コード例 #5
0
def moveShip(instructions: list, startingPosition: Coordinate, startingDirection: ACTION) -> (Coordinate, ACTION):
    position = Coordinate(startingPosition.x, startingPosition.y)
    direction = startingDirection

    for action, value in instructions:
        if action in DIRECTION:
            # Move ship position, but keep direction the same
            d = DIRECTION[action]
            position = Coordinate(position.x + value * d.x, position.y + value * d.y)
        elif action in ROTATION:
            # Rotate ship
            for _ in range(getNbTurns(value)):
                direction = ROTATION[action][direction]
        elif action == ACTION.FORWARD:
            # Move ship position in direction
            d = DIRECTION[direction]
            position = Coordinate(position.x + value * d.x, position.y + value * d.y)
        else:
            print(action)
            raise Exception('Unknown action !')

    return (position, direction)
コード例 #6
0
    def printCompletedPuzzlePieceIDs(self) -> None:
        xMax = max([p.x for p in self.matchedPiecePositions.keys()])
        yMax = max([p.y for p in self.matchedPiecePositions.keys()])

        separator = '---'.join(['-' * 4 for i in range(xMax + 1)]) + '------'

        print('Completed puzzle:')
        print(separator)
        for y in range(yMax + 1):
            print(
                '| ', '   '.join([
                    self.matchedPiecePositions[Coordinate(x, y)].id
                    for x in range(xMax + 1)
                ]), ' |')
        print(separator, '\n')
コード例 #7
0
def findSeaMonsters(image: Grid, seaMonster: Grid) -> int:
    # Keep only positions to match
    seaMonsterMatchingPositions = set()
    for y in range(seaMonster.height):
        for x in range(seaMonster.width):
            if seaMonster.data[y][x] == SYMBOL.HAZARD.value:
                seaMonsterMatchingPositions.add(Coordinate(x, y))

    # Find all sea monsters
    seaMonstersCount = 0

    y = 0
    while y + seaMonster.height < image.height:
        x = 0
        while x + seaMonster.width < image.width:
            # Check if sea monster in current view
            seaMonsterVisible = all(
                image.data[y + p.y][x + p.x] == SYMBOL.HAZARD.value
                for p in seaMonsterMatchingPositions)

            if seaMonsterVisible is True:
                # Increasing sea monsters count
                seaMonstersCount += 1

                # Marking sea monster on image
                for p in seaMonsterMatchingPositions:
                    image.data[y + p.y][x + p.x] = SYMBOL.SEA_MONSTER.value

                # Skipping to next possible non overlapping sea monster
                x += seaMonster.width
            else:
                x += 1

        if seaMonsterVisible is True:
            # Skipping to next possible non overlapping sea monster
            y += seaMonster.height
        else:
            y += 1

    return seaMonstersCount
コード例 #8
0
def rotatePosition(p: Coordinate, r: ROTATION):
    if r == ACTION.RIGHT: # Clockwise
        return Coordinate(p.y, -p.x)
    else: # Counterclockwise
        return Coordinate(-p.y, p.x)
コード例 #9
0
###########################
# region COMMON
# endregion COMMON
###########################

class ACTION(Enum):
    NORTH = 'N'
    SOUTH = 'S'
    EAST = 'E'
    WEST = 'W'
    LEFT = 'L'
    RIGHT = 'R'
    FORWARD = 'F'

DIRECTION = {
    ACTION.NORTH: Coordinate(0, 1),
    ACTION.SOUTH: Coordinate(0, -1),
    ACTION.EAST: Coordinate(1, 0),
    ACTION.WEST: Coordinate(-1, 0)
}

ROTATION = {
    ACTION.LEFT: {
        ACTION.NORTH: ACTION.WEST,
        ACTION.SOUTH: ACTION.EAST,
        ACTION.EAST: ACTION.NORTH,
        ACTION.WEST: ACTION.SOUTH
    },
    ACTION.RIGHT: {
        ACTION.NORTH: ACTION.EAST,
        ACTION.SOUTH: ACTION.WEST,
コード例 #10
0
    def solve(self, log=False) -> None:
        # Warning: currrent solving solution only works if each puzzle piece borders match with a single other puzzle piece !
        if set([
                p for id, p in self.pieces.items()
                if p.getNbMatchingPieces() > 4
        ]):
            raise Exception(
                'Solution cannot work for puzzle with non unique matching piece borders !'
            )

        if len(self.matchedPiecePositions.keys()) > 0:
            return  # Already solved

        print('Solving puzzle...\n------------------')

        # 1) Starting with any corner in fixed orientation
        startingCorner = self._findStartingCorner()

        # 2) Adding all pieces clockwise in a spiral from starting corner
        matchedPieces = set()
        currentPiece = startingCorner
        currentPosition = Coordinate(0, 0)
        currentDirection = BORDER_TYPE.RIGHT
        while True:
            # Adding current piece to solved puzzle
            matchedPieces.add(currentPiece)
            self.matchedPiecePositions[currentPosition] = currentPiece

            # Finding next piece
            nextPiece = next(iter(
                currentPiece.matchingPiece[currentDirection]))
            if nextPiece in matchedPieces:
                if len(matchedPieces) == self.nbPieces:
                    break  # Done, all pieces are matched

                # Changing direction inward
                currentDirection = NEXT_CLOCKWISE_DIRECTION[currentDirection]
                nextPiece = next(
                    iter(currentPiece.matchingPiece[currentDirection]))

            if log:
                print('(%s, %s) currentPiece %s --> %s --> %s' %
                      (currentPosition.x, currentPosition.y, currentPiece.id,
                       currentDirection.name, nextPiece.id))

            # Flipping / rotating next piece until adjacent border matched
            oppositeDirection = OPPOSITE_DIRECTION[currentDirection]
            currentBorderToMatch = currentPiece.getBorder(
                currentDirection).data
            currentFlippedBorderToMatch = currentBorderToMatch[::-1]
            while currentBorderToMatch != nextPiece.getBorder(
                    oppositeDirection).data:
                if currentFlippedBorderToMatch == nextPiece.getBorder(
                        oppositeDirection).data:
                    if BORDER_TYPE_ORIENTATION[
                            currentDirection] == ORIENTATION.HORIZONTAL:
                        nextPiece.flipY()
                    else:
                        nextPiece.flipX()
                else:
                    nextPiece.rotate()

            # Moving to next piece
            currentPiece = nextPiece
            currentPosition = ADJACENT_POSITION[currentDirection](
                currentPosition)
            if nextPiece in self.cornerPieces:
                # Changing direction at border (so we don't leave puzzle area)
                currentDirection = NEXT_CLOCKWISE_DIRECTION[currentDirection]

        print('------------------\n')
コード例 #11
0
    BORDER_TYPE.LEFT: BORDER_TYPE.RIGHT,
    BORDER_TYPE.RIGHT: BORDER_TYPE.LEFT
}

NEXT_CLOCKWISE_DIRECTION = {
    # Current direction: next clockwise direction
    BORDER_TYPE.TOP: BORDER_TYPE.RIGHT,
    BORDER_TYPE.RIGHT: BORDER_TYPE.BOTTOM,
    BORDER_TYPE.BOTTOM: BORDER_TYPE.LEFT,
    BORDER_TYPE.LEFT: BORDER_TYPE.TOP,
}

ADJACENT_POSITION = {
    # Current direction: next position
    BORDER_TYPE.TOP:
    lambda p: Coordinate(p.x, p.y - 1),
    BORDER_TYPE.BOTTOM:
    lambda p: Coordinate(p.x, p.y + 1),
    BORDER_TYPE.LEFT:
    lambda p: Coordinate(p.x - 1, p.y),
    BORDER_TYPE.RIGHT:
    lambda p: Coordinate(p.x + 1, p.y)
}


class PuzzlePieceBorder():
    def __init__(self, type: BORDER_TYPE, data: list):
        self.type = type
        self.data = data

    def __str__(self):