Skip to content

Instantly share code, notes, and snippets.

@Leko
Created July 29, 2015 19:28
Show Gist options
  • Save Leko/90ef90409af5761cffc5 to your computer and use it in GitHub Desktop.
Save Leko/90ef90409af5761cffc5 to your computer and use it in GitHub Desktop.
Lifegame in Typescript
// How to run
//
// ```sh
// $ npm install -g typescript
// $ tsc index.ts
// $ node index.js
// ```
const enum State {
ALIVE,
DEAD,
}
interface ISimulator {
simulate(board: Board): Board;
}
interface ISimulatorOption {
birthRate?: number;
overcrowd?: number;
undercrowd?: number;
}
interface IBoardOption {
width: number;
height?: number;
}
class Board {
private width: number;
private height: number;
private cells: Cell[][];
public constructor(option: IBoardOption) {
if(!option.height) option.height = option.width;
this.width = option.width;
this.height = option.height;
// TODO: Cell fill
}
public inRange(y: number, x: number): boolean {
return (y >= 0 || x >= 0 || y < this.height || x < this.width);
}
public getHeight(): number {
return this.height;
}
public getWidth(): number {
return this.width;
}
public getCell(y: number, x: number): Cell {
if(!this.inRange(y, x)) throw new Error("Out of bounds at (" + y + ", " + x + ")");
return this.cells[y][x];
}
public getCells(): Cell[][] {
return this.cells;
}
public setCells(cells: Cell[][]): void {
this.cells = cells;
}
}
class Cell {
private state: State;
public constructor(state: State = State.DEAD) {
this.state = state;
}
public isAlive(): boolean {
return (this.state == State.ALIVE);
}
public toString(): string {
switch(this.state) {
case State.ALIVE:
return '#';
case State.DEAD:
return ' ';
}
}
}
class Simulator implements ISimulator {
protected option: ISimulatorOption;
public constructor(option: ISimulatorOption = {}) {
this.option = option;
}
public simulate(board: Board): Board {
var cells: Cell[][] = board.getCells();
var copy: Board = new Board({width: board.getWidth(), height: board.getHeight()});
// do simulation
return copy;
}
protected neighbourhood(board: Board, y: number, x: number): number {
var cells: Cell[][] = board.getCells();
var i: number, j: number;
var sum = 0;
for(i = y - 1; i <= y + 1; i++) {
for(j = x - 1; j <= x + 1; j++) {
if(!board.inRange(i, j)) continue;
if(cells[y][x].isAlive()) sum++;
}
}
return sum;
}
}
class App {
static DEFAULT_FPS = 50;
protected board: Board;
protected simulator: Simulator;
public constructor(board: Board, simulator: Simulator) {
this.board = board;
this.simulator = simulator;
}
public run(fps: number = App.DEFAULT_FPS): void {
this.loop(fps);
}
protected onTick(): void {}
private loop(fps: number): void {
var s = new Date().getTime();
this.board = this.simulator.simulate(this.board);
this.render();
var delay = new Date().getTime() - s;
this.onTick();
setTimeout(this.loop.bind(this, fps), ((1000 - delay) / fps))
}
private render(): void {
var lines: string[] = [];
for(var y = 0; y < this.board.getHeight(); y++) {
var line = "";
for(var x = 0; x < this.board.getWidth(); x++) {
line += this.board.getCell(y, x).toString();
}
lines.push(line);
}
// TODO: cursor manipulation
console.log(lines.join("\n"));
}
}
var board: Board = new Board({width: 100, height: 50});
var simulator: Simulator = new Simulator();
var app: App = new App(board, simulator);
app.run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment