Solving the 15-puzzle in Swift: A Look at Algorithms and Speed
Algorithms and optimization can sound daunting, but are a really interesting programming problem. In this talk, we'll be looking at writing a solver for a puzzle, improving it along the way by making it more performant.
1...moves { let adjacentToEmpty = adjacentPositions(to: position(for: .empty)) precondition( adjacentToEmpty.count >= 2, "Should always have at least two positions adjacent to empty" ) // Remove the previously moved tile, so we do not move a tile // back-and-forth. That would be rather pointless. let adjacentWithoutPrevious = adjacentToEmpty .filter { $0 != position(for: _previouslyShuffledTile) } let randomAdjacent = adjacentWithoutPrevious.randomElement()! let randomTile = tile(at: randomAdjacent) move(tile: randomTile) _previouslyShuffledTile = randomTile } } 49 — @basthomas
1...moves { let adjacentToEmpty = adjacentPositions(to: position(for: .empty)) precondition( adjacentToEmpty.count >= 2, "Should always have at least two positions adjacent to empty" ) // Remove the previously moved tile, so we do not move a tile // back-and-forth. That would be rather pointless. let adjacentWithoutPrevious = adjacentToEmpty .filter { $0 != position(for: _previouslyShuffledTile) } let randomAdjacent = adjacentWithoutPrevious.randomElement()! let randomTile = tile(at: randomAdjacent) move(tile: randomTile) _previouslyShuffledTile = randomTile } } 49 — @basthomas
1...moves { let adjacentToEmpty = adjacentPositions(to: position(for: .empty)) precondition( adjacentToEmpty.count >= 2, "Should always have at least two positions adjacent to empty" ) // Remove the previously moved tile, so we do not move a tile // back-and-forth. That would be rather pointless. let adjacentWithoutPrevious = adjacentToEmpty .filter { $0 != position(for: _previouslyShuffledTile) } let randomAdjacent = adjacentWithoutPrevious.randomElement()! let randomTile = tile(at: randomAdjacent) move(tile: randomTile) _previouslyShuffledTile = randomTile } } 49 — @basthomas
1...moves { let adjacentToEmpty = adjacentPositions(to: position(for: .empty)) precondition( adjacentToEmpty.count >= 2, "Should always have at least two positions adjacent to empty" ) // Remove the previously moved tile, so we do not move a tile // back-and-forth. That would be rather pointless. let adjacentWithoutPrevious = adjacentToEmpty .filter { $0 != position(for: _previouslyShuffledTile) } let randomAdjacent = adjacentWithoutPrevious.randomElement()! let randomTile = tile(at: randomAdjacent) move(tile: randomTile) _previouslyShuffledTile = randomTile } } 49 — @basthomas
1...moves { let adjacentToEmpty = adjacentPositions(to: position(for: .empty)) precondition( adjacentToEmpty.count >= 2, "Should always have at least two positions adjacent to empty" ) // Remove the previously moved tile, so we do not move a tile // back-and-forth. That would be rather pointless. let adjacentWithoutPrevious = adjacentToEmpty .filter { $0 != position(for: _previouslyShuffledTile) } let randomAdjacent = adjacentWithoutPrevious.randomElement()! let randomTile = tile(at: randomAdjacent) move(tile: randomTile) _previouslyShuffledTile = randomTile } } 49 — @basthomas
amountOfValidPositionsList.max() precondition( largestAmountOfValidPositions != nil, "No maximum valid positions found in \(boardOptions)" ) 55 — @basthomas
bestStepIndex = boardOptions.firstIndex { $0.validPositions == nextBestSteps.first } precondition(bestStepIndex != nil, "Should always have an index for the next best step") let bestOption = boardOptions[bestStepIndex!] self.currentBoard = bestOption.board _previousNextTile = bestOption.moved 56 — @basthomas