From 681772b0ca59b428d24da7b1f030db7b5ca295e7 Mon Sep 17 00:00:00 2001
From: Will Billingsley <wbilling@une.edu.au>
Date: Tue, 24 Jul 2018 03:50:57 +1000
Subject: [PATCH] Solution to tutorial 3

---
 gameOfLife.js     | 151 ++++++++++---------------
 gameOfLife.ts     |  77 +++++++++++++
 index.html        |   6 +-
 package-lock.json | 280 ++++++++++++++++++++++++++++++++++++++++++++++
 package.json      |  20 ++++
 render.js         |  69 +++++-------
 render.ts         |  37 ++++++
 tsconfig.json     |  59 ++++++++++
 8 files changed, 565 insertions(+), 134 deletions(-)
 create mode 100644 gameOfLife.ts
 create mode 100644 package-lock.json
 create mode 100644 package.json
 create mode 100644 render.ts
 create mode 100644 tsconfig.json

diff --git a/gameOfLife.js b/gameOfLife.js
index b98b705..ba7da91 100644
--- a/gameOfLife.js
+++ b/gameOfLife.js
@@ -1,101 +1,68 @@
 "use strict";
-
-// Our code is wrapped in an anonymous function to keep 
-// variables private by default
-(function () {
-
-    let h = 20 // height of the board
-    let w = 40 // width of the board
-
-    /* 
-    The board is represented in memory as a flat array, eg:
-    [ 0, 0, 0, 0, 
-        0, 0, 0, 0, 
-        0, 0, 0, 0 ]
-    But we'll initialise its contents in a function.
-    */
-    let board = []
-
-    // Calculates an index into the board for a given (x, y) location
-    function boardIndex(x, y) {
-        return y * w + x
+var Life = /** @class */ (function () {
+    function Life(w, h) {
+        if (w === void 0) { w = 40; }
+        if (h === void 0) { h = 20; }
+        this.w = w;
+        this.h = h;
+        this.board = this.emptyBoard();
     }
-
-    // Zeroes the contents of the board array
-    function emptyBoard() {
-        for (let x = 0; x < w; x++) {
-            for (let y = 0; y < h; y++) {
-                board[boardIndex(x, y)] = 0
-            }
+    Life.prototype.boardIndex = function (x, y) {
+        return y * this.w + x;
+    };
+    Life.prototype.x = function (index) {
+        return index % this.w;
+    };
+    Life.prototype.y = function (index) {
+        return Math.floor(index / this.w);
+    };
+    Life.prototype.emptyBoard = function () {
+        var arr = [];
+        for (var i = 0; i < this.h * this.w; i++) {
+            arr.push(false);
         }
-    }
-
-    // toggles wheter a cell is "alive" or not
-    function toggleCell(x, y) {
-        let idx = boardIndex(x, y)
-        board[idx] = !board[idx]
-    }
-
-    // determines whether a cell is alive, dealing with range checks
-    function isAlive(x, y) {
-        let idx = boardIndex(x, y)
-        return (x >= 0) && (y >= 0) && (x < w) && (y < h) && board[idx]
-    }
-
-    function liveNeighbours(x, y) {
-        let count = 0
-        for (let i = x - 1; i <= x + 1; i++) {
-            for (let j = y - 1; j <= y + 1; j++) {
-                if (isAlive(i,j) && ((i != x) || (j != y))) {
-                    count++
+        return arr;
+    };
+    Life.prototype.toggleCell = function (x, y) {
+        var b = this.boardIndex(x, y);
+        this.board[b] = !this.board[b];
+    };
+    Life.prototype.isAlive = function (x, y) {
+        var b = this.boardIndex(x, y);
+        return (x >= 0) && (y >= 0) && (x < this.w) && (y < this.h)
+            && this.board[b];
+    };
+    Life.prototype.liveNeighbours = function (x, y) {
+        var live = 0;
+        for (var _i = 0, _a = [x - 1, x, x + 1]; _i < _a.length; _i++) {
+            var i = _a[_i];
+            for (var _b = 0, _c = [y - 1, y, y + 1]; _b < _c.length; _b++) {
+                var j = _c[_b];
+                if (this.isAlive(i, j) && (i != x || j != y)) {
+                    live++;
                 }
             }
         }
-        return count
-    }
-
-    // Steps the game forward by a single tick, by calculating the 
-    // next state of the board's cells
-    function stepGame() {
-        let nextBoard = []
-
-        for (var x = 0; x < w; x++) {
-            for (let y = 0; y < h; y++) {
-                let idx = boardIndex(x, y)
-                let alive = isAlive(x, y)
-                let neighbours = liveNeighbours(x, y)
-
-                if (
-                    (alive && (neighbours == 2 || neighbours == 3)) ||
-                    (!alive && neighbours == 3)
-                ) {
-                    nextBoard[idx] = 1
-                } else {
-                    nextBoard[idx] = 0
+        return live;
+    };
+    Life.prototype.stepGame = function () {
+        var nextBoard = this.emptyBoard();
+        for (var x = 0; x < this.w; x++) {
+            for (var y = 0; y < this.h; y++) {
+                var index = this.boardIndex(x, y);
+                var alive = this.isAlive(x, y);
+                var neighbours = this.liveNeighbours(x, y);
+                if ((alive && (neighbours == 2 || neighbours == 3)) ||
+                    (!alive && neighbours == 3)) {
+                    nextBoard[index] = true;
+                }
+                else {
+                    nextBoard[index] = false;
                 }
             }
         }
-
-        board = nextBoard
-    }
-
-    
-    // publish our game on the window object
-    window.gameOfLife = {
-
-        getW: function() { return w },
-
-        getH: function() { return h },
-
-        isAlive: isAlive,
-
-        emptyBoard: emptyBoard,
-
-        toggleCell: toggleCell,
-
-        stepGame: stepGame
-
-    }
-
-
-})()
\ No newline at end of file
+        this.board = nextBoard;
+    };
+    return Life;
+}());
+//# sourceMappingURL=gameOfLife.js.map
\ No newline at end of file
diff --git a/gameOfLife.ts b/gameOfLife.ts
new file mode 100644
index 0000000..ecf4b91
--- /dev/null
+++ b/gameOfLife.ts
@@ -0,0 +1,77 @@
+
+class Life {
+
+    board: Array<boolean>
+
+    constructor(public w:number = 40, public h:number = 20) {
+        this.board = this.emptyBoard()
+    }
+
+    boardIndex(x:number, y:number):number {
+        return y * this.w + x
+    }
+
+    x(index:number) {
+        return index % this.w
+    }
+
+    y(index:number) {
+        return Math.floor(index / this.w)
+    }
+
+    emptyBoard():boolean[] {
+        let arr = <boolean[]>[]
+        for (let i = 0; i < this.h * this.w; i++) {
+            arr.push(false)
+        }
+        return arr
+    }
+
+    toggleCell(x:number, y:number):void {
+        let b = this.boardIndex(x,y)
+        this.board[b] = !this.board[b]
+    }
+
+    isAlive(x:number, y:number):boolean {
+        let b = this.boardIndex(x,y)
+        return (x >= 0) && (y >= 0) && (x < this.w) && (y < this.h) 
+          && this.board[b]
+    }
+
+    liveNeighbours(x:number, y:number) {
+        let live = 0
+        for (let i of [x - 1, x, x + 1]) {
+            for (let j of [y - 1, y, y + 1]) {
+                if (this.isAlive(i,j) && (i != x || j != y)) {
+                    live++
+                }
+            }
+        }
+        return live
+    }
+
+    stepGame():void {
+        let nextBoard = this.emptyBoard()
+        for (let x = 0; x < this.w; x++) {
+            for (let y = 0; y < this.h; y++) {
+                let index = this.boardIndex(x, y)
+                let alive = this.isAlive(x, y)
+                let neighbours = this.liveNeighbours(x, y)
+
+                if (
+                    (alive && (neighbours == 2 || neighbours == 3)) ||
+                    (!alive && neighbours == 3)
+                ) {
+                    nextBoard[index] = true
+                } else {
+                    nextBoard[index] = false
+                }    
+            }
+        }
+        this.board = nextBoard
+    }
+
+}
+
+
+
diff --git a/index.html b/index.html
index c926c6b..0d9bfd1 100644
--- a/index.html
+++ b/index.html
@@ -7,14 +7,14 @@
     <h1>Conway's Game of Life</h1>
     <svg xmlns="http://www.w3.org/2000/svg" id="game" width="640" height="400"></svg>
     <div>
-        <button class="btn btn-primary" onclick="javascript: { gameOfLife.stepGame(); render(); }">Step</button>
+        <button class="btn btn-primary" onclick="javascript: { life.stepGame(); render(); }">Step</button>
     </div>
   </div>
 
+  <script src="https://d3js.org/d3.v5.min.js"></script>
   <script src="gameOfLife.js"></script>
   <script src="render.js"></script>
-  <script>
-    gameOfLife.emptyBoard()
+  <script>    
     render()
   </script>
 
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..85d5906
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,280 @@
+{
+  "name": "tutorial-conway-life-t3",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@types/d3": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@types/d3/-/d3-5.0.0.tgz",
+      "integrity": "sha512-BVfPw7ha+UgsG24v6ymerMY4+pJgQ/6p+hJA4loCeaaqV9snGS/G6ReVaQEn8Himn67dWn/Je9WhRbnDO7MzLw==",
+      "dev": true,
+      "requires": {
+        "@types/d3-array": "*",
+        "@types/d3-axis": "*",
+        "@types/d3-brush": "*",
+        "@types/d3-chord": "*",
+        "@types/d3-collection": "*",
+        "@types/d3-color": "*",
+        "@types/d3-contour": "*",
+        "@types/d3-dispatch": "*",
+        "@types/d3-drag": "*",
+        "@types/d3-dsv": "*",
+        "@types/d3-ease": "*",
+        "@types/d3-fetch": "*",
+        "@types/d3-force": "*",
+        "@types/d3-format": "*",
+        "@types/d3-geo": "*",
+        "@types/d3-hierarchy": "*",
+        "@types/d3-interpolate": "*",
+        "@types/d3-path": "*",
+        "@types/d3-polygon": "*",
+        "@types/d3-quadtree": "*",
+        "@types/d3-random": "*",
+        "@types/d3-scale": "*",
+        "@types/d3-scale-chromatic": "*",
+        "@types/d3-selection": "*",
+        "@types/d3-shape": "*",
+        "@types/d3-time": "*",
+        "@types/d3-time-format": "*",
+        "@types/d3-timer": "*",
+        "@types/d3-transition": "*",
+        "@types/d3-voronoi": "*",
+        "@types/d3-zoom": "*"
+      }
+    },
+    "@types/d3-array": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.1.tgz",
+      "integrity": "sha512-YBaAfimGdWE4nDuoGVKsH89/dkz2hWZ0i8qC+xxqmqi+XJ/aXiRF0jPtzXmN7VdkpVjy1xuDmM5/m1FNuB6VWA==",
+      "dev": true
+    },
+    "@types/d3-axis": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-1.0.10.tgz",
+      "integrity": "sha512-5YF0wfdQMPKw01VAAupLIlg/T4pn5M3/vL9u0KZjiemnVnnKBEWE24na4X1iW+TfZiYJ8j+BgK2KFYnAAT54Ug==",
+      "dev": true,
+      "requires": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "@types/d3-brush": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-1.0.8.tgz",
+      "integrity": "sha512-9Thv09jvolu9T1BE3fHmIeYSgbwSpdxtF6/A5HZEDjSTfgtA0mtaXRk5AiWOo0KjuLsI+/7ggD3ZGN5Ye8KXPQ==",
+      "dev": true,
+      "requires": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "@types/d3-chord": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.7.tgz",
+      "integrity": "sha512-WbCN7SxhZMpQQw46oSjAovAmvl3IdjhLuQ4r7AXCzNKyxtXXBWuihSPZ4bVwFQF3+S2z37i9d4hfUBatcSJpog==",
+      "dev": true
+    },
+    "@types/d3-collection": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-collection/-/d3-collection-1.0.7.tgz",
+      "integrity": "sha512-vR3BT0GwHc5y93Jv6bxn3zoxP/vGu+GdXu/r1ApjbP9dLk9I2g6NiV7iP/QMQSuFZd0It0n/qWrfXHxCWwHIkg==",
+      "dev": true
+    },
+    "@types/d3-color": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.2.1.tgz",
+      "integrity": "sha512-xwb1tqvYNWllbHuhMFhiXk63Imf+QNq/dJdmbXmr2wQVnwGenCuj3/0IWJ9hdIFQIqzvhT7T37cvx93jtAsDbQ==",
+      "dev": true
+    },
+    "@types/d3-contour": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-1.2.1.tgz",
+      "integrity": "sha512-p8iC4KeVFyT3qRTGQRj0Jf5QDdPsDUevBEnma7gEsY1yDolVSLanG2eFAiLV+xj8/5DK7oU7Ey8z0drs3pbsug==",
+      "dev": true,
+      "requires": {
+        "@types/d3-array": "*",
+        "@types/geojson": "*"
+      }
+    },
+    "@types/d3-dispatch": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-1.0.6.tgz",
+      "integrity": "sha512-xyWJQMr832vqhu6fD/YqX+MSFBWnkxasNhcStvlhqygXxj0cKqPft0wuGoH5TIq5ADXgP83qeNVa4R7bEYN3uA==",
+      "dev": true
+    },
+    "@types/d3-drag": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-1.2.1.tgz",
+      "integrity": "sha512-J9liJ4NNeV0oN40MzPiqwWjqNi3YHCRtHNfNMZ1d3uL9yh1+vDuo346LBEr8yyBm30WHvrHssAkExVZrGCswtA==",
+      "dev": true,
+      "requires": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "@types/d3-dsv": {
+      "version": "1.0.33",
+      "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.0.33.tgz",
+      "integrity": "sha512-jx5YvaVC3Wfh6LobaiWTeU1NkvL2wPmmpmajk618bD+xVz98yNWzmZMvmlPHGK0HXbMeHmW/6oVX48V9AH1bRQ==",
+      "dev": true
+    },
+    "@types/d3-ease": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-1.0.7.tgz",
+      "integrity": "sha1-k6MBhovp4VBh89RDQ7GrP4rLbwk=",
+      "dev": true
+    },
+    "@types/d3-fetch": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-1.1.2.tgz",
+      "integrity": "sha512-w6ANZv/mUh+6IV3drT22zgPWMRobzuGXhzOZC8JPD+ygce0/Vx6vTci3m3dizkocnQQCOwNbrWWWPYqpWiKzRQ==",
+      "dev": true,
+      "requires": {
+        "@types/d3-dsv": "*"
+      }
+    },
+    "@types/d3-force": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.1.1.tgz",
+      "integrity": "sha512-ePkELuaFWY4yOuf+Bvx5Xd+ihFiYG4bdnW0BlvigovIm8Sob2t76e9RGO6lybQbv6AlW9Icn9HuZ9fmdzEoJyg==",
+      "dev": true
+    },
+    "@types/d3-format": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.3.0.tgz",
+      "integrity": "sha512-ZiY4j3iJvAdOwzwW24WjlZbUNvqOsnPAMfPBmdXqxj3uKJbrzBlRrdGl5uC89pZpFs9Dc92E81KcwG2uEgkIZA==",
+      "dev": true
+    },
+    "@types/d3-geo": {
+      "version": "1.10.3",
+      "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-1.10.3.tgz",
+      "integrity": "sha512-hfdaxM2L0wA9mDZrrSf2o+DyhEpnJYCiAN+lHFtpfZOVCQrYBA5g33sGRpUbAvjSMyO5jkHbftMWPEhuCMChSg==",
+      "dev": true,
+      "requires": {
+        "@types/geojson": "*"
+      }
+    },
+    "@types/d3-hierarchy": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.2.tgz",
+      "integrity": "sha512-L+Ht4doqlCIH8jYN2AC1mYIOj13OxlRhdWNWXv2pc3o5A9i3YmQ0kz6A7w8c+Ujylfusi/FO+zVlVnQoOHc2Qw==",
+      "dev": true
+    },
+    "@types/d3-interpolate": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.2.0.tgz",
+      "integrity": "sha512-qM9KlUrqbwIhBRtw9OtAEbkis1AxsOJEun2uxaX/vEsBp3vyNBmhPz9boXXEqic9ZRi7fCpUNRwyZvxa0PioIw==",
+      "dev": true,
+      "requires": {
+        "@types/d3-color": "*"
+      }
+    },
+    "@types/d3-path": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.7.tgz",
+      "integrity": "sha512-U8dFRG+8WhkLJr2sxZ9Cw/5WeRgBnNqMxGdA1+Z0+ZG6tK0s75OQ4OXnxeyfKuh6E4wQPY8OAKr1+iNDx01BEQ==",
+      "dev": true
+    },
+    "@types/d3-polygon": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-1.0.6.tgz",
+      "integrity": "sha512-E6Kyodn9JThgLq20nxSbEce9ow5/ePgm9PX2EO6W1INIL4DayM7cFaiG10DStuamjYAd0X4rntW2q+GRjiIktw==",
+      "dev": true
+    },
+    "@types/d3-quadtree": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-1.0.5.tgz",
+      "integrity": "sha1-HOHmWerkUw3wyxJ/KX8XQaNnqC4=",
+      "dev": true
+    },
+    "@types/d3-random": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-1.1.1.tgz",
+      "integrity": "sha512-jUPeBq1XKK9/5XasTvy5QAUwFeMsjma2yt/nP02yC2Tijovx7i/W5776U/HZugxc5SSmtpx4Z3g9KFVon0QrjQ==",
+      "dev": true
+    },
+    "@types/d3-scale": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-2.0.1.tgz",
+      "integrity": "sha512-D5ZWv8ToLvqacE7XkdMNHMiiVDULdDxT7FMMGU0YJC3/nVzBmApjyTyxracUWOQyY3KK7YhZ05on8pOcNi0dfQ==",
+      "dev": true,
+      "requires": {
+        "@types/d3-time": "*"
+      }
+    },
+    "@types/d3-scale-chromatic": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-1.2.0.tgz",
+      "integrity": "sha512-bhS2SVzUzRtrxp1REhGCfHmj8pyDv9oDmsonYiPvBl8KCxPJTxnfXBF39PzAJrYnRKM41TR0kQzsJvL+NmcDtg==",
+      "dev": true
+    },
+    "@types/d3-selection": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.3.1.tgz",
+      "integrity": "sha512-G+eO+2G1iW3GNrROxhoU+ar+bIJbQq1QkxcfhwjQ19xA20n3T31j5pSJqAOWvPSoFTz4Ets/DQgYhmgT4jepDg==",
+      "dev": true
+    },
+    "@types/d3-shape": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.2.3.tgz",
+      "integrity": "sha512-iP9TcX0EVi+LlX+jK9ceS+yhEz5abTitF+JaO2ugpRE/J+bccaYLe/0/3LETMmdaEkYarIyboZW8OF67Mpnj1w==",
+      "dev": true,
+      "requires": {
+        "@types/d3-path": "*"
+      }
+    },
+    "@types/d3-time": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.0.8.tgz",
+      "integrity": "sha512-/UCphyyw97YAq4zKsuXH33R3UNB4jDSza0fLvMubWr/ONh9IePi1NbgFP222blhiCe724ebJs8U87+aDuAq/jA==",
+      "dev": true
+    },
+    "@types/d3-time-format": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz",
+      "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==",
+      "dev": true
+    },
+    "@types/d3-timer": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-1.0.7.tgz",
+      "integrity": "sha512-830pT+aYZrgbA91AuynP3KldfB1A1s60d0gKiV+L7JcSKSJapUzUffAm8VZod7RQOxF5SzoItV6cvrTzjbmrJQ==",
+      "dev": true
+    },
+    "@types/d3-transition": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.1.2.tgz",
+      "integrity": "sha512-sTENKlKkUaKUYjeYIj69VYIi3VKeBinY/pYdy5VkjNmEOIasUtZIyAY04waMU4Rq7u+czKQdcP7Aoaf5wpDGfA==",
+      "dev": true,
+      "requires": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "@types/d3-voronoi": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.7.tgz",
+      "integrity": "sha512-/dHFLK5jhXTb/W4XEQcFydVk8qlIAo85G3r7+N2fkBFw190l0R1GQ8C1VPeXBb2GfSU5GbT2hjlnE7i7UY5Gvg==",
+      "dev": true
+    },
+    "@types/d3-zoom": {
+      "version": "1.7.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.7.1.tgz",
+      "integrity": "sha512-Ofjwz6Pt53tRef9TAwwayN+JThNVYC/vFOepa/H4KtwjhsqkmEseHvc2jpJM7vye5PQ5XHtTSOpdY4Y/6xZWEg==",
+      "dev": true,
+      "requires": {
+        "@types/d3-interpolate": "*",
+        "@types/d3-selection": "*"
+      }
+    },
+    "@types/geojson": {
+      "version": "7946.0.4",
+      "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.4.tgz",
+      "integrity": "sha512-MHmwBtCb7OCv1DSivz2UNJXPGU/1btAWRKlqJ2saEhVJkpkvqHMMaOpKg0v4sAbDWSQekHGvPVMM8nQ+Jen03Q==",
+      "dev": true
+    },
+    "typescript": {
+      "version": "2.9.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
+      "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
+      "dev": true
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..9808823
--- /dev/null
+++ b/package.json
@@ -0,0 +1,20 @@
+{
+  "name": "tutorial-conway-life-t3",
+  "version": "1.0.0",
+  "description": "For the second tutorial, we're going to work with SVG, and CSS via SASS.",
+  "main": "gameOfLife.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git@gitlab.une.edu.au:cosc360in2018/tutorial-conway-life-t2.git"
+  },
+  "author": "",
+  "license": "ISC",
+  "devDependencies": {
+    "@types/d3": "^5.0.0",
+    "typescript": "^2.9.2"
+  },
+  "dependencies": {}
+}
diff --git a/render.js b/render.js
index 5118aff..1874a42 100644
--- a/render.js
+++ b/render.js
@@ -1,41 +1,32 @@
 "use strict";
-
+/// <reference types="d3" />
+var life = new Life();
+var game = d3.select("#game").append("g");
+var cellSize = 20;
 function render() {
-
-    let xmlns = "http://www.w3.org/2000/svg"
-
-    let cellSize = 20
-
-    let gameDiv = document.getElementById("game")
-    gameDiv.innerHTML = ""
-
-    for (let y = 0; y < gameOfLife.getH(); y++) {
-        let row = document.createElementNS(xmlns, "g")
-        row.setAttribute("class", "gamerow")
-        gameDiv.appendChild(row)
-
-        for (let x = 0; x < gameOfLife.getW(); x++) {
-            
-            let t = document.createElementNS(xmlns, "rect")
-            t.setAttribute("x", x * cellSize)
-            t.setAttribute("y", y * cellSize)
-            t.setAttribute("width", cellSize)
-            t.setAttribute("height", cellSize)
-            t.classList.add("cell")
-
-            if (gameOfLife.isAlive(x, y)) {
-                t.classList.add("alive")
-            }
-
-            let handler = function(evt) {
-                gameOfLife.toggleCell(x, y)
-                render()
-            }
-                
-            t.addEventListener("mousedown", handler)
-
-            row.appendChild(t)
-        }
-    }
-
-}
\ No newline at end of file
+    console.log("rendering");
+    var update = game.selectAll("rect").data(life.board);
+    update.attr("class", function (d) {
+        return d ? "cell alive" : "cell";
+    });
+    update.enter()
+        .append("rect")
+        .attr("class", function (d) {
+        return d ? "cell alive" : "cell";
+    })
+        .attr("x", function (val, i) {
+        return life.x(i) * cellSize;
+    })
+        .attr("y", function (val, i) {
+        return life.y(i) * cellSize;
+    })
+        .attr("width", cellSize)
+        .attr("height", cellSize)
+        .on("click", function (d, i) {
+        var x = life.x(i);
+        var y = life.y(i);
+        life.toggleCell(x, y);
+        render();
+    });
+}
+//# sourceMappingURL=render.js.map
\ No newline at end of file
diff --git a/render.ts b/render.ts
new file mode 100644
index 0000000..4350c65
--- /dev/null
+++ b/render.ts
@@ -0,0 +1,37 @@
+/// <reference types="d3" />
+
+const life = new Life()
+const game = d3.select("#game").append("g")
+const cellSize = 20
+
+function render() {
+    console.log("rendering")
+    
+    let update = game.selectAll("rect").data(life.board)
+      
+    update.attr("class", (d) => {
+        return d ? "cell alive" : "cell"            
+    })
+      
+    update.enter()
+        .append("rect")
+        .attr("class", (d) => {
+            return d ? "cell alive" : "cell"            
+        })
+        .attr("x", (val,i) => {
+          return life.x(i) * cellSize
+        })
+        .attr("y", (val,i) => {
+          return life.y(i) * cellSize
+        })
+        .attr("width", cellSize)
+        .attr("height", cellSize)
+        .on("click", (d,i) => {
+            let x = life.x(i)
+            let y = life.y(i)
+            life.toggleCell(x,y)
+            render()
+        })
+  
+
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..c00ff48
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,59 @@
+{
+  "compilerOptions": {
+    /* Basic Options */
+    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
+    //"module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
+    // "lib": [],                             /* Specify library files to be included in the compilation. */
+    // "allowJs": true,                       /* Allow javascript files to be compiled. */
+    // "checkJs": true,                       /* Report errors in .js files. */
+    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
+    // "declaration": true,                   /* Generates corresponding '.d.ts' file. */
+    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
+    "sourceMap": true,                     /* Generates corresponding '.map' file. */
+    // "outFile": "./",                       /* Concatenate and emit output to single file. */
+    // "outDir": "./",                        /* Redirect output structure to the directory. */
+    // "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
+    // "composite": true,                     /* Enable project compilation */
+    // "removeComments": true,                /* Do not emit comments to output. */
+    // "noEmit": true,                        /* Do not emit outputs. */
+    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
+    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
+    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
+
+    /* Strict Type-Checking Options */
+    "strict": true,                           /* Enable all strict type-checking options. */
+    // "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
+    // "strictNullChecks": true,              /* Enable strict null checks. */
+    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
+    // "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
+    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
+    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */
+
+    /* Additional Checks */
+    // "noUnusedLocals": true,                /* Report errors on unused locals. */
+    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
+    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
+    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
+
+    /* Module Resolution Options */
+    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
+    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
+    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
+    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
+    // "typeRoots": [],                       /* List of folders to include type definitions from. */
+    // "types": [],                           /* Type declaration files to be included in compilation. */
+    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
+
+    /* Source Map Options */
+    // "sourceRoot": "./",                    /* Specify the location where debugger should locate TypeScript files instead of source locations. */
+    // "mapRoot": "./",                       /* Specify the location where debugger should locate map files instead of generated locations. */
+    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
+    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
+
+    /* Experimental Options */
+    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
+    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
+  }
+}
\ No newline at end of file
-- 
GitLab