FORUM Menu

The Konami Code Challenge

by kirupa   |   filed under JavaScript Tricks

If you’ve ever played some old-school/classic video games published by the game company Konami, you may have entered (or heard of) the following sequence of button presses:

This sequence, when entered correctly in games like Contra, Castlevania, Metal Gear, and others, gives your character some pretty big advantages. These advantages might include extra lives, better starting weapons, additional content, and so on. To use video game language, this sequence of button presses is more commonly referred to as a cheat code since it changes the default game behavior to (usually) give you as the player an unfair advantage. This particular cheat code, given its infamousness, has a formal name. It is known as the Konami Code.

In this challenge, guess what you are going to do? You are going to add support for the Konami Code on a web page.

Onwards!

OMG! A JavaScript Book Written by Kirupa?!!

To kick your JavaScript skills into outer space, everything you see here and more (with all its casual clarity!) is available in both paperback and digital editions.

BUY ON AMAZON

Challenge Details

In your web page, when the up, up, down, down, left, right, left, right, b, a button/key sequence is entered correctly, you will display Cheat code activated! inside an alert dialog (window.alert). If an incorrect key is pressed at any point, the code resets and you have to start over from the beginning. The keys need to be pressed relatively quickly in succession. If the time between subsequent keypresses goes over 1 second, the code resets and you have to start over - similar to what you would do if you pressed an incorrect key.

To get started, create a new HTML document and add the following boilerplate content into it:

<!DOCTYPE html>
<html>

<head>
  <title>Konami Code!</title>

  <style>
    body {
      background-color: #C6D8D3;
      padding: 30px;
    }

    h1,
    p,
    a {
      font-family: sans-serif;
    }

    h1 {
      font-size: 76px;
      color: #5B6361;
    }

    p {
      font-size: 24px;
      color: #353A39;
      cursor: pointer;
      margin-bottom: 3em;
    }

    a {
      padding: 10px;
      font-size: 24px;
      background-color: #5B6361;
      color: #FFF;
      text-decoration: none;
    }

    a:hover {
      background-color: #353A39;
    }
  </style>
</head>

<body>
  <div id="container">
    <h1>Konami Code</h1>
    <p>Click here to give the page focus and enter the Konami code!</p>
    <a href="https://forum.kirupa.com">Learn More</a>
  </div>

  <script>
    // the Konami Code goes here!
  </script>
</body>

</html>

This is a mostly empty page with some text and styling:

It is up to you to add support for the Konami Code inside the emptyscript tags.

And with that, it is time to begin! If you get stuck, the solution is presented below. You have to scroll a bit to see it.

Possibly Useful Hints

Spend some time thinking through the various pieces involved and how to represent that in JavaScript. If you need some optional pointers to tutorials that can help you complete this challenge, check out Arrays,Timers in JS, Working with the Keyboard, and Detecting if the User is Idle or Inactive.

 

 

 

 

( this space intentionally left blank...to keep you from accidentally seeing the solution )

 

 

 

 

One Possible Solution

At a high level, we need our code to do a few things:

  1. Each time a key is pressed, we need to double check that this key is not only part of the sequence, but that it is also in the right order. Beyond making sure the right keys are pressed...
  2. Time plays a role. Each correct key needs to be pressed within a certain amount of time.
  3. If an incorrect key is pressed or the time between key presses is too large, the sequence needs to start over.

These three steps capture the bulk of what our code will need to do. There are many ways to represent what we want in code, and the following is my attempt at making it work:

let keys = {
  37: "left",
  38: "up",
  39: "right",
  40: "down",
  65: "a",
  66: "b"
};

let konamiCode = ["up", "up", "down", "down", "left", "right", "left", "right", "b", "a"];
let keyCount = 0;

let timerID;

document.addEventListener("keydown", checkCode, false);

function checkCode(e) {
  let keyPressed = keys[e.keyCode];

  if (keyPressed === konamiCode[keyCount]) {
    keyCount++;

    // clear timer
    window.clearTimeout(timerID);

    // start timer with a 1 second delay before resetting state
    timerID = window.setTimeout(resetKeyState, 1000);

    // check if we are still on the right path
    if (keyCount === konamiCode.length) {
      cheatCodeActivated();
      resetKeyState();
    }
  } else {
    resetKeyState();
  }
}

function cheatCodeActivated() {
  alert("Cheat code activated!");
}

function resetKeyState() {
  console.log("Resetting state!");
  window.clearTimeout(timerID);
  keyCount = 0;
}

If you add these lines inside the script tag, preview in the browser, click on the page to give focus, and enter the Konami Code sequence, you should see an alert similar to the following:

If you were able to solve the challenge, and your code doesn't look like what I have, that's totally cool. There are many ways to solve this problem, and my solution may not even be the best approach. The comments below will have additional solutions, and you should feel free to share yours as well.

If you weren't able to solve the challenge, take a moment to look at my code and see where you and I may differ. To help make sense of my code, I'll explain the big pieces in the following sections.

Checking Which Keys Were Pressed

The biggest part of our code, unsurprisingly, deals with handling our key presses and checking whether the right keys were pressed in the right order. The starting point for making all this happen is the following:

document.addEventListener("keydown", checkCode, false);

Each time our page detects that a key is pressed, the checkCode function gets called:

function checkCode(e) {
  let keyPressed = keys[e.keyCode];

  if (keyPressed === konamiCode[keyCount]) {
    keyCount++;

    // clear timer
    window.clearTimeout(timerID);

    // start timer with a 1 second delay before resetting state
    timerID = window.setTimeout(resetKeyState, 1000);

    // check if we are still on the right path
    if (keyCount === konamiCode.length) {
      cheatCodeActivated();
      resetKeyState();
    }
  } else {
    resetKeyState();
  }
}

The first thing is our keyPressed variable which stores a reference to the key that was just pressed. By default, the pressed key is represented as a numerical code (e.keyCode). That is a challenge to make sense of, so what we do is represent the pressed key in the form of actual key names. That is done from the result of keys[e.keyCode], and our keys object looks as follows:

let keys = {
  37: "left",
  38: "up",
  39: "right",
  40: "down",
  65: "a",
  66: "b"
};

By using this approach, valid key presses can be represented as human-understandable names where the numerical value is stored using English letters instead. This is extra helpful when comparing the currently pressed key with the actual Konami Code itself, which we represent in its entirety via the konamiCode array:

let konamiCode = ["up", "up", "down", "down", "left", "right", "left", "right", "b", "a"];

From this point on, the rest of code is about checking that each key press matches the appropriate key in the konamiCode array. We just walk this array with each key press and keep on walking if the correct key has been pressed. To keep track of which key we are at, we use a counter variable (keyCount) that we increment each time a valid key has been pressed:

if (keyPressed === konamiCode[keyCount]) {
  keyCount++;
  .
  .
  .
}

If the user keeps pressing valid keys and we end up at the end of our konamiCode array, then that means the code has been entered correctly. We can check that by comparing the length of our konamiCode array with the current value of keyCount:

if (keyCount === konamiCode.length) {
  cheatCodeActivated();
  resetKeyState();
}

If this code runs, this is our good and happy state where we display our alert by calling cheatCodeActivated. We also reset the state of keyCount and a few other things to start everything over again by calling resetKeyState.

Now, we just saw what happens when all the keys are pressed correctly. When an incorrect key is pressed, we reset keyCount back to 0 and start everything over again by calling resetKeyState:

if (keyPressed === konamiCode[keyCount]) {
  keyCount++;
   .
   .
   .
} else {
  resetKeyState();
}

By relying on keyCount and our konamiCode array, we can address all of the important key checking scenarios without a whole lot of drama.

Dealing with Time

Hiding in plain sight of our key checking code is everything relating to ensuring each of our key presses happen within a certain period of time:

let timerID;

function checkCode(e) {
  var keyPressed = keys[e.keyCode];

  if (keyPressed === konamiCode[keyCount]) {
    keyCount++;

    // clear timer
    window.clearTimeout(timerID);

    // start timer with a 1 second delay before resetting state
    timerID = window.setTimeout(resetKeyState, 1000);

    // check if we are still on the right path
    if (keyCount === konamiCode.length) {
      cheatCodeActivated();
      resetKeyState();
    }
  } else {
    resetKeyState();
  }
}

The way we do all of this time-related malarkey is by starting and stopping a timer, represented by the timerID variable. The moment a valid key is pressed, we restart our timer, and the user has 1 second (1000 milliseconds) to enter the next valid key before resetKeyState is called. If the next key press is also a valid key, we restart our timer again and the countdown to 1 second restarts. If an invalid key is pressed or 1 second has elapsed, resetKeyState is called and our timer stops.

Resetting the State

We have spoken about resetKeyState quite a bit, so let's take a look at it:

function resetKeyState() {
  console.log("Resetting state!");
  window.clearTimeout(timerID);
  keyCount = 0;
}

This function gets called several times. It gets called when a wrong key is pressed. It gets called when the timer runs out. It also gets called when the full code sequence has been entered correctly and we need to start over!

What resetKeyState does is undo everything our code may have done. Saying everything sounds pretty dramatic, for it only undoes two things. It resets our keyCount value back to 0, and it removes our timer.

Conclusion

The Konami Code is a fun (at least for me!) challenge that ties together a lot of basic JavaScript techniques into something that is culturally relevant decades after first having been introduced. For example, as part of the most recent Fortnite launch, the teaser screen allowed you to play a mini-game when you...yep, entered the Konami Code:

If you have done something cool with the Konami Code on your end, do share in the comments below. Also, post your solution as well. It would be good to see the diversity of solutions you all come up with!

Got a question or just want to chat? Comment below or drop by our forums (they are actually the same thing!) where a bunch of the friendliest people you'll ever run into will be happy to help you out!

 

THE KIRUPA NEWSLETTER

Get cool tips, tricks, selfies, and more...personally hand-delivered to your inbox!

( View past issues for an idea of what you've been missing out on all this time! )

COMMENTS

Serving you freshly baked content since 1998!
Killer hosting by (mt) mediatemple

Twitter Youtube Facebook Pinterest Instagram Github