Preface
“Slide & Solve” is a fast-paced sliding puzzle game where players race to recreate predefined patterns as quickly as possible. With simple rules, it's perfect for family game nights or casual gatherings with friends. Since you don't have any friends around, I made a digital prototype in Phaser, so you can compete against a computer. Just click on the tiles of your puzzle to move them.
Digital Prototype
Details
System Design
General Info
First, let's look at how the game would play out in real life. It's made for one or more players, with no real limit on how many can join in. It's great for ages 6 and up and usually takes about 15-30 minutes to play.
Game Components
Here's what would come with the game if it were published. It's also a good idea to have a pen, some paper, and a die handy:
Setup
Each player takes a sliding puzzle and places it face down, while the pattern card deck is shuffled and placed face down in the center of the table. Every player starts with 3 lives.
Gameplay
- The starting player draws the top pattern card from the deck and places it face up in the center for everyone to see.
- All players count down together: “3, 2, 1, Go!” and pick up their sliding puzzles.
- Players slide their puzzle tiles simultaneously to match the pattern on the card.
- The first player to finish places their puzzle on top of the card, stopping the round.
- Check the pattern: if it's correct the player earns 1 point, if it's incorrect they lose 1 life.
- Set the puzzles face down for the next round.
Winning the Game
A player is eliminated when they run out of lives, and the game continues with the remaining players. The match can end in two ways: if a player earns 3 points, they win, or if only one player is left standing, that player is declared the winner.
Single Player Mode
Draw a pattern card and set a personal time limit to recreate the design. Try to solve as many cards as you can within the time limit, or challenge yourself against the computer in the prototype above.
Cards
As you may have noticed, the deck contains both white and black cards. The white cards are the standard template cards. You draw one, and your goal is to replicate the pattern as quickly as possible. The black cards, on the other hand, are event cards mentioned earlier. Each one introduces a unique twist to keep the game exciting. Below, you can see the different event cards I've created so far:
The Digital Prototype
Lastly, let me walk you through how the digital prototype works. I used Phaser to create a 3x3 sliding puzzle game where players compete against an AI opponent. The code sets up the game board, generates solvable puzzles, and lets both the player and the AI move tiles to match a given template. I've also included score tracking to include the competitive aspect.
Code Snippets
create() {
// Initialize the computer's solution path array
this.computerSolutionPath = [];
// Generate a puzzle configuration for the template
const templateConfiguration = this.generateSolvableConfiguration();
// Generate puzzle configuration for both player and computer
const puzzleConfiguration = this.generateSolvableConfiguration();
// Create the template puzzle in the top-center
this.createTemplatePuzzle(templateConfiguration);
// Create the player and computer puzzles in the bottom area
this.createPuzzles(puzzleConfiguration);
// Create the score text
this.createScores();
// Start the computer move timer
this.time.addEvent({
delay: Phaser.Math.Between(800, 1400), // time between computer moves
callback: this.computerMove,
callbackScope: this,
loop: true,
});
}
computerMove() {
if (!this.computerTiles || !this.computerTiles.tilesMap) {
console.error("Error: computerTiles or tilesMap is undefined");
return;
}
// If we have no solution path, or it's empty, generate one
if (!this.computerSolutionPath || this.computerSolutionPath.length === 0) {
const currentState = Array.from(this.computerTiles.tilesMap.values()).map(
(tile) => (tile ? tile.tileInfo.value : null)
);
const goalState = Array.from(this.templateTiles.tilesMap.values()).map(
(tile) => (tile ? tile.tileInfo.value : null)
);
this.computerSolutionPath = solvePuzzle(currentState, goalState);
}
// === Introduce a random move chance ===
// e.g. 30% chance to do a random legal move instead of following the solution
const RANDOM_MOVE_CHANCE = 0.3;
const doRandomMove = Math.random() < RANDOM_MOVE_CHANCE;
if (doRandomMove) {
this.randomComputerMove();
return;
}
// If we still have moves in the solution path, do one
if (this.computerSolutionPath && this.computerSolutionPath.length > 0) {
const currentState = Array.from(this.computerTiles.tilesMap.values()).map(
(tile) => (tile ? tile.tileInfo.value : null)
);
const nextState = this.computerSolutionPath.shift();
// Find how the empty tile changed from currentState to nextState
const emptyIndex = currentState.indexOf(null);
const nextEmptyIndex = nextState.indexOf(null);
const dx = (nextEmptyIndex % gridSize) - (emptyIndex % gridSize);
const dy =
Math.floor(nextEmptyIndex / gridSize) -
Math.floor(emptyIndex / gridSize);
// The tile we need to move is the one that ended up in the old empty position
const tileX = (emptyIndex % gridSize) + dx;
const tileY = Math.floor(emptyIndex / gridSize) + dy;
const tileKey = `${tileX},${tileY}`;
const tileToMove = this.computerTiles.tilesMap.get(tileKey);
if (tileToMove) {
this.moveTile(tileToMove, this.computerTiles, "computer");
}
}
}
checkMatch(type) {
let puzzle;
if (type === "player") {
puzzle = this.playerTiles;
} else if (type === "computer") {
puzzle = this.computerTiles;
} else {
return;
}
if (!puzzle) {
console.error("No puzzle data found for type:", type);
return;
}
const isMatching = this.isMatchingTemplate(puzzle);
if (isMatching) {
if (type === "player") {
playerScore++;
this.playerScoreText.setText(`Player: ${playerScore}`);
} else if (type === "computer") {
computerScore++;
this.computerScoreText.setText(`Computer: ${computerScore}`);
// Clear out the computer's old solution path so it can recalc later
this.computerSolutionPath = [];
}
// Re-randomize ONLY the template puzzle so that a new round can start
const newConfiguration = this.generateSolvableConfiguration();
this.applyStateToTiles(this.templateTiles, newConfiguration);
}
}
And that's it! I've been prototyping physical games for a while, but this was the first one where I really felt like I had to take it further. Playing it with friends and family has been a lot of fun so far, especially since you can feel yourself improving with each round. The event cards also add tons of variety and lead to some hilarious interactions. I created the digital prototype as a challenge to learn a new framework for web games: Phaser. It's incredibly powerful, and I'm definitely going to use it for more advanced projects in the future. But if you'd like to try the physical version of the game and own a 3D printer, feel free to reach out. I'd be happy to share the .stl files with you!