X-Git-Url: https://git.xandkar.net/?p=cellular-automata.git;a=blobdiff_plain;f=life%2F006%2Flife.ts;fp=life%2F006%2Flife.ts;h=0204e5f0d3a72f858e2b79687f5392868a14b760;hp=0000000000000000000000000000000000000000;hb=e16b8b54be348430aef022ac39696df272100cd7;hpb=3dade747beb29d8a3f8dfb14c4afe54efc06d2ae 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();