From e16b8b54be348430aef022ac39696df272100cd7 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Tue, 2 Aug 2016 15:52:46 -0400 Subject: [PATCH] Implement vanilla GoL in TypeScript --- life/006/.gitignore | 2 + life/006/Makefile | 22 +++++++ life/006/README.md | 5 ++ life/006/life | 6 ++ life/006/life.ts | 134 +++++++++++++++++++++++++++++++++++++++++ life/006/tsconfig.json | 14 +++++ life/006/typings.json | 5 ++ 7 files changed, 188 insertions(+) create mode 100644 life/006/.gitignore create mode 100644 life/006/Makefile create mode 100644 life/006/README.md create mode 100755 life/006/life create mode 100644 life/006/life.ts create mode 100644 life/006/tsconfig.json create mode 100644 life/006/typings.json diff --git a/life/006/.gitignore b/life/006/.gitignore new file mode 100644 index 0000000..71b2fc7 --- /dev/null +++ b/life/006/.gitignore @@ -0,0 +1,2 @@ +typings/ +life.js diff --git a/life/006/Makefile b/life/006/Makefile new file mode 100644 index 0000000..67af1eb --- /dev/null +++ b/life/006/Makefile @@ -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 index 0000000..65590ff --- /dev/null +++ b/life/006/README.md @@ -0,0 +1,5 @@ +``` +make deps +make build +make run +``` diff --git a/life/006/life b/life/006/life new file mode 100755 index 0000000..718b279 --- /dev/null +++ b/life/006/life @@ -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 index 0000000..0204e5f --- /dev/null +++ b/life/006/life.ts @@ -0,0 +1,134 @@ +type State = "Dead" | "Alive"; + +type States = Array; + +type Board = Array; + +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 => { + 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 index 0000000..c1dbee8 --- /dev/null +++ b/life/006/tsconfig.json @@ -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 index 0000000..05c1642 --- /dev/null +++ b/life/006/typings.json @@ -0,0 +1,5 @@ +{ + "globalDependencies": { + "node": "registry:dt/node#0.12.0+20160720000508" + } +} -- 2.20.1