This app generates a solveable 15-puzzle based off of a randomly selected image retrieved from the Unsplash API
The meat and potatoes of this project is a React app, based off of Create React App (CRA).
In an effort to obscure the api key, a Node server is being used as a proxy for the api call to Unsplash.
The following libraries are also used:
React-redux was purposely not used as it was deemed more appropriate to let each <Puzzle>
manage its own internal state.
These instructions will get you a copy of the project up and running on your local machine, and you can get your puzzling on.
You will need a valid Unsplash API key. You can obtain that here.
Clone the repo and navigate into the folder:
cd 15puzzle
Install the dependencies for the project by running the following command from the project's root:
npm install
This will install all necessary dependencies.
Create a .env
file in /server
and place your api key in there. Your folder structure should look like this:
/15puzzle
/client
...
/server
...
.env
# .env
UNSPLASH_API_KEY=<YOUR_API_KEY_HERE>
At this point, you should be ready to run!
From the project root, go ahead and start the app:
npm start
From the project root, go ahead and run
npm run build-client
You should now have an updated /build
folder in /15puzzle/client/
From the project root, go ahead and run the following command which creates a client build, starts the back-end server and runs the client build.
npm run start-prod
When a <GameBoard>
component mounts, we
- ping the Unsplash api for a random image
- persist the url of the received image in
<GameBoard>
's state - generate an array (to be used as tiles) containing integers [0...15] in a randomized order
- we repeat this step until a set of tiles is generated that leads to a solveable game
When a <GameBoard>
component render()
s, we
- We
.map()
throughpieces
and create a<GamePiece>
for each element-
Each
<GamePiece>
is provided the coordinates (x,y) of where that piece will be positioned in the 4 x 4 square once the puzzle is solved-
When a
<GamePiece>
is clicked, its location relative to the blacked out square is calculated and if it borders the blacked out square, the two are swapped. -
We keep track of the number of inversions on the board at any given time. An inversion is defined as any instance whereby a tile's current index is lower than its index in th solved puzzle.
-
When there are no inversions present, and the blacked out square is in the bottom-right corner of the board...the puzzle is solved!
-
-
Indices can be thought of as:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
- Each
<GamePiece>
is provided (via props) the url of the retrieved image from Unsplash. - Every
<GamePiece>
uses this image as itsbackground-image
- The
background-position
property is used to adjust the visible portion of the background image based on the<GamePiece>
's position on the 4x4 grid when the puzzle is solved
- Create tests to ensure custom components such as
<GamePiece>
render what they are supposed to, when they are supposed to - Incorporate e2e tests in the browser to test overall user experience
- Review current performance and number of times components are rendering unnecessarily, use
shouldComponentUpdate()
where helpful
- Look into cleaning up the main
App.js
file - perhaps create additional utilities fo "position" and "index" related functions
- Barry Ross
- Setting up React/Node Project - Very helpful tutorial regarding using node as a proxy in conjuction with React
- 3 Ways to Solve a 15 Puzzle
- How to Check if a 15 Puzzle is Solveable
- JavaScript 15 Puzzle
- Building a 15 Puzzle in Defold
- Fisher-Yates Shuffle