Skip to content

Instantly share code, notes, and snippets.

@toddlemoine
Created January 25, 2020 18:36
Show Gist options
  • Save toddlemoine/1d2949d96373e249f3c49bc2326b90d7 to your computer and use it in GitHub Desktop.
Save toddlemoine/1d2949d96373e249f3c49bc2326b90d7 to your computer and use it in GitHub Desktop.
One take on Conway's Game of Life in JS and React
import React from "react";
import "./styles.css";
function randomState() {
return Math.floor(Math.random() * Math.floor(2));
}
function createCell() {
const alive = randomState();
return { alive };
}
function countNeighbors(index, coll, cols) {
const [prevRow, nextRow] = [index - cols, index + cols];
const neighborIndexes = [
prevRow - 1,
prevRow,
prevRow + 1,
index - 1,
index + 1,
nextRow - 1,
nextRow,
nextRow + 1
];
return neighborIndexes.reduce((acc, i) => {
const neighbor = coll[i];
if (!neighbor) {
return acc;
}
return neighbor.alive ? acc + 1 : acc;
}, 0);
}
function applyRules(cell, numNeighbors) {
if (cell.alive) {
return { alive: numNeighbors === 2 || numNeighbors === 3 };
} else {
return { alive: numNeighbors === 3 };
}
}
function nextState(state, { rows, cols }) {
if (!state) {
return {
cells: [...Array(rows * cols)].map(createCell)
};
}
return {
cells: state.cells.map((cell, index) =>
applyRules(cell, countNeighbors(index, state.cells, cols))
)
};
}
function Cell({ alive }) {
return <td className={alive ? "alive" : "dead"} />;
}
function splitCellsIntoRows(cells, numRows, numCols) {
const rows = [];
for (let i = 0; i < numRows; i++) {
const start = i * numCols;
const row = cells.slice(start, start + numCols);
rows.push(row);
}
return rows;
}
class Game extends React.Component {
constructor(props) {
super();
this.state = nextState(null, props);
}
advance = () => {
this.setState(nextState(this.state, this.props));
};
reset = () => {
this.setState(nextState(null, this.props));
};
start = () => {
this.intervalId = setInterval(this.advance, 50);
};
stop = () => {
clearInterval(this.intervalId);
};
render() {
const { cells } = this.state;
const { cols, rows } = this.props;
const gridRows = splitCellsIntoRows(cells, rows, cols);
return (
<div>
<button onClick={this.reset}>Reset</button>
<button onClick={this.start}>Start</button>
<button onClick={this.stop}>Stop</button>
<table>
<tbody>
{gridRows.map((row, rowIndex) => (
<tr key={rowIndex}>
{row.map((cell, cellIndex) => (
<Cell key={cellIndex} alive={cell.alive} />
))}
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default function App() {
return (
<div className="App">
<Game rows={50} cols={50} />
</div>
);
}
.App {
font-family: sans-serif;
text-align: center;
}
table {
border: 1px solid gray;
border-collapse: collapse;
}
td {
border: 1px solid #f2f2f2;
width: 10px;
height: 10px;
padding: 0;
}
.alive {
background: skyblue;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment