Browse Source

Make it go

master
Dylan Baker 3 years ago
parent
commit
e09c69e02e
4 changed files with 134 additions and 29 deletions
  1. 84
    25
      src/Board.tsx
  2. 7
    4
      src/Cell.tsx
  3. 4
    0
      src/index.css
  4. 39
    0
      src/lib.ts

+ 84
- 25
src/Board.tsx View File

@@ -1,46 +1,105 @@
1
-import React, { useState } from 'react';
1
+import React from 'react';
2 2
 import Cell from './Cell';
3 3
 import Controls from './Controls';
4
+import { countLivingNeighbors } from './lib';
4 5
 
5 6
 interface Props {
6 7
   width?: number;
7 8
   height?: number;
9
+  speed?: number;
8 10
 }
9 11
 
10
-const Board = (props: Props) => {
11
-  const width = props.width ?? 5;
12
-  const height = props.height ?? 5;
12
+interface State {
13
+  grid: boolean[][];
14
+  running: boolean;
15
+}
16
+
17
+class Board extends React.Component<Props, State> {
18
+  timer: NodeJS.Timeout | null;
19
+
20
+  constructor(props: Props) {
21
+    super(props);
22
+    const height = props.height ?? 5;
23
+    const width = props.height ?? 5;
24
+    this.state = {
25
+      grid: Array(height).fill(Array(width).fill(false)),
26
+      running: false,
27
+    };
28
+    this.timer = null;
29
+  }
30
+
31
+  start = () => {
32
+    this.timer = setInterval(() => {
33
+      console.log('Iterating');
34
+      const { grid } = this.state;
35
+      const newGrid = [...grid].map((row, y) => {
36
+        const newRow = [...row].map((cell, x) => {
37
+          const isAlive = cell;
38
+          const livingNeighbors = countLivingNeighbors(grid, x, y);
39
+
40
+          if (isAlive) {
41
+            if (livingNeighbors === 2 || livingNeighbors === 3) {
42
+              return true;
43
+            } else {
44
+              return false;
45
+            }
46
+          } else {
47
+            if (livingNeighbors === 3) {
48
+              return true;
49
+            }
50
+          }
13 51
 
14
-  const initialGrid: boolean[][] = Array(height).fill(Array(width).fill(false));
52
+          return isAlive;
53
+        });
15 54
 
16
-  const [grid, setGrid] = useState<boolean[][]>(initialGrid);
55
+        return newRow;
56
+      });
17 57
 
18
-  const [running, setRunning] = useState<boolean>(false);
58
+      this.setState({ grid: newGrid });
59
+    }, 500);
60
+  };
61
+
62
+  stop = () => {
63
+    if (this.timer) clearInterval(this.timer);
64
+  };
19 65
 
20
-  const toggleCell = (x: number, y: number) => {
21
-    const newGrid = [...grid];
66
+  toggleCell = (x: number, y: number) => {
67
+    const newGrid = [...this.state.grid];
22 68
     const newRow = [...newGrid[y]];
23 69
     newRow[x] = !newGrid[y][x];
24 70
     newGrid[y] = newRow;
25
-    setGrid(newGrid);
71
+    this.setState({ grid: newGrid });
26 72
   };
27 73
 
28
-  const toggleRunning = () => {
29
-    setRunning(!running);
74
+  toggleRunning = () => {
75
+    if (this.state.running) this.stop();
76
+    if (!this.state.running) this.start();
77
+    this.setState({ running: !this.state.running });
30 78
   };
31 79
 
32
-  return (
33
-    <div className="board">
34
-      <Controls running={running} toggle={toggleRunning} />
35
-      {grid.map((row, y) => (
36
-        <div className="row" key={y}>
37
-          {row.map((cell, x) => (
38
-            <Cell x={x} y={y} alive={cell} toggle={toggleCell} key={x} />
39
-          ))}
40
-        </div>
41
-      ))}
42
-    </div>
43
-  );
44
-};
80
+  render() {
81
+    const { grid, running } = this.state;
82
+
83
+    return (
84
+      <div className="board">
85
+        <Controls running={running} toggle={this.toggleRunning} />
86
+        {grid.map((row, y) => (
87
+          <div className="row" key={y}>
88
+            {row.map((cell, x) => (
89
+              <Cell
90
+                disabled={running}
91
+                x={x}
92
+                y={y}
93
+                alive={cell}
94
+                toggle={this.toggleCell}
95
+                key={x}
96
+              />
97
+            ))}
98
+          </div>
99
+        ))}
100
+      </div>
101
+    );
102
+  }
103
+}
45 104
 
46 105
 export default Board;

+ 7
- 4
src/Cell.tsx View File

@@ -3,16 +3,19 @@ import React from 'react';
3 3
 interface Props {
4 4
   x: number;
5 5
   y: number;
6
-  alive?: boolean;
6
+  alive: boolean;
7
+  disabled: boolean;
7 8
   toggle: (x: number, y: number) => void;
8 9
 }
9 10
 
10 11
 const Cell = (props: Props) => {
11
-  const { alive, toggle, x, y } = props;
12
+  const { alive, toggle, x, y, disabled } = props;
12 13
   return (
13 14
     <span
14
-      onClick={() => toggle(x, y)}
15
-      className={`cell ${alive ? 'alive' : 'dead'}`}
15
+      onClick={() => (disabled ? null : toggle(x, y))}
16
+      className={`cell ${alive ? 'alive' : 'dead'} ${
17
+        disabled ? 'nonclickable' : 'clickable'
18
+      }`}
16 19
     ></span>
17 20
   );
18 21
 };

+ 4
- 0
src/index.css View File

@@ -50,6 +50,10 @@ code {
50 50
   background: black;
51 51
 }
52 52
 
53
+.cell.clickable {
54
+  cursor: pointer;
55
+}
56
+
53 57
 .controls {
54 58
   display: flex;
55 59
   margin-bottom: 1em;

+ 39
- 0
src/lib.ts View File

@@ -0,0 +1,39 @@
1
+export const countLivingNeighbors = (
2
+  grid: boolean[][],
3
+  x: number,
4
+  y: number,
5
+): number => {
6
+  return getNeighbors(grid, x, y).filter((el) => el).length;
7
+};
8
+
9
+export const getNeighbors = (
10
+  grid: boolean[][],
11
+  x: number,
12
+  y: number,
13
+): boolean[] => {
14
+  const neighbors = [];
15
+  const height = grid.length;
16
+  const width = grid[0].length;
17
+
18
+  const isNotOnTopRow = y > 0;
19
+  const isNotOnFarLeftRow = x > 0;
20
+  const isNotOnBottomRow = y < height - 1;
21
+  const isNotOnFarRightRow = x < width - 1;
22
+
23
+  if (isNotOnTopRow) {
24
+    neighbors.push(grid[y - 1][x]); // N
25
+    if (isNotOnFarLeftRow) neighbors.push(grid[y - 1][x - 1]); // NW
26
+    if (isNotOnFarRightRow) neighbors.push(grid[y - 1][x + 1]); // NE
27
+  }
28
+
29
+  if (isNotOnFarLeftRow) neighbors.push(grid[y][x - 1]); // W
30
+  if (isNotOnFarRightRow) neighbors.push(grid[y][x + 1]); // E
31
+
32
+  if (isNotOnBottomRow) {
33
+    neighbors.push(grid[y + 1][x]); // S
34
+    if (isNotOnTopRow) neighbors.push(grid[y + 1][x - 1]); // SW
35
+    if (isNotOnFarRightRow) neighbors.push(grid[y + 1][x + 1]); // SE
36
+  }
37
+
38
+  return neighbors;
39
+};

Loading…
Cancel
Save