Skip to content

Commit 31e4a4e

Browse files
committed
life
1 parent 2001486 commit 31e4a4e

File tree

3 files changed

+119
-6
lines changed

3 files changed

+119
-6
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "1.0.0",
44
"private": true,
55
"scripts": {
6-
"dev": "bun ./public/index.html",
6+
"dev": "bun --hot ./public/index.html",
77
"format": "prettier --write *.html *.css"
88
},
99
"devDependencies": {

public/index.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ <h3>about</h3>
2828
<a href="https://joinsecondnature.com" target="_blank">poppy</a>, etc.).
2929
</p>
3030
</section>
31-
32-
<code>
33-
34-
</code>
35-
3631
<section id="contact">
3732
<h3>contact</h3>
3833
<a href="https://linkedin.com/in/soohoonchoi" target="_blank">linkedin</a> .
@@ -41,6 +36,11 @@ <h3>contact</h3>
4136
<span>soohoonchoi [at] gmail [dot] com</span>
4237
</section>
4338
</main>
39+
<footer>
40+
<code id="life">
41+
<script src="life.js"></script>
42+
</code>
43+
</footer>
4444
</body>
4545

4646
</html>

public/life.js

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* < 2 neighbors: die
3+
* 2 <= x <= 3: live
4+
* > 3: die
5+
* dead and 3 neighbor -> live
6+
*/
7+
const targetElement = document.getElementById('life')
8+
9+
const PADDING = 5
10+
const DISPLAY_WIDTH = 48
11+
const DISPLAY_HEIGHT = 24
12+
const WIDTH = DISPLAY_WIDTH + 2 * PADDING
13+
const HEIGHT = DISPLAY_HEIGHT + 2 * PADDING
14+
15+
const BLOCK = "#"
16+
const SPACE = "."
17+
const NEWLINE = "<br />"
18+
const DIRECTIONS = [
19+
[1, 0],
20+
[-1, 0],
21+
[0, 1],
22+
[0, -1],
23+
[1, 1],
24+
[1, -1],
25+
[-1, 1],
26+
[-1, -1]
27+
];
28+
let state = Array(HEIGHT).fill().map(() => Array(WIDTH).fill(SPACE))
29+
// glider generator
30+
state[PADDING + 5][PADDING + 1] = BLOCK
31+
state[PADDING + 5][PADDING + 2] = BLOCK
32+
state[PADDING + 6][PADDING + 1] = BLOCK
33+
state[PADDING + 6][PADDING + 2] = BLOCK
34+
35+
state[PADDING + 3][PADDING + 13] = BLOCK
36+
state[PADDING + 3][PADDING + 14] = BLOCK
37+
state[PADDING + 4][PADDING + 12] = BLOCK
38+
state[PADDING + 5][PADDING + 11] = BLOCK
39+
state[PADDING + 6][PADDING + 11] = BLOCK
40+
state[PADDING + 7][PADDING + 11] = BLOCK
41+
state[PADDING + 8][PADDING + 12] = BLOCK
42+
state[PADDING + 9][PADDING + 13] = BLOCK
43+
state[PADDING + 9][PADDING + 14] = BLOCK
44+
45+
state[PADDING + 6][PADDING + 15] = BLOCK
46+
47+
state[PADDING + 4][PADDING + 16] = BLOCK
48+
state[PADDING + 5][PADDING + 17] = BLOCK
49+
state[PADDING + 6][PADDING + 17] = BLOCK
50+
state[PADDING + 6][PADDING + 18] = BLOCK
51+
state[PADDING + 7][PADDING + 17] = BLOCK
52+
state[PADDING + 8][PADDING + 16] = BLOCK
53+
54+
state[PADDING + 3][PADDING + 21] = BLOCK
55+
state[PADDING + 3][PADDING + 22] = BLOCK
56+
state[PADDING + 4][PADDING + 21] = BLOCK
57+
state[PADDING + 4][PADDING + 22] = BLOCK
58+
state[PADDING + 5][PADDING + 21] = BLOCK
59+
state[PADDING + 5][PADDING + 22] = BLOCK
60+
61+
state[PADDING + 2][PADDING + 23] = BLOCK
62+
state[PADDING + 6][PADDING + 23] = BLOCK
63+
state[PADDING + 1][PADDING + 25] = BLOCK
64+
state[PADDING + 2][PADDING + 25] = BLOCK
65+
state[PADDING + 6][PADDING + 25] = BLOCK
66+
state[PADDING + 7][PADDING + 25] = BLOCK
67+
68+
state[PADDING + 3][PADDING + 35] = BLOCK
69+
state[PADDING + 3][PADDING + 36] = BLOCK
70+
state[PADDING + 4][PADDING + 35] = BLOCK
71+
state[PADDING + 4][PADDING + 6] = BLOCK
72+
73+
let lifeInterval = setInterval(() => {
74+
const displayState = state.slice(PADDING, PADDING + DISPLAY_HEIGHT).map(row =>
75+
row.slice(PADDING, PADDING + DISPLAY_WIDTH)
76+
)
77+
targetElement.innerHTML = NEWLINE + displayState.map(row => row.join('')).join(NEWLINE)
78+
let new_state = Array(HEIGHT).fill().map(() => Array(WIDTH).fill(SPACE))
79+
for (let i = 1; i < HEIGHT - 1; i += 1) {
80+
for (let j = 1; j < WIDTH - 1; j += 1) {
81+
let alive = state[i][j] === BLOCK
82+
let count = DIRECTIONS.reduce((acc, [di, dj]) => {
83+
return acc + (state[i + di][j + dj] === BLOCK ? 1 : 0)
84+
}, 0)
85+
new_state[i][j] = ((alive && (count === 2 || count === 3)) || (!alive && count === 3)) ? BLOCK : SPACE
86+
}
87+
}
88+
state = new_state
89+
}, 100)
90+
91+
const handleInteraction = (e) => {
92+
const rect = targetElement.getBoundingClientRect()
93+
const touch = e.touches ? e.touches[0] : e
94+
const x = touch.clientX - rect.left
95+
const y = touch.clientY - rect.top
96+
const charWidth = rect.width / DISPLAY_WIDTH
97+
const charHeight = rect.height / DISPLAY_HEIGHT
98+
99+
const col = Math.floor(x / charWidth)
100+
const row = Math.floor(y / charHeight)
101+
102+
if (row >= 0 && row < DISPLAY_HEIGHT && col >= 0 && col < DISPLAY_WIDTH) {
103+
state[row + PADDING][col + PADDING] = BLOCK
104+
}
105+
}
106+
107+
targetElement.addEventListener('mousemove', handleInteraction)
108+
targetElement.addEventListener('touchmove', handleInteraction)
109+
targetElement.addEventListener('touchstart', handleInteraction)
110+
111+
window.addEventListener('pagehide', () => {
112+
clearInterval(lifeInterval)
113+
})

0 commit comments

Comments
 (0)