Designing and building a hangman game is a common task in a programming job interviews. Here we’ll explain our own implementation for it using ReactJS: Create a new project -> Do some component design -> Add business logic -> polish our CSS -> Jumping around happy.
TLDR; The code for this project can be found in my github here, would appreciate your stars and comments 🙂
Credit to cover image goes to: skeeze from Pixabay
This is a followup post that provides a tutorial to build React+ES6+Webpack hangman game implementation. This answers the “hangman job interview question for front end developers“.
Our goal is to code the hangman game, and more than that – to do it in the way I really work in real life.
At the end it should look like this:
There are many tutorials and guides out there. What makes this one unique is that I don’t know how the project will look like when it will be ready. Also, it will be developed in the order of things that I do when working on a REAL project – by iterations, not perfect from the start.
My development order will be something like:
- have a boiler plate project running with React and Webpack
- Do the component design
- Code the components with some basic CSS
- Add business logic
- Test a few cases
- Polish the CSS again
- Add a deployment pipeline.
- Go over the code to make it prettier, making sure it’s human readable
- Sleep
First step – clone a boiler plate project
Google offered a few options for an empty es6+webpack+react boiler plate project. I chose this one, running this command on my terminal:
This project have already defined a development server for us that runs on port 8080, transpiles es6 into regular java script, and can handle ReactJS. More than enough for me at the moment.
git clone https://github.com/HashemKhalifa/webpack-react-boilerplate.gitAfter cloning complete, install the project’s dependencies using:
npm iand then start the server
npm startnow open the browser and go to localhost:8080, you should see the nice hello world looking at you.
Need some help? you are welcomed to leave a comment, or visit the github page of the project at https://github.com/HashemKhalifa/webpack-react-boilerplate.
The Hello World code we just checked out (cloned) has 2 interesting parts. App.jsx file – the root of the project.
HelloWorld folder, with index.jsx in it.
App.jsx imports HelloWorld component and uses it.
As a first step, I’ll play with the HelloWorld component, to see I can work with this project, and to make sure the hot module replacement plugin works and my changes are displayed instantly,
I tried to change the color of the text to red, did it in file called: hello-world.css
works, let’s start designing our own app.
The hard part is behind us, now – to work!
Component design for ReactJS hangman game
This is what I have in mind for now:
A. Some kind of wrapper component (maybe the App.jsx itself?).
B. Inside the wrapper a component with the current state of the game, that holds:
(1) The hanged man drawing according to the number of errors.
(2) A component that holds the word with gaps.
And another component inside the wrapper, that handles the user input, validation, the submit button, etc.
In a drawing, perhaps clearer:
This design is not perfect, but it will do for now. Note to self – forget about CSS for now.
First make it work, then make it pretty.
@RanEilam, my first guru
When coding these component, I prefer to start from the container/wrapper, and then make the components inside of it. It makes you also think what kind of data each of the components need, and what should it do.
For example, the Letter component obviously needs to get the letter to show as an input, but what happens when the user didn’t reveal that letter yet? In that case we would want to keep the space (width) for it, but not to show it. A show=true prop will do the trick.
For me, the project structure has a big significance in making my mind cleared about what I need to do. So I copied the HelloWorld component from the original repo, and created these component. For now – the don’t do anything, perhaps even don’t compile. doesn’t matter.
This is the project structure we have at the moment, each component has it’s own JSX file, and own CSS file imported from the JSX file.
Connecting the components together is now our goal.
- App.JSX should render the game status and user interaction.
- Game-status.jsx should render the painted status and the word display
- word-display.jsx should render the letters
- user-interaction.jsx should show an input field and a button
After connecting them, and fixing all the broken imports, it still looks ugly. For example, the game-wrapper.jsx component code looks like this:
See stuff on the browser for the first time
As said, it looks like a mess.. a bit of CSS to make it better, not perfect.
I’ll start by adding some standard rules to the game-wrapper’s CSS (game-wrapper.css), first one will be
box-sizing: border-box;
What is box sizing? here
Now, to make it look OK, we’ll make each component return a static HTML snippet, a text maybe. The Letter.jsx component will return the letter L, the painted status will return the text “5 Errors”, and the user interaction component will return a button and the text “Enter a letter”.
This is what we got:
One last thing to make it a bit easier to style, is to replace the “5 Errors” with an actual image. I painted one in MSPaint, and converted to base 64 using this service, so I could use it. You can make the painted-status component return an img tag containing this image.
And it will show this image
First round of CSS
Our goal now is to make the screen look better, not to polish yet.
To do so, I’ll focus on each component giving it very basic CSS attributes, starting from the game wrapper.
Because I would like to use flex box for components alignment, I’ll define the game-wrapper to contain flex box elements. And some padding from the top of the screen.
.game-wrapper {
box-sizing: border-box;
display: flex;
flex-direction: column;
padding-top: 20px;
}
Each of the game-wrapper’s children will get a flex: XXX; rule as well. I think a 5 to 1 ratio makes sense between the status and the input parts, so I added:
.game-status{
flex: 5;
display: flex;
flex-direction: column;
}
.user-interaction {
display:flex;
flex-direction: row;
justify-content: space-between;
padding-top: 40px;
font-size:30px;
flex: 1;
}
Actually, I added display: flex; rule to all parent components.
The flex-direction: column; rule makes them paint the child elements from top to bottom, instead of the default left to right.
To make the app in the center of the screen we used the margin: 0 auto; method. There are other ways to do it as well.
Also, added some style to the Letter.jsx component, so it will look a bit better, copied style from here
Now it looks like this:
Before diving into the logical part, let’s add some style to the input button and text at the bottom.
To make it work, we added an input field, with a limit of one character, and made it all centered with justify-content: space-between; rule.
Now it looks like this:
Thanks for reading so far. I thought it’s gonna be a single post, but it’s starting to be supppper long. So that’s it for now.
Where is the code?
You can find the code of this project right here in github: https://github.com/AsafShochet/hangman-es6-react-webpack
feel free to clone and comment.
Enters the business logic
A short wrap up: We are on a journey to develop a hangman game app using ReactJS. So for we created a project configured with webpack, es6 and React, created components and added basic CSS.
Now it’s time to add the logical part of the game, add deployment script that bundles the app and uploads it to Heroku, and tidy up the CSS.
Out app looks like this at the moment:
The source code for this tutorial can be found here: https://github.com/AsafShochet/hangman-es6-react-webpack
I imagine that in the end of the project there will be a server that saves the states, and chooses a word to guess according to the user’s preference. For now we will not use a server.
General approach to the business logic
Although this is a “React” JS application, and it is attempting to put the logic inside the components themselves, it’s considered a bad practice.
What we WILL want is to separate the business logic from the component. For that I’ll create a “services” layer. The services will be responsible for actions like:
- Choosing a word to guess for the user.
- Checking if the user guessed correctly or not.
- More things to come (?)
This means that I’m adding the /services folder under the src folder.
Choosing a random word
Our first service! In real life I assume this will be done in the server. But here, we’ll do it in the service itself.
I will make the method that generates a random word return a promise, so in the future it will be easy to replace it with a real XHR to the server.
This is what I came up with
Great, now we can generate the word. Let’s make the App call it on initialization and start passing it to the correct places in our app.
looks like this:
This is the phase that I check that the app “compiles” and I can still see things on the browser. Most of the times it doesn’t on the first try, so analyzing the errors helps.
Now, I’ll add a simple error counter to show the number of errors in the PaintedStatus component, and make the Letter component show the correct word. It will be ugly but will show the counter.
Showing image by number of errors
You know what, I think it’s time to add the images. Because we are using webpack, it’s a good idea to use the file-loader. You can read about it here: https://stackoverflow.com/questions/37671342/how-to-load-image-files-with-webpack-file-loader
Importing the files using this plugin makes the build process add the images to the /dist folder, so it will be there when deployed. you can see them under resources/images here: https://github.com/AsafShochet/hangman-es6-react-webpack
ReactJS hangman – Managing the game state
I thought about the state of the game and how can it be modified during the game. When the user submits a letter, it needs to be:
- validated (to see it is a letter)
- check that the letter is part of the word or not
- cause a change in the game status area of the screen – changing the word itself and the hangman drawing.
To do so, we’ll have a “state” inside the GameWrapper.jsx, that will be changed after submit. As it looks at the moment – the GameWrapper is going to be our smartest component.
You can read more about smart components here
The state should have all the data that will be changed during the game from the GameWrapper component itself or from its child components.
Every time the user submits a new letter, the GameWrapper will check if this letter exists or not in the word, and will update the errorCount accordingly. Also, if the user guessed all the letters before the game is over it will set the userWon parameter to be true.
These parameters will be passed to child components to show the right picture and right word with blanks.
Now, to make the submit button send the correct letter, I wrapped the input text and button in a simple <form> tag, and then added a callback to the onSubmit of the form. Like the first example here: https://reactjs.org/docs/forms.html
Adding the glue between the components makes us to test and see that all the data passes from place to place. That’s good.
For now – we have a working game, pretty nice!
Conclusion:
We started by creating a new project from an existing boiler plate repository we found on github. Then, designed the components to be used in the game and created very dumb components. Afterwards we added some CSS to make it look better, and only then we added the business logic to make it do what we want.
*** There are other ways to do it ***
And maybe I will choose a different way or approach next time.
Hope you enjoyed, please comment and tell what do you think 🙂