DEV Community

Cover image for Let's Make a Hacker_Man Game using React!
christine
christine

Posted on • Edited on

Let's Make a Hacker_Man Game using React!

When I think of the game hangman, I get strangely uncomfortable at the thought that as kids we played a game where we hang a person! I don't want to hang a person, even if it is just a game, and also, I'm a grown up now, and I would rather play a game where I hack people (thank you Watch Dogs). That's why I decided to do my own little twist of the classic hangman game, called Hacker_Man. ๐Ÿ˜Ž๐Ÿ‘พ

Hacker Man Preview

With Hacker_Man, you need to guess the correct string of word(s) in order to unlock the secret key - yes it works, and you will be shown some sensitive data upon success! If you don't succeed, instead of hanging someone, you get locked out of the "system" and told to try again.

Today, I am going to show you how to also make this game, and you of course can opt to make it a little bit more traditional if you want, or you can join me at the hackerspace and make something cool.

Now, I would like to suggest that you code along with me because it is best to type in the code yourself than to copy it because it builds up that muscle memory. Making little games like this is great for developing your own skills, so when you're ready, let's get started - future React Master! ๐Ÿ˜‰

All explanations for the project are in the code itself via the comments, but if you get stuck or want to view my CSS file, use the images or custom fonts, check it out on my GitHub Repository.

Want to test it before you make it? Test it out on Heroku.

Pre Setup - Installing Packages

To complete this project exactly as (or however you want) I did, you will need to do the following in your preferred command line:

npx create-react-app hacker-man
npm i bootstrap react-page-loading --save
cd hacker-man
Enter fullscreen mode Exit fullscreen mode

Step 1 - Initial Setup

Now its time to head over to your code editor. Set up your index.js to contain the bootstrap modules that we will need for this project.

Also, don't forget to head over to my GitHub and copy the CSS and images needed for the project, you should alter this to make it your own later on.

//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import 'bootstrap/dist/css/bootstrap.min.css';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();
Enter fullscreen mode Exit fullscreen mode

This being said, you can edit your App.js file as follows and create a the following folders and files in your ./src folder:

components (folder)

  • Game.js (components file)
  • Randomize.js (components file)

layout (folder)

  • Header.js (layout file)
  • Loader.js (layout file)
  • Glitch.js (layout file)
//App.js
import Game from './components/Game';
import Header from './layout/Header';
import Glitch from './layout/Glitch';
import Loader from './layout/Loader';

//main component
function App() {
  return (
    <div className="App">
      <div className="row">
        {/* Header */}
        <Loader />   
       </div>
      <div className="row">
        {/* Header */}
        <Header />   
       </div>
      <div className="row">
        {/* Game */}
        <Game />
      <div className="background">
        {/* Glitch Effect */}
        <Glitch />
      </div>
    </div>
  </div> 
  );
}

//exports for use in other files
export default App;
Enter fullscreen mode Exit fullscreen mode

Step 2 - Layout Files

For this section, we will create our least-important files for the project just to get it out of the way. These are just UI components, so it's best to do it first (at least for me) so that we can focus on the functionality of our project more.

The Header.js file will contain our App Title, so make the following changes:

//Header.js
import React from "react";

//out main title which will have glitch effect
const Header = () => {
  return (
    <div className="row">
        <div className="title">
            <h1>Hacker_Man</h1>
        </div>
    </div>
  );
};

//exports for use in other files
export default Header;
Enter fullscreen mode Exit fullscreen mode

And then make the following changes to your Glitch.js which will add our background glitch effect and save:

//Glitch.js

import React from "react";

//will add a glitch effect background by animating over the image
const Glitch = () => {
  return (
    <div className="glitch-demo">
    <div className="glitch">
      <div className="glitch__img"></div>
      <div className="glitch__img"></div>
      <div className="glitch__img"></div>     
      <div className="glitch__img"></div> 
      <div className="glitch__img"></div>
    </div>
  </div>
  );
};

//exports for use in other files
export default Glitch;
Enter fullscreen mode Exit fullscreen mode

Then lastly, add the following changes to your Loader.js file which will add our app loader when we load or reload the game.

//Loader.js
import React, { Component } from 'react'
import Page from 'react-page-loading'

//page loader
export default class Loader extends Component {
    render() {    
      return (
        <div>
          <Page loader={"bubble-spin"} color={"rgb(179, 2, 2)"}size={20}>
          </Page>
        </div>
      )
    }
  }
Enter fullscreen mode Exit fullscreen mode

Step 3 - Word Randomizer

For this game, we will create an array in our Randomize.js component file that will contain the words to be guessed by our players. Now, you can change these words to match your game and style.

//Randomize.js
//array of hidden codes
var hidden_codes = [
    "phishing",
    "pharming",
    "ransomware",
    "spoofing",
    "adware",
    "zerodaythreat",
    "brute",
    "kioptrix", 
    "payload",
    "rootkit",
    "cloaking",
    "metasploit",
    "javascript",
    "java",
    "react",
    "mongodb"
]

//this will randomize our codes to display at random
function randomWord() {
  return hidden_codes[Math.floor(Math.random() * hidden_codes.length)]
}

// - Math.random generates a value between 0 and 1, that isnโ€™t a whole number, and also isnโ€™t 1. 
// - To get a singular word, for example "react", we multiply this by our array.length. (Math.random() * hidden_codes.length)
// - To get it to return a whole number value, we apply Math.floor, which rounds down to the nearest whole number(array value). (Math.floor(Math.random() * hidden_codes.length))
// - Together, this function randomWord() will return only one value from our array.

//exports for use in other files
export { randomWord }
Enter fullscreen mode Exit fullscreen mode

Step 4 - Hacker_Man Game

Now we will import our Randomize.js file to our Game.js file and add functionality to our game so that we can generate a random word after each page load/round reset, add the option to generate a new code, display a success/fail message upon each round end, and also generate image parts to load upon each incorrect guess.

//Game.js
import React, { Component } from 'react';
//imports our randomizer and images needed for each step
import { randomWord } from './Randomize';
import step0 from "../css/images/0.png";
import step1 from "../css/images/1.png";
import step2 from "../css/images/2.png";
import step3 from "../css/images/3.png";
import step4 from "../css/images/4.png";
import step5 from "../css/images/5.png";
import step6 from "../css/images/6.png";

//creates a state component that will compose our hangman (hackerman) game
class Hangman extends Component {

  //sets the default state for the incorrect steps + images to render
  static defaultProps = {
    maxWrong: 6,
    images: [step0, step1, step2, step3, step4, step5, step6]
  }

  //the initital state after each round/reload which will return mistakes to 0 and generate a new word
  constructor(props) {
    super(props);
    this.state = {
      mistake: 0,
      guessed: new Set([]),
      answer: randomWord()
    }
  }

  //will add the correct letter upon correct guess, or blur out letter upon incorrect guess
  handleGuess = e => {
    let letter = e.target.value;
    this.setState(st => ({
      guessed: st.guessed.add(letter),
      mistake: st.mistake + (st.answer.includes(letter) ? 0 : 1)
    }));
  }

  //will display the letter guessed when word matches
  guessedWord() {
    return this.state.answer.split("").map(letter => (this.state.guessed.has(letter) ? letter : " _ "));
  }

  //will generate the "keyboard" buttons for user input during guessing
  generateButtons() {
    return "abcdefghijklmnopqrstuvwxyz#@$&".split("").map(letter => (
      <button
        className='btn btn-lg btn-primary m-2'
        key={letter}
        value={letter}
        onClick={this.handleGuess}
        disabled={this.state.guessed.has(letter)}
      >{letter}
      </button>
    ));
  }

  //reset Button that will reset the number of mistakes and generate a new word
  resetButton = () => {
    this.setState({
      mistake: 0,
      guessed: new Set([]),
      answer: randomWord()
    });
  }

  //will display winner/loser results
  render() {
    //game over upon max number of incorrect guesses(6)
    const gameOver = this.state.mistake >= this.props.maxWrong;
    //game won upon correct guess
    const isWinner = this.guessedWord().join("") === this.state.answer;      

    //will generate the outcome
    let gameStat = this.generateButtons();

    //if the player guessed the right word, give access to secret key
    if (isWinner) {
       gameStat = <div>
         <p  className="success">Wow!</p>
        <a rel="noopener noreferrer" href="https://youtu.be/dQw4w9WgXcQ" target="_blank"> UNLOCK REWARD: <i className="fas fa-key"></i></a>
      </div>
    }

    //if the player guessed incorrectly, try again
    if (gameOver) {
      gameStat = <p className="fail">Try Again!</p>
    }

    //returns the display of the actual game
    return (
      <div className="Hangman container-fluid">
        {/* this will display the current number of incorrect guesses per round */}
       <div className="row">
          <div className="text-center text-error">Error 403 Received: {this.state.mistake} out of {this.props.maxWrong}
          </div>
        </div>
        {/* container for decorative image */}
        <div className="binary col-12">
        </div>
        {/* instructions and entry form */}
        <div className="row">
          <div className="text-center col-12">
            <p className="text-desc">Crack The Secret Code To Gain System Access:</p>
            {/* if the letter/word is correct, enter it/show success message, else show failure message and answer */}
            <p className="text-center text-answer col-md-4">{!gameOver ? this.guessedWord() : this.state.answer}</p>
          </div>
        </div>
        {/* image that will render more steps upon mistakes */}
        <div className="row text-center ">
        <div className="col-lg-6 col-12">
              <div className="col-lg-3 images-top"></div>
              <img src={this.props.images[this.state.mistake]} alt=""/>  
          </div>

        <div className="col-lg-6 col-12">
          {/* keyboard input */}
          <div className="text-result">
                <p className="terminal">  
                  <span className="terminal-text">root@youcanthackme:</span>
                  {gameStat}
                </p>
            </div>
            {/* reset button */}
                <button className='btn btn-info' onClick={this.resetButton}> CODE RESET </button>
                <div className="col-lg-3 images"></div>
              </div>
            </div>
      </div>
    )
  }
}
//exports for use in other files
export default Hangman;
Enter fullscreen mode Exit fullscreen mode

Step 5 - Tying It Together

After you've completed the Game.js and Randomize.js files, it is now time to test our project. I do this frequently during project creation to test my code, but during this tutorials we only test it at the end - however you want to do it, is up to you! Run your project with the following command:

npm start
Enter fullscreen mode Exit fullscreen mode

You should get something similar to this:
image
image
image
image
Good job for reaching the end of this tutorial. When you're done, deploy it to GitHub and take a break. Did you learn something new? Did you guess the right word and took a look at the secret key? What would you do different? Let me know in the comments down below!๐Ÿ˜Š

Top comments (2)

Collapse
 
siddharthshyniben profile image
Info Comment hidden by post author - thread only accessible via permalink
Siddharth

Hey! In the glitch component (and other places) you seem to be using class= instead of className=. Now I'm no React user, but I think that's wrong. I've even opened a GitHub issue. Cheers!

Collapse
 
christinec_dev profile image
christine

Oof, my bad (it's that late night coding ๐Ÿ˜‚). Fixed it, thanks!

Some comments have been hidden by the post's author - find out more