Skip to content

Commit fd1459f

Browse files
committed
Chapter 18
1 parent b1f4161 commit fd1459f

File tree

3 files changed

+208
-0
lines changed

3 files changed

+208
-0
lines changed

chapter-18/content-negotiation.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const fetchAs = async (url, mediaType) => {
2+
const response = await fetch(url, {
3+
headers: {
4+
Accept: mediaType,
5+
},
6+
});
7+
if (response.status !== 200) {
8+
throw new Error(`[${response.status}]: ${response.statusText}`);
9+
}
10+
return mediaType === 'application/json' ? response.json() : response.text();
11+
};
12+
13+
(async () => {
14+
try {
15+
const contentAsPlainText = await fetchAs('https://eloquentjavascript.net/author', 'text/plain');
16+
console.log(contentAsPlainText);
17+
const contentAsHtml = await fetchAs('https://eloquentjavascript.net/author', 'text/html');
18+
console.log(contentAsHtml);
19+
const contentAsJson = await fetchAs('https://eloquentjavascript.net/author', 'application/json');
20+
console.log(contentAsJson);
21+
const contentAsRainbowsUnicorns = await fetchAs(
22+
'https://eloquentjavascript.net/author',
23+
'application/rainbows+unicorns'
24+
);
25+
console.log(contentAsRainbowsUnicorns);
26+
} catch (e) {
27+
console.log(e);
28+
}
29+
})();

chapter-18/game-of-life.html

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<div id="rules">
2+
<p>
3+
The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John
4+
Horton Conway in 1970.[1] It is a zero-player game,[2][3] meaning that its evolution is determined by its initial
5+
state, requiring no further input. One interacts with the Game of Life by creating an initial configuration and
6+
observing how it evolves. It is Turing complete and can simulate a universal constructor or any other Turing
7+
machine.
8+
</p>
9+
<p>
10+
Rules:
11+
<ol>
12+
<li>Any live cell with two or three live neighbours survives.</li>
13+
<li>Any dead cell with three live neighbours becomes a live cell.</li>
14+
<li>All other live cells die in the next generation. Similarly, all other dead cells stay dead.</li>
15+
</ol>
16+
</p>
17+
</div>
18+
<div id="settings">
19+
<label for="size">Grid size: </label>
20+
<input type="text" id="size" />
21+
<button id="start">Start</button>
22+
</div>
23+
<div id="game" style="display: none">
24+
<div style="display: flex; gap: 10px; margin-bottom: 15px">
25+
<div style="display: none">
26+
<label for="previous-grid">Previous state</label>
27+
<fieldset id="previous-grid" disabled style="border: solid 1px black"></fieldset>
28+
</div>
29+
<div>
30+
<label for="grid">Current state</label>
31+
<fieldset id="grid" style="border: solid 1px black"></fieldset>
32+
</div>
33+
</div>
34+
<button id="next">Next generation</button>
35+
<button id="auto">Auto</button>
36+
</div>
37+
38+
<script>
39+
const gameOfLife = (size) => {
40+
const state = [...Array(size)].map(() => [...Array(size)].map(() => Math.floor(Math.random() * 2)));
41+
42+
function draw(container) {
43+
// First empty the container
44+
while (container.firstChild) {
45+
container.removeChild(container.firstChild);
46+
}
47+
const { state } = this;
48+
49+
for (let i = 0; i < state.length; i++) {
50+
const row = state[i];
51+
const rowDiv = document.createElement('div');
52+
for (let j = 0; j < row.length; j++) {
53+
const cell = row[j];
54+
const checkbox = document.createElement('input');
55+
checkbox.type = 'checkbox';
56+
checkbox.checked = !!cell;
57+
checkbox.addEventListener('change', () => {
58+
state[i][j] = checkbox.checked ? 1 : 0;
59+
});
60+
rowDiv.appendChild(checkbox);
61+
}
62+
container.appendChild(rowDiv);
63+
}
64+
}
65+
66+
function next() {
67+
const nextState = [...Array(size)].map(() => [...Array(size)]);
68+
const { state } = this;
69+
70+
for (let i = 0; i < state.length; i++) {
71+
const prevRow = state[i - 1] ?? [];
72+
const row = state[i];
73+
const nextRow = state[i + 1] ?? [];
74+
for (let j = 0; j < row.length; j++) {
75+
const liveNeighbors =
76+
(prevRow[j - 1] ?? 0) +
77+
(prevRow[j] ?? 0) +
78+
(prevRow[j + 1] ?? 0) +
79+
(row[j - 1] ?? 0) +
80+
(row[j + 1] ?? 0) +
81+
(nextRow[j - 1] ?? 0) +
82+
(nextRow[j] ?? 0) +
83+
(nextRow[j + 1] ?? 0);
84+
// Cell keeps living if it has 2 or 3 neighbors alive.
85+
// Dead cell becomes alive with 3 live neighbors.
86+
nextState[i][j] = (liveNeighbors === 2 && row[j]) || liveNeighbors === 3 ? 1 : 0;
87+
}
88+
}
89+
90+
return {
91+
state: nextState,
92+
draw,
93+
next,
94+
};
95+
}
96+
97+
return {
98+
state,
99+
draw,
100+
next,
101+
};
102+
};
103+
104+
const startBtn = document.querySelector('#start');
105+
startBtn.addEventListener('click', () => {
106+
const sizeInput = document.querySelector('#size');
107+
const gridSize = Number(sizeInput.value);
108+
if (gridSize === 0 || isNaN(gridSize)) {
109+
alert("Please enter a number for 'Grid size'");
110+
return;
111+
}
112+
const settingsDiv = document.querySelector('#settings');
113+
settingsDiv.remove();
114+
115+
const gameDiv = document.querySelector('#game');
116+
gameDiv.style.display = 'block';
117+
118+
const previousGrid = document.querySelector('#previous-grid');
119+
const currentGrid = document.querySelector('#grid');
120+
let game = gameOfLife(gridSize);
121+
122+
function cycleGame() {
123+
game.draw(previousGrid);
124+
game = game.next();
125+
game.draw(currentGrid);
126+
}
127+
128+
cycleGame();
129+
130+
const nextBtn = document.querySelector('#next');
131+
nextBtn.addEventListener('click', () => {
132+
previousGrid.parentNode.style.display = 'block';
133+
cycleGame();
134+
});
135+
136+
const autoBtn = document.querySelector('#auto');
137+
let running = false;
138+
let interval;
139+
autoBtn.addEventListener('click', () => {
140+
if (running) {
141+
currentGrid.disabled = false;
142+
nextBtn.disabled = false;
143+
autoBtn.textContent = 'Auto';
144+
clearInterval(interval);
145+
running = false;
146+
} else {
147+
currentGrid.disabled = true;
148+
nextBtn.disabled = true;
149+
autoBtn.textContent = 'Stop';
150+
cycleGame();
151+
interval = setInterval(() => {
152+
cycleGame();
153+
}, 2000);
154+
running = true;
155+
}
156+
});
157+
});
158+
</script>

chapter-18/javascript-workbench.html

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<textarea id="code">return "hi";</textarea>
2+
<button id="button">Run</button>
3+
<pre id="output"></pre>
4+
5+
<script>
6+
const button = document.querySelector('#button');
7+
const editor = document.querySelector('#code');
8+
const output = document.querySelector('#output');
9+
10+
const isObject = (value) => value !== null && typeof value === 'object';
11+
button.addEventListener('click', () => {
12+
try {
13+
const fn = Function(editor.value);
14+
const returnValue = fn();
15+
// Javascript Arrays are also objects, but it doesn't matter because it is safe to use stringify on them
16+
output.textContent = isObject(returnValue) ? JSON.stringify(returnValue) : String(returnValue);
17+
} catch (e) {
18+
output.textContent = e.message;
19+
}
20+
});
21+
</script>

0 commit comments

Comments
 (0)