Table of Contents
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!
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.
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.
Once you have completed this challenge, you have earned the awesome bragworthy privilege of adding the following badge to your collection:
To claim it, head over to the forums and respond in the Konamic Code topic. Be sure to include a link to your solution or insert a copy of your HTML/CSS/JS in the body of the message:
Once you have created your topic, Kirupa will give you a virtual high-five and ensure this badge is added to your list of assigned badges.
We want to make this a fun learning activity. If you are stuck and need help, please ask on the forums. Please explain your problem in detail and one of the many helpful forum members will help you out.
If you want to see one way of solving this, check our Kirupa's video and article below:
At a high level, we need our code to do a few things:
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.
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.
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.
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.
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!
Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!
:: Copyright KIRUPA 2024 //--