JavaScript Hangman demo - javascript

I need to put an id of each div and then if I type or if you have another idea how to enter a letter, for example, the secret_word is emir so if I type E the lo dash (___) to deleted and replaced with E.
Unfortunately, this is how I learn javascript I am absolute beginner so I would appreciate any help or advice I don't know if it will make some bag in the future but this is a photo of how the divs are in the console and I might need to hardcode number 1 instead of var sw= ''; to I am really not sure.
Also, I think somehow with a prompt is a good way to get a word my teachers are my friends and they divided the task into pieces I can ask them or use StackOverflow. Also if you can refer me to some link where can I find some usable advice I would be greatly appreciated.
function getTheWord(){
//var secret_word = document.getElementById("secret").value;
secret_word = "emir";
var sw = '';
for(i=1; i <= secret_word.length;i++){
console.log(i);
console.log(sw);
sw += '<div style="display:inline-block;"> ___ </div>';
}
document.getElementById('secret').innerHTML = sw;
}
function GetValue()
{
var my_array= new Array("head","hand1","hand2","body","leg1","leg2");
var random_array = my_array[Math.floor(Math.random() * my_array.length)];
console.log(random_array);
document.getElementById("message").innerHTML=random_array;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="style.css" rel="stylesheet" type="text/css">
<title>Document</title>
</head>
<body onload="getTheWord();">
<input type="button" id="btnSearch" value="Search" onclick="GetValue();" />
<p id="message" ></p>
<div id="secret"></div>
<br>
<input type="text" id="secret" />
</body>
</html>

At the bottom of this post you will find a working hangman game. What follows is a attempt to explain how it works. As surprising as it may sound, there is much to say about this small program, thus I've decided to split my explanations into three parts :
The JavaScript builtins : a quick look at the native functions involved in this program.
The game's state and loop : an overview of the structure and logic of the program.
A bit of painting : a focus on the source code related to the program's output.
1. The JavaScript builtins
This section aims to draw a clear line between our own functions and the native functions involved in this program. I'm going to highlight key functions, how to use them, and how they interact with each other. With this basic knowledge in mind, you should be able to understand the program faster. Here is a summary table :
Name | Array | String | Usage -> Output
---------|---------|---------|-------------------------------------------
repeat | | X | "123".repeat(3) -> "123123123"
split | | X | "1|2|3".split("|") -> [1, 2, 3]
join | X | | [1, 2, 3].join("|") -> "1|2|3"
map | X | | [1, 2, 3].map(x => 2 * x) -> [2, 4, 6]
reduce | X | | [1, 2, 3].reduce((a, x) => a + x, 0) -> 6
indexOf | X | X | [1, 2, 3].indexOf(2) -> 1
concat | X | X | [1].concat([2, 3]) -> [1, 2, 3]
Although most of these functions are self-explanatory, I'd like to bring out a few points :
Some of these functions can be applied to both arrays and strings. indexOf for example can also be used like this : "123".indexOf(2).
join is the reverse function of split. It's often used to prepare the data for storage and output. For example, console.log("[" + [1, 2, 3].join(", ") + "]").
map takes an array, applies the given function to each item, and returns a new array. Easy to understand, more readable than a for loop, and extremely useful.
split, map and join are often used together. Stupid usage example here, but good to get the idea : "123".split("").map(x => 2 * x).join("") gives "246".
reduce is probably the most tricky function. Since there is only one call to this function, I won't go into details. All you need to know is that it gets the longest line in the "ASCII art". By the way, we could replace it with a good old for loop :
var CANVAS_WIDTH = 0;
for (var i = 0; i < HANGMAN.length; i++) {
CANVAS_WIDTH = Math.max(HANGMAN[i].length, CANVAS_WIDTH);
}
That's it for the JavaScript builtins. If you want more details, I can suggest you to Google "mdn [name of the function]". MDN is for Mozilla Developer Network, think of it as a manual for web developers.
2. The game's state and loop
The hangman game is a typical interactive program. When the player types something, the program updates it's state according to the input, gives a feedback to the player, and waits for the next input. This pattern repeats again and again until the end of the game : wait, input, update, output, wait, input, update, output, and so on... Three functions play a key role in this mechanism :
Name | Short description
-------------|------------------------------------------------------
main | Entry point of the program. Starts the game's loop.
isGameOver | Returns true or false depending on the game's state.
updateState | Contains the logic related to the player's input.
The functions' body is quite short and easy to read, so I won't describe the source code line by line, I leave this job to you. However, let me suggest you to read the entire section first.
The game's state is made of two variables, a fails counter and a progress array. The main function is in charge of initializing them. At starting, fails is set to 0, and progress is filled up with placeholders (_). Then, updateState takes care of keeping the variables up to date. A wrong guess increments the fails counter, while a good guess replaces the placeholders with the given letter. Let me show you :
> | secret = "secret",
| progress = ["_", "_", "_", "_", "_", "_"],
| state = { fails: 0, progress: progress }
< | {
| fails: 0,
| progress: ["_", "_", "_", "_", "_", "_"]
| }
> | updateState("e", secret, state),
| state
< | {
| fails: 0,
| progress: ["_", "e", "_", "_", "e", "_"]
| }
> | updateState("a", secret, state),
| state
< | {
| fails: 1,
| progress: ["_", "e", "_", "_", "e", "_"]
| }
The main function also initializes the game's loop. Then, each new input triggers one iteration. On each iteration, isGameOver checks the game's state in order to decide whether the program should keep on talking to the player. The dialog stops when either the secret is revealed (there is no remaining placeholder in the progress array) or the drawing is complete (the fails counter reached its maximum value). Here is the corresponding code snippet :
input.onkeyup = function (ev) {
if (ev.which === 13) {
var value = this.value;
...
} else if (!isGameOver(state)) {
updateState(value, secret, state);
}
}
};
Since 13 is the key code of ENTER, the above code could be expressed like this : "When ENTER is pressed, and if the game is not over, decide if the player's guess is right or wrong.".
3. A bit of painting
An improvement can be found here : https://stackoverflow.com/a/50085635/1636522. However, the best implementation is here : https://stackoverflow.com/a/50090320/1636522. It replaces sections 3.1 and 3.2, but section 3.3 is still relevant.
So far we have covered around 50% of the source code. We are able to distinguish native and user defined functions, and we have an good overview of the structure and logic of the program. Now it's time to talk about the remaining 50% code, which is related to the output of the program.
Hang on, the tough part is yet to come +0+'
3.1. The data structures
The three data structures I'm going to describe are involved in drawing the gallows. Note that if you want another ASCII art, you only have to change these structures, the program should keep working fine. Also, they are supposed to be "read only", that's why I named them using capital letters, a widespread convention for constants :
Name | Type | Short description
----------------|------------|--------------------------------
HANGMAN | [String] | The ASCII art.
STROKES_COORDS | [[Int]] | Coordinates of the strokes.
DRAWING_STEPS | [Int] | Steps to complete the drawing.
Not much to say about HANGMAN except that it should be seen as a xy-coordinate plane :
x = 0, y = 0
HANGMAN[y] // "+----+"
HANGMAN[y][x] // "+"
STROKES_COORDS contains the coordinates of the strokes that you can find in the HANGMAN plane. As an example, STROKES_COORDS[5] gives [0,0], which points to the first "+". Furthermore, the array is sorted into chronological order. As a consequence, if you print the first six strokes, you get a snapshot of gallows pole (read from bottom to top) :
STROKES_COORDS[5] -> [0,0] -> +
STROKES_COORDS[4] -> [0,1] -> |
STROKES_COORDS[3] -> [0,2] -> |
STROKES_COORDS[2] -> [0,3] -> |
STROKES_COORDS[1] -> [0,4] -> |
STROKES_COORDS[0] -> [0,5] -> |
DRAWING_STEPS can be seen as another level of indirection on top of STROKES_COORDS. This array is also sorted into chronological order and contains the number of strokes to paint after each wrong guess. The following figure illustrates that three fails leads to print six strokes :
DRAWING_STEPS[3] -> 6 -> +
|
|
|
|
|
After DRAWING_STEPS.length - 1 fails, the drawing is complete and the game is over. As a consequence, the maximum amount of wrong guesses depends on DRAWING_STEPS.length :
var MAX_FAILS = (
DRAWING_STEPS.length - 1
);
3.2. Drawing the gallows
The drawGallows function takes the amount of wrong guesses at some point of the game, and returns the ongoing drawing in the form of a two dimensional array ([[String]]) :
> | // 3 fails -> 6 strokes
| drawGallows(3)
< | [
| ["+", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "]
| ]
To build the ongoing drawing, drawGallows relies on the data structures described previously. The function first creates an empty canvas, then it loops through the STROKES_COORDS array and fills the blanks with copies of the first n strokes found in HANGMAN. In the next code snippet you can see the copy in action :
> | canvas = HANGMAN.map(
| () => BLANK_ROW.split("")
| );
< | [
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "]
| ]
> | fails = 3;
| n = DRAWING_STEPS[fails]; // 6
| for (i = 0; i < n; i++) {
| x = STROKES_COORDS[i][0];
| y = STROKES_COORDS[i][1];
| canvas[y][x] = HANGMAN[y][x]; // <- copy
| }
| canvas
< | [
| ["+", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "]
| ]
3.3. A drop of glue
As you can see while playing the game, the program does a little more than printing the ASCII art. We can see a message, the letters and placeholders, the floor under the gallows, and the fails counter. These additions come from the outputState function that combines everything and forwards the result to the output function for printing.
Note that output takes an array of string as argument, hence it's necessary to join the columns of the canvas returned by drawGallows. At the same time, the lines are shifted to the right in order to center the gallows horizontally :
> | drawGallows(3).map(
| x => " ".repeat(3) + x.join("")
| )
< | [
| " + ",
| " | ",
| " | ",
| " | ",
| " | ",
| " | "
| ]
That's all.
We are done !
Congratulations and thanks for reading :-) This answer looks more like a blog post but I hope you appreciate anyway. Drop a comment if you need further explanations.
var HANGMAN = [
"+----+"
, "| |"
, "| o"
, "| /M\\"
, "| / \\"
, "|"
];
var STROKES_COORDS = [
[0,5], [0,4], [0,3], [0,2],
[0,1], [0,0], [1,0], [2,0],
[3,0], [4,0], [5,0], [5,1], [5,2],
[5,3], [4,3], [6,3], [4,4], [6,4]
];
var DRAWING_STEPS = [
0, 2, 4, 6, 8,
11, 13, 16, 18
];
var CANVAS_WIDTH = HANGMAN.reduce(
(a, x) => Math.max(x.length, a), 0
);
var BLANK_ROW = (
" ".repeat(CANVAS_WIDTH)
);
var MAX_FAILS = (
DRAWING_STEPS.length - 1
);
onload = function () {
main("save earth");
};
function main (secret) {
var placeholders = "_".repeat(secret.length);
var state = { fails: 0, progress: placeholders.split("") };
var input = document.getElementById("input");
outputState(state, "Let's try!");
input.onkeyup = function (ev) {
if (ev.which === 13) {
var value = this.value;
this.value = ""; // reset input box
if (value === "reset") {
state.fails = 0;
state.progress = placeholders.split("");
outputState(state, "Let's try again!");
} else if (!isGameOver(state)) {
updateState(value, secret, state);
}
}
};
}
function isGameOver (state) {
return state.fails >= MAX_FAILS || (
state.progress.indexOf("_") === -1
);
}
function updateState (input, secret, state) {
if (fillIn(input, state.progress, secret)) {
if (state.progress.indexOf("_") === -1) {
outputState(state, "Good job :-)");
} else {
outputState(state, "Yes! Keep it up :-D");
}
} else {
if (++state.fails === MAX_FAILS) {
outputState(state, "Bad job :-(");
} else {
outputState(state, "No... Hang on :-P");
}
}
}
function fillIn (letter, progress, secret) {
var found = false;
for (var i = 0; i < secret.length; i++) {
if (secret[i] === letter) {
found = true, progress[i] = secret[i];
}
}
return found;
}
function drawGallows (fails) {
var canvas = HANGMAN.map(
() => BLANK_ROW.split("")
);
var n = DRAWING_STEPS[fails];
for (var i = 0; i < n; i++) {
var x = STROKES_COORDS[i][0];
var y = STROKES_COORDS[i][1];
canvas[y][x] = HANGMAN[y][x];
}
return canvas;
}
function outputState (state, message) {
output([
message, "",
state.progress.join(" "), ""
].concat(
drawGallows(state.fails).map(
x => " ".repeat(3) + x.join("")
)
).concat((
"-".repeat(CANVAS_WIDTH + 6)
) + " fails = " + (
state.fails + " / " + MAX_FAILS
)));
}
function output (lines) {
var p = document.getElementById("pre");
p.textContent = " " + lines.join("\n ");
}
<table width="100%" cellspacing="0">
<tr>
<td width="40%" valign="top" style="text-align: center;">
<p style="font-size: 14px;">
Type a character or "reset"<br>
(white spaces matter),<br>
then press ENTER.
</p>
<input id="input" type="text">
</td>
<td valign="top" style="border-left: 1px solid #999;">
<pre id="pre" style="
font-size: 12px;
font-family: monospace, monospace;
"></pre>
</td>
</tr>
</table>

I didn't actually understand what you mean but I think you could do something like this
for(i=1; i <= secret_word.length;i++){
let elem = document.createElement("div");
elem.setAttribute("id", i)
document.appendChild(elem);
}
You will create a div for each letter them you can select them individualy.

What follows comes after this answer : https://stackoverflow.com/a/49974142/1636522.
A better implementation can be found here : https://stackoverflow.com/a/50090320/1636522.
In the previous post, section 3.1, "The data structures", I describe three arrays named HANGMAN, STROKES_COORDS and DRAWING_STEPS. I start by telling you that...
[...] if you want another ASCII art, you only have to change these structures, [...]
Good. However, regarding the first version of the program, it can be a tedious task. Imagine you want an extra dash (-). Then, you'll have to insert the new coordinates into STROKES_COORDS, so far so good, but you'll also have to update the coordinates of all subsequent strokes that must be shifted to the right accordingly. And the same applies to DRAWING_STEPS. Boring right ? Now imagine your ASCII art is ten times bigger... +0+'
To address this problem, we can take advantage of the fact that the position of one stroke depends on the position of the previous stroke, and turn absolute positioning into relative positioning. The trick is to use each pair of coordinates as an offset to compute the next one. The following figure is an attempt to illustrate this mechanism (read from bottom to top) :
[+0,-1] -> [0,0] -> +
[+0,-1] -> [0,1] -> |
[+0,-1] -> [0,2] -> |
[+0,-1] -> [0,3] -> |
[+0,-1] -> [0,4] -> |
[+0,+5] -> [0,5] -> |
The next snippet is the corresponding implementation. It links xy, the relative coordinates of the current stroke, with xys[i-1], the offset coordinates of the previous stroke :
STROKES_COORDS.map(function (xy, i, xys) {
return i > 0 && (
xy[0] += xys[i - 1][0],
xy[1] += xys[i - 1][1]
), xy;
})
Thanks to this trick, when you insert new strokes, subsequent strokes update their positions automatically. Here is an example :
var HANGMAN = [
"+---------+" // <- +5 dashes
, "| |"
, "| o"
, "| /M\\"
, "| / \\"
, "|"
];
var STROKES_COORDS = [
// first stroke
[+0,+5],
// vertical line
[+0,-1], [+0,-1], [+0,-1], [+0,-1], [+0,-1],
// horizontal line
[+1,+0], [+1,+0], [+1,+0], [+1,+0], [+1,+0],
[+1,+0], [+1,+0], [+1,+0], [+1,+0], [+1,+0],
// rope and head
[+0,+1], [+0,+1],
// body and arms
[-1,+1], [+1,+0], [+1,+0],
// legs
[-2,+1], [+2,+0]
];
var DRAWING_STEPS = [
+0, // nothing
+2, +2, +2, // vertical line
+3, +4, +3, // horizontal line
+2, +3, +2 // character
];
As you can see, there is a very little difference with the old code :
$ diff a b
2,6c2,6
< "+----+"
< , "| |"
< , "| o"
< , "| /M\\"
< , "| / \\"
---
> "+---------+" // <- +5 dashes
> , "| |"
> , "| o"
> , "| /M\\"
> , "| / \\"
16a17
> [+1,+0], [+1,+0], [+1,+0], [+1,+0], [+1,+0],
28c29
< +2, +3, // horizontal line
---
> +3, +4, +3, // horizontal line
That's all :-)
var HANGMAN = [
"+----+"
, "| |"
, "| o"
, "| /M\\"
, "| / \\"
, "|"
];
var STROKES_COORDS = [
// first stroke
[+0,+5],
// vertical line
[+0,-1], [+0,-1], [+0,-1], [+0,-1], [+0,-1],
// horizontal line
[+1,+0], [+1,+0], [+1,+0], [+1,+0], [+1,+0],
// rope and head
[+0,+1], [+0,+1],
// body and arms
[-1,+1], [+1,+0], [+1,+0],
// legs
[-2,+1], [+2,+0]
];
var DRAWING_STEPS = [
+0, // nothing
+2, +2, +2, // vertical line
+2, +3, // horizontal line
+2, +3, +2 // character
];
var CANVAS_WIDTH = HANGMAN.reduce(
(a, x) => Math.max(x.length, a), 0
);
var BLANK_ROW = (
" ".repeat(CANVAS_WIDTH)
);
var MAX_FAILS = (
DRAWING_STEPS.length - 1
);
STROKES_COORDS = (
STROKES_COORDS.map(function (xy, i, xys) {
return i > 0 && (
xy[0] += xys[i - 1][0],
xy[1] += xys[i - 1][1]
), xy;
})
);
DRAWING_STEPS = (
DRAWING_STEPS.map(function (x, i, xs) {
return i === 0 ? x : (
xs[i] += xs[i - 1]
);
})
);
onload = function () {
main("save earth");
};
function main (secret) {
var placeholders = "_".repeat(secret.length);
var state = { fails: 0, progress: placeholders.split("") };
var input = document.getElementById("input");
outputState(state, "Let's try!");
input.onkeyup = function (ev) {
if (ev.which === 13) {
var value = this.value;
this.value = ""; // reset input box
if (value === "reset") {
state.fails = 0;
state.progress = placeholders.split("");
outputState(state, "Let's try again!");
} else if (!isGameOver(state)) {
updateState(value, secret, state);
}
}
};
}
function isGameOver (state) {
return state.fails >= MAX_FAILS || (
state.progress.indexOf("_") === -1
);
}
function updateState (input, secret, state) {
if (fillIn(input, state.progress, secret)) {
if (state.progress.indexOf("_") === -1) {
outputState(state, "Good job :-)");
} else {
outputState(state, "Yes! Keep it up :-D");
}
} else {
if (++state.fails === MAX_FAILS) {
outputState(state, "Bad job :-(");
} else {
outputState(state, "No... Hang on :-P");
}
}
}
function fillIn (letter, progress, secret) {
var found = false;
for (var i = 0; i < secret.length; i++) {
if (secret[i] === letter) {
found = true, progress[i] = secret[i];
}
}
return found;
}
function drawGallows (fails) {
var canvas = HANGMAN.map(
() => BLANK_ROW.split("")
);
var n = DRAWING_STEPS[fails];
for (var i = 0; i < n; i++) {
var x = STROKES_COORDS[i][0];
var y = STROKES_COORDS[i][1];
canvas[y][x] = HANGMAN[y][x];
}
return canvas;
}
function outputState (state, message) {
output([
message, "",
state.progress.join(" "), ""
].concat(
drawGallows(state.fails).map(
x => " ".repeat(3) + x.join("")
)
).concat((
"-".repeat(CANVAS_WIDTH + 6)
) + " fails = " + (
state.fails + " / " + MAX_FAILS
)));
}
function output (lines) {
var p = document.getElementById("pre");
p.textContent = " " + lines.join("\n ");
}
<table width="100%" cellspacing="0">
<tr>
<td width="40%" valign="top" style="text-align: center;">
<p style="font-size: 14px;">
Type a character or "reset"<br>
(white spaces matter),<br>
then press ENTER.
</p>
<input id="input" type="text">
</td>
<td valign="top" style="border-left: 1px solid #999;">
<pre id="pre" style="
font-size: 12px;
font-family: monospace, monospace;
"></pre>
</td>
</tr>
</table>

What follows comes after this answer : https://stackoverflow.com/a/50085635/1636522.
While I was looking for another ASCII art, I stumbled upon this one :
0000000000000
0 0
0 1
0 1 1
0 1
0 324
0 3 2 4
0 3 2 4
0 5 6
0 5 6
0 5 6
0 5 6
0
0
0
I immediately figured out the idea, which is far smarter than mine... +0+' This is a mask containing the minimum amount of fails required to print each character. Here is what we get regarding our implementation, you should see the drawing behind the numbers :
var HANGMAN_STEPS = [
[3, 4, 4, 5, 5, 5, 0]
// + - - - - +
, [3, 0, 0, 0, 0, 6, 0]
// | |
, [2, 0, 0, 0, 0, 6, 0]
// | o
, [2, 0, 0, 0, 7, 7, 7]
// | / M \
, [1, 0, 0, 0, 8, 0, 8]
// | / \
, [1, 0, 0, 0, 0, 0, 0]
// |
];
This structure contains the information of both STROKES_COORDS and DRAWING_STEPS described previously, what makes it easier to read and easier to change. Moreover, drawGallows becomes smaller. Indeed, since HANGMAN and HANGMAN_STEPS match perfectly, it's not necessary to translate indices anymore :
function drawGallows (fails) {
return HANGMAN_STEPS.map((l, y) => (l.map(
(i, x) => i > fails ? " " : HANGMAN[y][x]
)));
}
Give me a rope please...
var HANGMAN = [
"+----+ "
, "| | "
, "| o "
, "| /M\\"
, "| / \\"
, "| "
];
var HANGMAN_STEPS = [
[3, 4, 4, 5, 5, 5, 0]
, [3, 0, 0, 0, 0, 6, 0]
, [2, 0, 0, 0, 0, 6, 0]
, [2, 0, 0, 0, 7, 7, 7]
, [1, 0, 0, 0, 8, 0, 8]
, [1, 0, 0, 0, 0, 0, 0]
];
var MAX_FAILS = HANGMAN_STEPS.reduce((max, l) => (
l.reduce((max, i) => Math.max(max, i), max)
), 0);
var CANVAS_WIDTH = HANGMAN.reduce(
(a, x) => Math.max(x.length, a), 0
);
onload = function () {
main("save earth");
};
function main (secret) {
var placeholders = "_".repeat(secret.length);
var state = { fails: 0, progress: placeholders.split("") };
var input = document.getElementById("input");
outputState(state, "Let's try!");
input.onkeyup = function (ev) {
if (ev.which === 13) {
var value = this.value;
this.value = ""; // reset input box
if (value === "reset") {
state.fails = 0;
state.progress = placeholders.split("");
outputState(state, "Let's try again!");
} else if (!isGameOver(state)) {
updateState(value, secret, state);
}
}
};
}
function isGameOver (state) {
return state.fails >= MAX_FAILS || (
state.progress.indexOf("_") === -1
);
}
function updateState (input, secret, state) {
if (fillIn(input, state.progress, secret)) {
if (state.progress.indexOf("_") === -1) {
outputState(state, "Good job :-)");
} else {
outputState(state, "Yes! Keep it up :-D");
}
} else {
if (++state.fails === MAX_FAILS) {
outputState(state, "Bad job :-(");
} else {
outputState(state, "No... Hang on :-P");
}
}
}
function fillIn (letter, progress, secret) {
var found = false;
for (var i = 0; i < secret.length; i++) {
if (secret[i] === letter) {
found = true, progress[i] = secret[i];
}
}
return found;
}
function drawGallows (fails) {
return HANGMAN_STEPS.map((l, y) => (l.map(
(i, x) => i > fails ? " " : HANGMAN[y][x]
)));
}
function outputState (state, message) {
output([
message, "",
state.progress.join(" "), ""
].concat(
drawGallows(state.fails).map(
x => " ".repeat(3) + x.join("")
)
).concat((
"-".repeat(CANVAS_WIDTH + 6)
) + " fails = " + (
state.fails + " / " + MAX_FAILS
)));
}
function output (lines) {
var p = document.getElementById("pre");
p.textContent = " " + lines.join("\n ");
}
<table width="100%" cellspacing="0">
<tr>
<td width="40%" valign="top" style="text-align: center;">
<p style="font-size: 14px;">
Type a character or "reset"<br>
(white spaces matter),<br>
then press ENTER.
</p>
<input id="input" type="text">
</td>
<td valign="top" style="border-left: 1px solid #999;">
<pre id="pre" style="
font-size: 12px;
font-family: monospace, monospace;
"></pre>
</td>
</tr>
</table>

Related

How to make Java Script ignore or maintain spaces, not delete them

I'm trying to have a function cover a multi-word region with dashes, but not cover the space between the words with a dash in Java Script. So, I basically need JS to ignore the spaces (or maintain then?) but all I've found online is how to remove spaces from a string. If I do that, then there will still be no spaces between the dashes covering the region (though it would technically be the correct length without the space).
This is the function I'm working with for this:
Begin Routine:
sentenceList = Sentence.split(",");
wordNumber = (- 2);
Each Frame:
var _pj;
function replaceWithdash(sentenceList, currentWordNumber) {
var index, result, word;
result = "";
index = 0;
while ((index < sentenceList.length)) {
word = sentenceList[index];
if ((index !== currentWordNumber)) {
result = ((result + ("-".repeat(word.length))) + " ");
} else {
result = ((result + word) + " ");
}
index = (index + 1);
}
return result;
}
Regions are separated by the delimiter "," so that multiple words can be included. The variable "word" basically indexes through these regions in the sentence. The function 'replaceWithdash' replaces the 'word' length (total region) with dashes. I don't know how to somehow keep the display as region by region but have the replaceWithdash function ignore or maintain spaces. Input: The dog, ate, the food.
Current display:
------- --- --------
The dog --- --------
Desired display:
--- --- --- --- ----
The dog --- --------
Does anyone know a way around this?
If I understood correctly, this is what you are looking or, right?
function replaceWithdash(sentenceList, currentWordNumber) {
const regions = sentenceList.split(",")
const sigil = regions.map(s => s.replaceAll(/[^\s]/g, "-"))
if (currentWordNumber !== undefined) {
sigil.splice(currentWordNumber, 1, regions[currentWordNumber])
}
return sigil.join("")
}
str = "The dog, ate, the food"
console.log(replaceWithdash(str))
//"--- --- --- --- ----"
console.log(replaceWithdash(str, 0))
//"The dog --- --- ----"
console.log(replaceWithdash(str, 1))
//"--- --- ate --- ----"
console.log(replaceWithdash(str, 2))
// "--- --- --- the food"

Converting prefix to infix in JavaScript

I am trying to write a program that takes in an prefix expression and outputs an infix expression. I have examples listed below to help demonstrate what I am talking about. I have pasted my code below, could someone please help me figure out how I can move the symbol between 2 numbers in an expression? Please see example 1 to see my approach on how I tried to get it, but it doesn't work. Any answers would be helpful or tips as to what to do. Thank you for your help!
/* The goal is to take in an expression in prefix notation and output it in infix notation
for example:
+ 1 2 outputs output 1 + 2
+ - 3 4 5 outputs 3 + 4 - 5
% + / - 0 9 3 8 5 outputs 0 % 9 + 3 / 8 - 5
*/
function convert(input){
var x = input.split(''); // splits each variable and stores it in an array
var output = "";
// these are the valid symbols we can take, we will use these later
var symbols = ['+', '-', '*', '/', '%'];
// lets loop through all the values in x, starting at position 0
for(var i = 0; i < x.length; i++){
if(symbols.includes(x[i])) { // we hit a symbol, lets move it between 2 numbers
/* now we need to figure out where to store the symbol. every 2 spaces starting at index 0
we can insert a symbol (so spots like 1 3 5 7 etc). this loop will help us figure out what spot is empty
, and it will store the symbol at that spot [see example 1 for a visualizaton]*/
for(var j = 0; j < input.length; j+=2){
if(output[j] == " "){
// great, we can save the symbol here
output = output + x[i];
}
}
}
// otherwise we have a number on our hands
else{
output = output + x[i];
console.log(output);
}
}
}
console.log(convert("+ 1 2"));
/*
example 1
if I have "+ 1 2"
+ is position 0
1 is position 2
2 is position 4
so the whitespace is at position 1 and 3. these are the spots where we can output the symbols
using the original expression + 1 2
position: value:
-------- | ------
0 | 1
-------- | ------
1 | " "
-------- | ------
2 | +
-------- | ------
3 | " "
-------- | ------
4 | 2
*/
function result_expression(expression, variables) {
let opernads=['+','-','*','/'];
let arr=[...expression.split(" ")];
var len=arr.length;
while(len>0){
let d1=arr[len-1]
let d2=arr[len-2]
let d3=arr[len-3]
if(opernads.includes(d3)){
if(isNaN(d2)){
let tmp=variables[d2]
d2=tmp;
}
if(isNaN(d1)){
let tmp1=variables[d1]
d1=tmp1;
}
let a=d2.toString().concat(d3).concat(d1)
delete arr[len-1]
delete arr[len-2]
delete arr[len-3]
let na=[];
arr[len-3]=eval(a)
arr.forEach(e=>{
if(!(typeof e==='undefined')){
na.push(e)
}
})
arr=[...na]
console.log('arr',arr)
len=arr.length;
// arr=[...newar]
// len=arr.length
}else{
len--
}
if(len==1){
return arr[0]
}
}
}
//let expression="+ 6 * - 4 + 2 3 8";
//let expression="+ 6 * - 4 a b + 2 3 8";
let expression="+ * 6 5 3 2 2";
let variables={a:20,b:1}
let k=result_expression(expression, variables);
console.log('finalresult',k)
So long as you're only using simple expressions, I would suggest dividing the input into two arrays, numbers and symbols, and then merging them together.
var symbols = ['+', '-', '*', '/', '%'];
function convert(input) {
var
response = '',
infixes = [],
numbers = [];
// Divide input into two arrays, infixes (or symbols) and numbers
infixes = input.split(' ').filter(function(o) {
if (symbols.includes(o)) {
return true;
} else {
numbers.push(o);
}
});
// Merge arrays
for (let i = 0; i < numbers.length; i++) {
if (infixes[i]) {
response =
response +
numbers[i] + ' ' +
infixes[i] + ' ';
} else {
response =
response + numbers[i] + ' ';
}
}
response = response.slice(0, -1);
return response;
};
This function works for all your examples, but if you need to make it more intelligent you can easily modify and test the above function on codepen here.

Given string how do I replace certain words with multiple words in an array?

Let's say I have a sentence and an array of words:
let sentence = 'My * is * years old.';
let words = ['dog', 3];
//expected result => My dog is 9 years old.
How would I replace each asterisk (*) with the appropriate word in the given array?
But let's also say that there's case where there are more asterisks than elements in the array:
let sentence = 'The soldiers marched *, *, *, *.';
let words = ['left', 'right'];
//expected result => The soldiers marched left, right, left, right.
Is using regex the only way to solve this or is there a vanilla JS solution?
You could take a replacement function with an additional value for the starting index, which has a default value of zero.
For keeping the index in a valid range, you could take the remainder operator % with the length of the array.
const
replace = (string, array, i = 0) =>
string.replace(/\*/g, _=> array[i++ % array.length]);
console.log(replace('My * is * years old.', ['dog', 3]));
console.log(replace('The soldiers marched *, *, *, *.', ['left', 'right']));
let sentence = 'My * is * years old.';
let words = ['dog', 3];
let count =0;
while (sentence.indexOf('*') > -1) {
sentence = sentence.replace('*', words[count++]);
if (count >= words.length) count = 0;
}
console.log(sentence);
shows: "My dog is 3 years old."
If you really dislike regular expressions you could do this:
words = ["left", "right"];
"The soldiers marched *, *, *, *.".split("*").map(function (x, i) {
return i === 0 ? x : words[(i + 1) % words.length] + x;
}).join("");
Trace of execution:
init | "The soldiers marched *, *, *, *."
split | ["The soldiers marched ", ", ", ", ", ", ", "."]
i = 0 | ["The soldiers marched ", ", ", ", ", ", ", "."]
i = 1 | ["The soldiers marched ", "left, ", ", ", ", ", "."]
i = 2 | ["The soldiers marched ", "left, ", "right, ", ", ", "."]
i = 3 | ["The soldiers marched ", "left, ", "right, ", "left, ", "."]
i = 4 | ["The soldiers marched ", "left, ", "right, ", "left, ", "right."]
join | "The soldiers marched left, right, left, right."
Another regexp free option:
s = "The soldiers marched *, *, *, *.";
f = Function("words", "var i = 0; return \"" + s.split("*").join(
"\" + words[(i++) % words.length] + \""
) + "\";");
> | f(["L", "R"])
< | "The soldiers marched L, R, L, R."
> | f(["L", "R"].reverse())
< | "The soldiers marched R, L, R, L."
> | f(["L", "R", "R"])
< | "The soldiers marched L, R, R, L."
Beware of malicious code though:
s = "The soldiers marched *, *, *, *.";
s = "\", console.log(\"VIRUS ATTACK!!! CALL +XX-XXXXX-XXXXX NOW!!!\"), \"" + s;
f = Function("words", "var i = 0; return \"" + s.split("*").join(
"\" + words[(i++) % words.length] + \""
) + "\";");
> | f(["L", "R"])
| VIRUS ATTACK!!! CALL +XX-XXXXX-XXXXX NOW!!!
< | "The soldiers marched L, R, L, R."
You should always sanitize the input:
s = "The soldiers marched *, *, *, *.";
s = "\", alert(\"VIRUS ATTACK!!! CALL +XX-XXXXX-XXXXX NOW!!!\"), \"" + s;
s = s.split("\"").join("\\\""); // potentially not sufficient!
f = Function("words", "var i = 0; return \"" + s.split("*").join(
"\" + words[(i++) % words.length] + \""
) + "\";");
> | f(["L", "R"])
< | "", alert("VIRUS ATTACK!!! CALL +XX-XXXXX-XXXXX NOW!!!"), "The soldiers marched L, R, L, R."
But I would not venture that it's bullet proof :-|
One character after the other:
input = "The soldiers marched *, *, *, *.";
words = ["left", "right"];
output= ""
for (i = 0, j = 0; i < input.length; i++) {
output += input[i] !== "*" ? input[i] : (
words[(j++) % words.length]
);
}
console.log(output)
As you can see, there are multiple alternatives to regular expressions. Anyway, what you really need to understand is the remainder operator (%):
0 % 2 = 0 | 0 -> 0
1 % 2 = 1 | 1 -> 1
2 % 2 = 0 | 2 -> 0
3 % 2 = 1 | 3 -> 1
4 % 2 = 0 | 4 -> 0
0, 1, 0, 1, 0, 1, ... Got it? The result never reaches the right operand. This is especially useful when you need to iterate over the same array more than once:
abc = ["A", "B", "C"]
for (i = 0; i < 2 * abc.length; i++) {
// j will never reach abc.length
j = i % abc.length; // 0, 1, 2, 0, ...
console.log(i, j, abc[j]);
}

In Javascript, how do I print 2 diagrams side by side?

I am doing a JavaScript practice problem on Practice.it, and there's a question to print 2 rocket ships side by side.
I have printed one out but I can't figure out how to print the other rocket ship right next to the first one.
Also, is there way to do this using for loops?
function rocket(){
triangle();
line();
sides();
line();
console.log("|Rocket |");
console.log("| #1 |");
line();
sides();
line();
triangle();
}
function triangle(){
console.log(" / \\");
console.log(" / \\");
console.log(" / \\");
}
function line(){
console.log("+-------+");
}
function sides(){
console.log("| |");
}
rocket();
Output:
/ \
/ \
/ \
+-------+
| |
+-------+
|Rocket |
| #2 |
+-------+
| |
+-------+
/ \
/ \
/ \
A quick and dirty way would just be to concatenate each string with itself. So for every instance of console.log("+--------+") use:
console.log("+--------+".repeat(2));
And just do this for each string.
Instead of logging right way in your functions, you should put your diagram strings in a array.
Ex:
function triangle(){
return
[" / \\",
" / \\",
" / \\"]
}
That way, if you want to print two side by side, you just make a function that receives the diagrams, and an amount of spaces used to separate them horizontally. That function will print the diagrams line by line (index by index of the arrays).
Ex:
function printDiagrams(diagramList /* This is an array of arrays */, spacing) {
// Get the size of the biggest array in diagramList
var size= biggestDiagramSize(diagramList )
// Here, you iterate in the diagrams array line by line and print
for(i = 0, i < size, i++ ) {
// Iterate over diagramList and print its lines
// Careful not to exceed arrays bound.
// Ex: console.log(diagram1[i] + spacing + diagram2[i] + spacing + diagramN[i])
}
}
You're also going to need a function to compose the diagrams. It just receives arrays and returns the concatenation of them.
Note: That will work even if you print different diagrams side by side.
You can define a parameter for rocket function, use String.prototype.repeat() and String.prototype.replace() within the function for the ability to draw N diagrams side by side.
function rocket(n = 1) {
let props = ["|Rocket |", "| #N |"];
let j = 0;
let s = props[1].match(/\s+(?=\|)/)[0].length;
triangle(n);
line(n);
sides(n);
line(n);
for (var i = 0; i < props.length; i++) {
console.log(
props[i]
.repeat(n)
.replace(/(N)(\s+(?=\|))/g
, (_, a, b) => ++j + (j >=10 ? " ".repeat(s-1) : b)));
}
line(n);
sides(n);
line(n);
triangle(n);
}
function triangle(n){
var props = [" / \\ ", " / \\ ", " / \\ "];
draw(props, n);
}
function line(n){
var props = ["+-------+"];
draw(props, n);
}
function sides(n){
var props = ["| |"];
draw(props, n);
}
function draw(props, n) {
for (var prop of props) console.log(prop.repeat(n));
}
rocket(15);

How can I guarantee that my Rubik's cube scrambling algorithm doesn't select the same direction twice in a row?

I am working on a Rubik's Cube Timer Website, (JavaScript) and it requires a scrambling algorithm. It would be easy if it was just picking random letters from an array, but there are requirements that it needs to meet. Each Letter Represents a move in the Rubik's Cube Algorithmic notation, so for example "L" would mean to move the Left side clockwise. Or "U2" would mean to move the Upper side two times, and " B' " would mean to move the Backside anticlockwise. and so on.
The thing is that there cannot be two of the same letters next to each other, and not even if they are in different directions. For example, U cannot be next to U', or U2 and so on. It must be a different letter. Sometimes, my code generates 2 of the same letter next to each other.
Here's my code:
function generateScramble() {
//Possible Letters
var array = new Array(" U", " D", " R", " L", " F", " B", " U\'", " D\'", " R\'", " L\'", " F\'", " B\'", " U2", " D2", " R2", " L2", " F2", " B2");
var array2 = new Array(); // The Scramble.
var rdArr = new Array(); // The Array of random numbers.
for (var i = 0; i < 20; i++) {
var random = Math.floor(Math.random() * array.length);
rdArr.unshift(random);
if (rdArr[1] - rdArr[0] == 0 ||
rdArr[0] - rdArr[1] == 0 ||
rdArr[1] - rdArr[0] == 6 ||
rdArr[0] - rdArr[1] == 6 ||
rdArr[1] - rdArr[0] == 12 ||
rdArr[0] - rdArr[1] == 12) { // Check whether a D is next to D' or D2, or if F is next to F' or F2, R next to R' or R2, and so on
if (random < 17) {
random++;
} else {
random--;
}
}
array2.push(array[random]); // Get letters in random order in the array.
}
var scramble = "Scramble: " + array2[0] + array2[1] + array2[2] + array2[3] + array2[4]
+ array2[5] + array2[6] + array2[7] + array2[8] + array2[9]
+ array2[10] + array2[11] + array2[12] + array2[13] + array2[14]
+ array2[15] + array2[16] + array2[17] + array2[18] + array2[19];
document.getElementById("Scramble").innerHTML = scramble; // Display the scramble
}
I think, the code could be as it:
generateScramble();
function generateScramble() {
// Possible Letters
var array = new Array(" U", " D", " R", " L", " F", " B")
// Possible switches
var switches = ["", "\'", "2"];
var array2 = new Array(); // The Scramble.
var last = ''; // Last used letter
var random = 0;
for (var i = 0; i < 20; i++) {
// the following loop runs until the last one
// letter is another of the new one
do {
random = Math.floor(Math.random() * array.length);
} while (last == array[random])
// assigns the new one as the last one
last = array[random];
// the scramble item is the letter
// with (or without) a switch
var scrambleItem = array[random] + switches[parseInt(Math.random()*switches.length)];
array2.push(scrambleItem); // Get letters in random order in the array.
}
var scramble = "Scramble: ";
// Appends all scramble items to scramble variable
for(i=0; i<20; i++) {
scramble += array2[i];
}
document.getElementById("Scramble").innerHTML = scramble; // Display the scramble
}
<div id="Scramble"></div>
Hope it helps.

Categories