mirror of
https://github.com/Aviortheking/game-of-life.js.git
synced 2025-04-22 10:52:11 +00:00
v2 pouet
This commit is contained in:
parent
823b453999
commit
31deec5751
@ -10,11 +10,17 @@
|
|||||||
canvas {
|
canvas {
|
||||||
background: grey
|
background: grey
|
||||||
}
|
}
|
||||||
|
p {
|
||||||
|
display: inline
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas></canvas>
|
<canvas></canvas>
|
||||||
<button class="start">Start/Continue</button>
|
<button class="start">Start/Continue</button>
|
||||||
|
<button class="step">Step</button>
|
||||||
<button class="pause">Pause</button>
|
<button class="pause">Pause</button>
|
||||||
|
<button class="grid">Switch Grid</button>
|
||||||
|
<p>Counter: <span class="counter">0</span> Cells alive: <span class="cell-count">0</span> Time to handle: <span class="speed">0</span></p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
222
main.ts
222
main.ts
@ -1,175 +1,4 @@
|
|||||||
class GOF {
|
import GOF from './src/GOF'
|
||||||
canvas: HTMLCanvasElement
|
|
||||||
ctx: CanvasRenderingContext2D
|
|
||||||
|
|
||||||
cellSize: number
|
|
||||||
width: number
|
|
||||||
height: number
|
|
||||||
|
|
||||||
alive: Cell[] = []
|
|
||||||
public constructor(canvas: HTMLCanvasElement, width: number = 100, height: number = 100, size: number = 10) {
|
|
||||||
this.ctx = canvas.getContext("2d")
|
|
||||||
this.canvas = canvas
|
|
||||||
this.width = width
|
|
||||||
this.canvas.width = width
|
|
||||||
this.height = height
|
|
||||||
this.canvas.height = height
|
|
||||||
this.cellSize = size
|
|
||||||
console.log(this.alive)
|
|
||||||
}
|
|
||||||
|
|
||||||
public addCell(x: number, y: number): Cell {
|
|
||||||
let cell = new Cell(x, y, this.cellSize, this, true)
|
|
||||||
this.alive.push(cell)
|
|
||||||
return cell
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCellAt(x: number, y: number): Cell {
|
|
||||||
return (this.alive as any).find((el: Cell) => {return el.x == x && el.y == y})
|
|
||||||
}
|
|
||||||
|
|
||||||
public update() {
|
|
||||||
let cellsToCheck: Cell[] = []
|
|
||||||
|
|
||||||
this.ctx.clearRect(0,0,this.width,this.height)
|
|
||||||
this.alive.forEach(cell => {
|
|
||||||
cellsToCheck.push(...cell.getDeadNeighbour())
|
|
||||||
// console.log(...cell.getDeadNeighbour())
|
|
||||||
})
|
|
||||||
cellsToCheck.push(...this.alive)
|
|
||||||
// console.log(cellsToCheck)
|
|
||||||
let tAlive: Cell [] = []
|
|
||||||
cellsToCheck.forEach((cell: Cell) => {
|
|
||||||
cell.prepareNextTurn()
|
|
||||||
if (
|
|
||||||
cell.ntValue == true &&
|
|
||||||
!(tAlive as any).find((el: Cell) => {return el.x == cell.x && el.y == cell.y})
|
|
||||||
) {
|
|
||||||
tAlive.push(cell)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.alive = tAlive
|
|
||||||
|
|
||||||
this.alive.forEach(cell => {
|
|
||||||
cell.draw()
|
|
||||||
})
|
|
||||||
this.ctx.fillStyle = "black"
|
|
||||||
this.ctx.beginPath()
|
|
||||||
for (let index = 0; index < this.height; index += this.cellSize) {
|
|
||||||
this.ctx.moveTo(0, index)
|
|
||||||
this.ctx.lineTo(this.width, index)
|
|
||||||
this.ctx.stroke()
|
|
||||||
}
|
|
||||||
for (let index = 0; index < this.width; index += this.cellSize) {
|
|
||||||
this.ctx.moveTo(index, 0)
|
|
||||||
this.ctx.lineTo(index, this.height)
|
|
||||||
this.ctx.stroke()
|
|
||||||
}
|
|
||||||
this.ctx.closePath()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Cell {
|
|
||||||
|
|
||||||
// public constructor(x:number, y: number, size: number, engine: GOF) {
|
|
||||||
// this.x = x
|
|
||||||
// this.y = y
|
|
||||||
// this.size = size
|
|
||||||
// this.engine = engine
|
|
||||||
// }
|
|
||||||
|
|
||||||
public constructor(x:number, y: number, size: number, engine: GOF, value: boolean = false) {
|
|
||||||
this.x = x
|
|
||||||
this.y = y
|
|
||||||
this.size = size
|
|
||||||
this.engine = engine
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private color: string = "yellow"
|
|
||||||
|
|
||||||
private _engine: GOF
|
|
||||||
public set engine(v: GOF) {
|
|
||||||
this._engine = v
|
|
||||||
}
|
|
||||||
public get engine(): GOF {
|
|
||||||
return this._engine
|
|
||||||
}
|
|
||||||
|
|
||||||
private _x: number
|
|
||||||
public set x(v: number) {
|
|
||||||
this._x = v
|
|
||||||
}
|
|
||||||
public get x(): number {
|
|
||||||
return this._x
|
|
||||||
}
|
|
||||||
|
|
||||||
private _y: number
|
|
||||||
public set y(v: number) {
|
|
||||||
this._y = v
|
|
||||||
}
|
|
||||||
public get y(): number {
|
|
||||||
return this._y
|
|
||||||
}
|
|
||||||
|
|
||||||
private _size: number
|
|
||||||
public set size(v: number) {
|
|
||||||
this._size = v
|
|
||||||
}
|
|
||||||
public get size(): number {
|
|
||||||
return this._size
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private _value: boolean = false
|
|
||||||
public set value(v: boolean) {
|
|
||||||
this._value = v
|
|
||||||
}
|
|
||||||
public get value(): boolean {
|
|
||||||
return this._value
|
|
||||||
}
|
|
||||||
|
|
||||||
private _ntValue: boolean
|
|
||||||
public set ntValue(v: boolean) {
|
|
||||||
this._ntValue = v
|
|
||||||
}
|
|
||||||
public get ntValue(): boolean {
|
|
||||||
return this._ntValue
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public getDeadNeighbour() {
|
|
||||||
let nb: Cell[] = []
|
|
||||||
for (let i = -1; i <= 1; i++) {
|
|
||||||
for (let j = -1; j <= 1; j++) {
|
|
||||||
let cell = this.engine.getCellAt(this.x+i, this.y+j)
|
|
||||||
if (cell === undefined) {
|
|
||||||
nb.push(new Cell(this.x+i, this.y+j, this.size, this.engine))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nb
|
|
||||||
}
|
|
||||||
|
|
||||||
public draw() {
|
|
||||||
if (this.ntValue) this.value = true
|
|
||||||
this.ntValue = undefined
|
|
||||||
this.engine.ctx.fillStyle = this.color
|
|
||||||
this.engine.ctx.fillRect(this.x*this.size,this.y*this.size,this.size,this.size)
|
|
||||||
// this.engine.ctx.fillStyle = "black"
|
|
||||||
// this.engine.ctx.font = "30px Roboto"
|
|
||||||
// this.engine.ctx.fillText(this.getDeadNeighbour().length + "", this.x*this.size+this.size/2.5,this.y*this.size+this.size/1.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
public prepareNextTurn() {
|
|
||||||
let nLength = this.getDeadNeighbour().length
|
|
||||||
if (!this.value && nLength == 6) this.ntValue = true
|
|
||||||
if (this.value && (nLength > 6 || nLength < 5)) this.ntValue = false
|
|
||||||
if (this.ntValue === undefined) this.ntValue = this.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
go to each alive cells
|
go to each alive cells
|
||||||
@ -185,18 +14,35 @@ For a space that is 'empty' or 'unpopulated'
|
|||||||
Each cell with three neighbors becomes populated. 6 dead
|
Each cell with three neighbors becomes populated. 6 dead
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
let canvasWidth = 1000
|
||||||
|
let cellNumber = 50
|
||||||
|
let cellSize = canvasWidth/cellNumber
|
||||||
|
|
||||||
const c: HTMLCanvasElement = document.querySelector("canvas")
|
const c: HTMLCanvasElement = document.querySelector("canvas")
|
||||||
let gof = new GOF(c, 900, 900, 900/100);
|
|
||||||
|
c.addEventListener("mousedown", (e) => {
|
||||||
|
const rect = c.getBoundingClientRect()
|
||||||
|
const x = (Math as any).trunc((e.clientX - rect.left)/cellSize)
|
||||||
|
const y = (Math as any).trunc((e.clientY - rect.top)/cellSize)
|
||||||
|
console.log("x: " + x + " y: " + y)
|
||||||
|
let tCell = gof.getCellAt(x, y)
|
||||||
|
if (tCell !== undefined) {
|
||||||
|
tCell.value = false
|
||||||
|
tCell.ntValue = false
|
||||||
|
}
|
||||||
|
else tCell = gof.addCell(x, y)
|
||||||
|
tCell.draw()
|
||||||
|
})
|
||||||
|
|
||||||
|
let gof = new GOF(c, canvasWidth, canvasWidth, cellSize);
|
||||||
(window as any).gof = gof
|
(window as any).gof = gof
|
||||||
gof.update()
|
gof.update()
|
||||||
// gof.addCell(3,4)
|
// gof.addCell(3,4)
|
||||||
// let cell = gof.addCell(4,4)
|
// let cell = gof.addCell(4,4)
|
||||||
gof.addCell(5,4)
|
// for (let k = 0; k < cellNumber; k++) {
|
||||||
for (let k = 0; k < 100; k++) {
|
// gof.addCell(k, cellNumber/2)
|
||||||
gof.addCell(k, 100/2)
|
|
||||||
|
|
||||||
}
|
// }
|
||||||
gof.alive.forEach(el => {
|
gof.alive.forEach(el => {
|
||||||
el.draw()
|
el.draw()
|
||||||
})
|
})
|
||||||
@ -205,11 +51,27 @@ gof.alive.forEach(el => {
|
|||||||
let interval: number
|
let interval: number
|
||||||
|
|
||||||
document.querySelector(".start").addEventListener("click", () => {
|
document.querySelector(".start").addEventListener("click", () => {
|
||||||
interval = setInterval(() => {
|
if (interval === undefined) interval = setInterval(() => {
|
||||||
|
let start = new Date().getTime()
|
||||||
gof.update()
|
gof.update()
|
||||||
}, 10)
|
let speed = document.querySelector(".speed")
|
||||||
|
speed.innerHTML = new Date().getTime() - start + ""
|
||||||
|
}, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
document.querySelector(".pause").addEventListener("click", () => {
|
document.querySelector(".pause").addEventListener("click", () => {
|
||||||
clearInterval(interval)
|
if (interval != undefined) clearInterval(interval)
|
||||||
|
interval = undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
document.querySelector(".grid").addEventListener("click", () => {
|
||||||
|
gof.showGrid = !gof.showGrid
|
||||||
|
})
|
||||||
|
|
||||||
|
document.querySelector(".step").addEventListener("click", () => {
|
||||||
|
let start = new Date().getTime()
|
||||||
|
gof.update()
|
||||||
|
let speed = document.querySelector(".speed")
|
||||||
|
speed.innerHTML = new Date().getTime() - start + ""
|
||||||
|
|
||||||
})
|
})
|
||||||
|
99
src/Cell.ts
Normal file
99
src/Cell.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import GOF from './GOF'
|
||||||
|
|
||||||
|
export default class Cell {
|
||||||
|
|
||||||
|
public constructor(x:number, y: number, size: number, engine: GOF, value: boolean = false) {
|
||||||
|
this.x = x
|
||||||
|
this.y = y
|
||||||
|
this.size = size
|
||||||
|
this.engine = engine
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private color: string = "yellow"
|
||||||
|
|
||||||
|
private _engine: GOF
|
||||||
|
public set engine(v: GOF) {
|
||||||
|
this._engine = v
|
||||||
|
}
|
||||||
|
public get engine(): GOF {
|
||||||
|
return this._engine
|
||||||
|
}
|
||||||
|
|
||||||
|
private _x: number
|
||||||
|
public set x(v: number) {
|
||||||
|
this._x = v
|
||||||
|
}
|
||||||
|
public get x(): number {
|
||||||
|
return this._x
|
||||||
|
}
|
||||||
|
|
||||||
|
private _y: number
|
||||||
|
public set y(v: number) {
|
||||||
|
this._y = v
|
||||||
|
}
|
||||||
|
public get y(): number {
|
||||||
|
return this._y
|
||||||
|
}
|
||||||
|
|
||||||
|
private _size: number
|
||||||
|
public set size(v: number) {
|
||||||
|
this._size = v
|
||||||
|
}
|
||||||
|
public get size(): number {
|
||||||
|
return this._size
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _value: boolean = false
|
||||||
|
public set value(v: boolean) {
|
||||||
|
this._value = v
|
||||||
|
}
|
||||||
|
public get value(): boolean {
|
||||||
|
return this._value
|
||||||
|
}
|
||||||
|
|
||||||
|
private _ntValue: boolean
|
||||||
|
public set ntValue(v: boolean) {
|
||||||
|
this._ntValue = v
|
||||||
|
}
|
||||||
|
public get ntValue(): boolean {
|
||||||
|
return this._ntValue
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public getDeadNeighbour() {
|
||||||
|
let nb: Cell[] = []
|
||||||
|
for (let i = -1; i <= 1; i++) {
|
||||||
|
for (let j = -1; j <= 1; j++) {
|
||||||
|
let cell = this.engine.getCellAt(this.x+i, this.y+j)
|
||||||
|
if (cell === undefined) {
|
||||||
|
nb.push(new Cell(this.x+i, this.y+j, this.size, this.engine))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nb
|
||||||
|
}
|
||||||
|
|
||||||
|
public draw(draw: boolean = true) {
|
||||||
|
if (this.ntValue) this.value = true
|
||||||
|
this.ntValue = undefined
|
||||||
|
if (draw) {
|
||||||
|
this.engine.ctx.fillStyle = this.color
|
||||||
|
if (this.value)this.engine.ctx.fillRect(this.x*this.size,this.y*this.size,this.size,this.size)
|
||||||
|
else this.engine.ctx.clearRect(this.x*this.size,this.y*this.size,this.size,this.size)
|
||||||
|
}
|
||||||
|
// this.engine.ctx.fillStyle = "black"
|
||||||
|
// this.engine.ctx.font = "30px Roboto"
|
||||||
|
// this.engine.ctx.fillText(this.getDeadNeighbour().length + "", this.x*this.size+this.size/2.5,this.y*this.size+this.size/1.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
public prepareNextTurn() {
|
||||||
|
let nLength = this.getDeadNeighbour().length
|
||||||
|
if (!this.value && nLength == 6) this.ntValue = true
|
||||||
|
if (this.value && (nLength > 6 || nLength < 5)) this.ntValue = false
|
||||||
|
if (this.ntValue === undefined) this.ntValue = this.value
|
||||||
|
}
|
||||||
|
}
|
106
src/GOF.ts
Normal file
106
src/GOF.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import Cell from './Cell'
|
||||||
|
|
||||||
|
interface keyVal {
|
||||||
|
[key: string]: Cell
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class GOF {
|
||||||
|
canvas: HTMLCanvasElement
|
||||||
|
ctx: CanvasRenderingContext2D
|
||||||
|
|
||||||
|
cellSize: number
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
|
||||||
|
alive: Cell[] = []
|
||||||
|
|
||||||
|
showGrid: boolean = true
|
||||||
|
public constructor(canvas: HTMLCanvasElement, width: number = 100, height: number = 100, size: number = 10) {
|
||||||
|
this.ctx = canvas.getContext("2d")
|
||||||
|
this.canvas = canvas
|
||||||
|
this.width = width
|
||||||
|
this.canvas.width = width
|
||||||
|
this.height = height
|
||||||
|
this.canvas.height = height
|
||||||
|
this.cellSize = size
|
||||||
|
console.log(this.alive)
|
||||||
|
}
|
||||||
|
|
||||||
|
public addCell(x: number, y: number): Cell {
|
||||||
|
let cell = new Cell(x, y, this.cellSize, this, true)
|
||||||
|
this.alive.push(cell)
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCellAt(x: number, y: number): Cell {
|
||||||
|
return (this.alive as any).find((el: Cell) => {return el.x == x && el.y == y})
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeDups(cells: Cell[]): Cell[] {
|
||||||
|
let temp: keyVal = {}
|
||||||
|
for (const cell of cells) {
|
||||||
|
temp[`${cell.x}:${cell.y}`] = cell
|
||||||
|
}
|
||||||
|
let arr: Cell[] = []
|
||||||
|
for (const key in temp) {
|
||||||
|
if (temp.hasOwnProperty(key)) {
|
||||||
|
const cell = temp[key];
|
||||||
|
arr.push(cell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
public update() {
|
||||||
|
let counter = document.querySelector(".counter")
|
||||||
|
counter.innerHTML = parseInt(counter.innerHTML)+1 + ""
|
||||||
|
let cellsToCheck: Cell[] = []
|
||||||
|
|
||||||
|
this.ctx.clearRect(0,0,this.width,this.height)
|
||||||
|
this.alive.forEach(cell => {
|
||||||
|
cellsToCheck.push(...cell.getDeadNeighbour())
|
||||||
|
// console.log(...cell.getDeadNeighbour())
|
||||||
|
})
|
||||||
|
cellsToCheck.push(...this.alive)
|
||||||
|
cellsToCheck = this.removeDups(cellsToCheck)
|
||||||
|
// console.log(cellsToCheck)
|
||||||
|
let tAlive: Cell [] = []
|
||||||
|
cellsToCheck.forEach((cell: Cell) => {
|
||||||
|
cell.prepareNextTurn()
|
||||||
|
if (
|
||||||
|
cell.ntValue == true &&
|
||||||
|
// cell.x <= this.width/this.cellSize &&
|
||||||
|
// cell.y <= this.height/this.cellSize &&
|
||||||
|
!(tAlive as any).find((el: Cell) => {return el.x == cell.x && el.y == cell.y})
|
||||||
|
) {
|
||||||
|
tAlive.push(cell)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.alive = tAlive
|
||||||
|
let count = document.querySelector(".cell-count")
|
||||||
|
count.innerHTML = this.alive.length + ""
|
||||||
|
|
||||||
|
this.alive.forEach(cell => {
|
||||||
|
let toDraw = true
|
||||||
|
if (cell.y > this.height/this.cellSize || cell.y < 0) toDraw = false
|
||||||
|
if (cell.x > this.width/this.cellSize || cell.x < 0) toDraw = false
|
||||||
|
cell.draw(toDraw)
|
||||||
|
})
|
||||||
|
if (this.showGrid) {
|
||||||
|
this.ctx.fillStyle = "black"
|
||||||
|
this.ctx.beginPath()
|
||||||
|
for (let index = 0; index < this.height; index += this.cellSize) {
|
||||||
|
this.ctx.moveTo(0, index)
|
||||||
|
this.ctx.lineTo(this.width, index)
|
||||||
|
this.ctx.stroke()
|
||||||
|
}
|
||||||
|
for (let index = 0; index < this.width; index += this.cellSize) {
|
||||||
|
this.ctx.moveTo(index, 0)
|
||||||
|
this.ctx.lineTo(index, this.height)
|
||||||
|
this.ctx.stroke()
|
||||||
|
}
|
||||||
|
this.ctx.closePath()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user