Skip to content

Commit 8063328

Browse files
committed
Finished
0 parents  commit 8063328

21 files changed

+19379
-0
lines changed

game-of-life-ui.js

+104
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

game-of-life-ui.js.map

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

game-of-life-ui.ts

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/// <reference path="game-of-life.ts" />
2+
namespace Jason {
3+
4+
let grid: boolean[][] = [];
5+
let gameOfLife: GameOfLife | null = null;
6+
7+
let iterateTimer = 0;
8+
9+
/**
10+
* Get the timeout ms set by the user.
11+
*/
12+
function ms(): number {
13+
return $('#ms').val() as number;
14+
}
15+
16+
/**
17+
* Start the timer and enable/disable buttons.
18+
*/
19+
function start() {
20+
iterateTimer = setInterval(iterate, ms());
21+
$('#start').attr('disabled', 'disabled');
22+
$('#stop').removeAttr('disabled');
23+
}
24+
25+
/**
26+
* Stop the timer and enable/disable buttons.
27+
*/
28+
function stop() {
29+
clearInterval(iterateTimer);
30+
$('#stop').attr('disabled', 'disabled');
31+
$('#start').removeAttr('disabled');
32+
}
33+
34+
/**
35+
* Set the game of life to the next iteration, and re-draw the grid.
36+
* If the game of life is null, start it.
37+
*/
38+
function iterate() {
39+
if(gameOfLife == null) {
40+
gameOfLife = new GameOfLife(grid);
41+
gameOfLife = gameOfLife.nextIteration();
42+
}
43+
else {
44+
gameOfLife = gameOfLife.nextIteration();
45+
}
46+
47+
grid = gameOfLife.gridCopy();
48+
buildGrid(false);
49+
}
50+
51+
/**
52+
* Handle the onClick event for a table cell.
53+
* Change the grid and flip the color.
54+
*/
55+
function tableOnClick(x: number, y: number): void {
56+
let newLife = !grid[y][x];
57+
grid[y][x] = newLife;
58+
59+
let $td = $(`#${x}x${y}`);
60+
61+
if(newLife)
62+
$td.attr('class', 'live');
63+
else
64+
$td.attr('class', 'dead');
65+
}
66+
67+
/**
68+
* Build an HTML cell for an x/y pair.
69+
*/
70+
function $buildHtmlCell(x: number, y: number): JQuery<HTMLElement> {
71+
let idString = `${x}x${y}`;
72+
let tdClass = "dead";
73+
if(y < grid.length && x < grid[0].length && grid[y][x])
74+
tdClass = 'live';
75+
76+
let cell = $('<td>', {id: idString, class: tdClass});
77+
cell.on('click', () => tableOnClick(x,y) );
78+
79+
return cell;
80+
}
81+
82+
/**
83+
* Construct and set the table element and the internal grid structure.
84+
*/
85+
function buildGrid(clearGrid: boolean): void {
86+
let $table = $('<table>');
87+
if(clearGrid) {
88+
gameOfLife = null;
89+
grid = [];
90+
}
91+
92+
let width: number = $('#width').val() as number;
93+
let height: number = $('#height').val() as number;
94+
95+
for(let y = 0; y < height; y++) {
96+
let $rowHTML = $('<tr>');
97+
let rowData: boolean[] = [];
98+
99+
for(let x = 0; x < width; x++) {
100+
$rowHTML.append($buildHtmlCell(x, y));
101+
rowData.push(false);
102+
}
103+
104+
$table.append($rowHTML);
105+
grid.push(rowData);
106+
}
107+
108+
$('#table').html('')
109+
$('#table').append($table)
110+
}
111+
112+
window.onload = function() {
113+
buildGrid(true);
114+
$('#width').on('input',() => buildGrid(true));
115+
$('#height').on('input',() => buildGrid(true));
116+
$('#iterate').on('click',iterate);
117+
$('#start').on('click', start);
118+
$('#stop').attr('disabled', 'disabled');
119+
$('#stop').on('click', stop);
120+
$('#clear').on('click', () => buildGrid(true));
121+
}
122+
}

game-of-life.css

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
table {
2+
border-collapse: collapse;
3+
}
4+
5+
td {
6+
width: 25px;
7+
height: 25px;
8+
}
9+
10+
.live {
11+
background-color: rgb(0,150,0);
12+
}
13+
14+
.live:hover {
15+
background-color: rgb(0,220,0);
16+
}
17+
18+
.dead {
19+
background-color: rgb(50,50,50);
20+
}
21+
22+
.dead:hover {
23+
background-color: rgb(90,90,90);
24+
}

game-of-life.html

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<html>
2+
<head>
3+
<title>The Game of Life</title>
4+
<link rel="stylesheet" href="game-of-life.css">
5+
<script src="jquery.js"></script>
6+
<script src="grid.js"></script>
7+
<script src="game-of-life.js"></script>
8+
<script src="game-of-life-ui.js"></script>
9+
</head>
10+
<body>
11+
<form>
12+
Width: <input type="number" id="width" min="3" max="99" value="15"><br>
13+
Height: <input type="number" id="height" min="3" max="99" value="15"><br>
14+
Timeout (ms): <input type="number" id="ms" min="5" max="1000" value="200"><br>
15+
</form>
16+
<button id="iterate">Iterate</button>
17+
<button id="start">Start</button>
18+
<button id="stop">Stop</button>
19+
<button id="clear">Clear</button>
20+
<div id="table"></div>
21+
</body>
22+
</html>

game-of-life.js

+57
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

game-of-life.js.map

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

game-of-life.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/// <reference path="grid.ts" />
2+
namespace Jason {
3+
/**
4+
* Represents an immutable state in Conway's game of life, based on Grid.
5+
* Call the iterate() method to get the next state.
6+
*
7+
* True is a live cell, false is a dead cell.
8+
*/
9+
export class GameOfLife extends Grid<boolean> {
10+
11+
/**
12+
* Get the number of live neighbors to a cell.
13+
*/
14+
numLiveNeighbors(x: number, y: number): number {
15+
return this.neighbors(x,y).filter( (cell) => cell[0] ).length;
16+
}
17+
18+
/**
19+
* Get the state of a cell in the next iteration.
20+
* 0-1 & live: Dead
21+
* 2-3 & live: Live
22+
* 4+ & live: Dead
23+
* 3 & dead: Live
24+
*/
25+
nextState(x: number, y: number, state: boolean | null): boolean {
26+
let numLiveNeighbors = this.numLiveNeighbors(x,y);
27+
if(state == null)
28+
state = this.at(x,y);
29+
30+
if(!state)
31+
return numLiveNeighbors == 3;
32+
else
33+
return numLiveNeighbors == 2 || numLiveNeighbors == 3;
34+
}
35+
36+
/**
37+
* Get the next iteration in the game of life.
38+
*/
39+
nextIteration(): GameOfLife {
40+
return new GameOfLife(this.map(this.nextState.bind(this)));
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)