Wordle-styled game of life
Created for https://twitter.com/piannaf/status/1483070891961499651
by piannaf
HTML
<div ng-app="myApp" ng-controller="Ctrl">
<h1>AngularJS Game of Life</h1>
Height: <input type="text" size="3" ng-model="height"/>
Width: <input type="text" size="3" ng-model="width"/>
<button ng-click="newGame()">New</button>
<button ng-click="next()">Next</button>
<button ng-click="play()">Play</button>
<table id="board">
<tr ng-repeat="row in board">
<td ng-repeat="cell in row" ng-click="toggle($parent.$index, $index)"
class="{{cellClass($parent.$index, $index)}}">
<span ng-show="cell"></span>
</td>
</tr>
</table>
<p class="history" ng-show="history.length > 0">Previous steps (click to rewind)</p>
<table class="history">
<tr>
<td ng-repeat="step in history" ng-click="$parent.step($index)">{{$index}}</td>
</tr>
</table>
</div>
CSS
body {
background-color: #121213;
color: #d7dadc;
}
h1 {
font-size: 1.3em;
font-style: bold;
}
table {
border-spacing: 5px;
border-collapse: separate;
}
table#board td {
width: 40px;
height: 40px;
text-align: center;
vertical-align: middle;
border: solid 1px #3a3a3c;
}
table#board td.new {
background-color: #b59f3b;
}
table#board td.die {
background-color: #3a3a3c;
}
table#board td.alive {
background-color: #538d4e;
}
table#board td.empty {
background-color: #121213;
}
.history {
color: #777;
}
table.history td {
width: 1.5em;
height: 1.5em;
text-align: center;
vertical-align: middle;
border: solid 1px #eee;
}
JavaScript
angular.module('myApp', []);
function Ctrl($scope, $timeout) {
var play = function() {
$scope.next();
$timeout(play, 500);
}
$scope.newGame = function () {
$scope.history = [];
$scope.board = init($scope.height, $scope.width);
};
$scope.next = function () {
$scope.history.push($scope.board);
$scope.board = computeNext($scope.board);
};
$scope.play = function () {
$timeout(play, 500);
}
$scope.step = function (index) {
$scope.board = $scope.history[index];
$scope.history = $scope.history.slice(0, index);
};
$scope.toggle = function (row, cell) {
$scope.history = []; // Reset history as it is no longer accurate
$scope.board[row][cell] = !$scope.board[row][cell];
};
$scope.cellClass = function (row, cell) {
if (willDie($scope.board, row, cell)) {
return "die";
}
if (newCell($scope.board, row, cell)) {
return "new";
}
if (cellAt($scope.board, row, cell)) {
return "alive"
}
return "empty";
};
$scope.height = 6;
$scope.width = 5;
$scope.newGame();
function init(height, width) {
var board = [];
for (var h = 0 ; h < height ; h++) {
var row = [];
for (var w = 0 ; w < width ; w++) {
row.push(false);
}
board.push(row);
}
return board;
}
function computeNext(board) {
var newBoard = [];
for (var r = 0 ; r < board.length ; r++) {
var newRow = [];
for (var c = 0 ; c < board[r].length ; c++) {
newRow.push(willLive(board, r, c) || newCell(board, r, c));
}
newBoard.push(newRow);
}
return newBoard;
}
function willLive(board, row, cell) {
return cellAt(board, row, cell)
...