-
Notifications
You must be signed in to change notification settings - Fork 0
/
github-game-of-life.js
125 lines (105 loc) · 3.69 KB
/
github-game-of-life.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// GitHub Game of Life - 1.0.4
// Chris Johnson
// @defaced / defaced.dev / github.com/workeffortwaste
(function () {
const startGgol = () => {
// Settings
const cols = 7
const rows = 53
// Pull down the contributions from the graph.
const contributions = document.getElementsByClassName('js-calendar-graph')[0].children[0].querySelectorAll('tbody tr')
// Read contributions as rows from the contribution frame.
const readContributions = (contributions) => {
// Init output Arr.
const output = []
for (const contribution of contributions) {
const days = contribution.getElementsByTagName('td')
const lifeRow = []
for (const day of days) {
// Convert to live or dead cells.
lifeRow.push(day.getAttribute('data-level') > 0 ? 1 : 0)
}
// Add column to output.
output.push(lifeRow)
}
//Fill in any blanks in the first and last rows.
for (let i = 0; i < 54; i++) {
if (!output[0][i]) {
output[0][i] = 0
}
if (!output[output.length - 1][i]) {
output[output.length - 1][i] = 0
}
}
return output
}
// Our initial game of life state.
let lifeArray = readContributions(contributions)
// Write to the contributions graphic.
const writeContributions = (contributions, nextGenerationArray) => {
for (let i = 0; i < contributions.length; i++) {
const days = contributions[i].getElementsByTagName('td')
for (let d = 0; d < 54; d++) { // Magic number - 7 days of the week.
if (document.getElementsByTagName('html')[0].getAttribute('data-color-mode') === 'dark') {
try { days[d].setAttribute('data-level', nextGenerationArray[i][d] ? '2' : '0') } catch {}
} else {
try { days[d].setAttribute('data-level', nextGenerationArray[i][d] ? '2' : '0') } catch {}
}
}
}
}
const countNeighbors = (grid, x, y) => {
let sum = 0
for (let i = -1; i < 2; i++) {
for (let j = -1; j < 2; j++) {
const col = (x + i + cols) % cols
const row = (y + j + rows) % rows
sum += grid[col][row]
}
}
sum -= grid[x][y]
return sum
}
const generateNextIteration = (grid) => {
// Make empty array
const next = [...Array(7)].map(e => Array(54))
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
const state = grid[i][j]
const neighbors = countNeighbors(grid, i, j)
if (state === 0 && neighbors === 3) {
next[i][j] = 1
} else if (state === 1 && (neighbors < 2 || neighbors > 3)) {
next[i][j] = 0
} else {
next[i][j] = state
}
}
}
return next
}
const update = () => {
// Generate the next iteration.
const next = generateNextIteration(lifeArray)
// If the output is the same as the input we've reached a stable state so kill the interval.
if (JSON.stringify(next) === JSON.stringify(lifeArray)) {
clearInterval(timer)
}
// Update the lifeArray with the next generation.
lifeArray = next
writeContributions(contributions, lifeArray)
}
// Update every 500 ms.
const timer = setInterval(function () { update() }, 500)
}
const observerGgol = (entry) => {
if (entry[0].intersectionRatio > 0) {
// Kill the observer.
observer.disconnect()
// Start the game of life.
startGgol()
}
}
const observer = new IntersectionObserver(observerGgol)
try { observer.observe(document.getElementsByClassName('js-calendar-graph')[0]) } catch {}
})()