JavaScript Essentials: Part Mastermind in Javascript)
In this section, we will implement a game called Mastermind in JavaScript. This game development would cover a lot of the concepts that we have discussed so far. We will define functions, pass arguments to them, make use of variables, and make use of loops and if statements. We would briefly look at another concept around functions, known as IIFE, Immediately Invoked Function Expression. We will also look at how to take user input via the command line. At this point, it is just console applications.
You can reference a similar implementation here, Master mind in python
Mastermind is a simple board game that uses colours but We'd use numbers instead.
Summary: Behind a bar are four colours put up by one player. The other player can not see the first player's colours. The first player's colours are called the code maker and the other player's colours are the code breaker. The code breaker has, inclusively, between 2 to 12 attempts at guessing the code makers'. The number of attempts must be even.
Implementation
-
Create a folder called mastermind on your pc (or where you put your projects) and in mastermind, initialize a node project using npm init -y (on the command line). I am on a Linux machine so this is how I will set up my project.
- Open my terminal, run, cd to move me to the user folder.
- Then, cd ~/projects. projects is where I keep my projects.
- Then mkdir mastermind and cd mastermind to create the mastermind folder and change into that folder.
- Initialize a node project with npm init -y. A package.json file will be created.
- Create app.js with touch app.js.
- Write console.log("Mastermind") into app.js and run it with node app.js. I expect to see Mastermind else I have an issue with my setup.
The starting (entry) point of this game will be in App, a function. Let's create a function called App and add console.log("App"). We can then call App() and execute the code with node app.js. I won't be telling you to run your code but it is something you should be doing as you code along. This is the current content of my app.js file.
console.log("Mastermind"); function App() { console.log("App"); } App();
-
When the game starts
- user enters the number of rounds they want to play and the value entered must be validated
- user chooses whether to allow duplicates or not
- somewhere the code maker is randomly generated
- user has entered the code breaker
- the code breaker is compared to the code maker and a hint is given if it doesn't match
- in the process, we make the number of rounds
- and to make this more game-like we put the whole App into an infinite loop
Let's implement a function to generate random numbers for the code make, thereby setting random values to the code maker.
First, we need a way to generate random numbers. Not to interfere with the code in the app.js, let's create another file called scratch_pad.js and in this file we experiment.
JavaScript has a simple way to generate random numbers calling Math.random(). In the scratch pad, let's log 4 random numbers using a looping construct.
console.log("Mastermind"); function App() { console.log("App"); } App();
what we want are integers (numbers like) 0, 1, 2, ..., 9 not decimals. We can multiply the value returned from the Math.random() by 10 and we would have x.something where x will now be in 1,2,3,...,9. Remember these experiments are all done on the scratch pad. Give it a try.
What we want is a number before the dot, the whole number part. We can write code to convert the number to a string and then split it by the "." and get the first element. However, there is a functionality for that called floor which we can use.
for (let i = 0; i < 4; i++) { console.log(Math.random()); } // 0.10037268097853191 // 0.20981624777230534 // 0.47828165742292583 // 0.8160883929470153
- The way this works is that, if we want to get random numbers between some number min and max, where max is greater than min, then we can do, min Math.floor(Math.random() * (max - min 1)). min is the minimum expected value and max is the maximum expected value. In our case, we have our minimum value to be 0 and maximum to be 9.
- This is my snippet for generating the random number. I added parameters to the function because I don't want the function to have an internal state.
for (let i = 0; i < 4; i++) { console.log(Math.floor(Math.random() * 10)); } // 4 // 7 // 3 // 4
At this point, we can now go back into our app.js and add the function above to generate the random numbers for the code maker. Put it above the App function.
From the summary the number of colours used is 4. So we need to generate 4 numbers for the code maker. We also have to handle if duplicates are allowed. Back to the scratchpad.
We have functions, if and else statements, the for and while loops, etc. These constructs all have a block or a body. Variables initialized in these blocks can be used within the block and not outside of it. This is known as the scope of a variable. So a variable can exist in the global scope, which means that that variable can be used or assessed everywhere. When we declare a variable in a block. The variable becomes internal or limited in that scope. Run this in the scratchpad.
console.log("Mastermind"); function App() { console.log("App"); } App();
- Now update this by initializing a variable,x, in the if statement, console.log(x) outside the if block and run your scratch pad. You should get an error similar to this.
for (let i = 0; i < 4; i++) { console.log(Math.random()); } // 0.10037268097853191 // 0.20981624777230534 // 0.47828165742292583 // 0.8160883929470153
At this point I want to bring to your attention the idea about scopes.
- When generating the code maker, we want to know if duplicates are allowed and at this point, we know that the code maker is an array of numbers (or numeric strings). Let's start with the scratchpad. We want to implement a function that takes in a boolean argument indicating if duplicates are allowed. The function will add (push) four numbers into the code maker but before that, we have to check if duplicates are allowed and handle when not.
for (let i = 0; i < 4; i++) { console.log(Math.floor(Math.random() * 10)); } // 4 // 7 // 3 // 4
- we also have written our code in such a way that the code maker isn't accessed globally in the code maker function. So will return the code maker instead.
function generateRandomNumbersBetween(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } for (let i = 0; i < 4; i++) { console.log(generateRandomNumbersBetween(0, 9)); }
- In app.js we can now add the code maker function and a variable for the code make.
- Now back to the scratchpad. We want to take input from the user from the terminal. Javascript has a way to do that too. Try this snippet.
const HP = 100; if (true) { console.log("IF BLOCK::", HP); } console.log("End::", HP); // IF BLOCK:: 100 // End:: 100
There is no issue with this approach of taking user input. It is just that we have to use a callback function and there is no way to pass the entered input to the outer scope of the callback function of readlineOInstance.question.
What are you thinking? Try it out in the "scratch pad". If you are thinking about declaring a variable in the outer scope of readlineOInstance.question the assigning the input entered to it, then it is a good approach but ... Still try it.
Do you remember the concept of Promises? We can use promise here and resolve the input. However, we have to wrap the whole process in function. There are a few parts of the readlineOInstance.question has a header similar to question(query: string, callback: (answer: string) => void. The query is the query (or prompt) to the user and the callback is how we handle the input collection. Since we might reuse the same function somewhere later, we'd pass the query as an argument.
console.log("Mastermind"); function App() { console.log("App"); } App();
Copy after loginCopy after loginCopy after loginCopy after loginCopy after login- Now we can add the getInput function to the app.js. Do not forget the import, const readline = require("readline"). The content of the app.js should be similar to the snippet below.
for (let i = 0; i < 4; i++) { console.log(Math.random()); } // 0.10037268097853191 // 0.20981624777230534 // 0.47828165742292583 // 0.8160883929470153
Copy after loginCopy after loginCopy after loginCopy after login- Now we ask the user to enter the number of rounds and if a duplicate is allowed. We know that the number of rounds must be even and between 2 to 12. We will implement a function to validate a value (number) to be even and between 2 and 12. It will return a boolean. A number is even when the number modulo 2 is zero. (ie. number % 2 == 0).
for (let i = 0; i < 4; i++) { console.log(Math.floor(Math.random() * 10)); } // 4 // 7 // 3 // 4
Copy after loginCopy after loginCopy after loginCopy after login- In the body of the App function, we can ask for the inputs and validate them. We will continuously ask for the proper input for the number of rounds. For the duplicate values in the code, when the user enters anything other than the expected we'd assume that the user doesn't want duplicates. We will use a while loop and set the condition to be true and only break when the rounds are valid however using a try and a catch (for error handling), when the user enters an invalid value we log a message indicating that the value entered is invalid. Try it out.
function generateRandomNumbersBetween(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } for (let i = 0; i < 4; i++) { console.log(generateRandomNumbersBetween(0, 9)); }
Copy after loginCopy after loginCopy after loginRun the app.js and interact with it. This is a similar output during the interaction.
const HP = 100; if (true) { console.log("IF BLOCK::", HP); } console.log("End::", HP); // IF BLOCK:: 100 // End:: 100
Copy after loginCopy after loginCopy after login- We have taken the number of rounds and the value for duplication. Now we can generate the code maker. To do this we can call the generateCodeMaker function and pass the duplication option value to it (or leave it since it's by default false).
IF BLOCK:: 100 /home/Projects/mastermind/scratch_pad.js:8 console.log(x) ^ ReferenceError: x is not defined at Object.<anonymous> (/home/Projects/mastermind/scratch_pad.js:8:13) at Module._compile (node:internal/modules/cjs/loader:1469:14) at Module._extensions..js (node:internal/modules/cjs/loader:1548:10) at Module.load (node:internal/modules/cjs/loader:1288:32) at Module._load (node:internal/modules/cjs/loader:1104:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12) at node:internal/main/run_main_module:28:49 Node.js v20.17.0
Copy after loginCopy after login- Now we can ask the user for the code breaker and compare it to the code maker. The code breaker is also an array of numbers. We will also add a hint for the user to know how far they are from a particular code. So if the code for the code breaker is greater than the code of the code maker, we say more. We say equal when they are equal and else we say less when the code from the code breaker is less than the code of the code breaker. Let's head into the scratchpad.
- We will create a function that will take a numeric array of 4 elements and then compare the user's input (code breaker).
// a global code maker that is accessible inside any other scope let CODE_MAKER = []; function generateRandomNumbersBetween(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } function generateCodeMaker(isDuplicatesAllowed = false) { let counter = 0; while (counter < 4) { let code = generateRandomNumbersBetween(0, 9); if (isDuplicatesAllowed) { CODE_MAKER.push(code); counter += 1; } else if (!CODE_MAKER.includes(code)) { CODE_MAKER.push(code); counter += 1; } } } console.log(CODE_MAKER); generateCodeMaker(true); console.log(CODE_MAKER); // reset the code maker CODE_MAKER = []; generateCodeMaker(false); console.log(CODE_MAKER); // [] // [ 6, 6, 0, 9 ] // [ 2, 5, 0, 8 ]
Copy after loginCopy after login- We have a variable to handle the hints and a value for each code related to the code maker and breaker.
- We pass the code maker to the function to compare it against the input from the user.
- We update the hints to let the user know how to update the values in the code breaker
Now we can add the HINTS and compareCode function to the app.js. It is a great time to run your app.js, above the App function.
Now that we implemented a function to compare the code maker and the code breaker, we can now put this in a loop to account for the rounds (rounds = number of times to play the game). So if the number of rounds is 6, then the game would be played 6 times but we'd have to terminate the game when the user guesses all the codes correctly, that is when the values in the HINTS are all 0s. So when we count the number of 0s in HINTS and it is 4, we can terminate the game and say the user won.
console.log("Mastermind"); function App() { console.log("App"); } App();
Copy after loginCopy after loginCopy after loginCopy after loginCopy after login- The number of rounds is reduced and we'd know whether the user won or not if the number of rounds is not 0.
for (let i = 0; i < 4; i++) { console.log(Math.random()); } // 0.10037268097853191 // 0.20981624777230534 // 0.47828165742292583 // 0.8160883929470153
Copy after loginCopy after loginCopy after loginCopy after login- Some outputs when you run the program
for (let i = 0; i < 4; i++) { console.log(Math.floor(Math.random() * 10)); } // 4 // 7 // 3 // 4
Copy after loginCopy after loginCopy after loginCopy after login- When I hit enter
function generateRandomNumbersBetween(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } for (let i = 0; i < 4; i++) { console.log(generateRandomNumbersBetween(0, 9)); }
Copy after loginCopy after loginCopy after loginI guess we can enjoy our hard work so far. I have about 130 lines. How many do you have?
This is the full code
const HP = 100; if (true) { console.log("IF BLOCK::", HP); } console.log("End::", HP); // IF BLOCK:: 100 // End:: 100
Copy after loginCopy after loginCopy after loginIs there room for improvement?
Even though this is a simple console/terminal/text-based app, there is more we can do about it.
- We can replace all constants such as strings and numbers.
- We could pull out (refactor) the code breaker input and splitting of it, out of the compare code and then pass the code breaker and code maker as arguments. We could even let the function return the hints rather than accessing the hints globally. We will create a new hints variable and return it. So compareCode will return hints assigned to the hints variable.
IF BLOCK:: 100 /home/Projects/mastermind/scratch_pad.js:8 console.log(x) ^ ReferenceError: x is not defined at Object.<anonymous> (/home/Projects/mastermind/scratch_pad.js:8:13) at Module._compile (node:internal/modules/cjs/loader:1469:14) at Module._extensions..js (node:internal/modules/cjs/loader:1548:10) at Module.load (node:internal/modules/cjs/loader:1288:32) at Module._load (node:internal/modules/cjs/loader:1104:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12) at node:internal/main/run_main_module:28:49 Node.js v20.17.0
Copy after loginCopy after login- we can also wrap the console.clear() into a function.
- we can let the program slow down before the next game
- we can pull out HINTS.filter((value) => 0 === value).length === 4 as a function. The purpose of it is to check if the code breaker has guessed correctly the code maker.
- we can also do the same for declaring who won the game
// a global code maker that is accessible inside any other scope let CODE_MAKER = []; function generateRandomNumbersBetween(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } function generateCodeMaker(isDuplicatesAllowed = false) { let counter = 0; while (counter < 4) { let code = generateRandomNumbersBetween(0, 9); if (isDuplicatesAllowed) { CODE_MAKER.push(code); counter += 1; } else if (!CODE_MAKER.includes(code)) { CODE_MAKER.push(code); counter += 1; } } } console.log(CODE_MAKER); generateCodeMaker(true); console.log(CODE_MAKER); // reset the code maker CODE_MAKER = []; generateCodeMaker(false); console.log(CODE_MAKER); // [] // [ 6, 6, 0, 9 ] // [ 2, 5, 0, 8 ]
Copy after loginCopy after login- Put all functions that can stand alone into their own file, functions.js and export them. We can then refactor standalone functions that depend on a global variable and then pass that data as an argument to the function using a parameter.
- We can even have a separate file for
// a global code maker that is accessible inside any other scope let CODE_MAKER = []; function generateRandomNumbersBetween(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } function generateCodeMaker(isDuplicatesAllowed = false) { let counter = 0; let codeMaker = []; while (counter < 4) { let code = generateRandomNumbersBetween(0, 9); if (isDuplicatesAllowed) { codeMaker.push(code); counter += 1; } else if (!codeMaker.includes(code)) { codeMaker.push(code); counter += 1; } } return codeMaker; } console.log(CODE_MAKER); CODE_MAKER = generateCodeMaker(true); console.log(CODE_MAKER); CODE_MAKER = generateCodeMaker(false); console.log(CODE_MAKER); // [] // [ 6, 6, 0, 9 ] // [ 2, 5, 0, 8 ]
Copy after loginConclusion
We have used all that we have learnt in this project and there is more. I mentioned that we could group some functions and export them. For this, we will discuss how to import and export in Javascript. I will provide another project that I think will be useful to you. This is the end of the mastermind game and I hope you will also do some refactoring since there are a lot of places that need to be refactored. Best of luck...
const readline = require("readline"); const readlineOInstance = readline.createInterface({ input: process.stdin, output: process.stdout, }); readlineOInstance.question("Enter code maker: ", (userInput) => { console.clear(); console.log(`INPUT: ${userInput}`); readlineOInstance.close(); });
Copy after loginSources
- wiki-play-mastermind
- wikipedia-mastermind
- Master mind in python
The above is the detailed content of JavaScript Essentials: Part Mastermind in Javascript). For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











Frequently Asked Questions and Solutions for Front-end Thermal Paper Ticket Printing In Front-end Development, Ticket Printing is a common requirement. However, many developers are implementing...

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

There is no absolute salary for Python and JavaScript developers, depending on skills and industry needs. 1. Python may be paid more in data science and machine learning. 2. JavaScript has great demand in front-end and full-stack development, and its salary is also considerable. 3. Influencing factors include experience, geographical location, company size and specific skills.

Discussion on the realization of parallax scrolling and element animation effects in this article will explore how to achieve similar to Shiseido official website (https://www.shiseido.co.jp/sb/wonderland/)...

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

How to merge array elements with the same ID into one object in JavaScript? When processing data, we often encounter the need to have the same ID...

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Explore the implementation of panel drag and drop adjustment function similar to VSCode in the front-end. In front-end development, how to implement VSCode similar to VSCode...
