From: Siraaj Khandkar Date: Wed, 3 Aug 2016 21:30:04 +0000 (-0400) Subject: Refactor with classes, assertions, const and more. X-Git-Url: https://git.xandkar.net/?a=commitdiff_plain;h=b1310fe0f74e4766a3a177b2ac4b0f241c7476d2;p=cellular-automata.git Refactor with classes, assertions, const and more. --- diff --git a/life/006/life.ts b/life/006/life.ts index 695de90..987f21e 100644 --- a/life/006/life.ts +++ b/life/006/life.ts @@ -1,12 +1,15 @@ -type State = "Dead" | "Alive"; - -type States = Array; - -type Board = Array; +"use strict"; type GridLocation = {r: number, k: number}; -class Grid { +interface GridInterface { + get : (location: GridLocation) => T; + map : (f : (location: GridLocation) => T) => Grid; + moore_neighbors: (origin : GridLocation) => Array; + print : (toString : (T: T) => string) => void; +}; + +class Grid implements GridInterface { private rows : number; private columns : number; private cells : Array>; @@ -21,7 +24,7 @@ class Grid { { this.rows = rows; this.columns = columns; - let cells = []; + const cells = []; for (let r = 0; r < rows; r++) { cells[r] = []; for (let k = 0; k < columns; k++) { @@ -31,87 +34,102 @@ class Grid { this.cells = cells }; + get({r, k}: GridLocation) : T { + return this.cells[r][k] + }; + moore_neighbors(origin : GridLocation) : Array { - let offsets = + const 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 = + const 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 = + const locations = offsets.map(offset_to_location); + const is_location_within_bounds = ({r, k}) => r >= 0 && k >= 0 && r < this.rows && k < this.columns; return locations.filter(is_location_within_bounds) }; - mapi(f : (location: GridLocation) => T) { - let cells = []; + map(f : (location: GridLocation) => T) { + const cells = []; for (let r = 0; r < this.rows; r++) { cells[r] = []; for (let k = 0; k < this.columns; k++) { - let location = {r: r, k: k}; - let neighbors = this.moore_neighbors(location); + const location = {r: r, k: k}; cells[r][k] = f(location); } }; - let init = ({r, k}) => cells[r][k]; - let grid = new Grid({rows: this.rows, columns: this.columns, init: init}); + const init = ({r, k}) => cells[r][k]; + const grid = new Grid({rows: this.rows, columns: this.columns, init: init}); return grid }; + + private print_border(): void { + process.stdout.write("+"); + for (let k = 0; k < this.columns; k++) { + process.stdout.write("-"); + }; + process.stdout.write("+"); + process.stdout.write("\n"); + }; + + print(to_string) : void { + this.print_border(); + for (let r = 0; r < this.rows; r++) { + process.stdout.write("|"); + for (let k = 0; k < this.columns; k++) { + const element = this.cells[r][k]; + const element_string = to_string(element); + process.stdout.write(element_string); + }; + process.stdout.write("|"); + process.stdout.write("\n"); + }; + this.print_border(); + }; }; -let state_of_integer = (i : number) : State => { +type State = "Dead" | "Alive"; + +type States = Array; + +type Board = Grid; + +const state_of_integer = (i : number) : State => { switch (i) { case 0 : return "Dead" ; case 1 : return "Alive" + ; default: throw("No known State for integer: " + i) } }; -let state_to_string = (state) : string => { +const state_to_string = (state : State) : string => { switch (state) { case "Dead" : return " " ; case "Alive": return "o" + ; default : throw("Illegal member of State type: " + state) } }; -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 : GridLocation) : 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]); +const board_new = ({rows, columns} : {rows: number, columns: number}) : Board => { + const init = (_) => state_of_integer(Math.round(Math.random())); + return new Grid({rows: rows, columns: columns, init: init}); }; -let state_is_alive = (s : State) : boolean => { - if (s === "Alive") {return true} else if (s === "Dead") {return false} +const state_is_alive = (s : State) : boolean => { + if (s === "Alive") { + return true + } else if (s === "Dead") { + return false + } else { + throw("Illegal member of State type: " + s) + } }; -let state_next = (state : State, neighbor_states : Array) : State => { - let neighbors_alive = neighbor_states.filter(state_is_alive).length; +const state_next = (state : State, neighbor_states : Array) : State => { + const neighbors_alive = neighbor_states.filter(state_is_alive).length; if (state === "Alive" && neighbors_alive < 2) { return "Dead" } else if (state === "Alive" && neighbors_alive < 4) { @@ -125,65 +143,38 @@ let state_next = (state : State, neighbor_states : Array) : 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; +const board_next = (b0 : Board) : Board => { + const b1 = b0.map( + (location) => { + const neighbor_locations = b0.moore_neighbors(location); + const neighbor_states = neighbor_locations.map((l) => b0.get(l)); + const state_0 = b0.get(location); + const state_1 = state_next(state_0, neighbor_states); + return 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"); +const console_clear = () : void => { + process.stdout.write("\x1B[2J"); } -let console_reset = () : void => { - process.stdout.write("\033[1;1H"); +const console_reset = () : void => { + process.stdout.write("\x1B[1;1H"); } -let board_loop = (b0 : Board) : void => { +const board_loop = (b0 : Board) : void => { console_reset(); - board_print(b0); - let b1 = board_next(b0); + b0.print(state_to_string); + const 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}); +const main = () : void => { + const height = parseInt(process.argv[2]) + const width = parseInt(process.argv[3]) + const b = board_new({rows: height - 3, columns: width - 2}); console_clear(); board_loop(b); };