Simple implementation of Conway's Game of Life in AngularJs. http://en.wikipedia.org/wiki/Conway's_Game_of_Life
github.com/alanrsoares
A Pen by Alan R. Soares on CodePen.
Simple implementation of Conway's Game of Life in AngularJs. http://en.wikipedia.org/wiki/Conway's_Game_of_Life
github.com/alanrsoares
A Pen by Alan R. Soares on CodePen.
| <html ng-app='app'> | |
| <head> | |
| <meta name="description" content="AngularJs solution for Conway's Game of Life - http://en.wikipedia.org/wiki/Conway's_Game_of_Life" /> | |
| <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script> | |
| <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.css"/> | |
| <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.2.0/slate/bootstrap.min.css" /> | |
| <meta charset="utf-8"> | |
| <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" /> | |
| </head> | |
| <body> | |
| <div class="container" ng-controller='GameController as vm'> | |
| <div class="page-header text-center"> | |
| <h1> | |
| <span class="text-muted">Conway's</span> Game of Life | |
| </h1> | |
| </div> | |
| <div> | |
| <div class="buttons-container"> | |
| <button class="btn btn-primary" | |
| ng-disabled="!vm.thumbs.length" | |
| ng-click="vm.reset()"> | |
| NEW | |
| </button> | |
| <button class="btn btn-success" | |
| ng-click="vm.save()"> | |
| SAVE | |
| </button> | |
| <button class='btn btn-default' | |
| ng-show="!vm.isStarted" | |
| ng-click="vm.life.next()"> | |
| NEXT | |
| </button> | |
| <label for="autoplay" class="btn btn-default"> | |
| <input id="autoplay" type="checkbox" | |
| ng-model="vm.isStarted" | |
| ng-change="vm.togglePlay()"> Autoplay | |
| </label> | |
| </div> | |
| </div> | |
| <table class='grid'> | |
| <tr ng-repeat="row in vm.board"> | |
| <td ng-repeat="cell in row" | |
| ng-class="{'alive':cell.isAlive}" | |
| ng-click="cell.toggle()"> | |
| </td> | |
| </tr> | |
| </table> | |
| <div class="thumbs-container"> | |
| <div class="thumb-container" | |
| ng-repeat="thumb in vm.thumbs"> | |
| <div> | |
| <table class="grid-thumb" | |
| ng-click="vm.load(thumb)"> | |
| <tr ng-repeat="row in thumb"> | |
| <td ng-repeat="cell in row" | |
| ng-class="{'alive':cell.isAlive}"> | |
| </td> | |
| </tr> | |
| </table> | |
| </div> | |
| <div class="icon-close-thumb" ng-click="vm.thumbs.splice($index,1)"> | |
| <i class="fa fa-trash"></i> | |
| <span class='text-small'>delete</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </body> | |
| </html> |
| //app.js | |
| (function(){ | |
| 'use strict'; | |
| angular.module('app', ['app.controllers']); | |
| }()); | |
| //app.controllers.js | |
| (function(){ | |
| 'use strict'; | |
| var app = angular.module('app.controllers', ['app.services']); | |
| app.controller('GameController',GameController); | |
| GameController.$inject = ['$interval','board','life']; | |
| function GameController($interval, board, life){ | |
| var vm = this; | |
| vm.thumbs = []; | |
| vm.reset = reset; | |
| vm.interval = 300; | |
| vm.load = load; | |
| vm.togglePlay = togglePlay; | |
| vm.save = save; | |
| function togglePlay(){ | |
| if(!vm.isStarted && vm.timer){ | |
| $interval.cancel(vm.timer); | |
| vm.isStarted = false; | |
| return; | |
| } | |
| vm.isStarted = true; | |
| vm.timer = $interval(vm.life.next, vm.interval); | |
| } | |
| function save(){ | |
| var board = angular.copy(vm.board); | |
| console.log(board); | |
| vm.thumbs.push(board); | |
| } | |
| function load(thumb){ | |
| reset(); | |
| vm.life = life.createNew(thumb); | |
| vm.board = vm.life.board; | |
| } | |
| function reset(){ | |
| if(vm.isStarted) vm.togglePlay(); | |
| var seed = board.createNew(15); | |
| vm.life = life.createNew(seed); | |
| vm.board = vm.life.board; | |
| vm.isStarted = false; | |
| } | |
| (function activate(){ | |
| reset(); | |
| vm.life = life.createNew(window.initialSeed); | |
| vm.board = vm.life.board; | |
| vm.togglePlay(); | |
| }()); | |
| } | |
| }()); | |
| //app.services.js | |
| (function(){ | |
| 'use strict'; | |
| var app = angular.module('app.services',[]); | |
| app.factory('cell', cell); | |
| app.factory('board', board); | |
| app.factory('life', life); | |
| function cell(){ | |
| return{ | |
| createNew: function(position, options){ | |
| return new Cell(position, options); | |
| } | |
| }; | |
| function Cell(position, options){ | |
| var defaults = { | |
| isAlive: false | |
| }; | |
| return { | |
| position: position, | |
| isAlive: options && options.isAlive, | |
| toggle: function(){this.isAlive = !this.isAlive;}, | |
| lives: function(){this.isAlive = true;}, | |
| dies: function(){this.isAlive = false;}, | |
| getAliveNeighbors: function(board){ | |
| var y = this.position.y; | |
| var x = this.position.x; | |
| var prevRow = board[y - 1] || []; | |
| var nextRow = board[y + 1] || []; | |
| var neighbors = [ | |
| prevRow[x - 1], prevRow[x], prevRow[x + 1], | |
| board[y][x - 1], board[y][x + 1], | |
| nextRow[x - 1], nextRow[x], nextRow[x + 1], | |
| ]; | |
| return neighbors.reduce(function(prev, curr) { | |
| if(curr){ | |
| return prev += +!!curr.isAlive; | |
| } | |
| return prev += 0; | |
| }, 0); | |
| } | |
| }; | |
| } | |
| } | |
| board.$inject = ['cell']; | |
| function board(cell){ | |
| return { | |
| createNew: createNew | |
| }; | |
| function createNew(size){ | |
| var newBoard = []; | |
| for(var y = 0; y < size; y++){ | |
| newBoard[y] = []; | |
| for(var x = 0; x < size; x++){ | |
| newBoard[y][x] = cell.createNew({y: y, x: x}); | |
| } | |
| } | |
| return newBoard; | |
| } | |
| } | |
| life.$inject = ['cell']; | |
| function life(cell){ | |
| return { | |
| createNew: createNew | |
| }; | |
| function createNew(seed){ | |
| var height = seed.length; | |
| var width = seed[0].length; | |
| var previousBoard = []; | |
| var board = angular.copy(seed); | |
| return{ | |
| next: next, | |
| board: board | |
| }; | |
| function newCellState(previousBoard, x, y){ | |
| var oldCell = previousBoard[y][x]; | |
| var newCell = cell.createNew(oldCell.position, {isAlive: oldCell.isAlive}); | |
| var neighbors = newCell.getAliveNeighbors(previousBoard); | |
| newCell.isAlive = newCell.isAlive | |
| ? neighbors >= 2 && neighbors <= 3 | |
| : neighbors === 3; | |
| return newCell; | |
| } | |
| function next(){ | |
| previousBoard = angular.copy(board); | |
| for (var y = 0; y < height; y++) { | |
| for (var x = 0; x < width; x++) { | |
| board[y][x] = newCellState(previousBoard, x, y); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }()); | |
| window.initialSeed = [[{"position":{"y":0,"x":0}},{"position":{"y":0,"x":1}},{"position":{"y":0,"x":2}},{"position":{"y":0,"x":3}},{"position":{"y":0,"x":4}},{"position":{"y":0,"x":5}},{"position":{"y":0,"x":6}},{"position":{"y":0,"x":7},"isAlive":false},{"position":{"y":0,"x":8}},{"position":{"y":0,"x":9}},{"position":{"y":0,"x":10}},{"position":{"y":0,"x":11}},{"position":{"y":0,"x":12}},{"position":{"y":0,"x":13}},{"position":{"y":0,"x":14}}],[{"position":{"y":1,"x":0}},{"position":{"y":1,"x":1}},{"position":{"y":1,"x":2},"isAlive":false},{"position":{"y":1,"x":3},"isAlive":true},{"position":{"y":1,"x":4},"isAlive":true},{"position":{"y":1,"x":5},"isAlive":true},{"position":{"y":1,"x":6},"isAlive":false},{"position":{"y":1,"x":7},"isAlive":false},{"position":{"y":1,"x":8}},{"position":{"y":1,"x":9},"isAlive":true},{"position":{"y":1,"x":10},"isAlive":true},{"position":{"y":1,"x":11},"isAlive":true},{"position":{"y":1,"x":12},"isAlive":false},{"position":{"y":1,"x":13}},{"position":{"y":1,"x":14}}],[{"position":{"y":2,"x":0}},{"position":{"y":2,"x":1}},{"position":{"y":2,"x":2},"isAlive":false},{"position":{"y":2,"x":3},"isAlive":false},{"position":{"y":2,"x":4},"isAlive":false},{"position":{"y":2,"x":5},"isAlive":false},{"position":{"y":2,"x":6}},{"position":{"y":2,"x":7},"isAlive":false},{"position":{"y":2,"x":8}},{"position":{"y":2,"x":9},"isAlive":false},{"position":{"y":2,"x":10},"isAlive":false},{"position":{"y":2,"x":11},"isAlive":false},{"position":{"y":2,"x":12}},{"position":{"y":2,"x":13}},{"position":{"y":2,"x":14}}],[{"position":{"y":3,"x":0}},{"position":{"y":3,"x":1},"isAlive":true},{"position":{"y":3,"x":2}},{"position":{"y":3,"x":3}},{"position":{"y":3,"x":4}},{"position":{"y":3,"x":5}},{"position":{"y":3,"x":6},"isAlive":true},{"position":{"y":3,"x":7}},{"position":{"y":3,"x":8},"isAlive":true},{"position":{"y":3,"x":9}},{"position":{"y":3,"x":10}},{"position":{"y":3,"x":11}},{"position":{"y":3,"x":12}},{"position":{"y":3,"x":13},"isAlive":true},{"position":{"y":3,"x":14}}],[{"position":{"y":4,"x":0}},{"position":{"y":4,"x":1},"isAlive":true},{"position":{"y":4,"x":2}},{"position":{"y":4,"x":3}},{"position":{"y":4,"x":4}},{"position":{"y":4,"x":5}},{"position":{"y":4,"x":6},"isAlive":true},{"position":{"y":4,"x":7}},{"position":{"y":4,"x":8},"isAlive":true},{"position":{"y":4,"x":9}},{"position":{"y":4,"x":10}},{"position":{"y":4,"x":11}},{"position":{"y":4,"x":12}},{"position":{"y":4,"x":13},"isAlive":true},{"position":{"y":4,"x":14}}],[{"position":{"y":5,"x":0}},{"position":{"y":5,"x":1},"isAlive":true},{"position":{"y":5,"x":2}},{"position":{"y":5,"x":3}},{"position":{"y":5,"x":4}},{"position":{"y":5,"x":5}},{"position":{"y":5,"x":6},"isAlive":true},{"position":{"y":5,"x":7},"isAlive":false},{"position":{"y":5,"x":8},"isAlive":true},{"position":{"y":5,"x":9}},{"position":{"y":5,"x":10}},{"position":{"y":5,"x":11}},{"position":{"y":5,"x":12}},{"position":{"y":5,"x":13},"isAlive":true},{"position":{"y":5,"x":14}}],[{"position":{"y":6,"x":0}},{"position":{"y":6,"x":1},"isAlive":false},{"position":{"y":6,"x":2}},{"position":{"y":6,"x":3},"isAlive":true},{"position":{"y":6,"x":4},"isAlive":true},{"position":{"y":6,"x":5},"isAlive":true},{"position":{"y":6,"x":6},"isAlive":false},{"position":{"y":6,"x":7}},{"position":{"y":6,"x":8},"isAlive":false},{"position":{"y":6,"x":9},"isAlive":true},{"position":{"y":6,"x":10},"isAlive":true},{"position":{"y":6,"x":11},"isAlive":true},{"position":{"y":6,"x":12}},{"position":{"y":6,"x":13},"isAlive":false},{"position":{"y":6,"x":14}}],[{"position":{"y":7,"x":0}},{"position":{"y":7,"x":1}},{"position":{"y":7,"x":2}},{"position":{"y":7,"x":3},"isAlive":false},{"position":{"y":7,"x":4},"isAlive":false},{"position":{"y":7,"x":5},"isAlive":false},{"position":{"y":7,"x":6}},{"position":{"y":7,"x":7}},{"position":{"y":7,"x":8}},{"position":{"y":7,"x":9},"isAlive":false},{"position":{"y":7,"x":10},"isAlive":false},{"position":{"y":7,"x":11},"isAlive":false},{"position":{"y":7,"x":12}},{"position":{"y":7,"x":13}},{"position":{"y":7,"x":14}}],[{"position":{"y":8,"x":0}},{"position":{"y":8,"x":1}},{"position":{"y":8,"x":2}},{"position":{"y":8,"x":3},"isAlive":true},{"position":{"y":8,"x":4},"isAlive":true},{"position":{"y":8,"x":5},"isAlive":true},{"position":{"y":8,"x":6}},{"position":{"y":8,"x":7}},{"position":{"y":8,"x":8}},{"position":{"y":8,"x":9},"isAlive":true},{"position":{"y":8,"x":10},"isAlive":true},{"position":{"y":8,"x":11},"isAlive":true},{"position":{"y":8,"x":12},"isAlive":false},{"position":{"y":8,"x":13}},{"position":{"y":8,"x":14}}],[{"position":{"y":9,"x":0}},{"position":{"y":9,"x":1},"isAlive":true},{"position":{"y":9,"x":2}},{"position":{"y":9,"x":3},"isAlive":false},{"position":{"y":9,"x":4},"isAlive":false},{"position":{"y":9,"x":5},"isAlive":false},{"position":{"y":9,"x":6},"isAlive":true},{"position":{"y":9,"x":7}},{"position":{"y":9,"x":8},"isAlive":true},{"position":{"y":9,"x":9},"isAlive":false},{"position":{"y":9,"x":10},"isAlive":false},{"position":{"y":9,"x":11},"isAlive":false},{"position":{"y":9,"x":12}},{"position":{"y":9,"x":13},"isAlive":true},{"position":{"y":9,"x":14}}],[{"position":{"y":10,"x":0}},{"position":{"y":10,"x":1},"isAlive":true},{"position":{"y":10,"x":2}},{"position":{"y":10,"x":3}},{"position":{"y":10,"x":4}},{"position":{"y":10,"x":5}},{"position":{"y":10,"x":6},"isAlive":true},{"position":{"y":10,"x":7}},{"position":{"y":10,"x":8},"isAlive":true},{"position":{"y":10,"x":9}},{"position":{"y":10,"x":10}},{"position":{"y":10,"x":11}},{"position":{"y":10,"x":12},"isAlive":false},{"position":{"y":10,"x":13},"isAlive":true},{"position":{"y":10,"x":14}}],[{"position":{"y":11,"x":0}},{"position":{"y":11,"x":1},"isAlive":true},{"position":{"y":11,"x":2}},{"position":{"y":11,"x":3}},{"position":{"y":11,"x":4}},{"position":{"y":11,"x":5}},{"position":{"y":11,"x":6},"isAlive":true},{"position":{"y":11,"x":7}},{"position":{"y":11,"x":8},"isAlive":true},{"position":{"y":11,"x":9}},{"position":{"y":11,"x":10}},{"position":{"y":11,"x":11}},{"position":{"y":11,"x":12}},{"position":{"y":11,"x":13},"isAlive":true},{"position":{"y":11,"x":14}}],[{"position":{"y":12,"x":0}},{"position":{"y":12,"x":1},"isAlive":false},{"position":{"y":12,"x":2}},{"position":{"y":12,"x":3},"isAlive":false},{"position":{"y":12,"x":4},"isAlive":false},{"position":{"y":12,"x":5},"isAlive":false},{"position":{"y":12,"x":6},"isAlive":false},{"position":{"y":12,"x":7},"isAlive":false},{"position":{"y":12,"x":8},"isAlive":false},{"position":{"y":12,"x":9}},{"position":{"y":12,"x":10}},{"position":{"y":12,"x":11}},{"position":{"y":12,"x":12}},{"position":{"y":12,"x":13},"isAlive":false},{"position":{"y":12,"x":14}}],[{"position":{"y":13,"x":0}},{"position":{"y":13,"x":1}},{"position":{"y":13,"x":2}},{"position":{"y":13,"x":3},"isAlive":true},{"position":{"y":13,"x":4},"isAlive":true},{"position":{"y":13,"x":5},"isAlive":true},{"position":{"y":13,"x":6}},{"position":{"y":13,"x":7}},{"position":{"y":13,"x":8}},{"position":{"y":13,"x":9},"isAlive":true},{"position":{"y":13,"x":10},"isAlive":true},{"position":{"y":13,"x":11},"isAlive":true},{"position":{"y":13,"x":12}},{"position":{"y":13,"x":13}},{"position":{"y":13,"x":14}}],[{"position":{"y":14,"x":0}},{"position":{"y":14,"x":1}},{"position":{"y":14,"x":2}},{"position":{"y":14,"x":3}},{"position":{"y":14,"x":4}},{"position":{"y":14,"x":5}},{"position":{"y":14,"x":6}},{"position":{"y":14,"x":7}},{"position":{"y":14,"x":8}},{"position":{"y":14,"x":9}},{"position":{"y":14,"x":10}},{"position":{"y":14,"x":11}},{"position":{"y":14,"x":12}},{"position":{"y":14,"x":13}},{"position":{"y":14,"x":14}}]]; |
| .text-center{ | |
| text-align: center; | |
| } | |
| .grid{ | |
| margin: auto; | |
| border-spacing: 0; | |
| border: solid 2px #111; | |
| tr{ | |
| td{ | |
| &.alive{ | |
| background: #fff; | |
| } | |
| &:hover{ | |
| cursor:pointer; | |
| } | |
| margin: 0; | |
| padding: 0; | |
| border: solid 1px #111; | |
| width: 22px; | |
| height: 22px; | |
| } | |
| } | |
| &-thumb{ | |
| tr{ | |
| td{ | |
| height:3px; | |
| width:3px; | |
| &.alive{ | |
| background: #fff; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| .buttons-container{ | |
| text-align: center; | |
| margin: 20px auto; | |
| } | |
| .thumbs-container{ | |
| margin: 15px auto; | |
| width: 357px; | |
| } | |
| .thumb-container{ | |
| border: solid 1px #6f6; | |
| display:inline-block; | |
| height: 47px; | |
| width: 47px; | |
| margin: 0 2px; | |
| overflow: hidden; | |
| .icon-close-thumb{ | |
| position: relative; | |
| top: 0; | |
| font-size: 12px; | |
| padding: 2px; | |
| color: #c33; | |
| background: rgba(400,400,400,0.9); | |
| height: 25px; | |
| transition: 0.5s; | |
| cursor: pointer; | |
| .text-small{ | |
| font-size: 10px; | |
| } | |
| } | |
| &:hover{ | |
| .icon-close-thumb{ | |
| top: -20px; | |
| } | |
| } | |
| } |