1 type State = "Dead" | "Alive";
3 type States = Array<State>;
5 type Board = Array<States>;
7 type GridLocation = {r: number, k: number};
10 private rows : number;
11 private columns : number;
12 private cells : Array<Array<T>>;
15 {rows, columns, init} :
18 , init : (location: GridLocation) => T
23 this.columns = columns;
25 for (let r = 0; r < rows; r++) {
27 for (let k = 0; k < columns; k++) {
28 cells[r][k] = init({r: r, k: k})
34 moore_neighbors(origin : GridLocation) : Array<GridLocation> {
36 [ {r: -1, k: -1}, {r: -1, k: 0}, {r: -1, k: 1}
37 , {r: 0, k: -1}, {r: 0, k: 1}
38 , {r: 1, k: -1}, {r: 1, k: 0}, {r: 1, k: 1}
40 let offset_to_location =
41 (offset) => {return {r: origin.r + offset.r, k: origin.k + offset.k}};
42 let locations = offsets.map(offset_to_location);
43 let is_location_within_bounds =
44 ({r, k}) => r >= 0 && k >= 0 && r < this.rows && k < this.columns;
45 return locations.filter(is_location_within_bounds)
48 mapi(f : (location: GridLocation) => T) {
50 for (let r = 0; r < this.rows; r++) {
52 for (let k = 0; k < this.columns; k++) {
53 let location = {r: r, k: k};
54 let neighbors = this.moore_neighbors(location);
55 cells[r][k] = f(location);
58 let init = ({r, k}) => cells[r][k];
59 let grid = new Grid({rows: this.rows, columns: this.columns, init: init});
64 let state_of_integer = (i : number) : State => {
66 { case 0 : return "Dead"
67 ; case 1 : return "Alive"
71 let state_to_string = (state) : string => {
73 { case "Dead" : return " "
74 ; case "Alive": return "o"
78 let board_new = ({rows, columns} : {rows: number, columns: number}) : Board => {
80 for (let r = 0; r < rows; r++) {
82 for (let k = 0; k < columns; k++) {
83 let zero_or_one = Math.round(Math.random());
84 b[r][k] = state_of_integer(zero_or_one);
90 let board_neighbors = (b : Board, origin : GridLocation) : States => {
92 let cols = b[0].length;
94 [ {r: -1, k: -1}, {r: -1, k: 0}, {r: -1, k: 1}
95 , {r: 0, k: -1}, {r: 0, k: 1}
96 , {r: 1, k: -1}, {r: 1, k: 0}, {r: 1, k: 1}
98 let offset_to_location =
99 (offset) => {return {r: origin.r + offset.r, k: origin.k + offset.k}};
100 let locations = offsets.map(offset_to_location);
101 let is_location_within_bounds =
103 return r >= 0 && k >= 0 && r < rows && k < cols
105 let locations_within_bounds = locations.filter(is_location_within_bounds);
106 return locations_within_bounds.map(({r, k}) => b[r][k]);
109 let state_is_alive = (s : State) : boolean => {
110 if (s === "Alive") {return true} else if (s === "Dead") {return false}
113 let state_next = (state : State, neighbor_states : Array<State>) : State => {
114 let neighbors_alive = neighbor_states.filter(state_is_alive).length;
115 if (state === "Alive" && neighbors_alive < 2) {
117 } else if (state === "Alive" && neighbors_alive < 4) {
119 } else if (state === "Alive" && neighbors_alive > 3) {
121 } else if (state === "Dead" && neighbors_alive === 3) {
128 let board_next = (b0 : Board) : Board => {
130 for (let r = 0; r < b0.length; r++) {
132 for (let k = 0; k < b0[r].length; k++) {
133 let neighbors = board_neighbors(b0, {r: r, k: k});
134 let state_0 = b0[r][k];
135 let state_1 = state_next(state_0, neighbors);
142 let board_print_border = (b : Board) : void => {
143 process.stdout.write("+");
144 for (let k = 0; k < b[0].length; k++) {
145 process.stdout.write("-");
147 process.stdout.write("+");
148 process.stdout.write("\n");
151 let board_print = (b : Board) : void => {
152 board_print_border(b);
154 let columns = b[0].length;
155 for (let r = 0; r < rows; r++) {
156 process.stdout.write("|");
157 for (let k = 0; k < columns; k++) {
159 let state_string = state_to_string(state);
160 process.stdout.write(state_string);
162 process.stdout.write("|");
163 process.stdout.write("\n");
165 board_print_border(b);
168 let console_clear = () : void => {
169 process.stdout.write("\033[2J");
172 let console_reset = () : void => {
173 process.stdout.write("\033[1;1H");
176 let board_loop = (b0 : Board) : void => {
179 let b1 = board_next(b0);
180 setTimeout(() => board_loop(b1), 250)
183 let main = () : void => {
184 let height = parseInt(process.argv[2])
185 let width = parseInt(process.argv[3])
186 let b = board_new({rows: height - 3, columns: width - 2});