Implement vanilla GoL in TypeScript
authorSiraaj Khandkar <siraaj@khandkar.net>
Tue, 2 Aug 2016 19:52:46 +0000 (15:52 -0400)
committerSiraaj Khandkar <siraaj@khandkar.net>
Tue, 2 Aug 2016 19:52:46 +0000 (15:52 -0400)
life/006/.gitignore [new file with mode: 0644]
life/006/Makefile [new file with mode: 0644]
life/006/README.md [new file with mode: 0644]
life/006/life [new file with mode: 0755]
life/006/life.ts [new file with mode: 0644]
life/006/tsconfig.json [new file with mode: 0644]
life/006/typings.json [new file with mode: 0644]

diff --git a/life/006/.gitignore b/life/006/.gitignore
new file mode 100644 (file)
index 0000000..71b2fc7
--- /dev/null
@@ -0,0 +1,2 @@
+typings/
+life.js
diff --git a/life/006/Makefile b/life/006/Makefile
new file mode 100644 (file)
index 0000000..67af1eb
--- /dev/null
@@ -0,0 +1,22 @@
+.PHONY: deps build_and_run build run clean clean_deps clean_all
+
+build_and_run: build run
+
+all: clean_all deps build_and_run
+
+deps:
+       @typings install
+
+build:
+       @tsc
+
+run:
+       @./life
+
+clean:
+       @rm life.js
+
+clean_deps:
+       @rm -rf ./typings
+
+clean_all: clean clean_deps
diff --git a/life/006/README.md b/life/006/README.md
new file mode 100644 (file)
index 0000000..65590ff
--- /dev/null
@@ -0,0 +1,5 @@
+```
+make deps
+make build
+make run
+```
diff --git a/life/006/life b/life/006/life
new file mode 100755 (executable)
index 0000000..718b279
--- /dev/null
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+HEIGHT=`stty size | awk '{print $1}'`
+WIDTH=`stty size | awk '{print $2}'`
+
+node life.js $HEIGHT $WIDTH
diff --git a/life/006/life.ts b/life/006/life.ts
new file mode 100644 (file)
index 0000000..0204e5f
--- /dev/null
@@ -0,0 +1,134 @@
+type State = "Dead" | "Alive";
+
+type States = Array<State>;
+
+type Board = Array<States>;
+
+let state_of_integer = (i : number) : State => {
+    switch (i)
+    { case 0 : return "Dead"
+    ; case 1 : return "Alive"
+    }
+};
+
+let state_to_string = (state) : string => {
+    switch (state)
+    { case "Dead" : return " "
+    ; case "Alive": return "o"
+    }
+};
+
+let board_new = ({rows, columns} : {rows: number, columns: number}) : Board => {
+    let b = [];
+    for (let r = 0; r < rows; r++) {
+        b[r] = [];
+        for (let k = 0; k < columns; k++) {
+            let zero_or_one = Math.round(Math.random());
+            b[r][k] = state_of_integer(zero_or_one);
+        };
+    };
+    return b
+};
+
+let board_neighbors = (b : Board, origin : {r: number, k: number}) : States => {
+    let rows = b.length;
+    let cols = b[0].length;
+    let offsets =
+        [ {r: -1, k: -1}, {r: -1, k: 0}, {r: -1, k: 1}
+        , {r:  0, k: -1},                {r:  0, k: 1}
+        , {r:  1, k: -1}, {r:  1, k: 0}, {r:  1, k: 1}
+        ];
+    let offset_to_location =
+        (offset) => {return {r: origin.r + offset.r, k: origin.k + offset.k}};
+    let locations = offsets.map(offset_to_location);
+    let is_location_within_bounds =
+        ({r, k}) => {
+            return r >= 0 && k >= 0 && r < rows && k < cols
+        };
+    let locations_within_bounds = locations.filter(is_location_within_bounds);
+    return locations_within_bounds.map(({r, k}) => b[r][k]);
+};
+
+let state_is_alive = (s : State) : boolean => {
+    if (s === "Alive") {return true} else if (s === "Dead") {return false}
+};
+
+let state_next = (state : State, neighbor_states : Array<State>) : State => {
+    let neighbors_alive = neighbor_states.filter(state_is_alive).length;
+    if (state === "Alive" && neighbors_alive < 2) {
+        return "Dead"
+    } else if (state === "Alive" && neighbors_alive < 4) {
+        return "Alive"
+    } else if (state === "Alive" && neighbors_alive > 3) {
+        return "Dead"
+    } else if (state === "Dead" && neighbors_alive === 3) {
+        return "Alive"
+    } else {
+        return state
+    }
+}
+
+let board_next = (b0 : Board) : Board => {
+    let b1 = [];
+    for (let r = 0; r < b0.length; r++) {
+        b1[r] = [];
+        for (let k = 0; k < b0[r].length; k++) {
+            let neighbors = board_neighbors(b0, {r: r, k: k});
+            let state_0 = b0[r][k];
+            let state_1 = state_next(state_0, neighbors);
+            b1[r][k] = state_1;
+        }
+    };
+    return b1
+};
+
+let board_print_border = (b : Board) : void => {
+    process.stdout.write("+");
+    for (let k = 0; k < b[0].length; k++) {
+        process.stdout.write("-");
+    };
+    process.stdout.write("+");
+    process.stdout.write("\n");
+};
+
+let board_print = (b : Board) : void => {
+    board_print_border(b);
+    let rows = b.length;
+    let columns = b[0].length;
+    for (let r = 0; r < rows; r++) {
+        process.stdout.write("|");
+        for (let k = 0; k < columns; k++) {
+            let state = b[r][k];
+            let state_string = state_to_string(state);
+            process.stdout.write(state_string);
+        };
+        process.stdout.write("|");
+        process.stdout.write("\n");
+    };
+    board_print_border(b);
+};
+
+let console_clear = () : void => {
+    process.stdout.write("\033[2J");
+}
+
+let console_reset = () : void => {
+    process.stdout.write("\033[1;1H");
+}
+
+let board_loop = (b0 : Board) : void => {
+    console_reset();
+    board_print(b0);
+    let b1 = board_next(b0);
+    setTimeout(() => board_loop(b1), 250)
+};
+
+let main = () : void => {
+    let height = parseInt(process.argv[2])
+    let width  = parseInt(process.argv[3])
+    let b = board_new({rows: height - 3, columns: width - 2});
+    console_clear();
+    board_loop(b);
+};
+
+main();
diff --git a/life/006/tsconfig.json b/life/006/tsconfig.json
new file mode 100644 (file)
index 0000000..c1dbee8
--- /dev/null
@@ -0,0 +1,14 @@
+{ "compilerOptions":
+    { "module"                     : "commonjs"
+    , "target"                     : "es5"
+    , "sourceMap"                  : false
+    , "noFallthroughCasesInSwitch" : true
+    }
+, "exclude":
+    [ "node_modules"
+    ]
+, "files":
+    [ "./typings/index.d.ts"
+    , "life.ts"
+    ]
+}
diff --git a/life/006/typings.json b/life/006/typings.json
new file mode 100644 (file)
index 0000000..05c1642
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "globalDependencies": {
+    "node": "registry:dt/node#0.12.0+20160720000508"
+  }
+}
This page took 0.024419 seconds and 4 git commands to generate.