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>