Conway's Game of Life as a React web app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Board.tsx 3.0KB

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