|
<!DOCTYPE html> |
|
<html> |
|
|
|
<head> |
|
|
|
<base href='/'> |
|
<style>body { |
|
background-color: #cccccc; |
|
font-family: Roboto, Arial, sans-serif; |
|
color: #333333; |
|
} |
|
|
|
canvas { |
|
background-color: #000000; |
|
margin-top: 6px; |
|
} |
|
</style> |
|
<script src='https://www.stemcstudio.com:/vendor/[email protected]/domready.js'></script> |
|
<script src='https://unpkg.com/[email protected]/dist/system.js'></script> |
|
</head> |
|
|
|
<body> |
|
<script> |
|
try { |
|
if (window['System']) { |
|
System.config({ |
|
"warnings": false, |
|
"map": {} |
|
}); |
|
} |
|
} catch(e) { console.error(e) } |
|
</script> |
|
<script> |
|
try { |
|
System.register("./index.js", ["./main.js"], function (exports_1, context_1) { |
|
"use strict"; |
|
var main_1; |
|
var __moduleName = context_1 && context_1.id; |
|
return { |
|
setters: [ |
|
function (main_1_1) { |
|
main_1 = main_1_1; |
|
} |
|
], |
|
execute: function () { |
|
DomReady.ready(main_1.main).catch(function (e) { console.error(e); }); |
|
} |
|
}; |
|
}); |
|
|
|
System.register("./main.js", ["./model.js", "./view.js"], function (exports_1, context_1) { |
|
"use strict"; |
|
var model_1, view_1; |
|
var __moduleName = context_1 && context_1.id; |
|
function main() { |
|
const model = new model_1.Model(40, 40, { "threshold": 0.80 }); |
|
const view = new view_1.View('game-canvas', model, { margin: 1 }); |
|
let running = false; |
|
const stopButton = document.getElementById('stop'); |
|
setRunning(false); |
|
stopButton.addEventListener('click', () => { |
|
console.log("Start/Stop button was clicked."); |
|
setRunning(!running); |
|
}); |
|
const stepButton = document.getElementById('step'); |
|
stepButton.addEventListener('click', () => { |
|
console.log("Step button was clicked."); |
|
setRunning(false); |
|
model.step(); |
|
}); |
|
const clearButton = document.getElementById('clear'); |
|
clearButton.addEventListener('click', () => { |
|
console.log("Clear button was clicked."); |
|
setRunning(false); |
|
model.clear(); |
|
}); |
|
const resetButton = document.getElementById('reset'); |
|
resetButton.addEventListener('click', () => { |
|
console.log("Reset button was clicked."); |
|
setRunning(false); |
|
model.reset(); |
|
}); |
|
view.canvas.addEventListener('mousedown', function (mouse) { |
|
setRunning(false); |
|
const { row, column } = view.toPosition(mouse.offsetX, mouse.offsetY); |
|
model.setAlive(row, column, !model.isAlive(row, column)); |
|
}); |
|
function setRunning(isRunning) { |
|
running = isRunning; |
|
stopButton.value = running ? 'Stop' : 'Start'; |
|
} |
|
let frame = 0; |
|
const animate = function () { |
|
if (running) { |
|
if (frame === 30) { |
|
model.step(); |
|
frame = 0; |
|
} |
|
frame += 1; |
|
} |
|
view.draw(); |
|
window.requestAnimationFrame(animate); |
|
}; |
|
window.requestAnimationFrame(animate); |
|
} |
|
exports_1("main", main); |
|
return { |
|
setters: [ |
|
function (model_1_1) { |
|
model_1 = model_1_1; |
|
}, |
|
function (view_1_1) { |
|
view_1 = view_1_1; |
|
} |
|
], |
|
execute: function () { |
|
} |
|
}; |
|
}); |
|
|
|
System.register("./model.js", [], function (exports_1, context_1) { |
|
"use strict"; |
|
var THRESHOLD_DEFAULT, Model; |
|
var __moduleName = context_1 && context_1.id; |
|
return { |
|
setters: [], |
|
execute: function () { |
|
THRESHOLD_DEFAULT = 0.5; |
|
Model = class Model { |
|
constructor(rows, columns, options = {}) { |
|
this.data = []; |
|
this.next = []; |
|
this.threshold = typeof options.threshold === 'number' ? options.threshold : THRESHOLD_DEFAULT; |
|
this.rows = rows; |
|
this.columns = columns; |
|
this.reset(); |
|
} |
|
indexFromPosition(row, column) { |
|
row = row + this.rows; |
|
column = column + this.columns; |
|
return (row % this.rows) * this.columns + (column % this.columns); |
|
} |
|
isAlive(row, column) { |
|
return this.data[this.indexFromPosition(row, column)]; |
|
} |
|
setAlive(row, column, alive) { |
|
this.data[this.indexFromPosition(row, column)] = alive; |
|
} |
|
clear() { |
|
for (let row = 0; row < this.rows; row++) { |
|
for (let column = 0; column < this.columns; column++) { |
|
this.setAlive(row, column, false); |
|
} |
|
} |
|
} |
|
reset() { |
|
for (let row = 0; row < this.rows; row++) { |
|
for (let column = 0; column < this.columns; column++) { |
|
this.setAlive(row, column, Math.random() > this.threshold); |
|
} |
|
} |
|
} |
|
neighbors(row, column) { |
|
let count = 0; |
|
if (this.isAlive(row - 1, column - 1)) { |
|
count += 1; |
|
} |
|
if (this.isAlive(row - 1, column)) { |
|
count += 1; |
|
} |
|
if (this.isAlive(row - 1, column + 1)) { |
|
count += 1; |
|
} |
|
if (this.isAlive(row, column - 1)) { |
|
count += 1; |
|
} |
|
if (this.isAlive(row, column + 1)) { |
|
count += 1; |
|
} |
|
if (this.isAlive(row + 1, column - 1)) { |
|
count += 1; |
|
} |
|
if (this.isAlive(row + 1, column)) { |
|
count += 1; |
|
} |
|
if (this.isAlive(row + 1, column + 1)) { |
|
count += 1; |
|
} |
|
return count; |
|
} |
|
step() { |
|
for (let row = 0; row < this.rows; row++) { |
|
for (let column = 0; column < this.columns; column++) { |
|
const index = this.indexFromPosition(row, column); |
|
const N = this.neighbors(row, column); |
|
if (this.isAlive(row, column)) { |
|
if (N < 2) { |
|
this.next[index] = false; |
|
} |
|
else if (N > 3) { |
|
this.next[index] = false; |
|
} |
|
else { |
|
this.next[index] = this.data[index]; |
|
} |
|
} |
|
else { |
|
if (N === 3) { |
|
this.next[index] = true; |
|
} |
|
else { |
|
this.next[index] = this.data[index]; |
|
} |
|
} |
|
} |
|
} |
|
for (let row = 0; row < this.rows; row++) { |
|
for (let column = 0; column < this.columns; column++) { |
|
const index = this.indexFromPosition(row, column); |
|
this.data[index] = this.next[index]; |
|
} |
|
} |
|
} |
|
}; |
|
exports_1("Model", Model); |
|
} |
|
}; |
|
}); |
|
|
|
System.register("./view.js", [], function (exports_1, context_1) { |
|
"use strict"; |
|
var View; |
|
var __moduleName = context_1 && context_1.id; |
|
return { |
|
setters: [], |
|
execute: function () { |
|
View = class View { |
|
constructor(canvasId, model, options = {}) { |
|
this.margin = typeof options.margin === 'number' ? options.margin : 1; |
|
this.model = model; |
|
this.canvas = document.getElementById(canvasId); |
|
if (this.canvas) { |
|
this.ctxt2d = this.canvas.getContext('2d'); |
|
this.stepX = this.canvas.width / model.columns; |
|
this.stepY = this.canvas.height / model.rows; |
|
this.tileX = (this.canvas.width / model.columns) - 2 * this.margin; |
|
this.tileY = (this.canvas.height / model.rows) - 2 * this.margin; |
|
} |
|
else { |
|
throw new Error(`${canvasId} is not an element identifier in the document.`); |
|
} |
|
} |
|
draw() { |
|
this.ctxt2d.fillStyle = '#444444'; |
|
this.ctxt2d.fillRect(0, 0, this.canvas.width, this.canvas.height); |
|
for (let row = 0; row < this.model.rows; row++) { |
|
for (let column = 0; column < this.model.columns; column++) { |
|
this.drawCell(row, column); |
|
} |
|
} |
|
} |
|
drawCell(row, column) { |
|
this.ctxt2d.fillStyle = this.model.isAlive(row, column) ? '#555577' : '#AAAACC'; |
|
const x = this.margin + column * this.stepX; |
|
const y = this.margin + row * this.stepY; |
|
this.ctxt2d.fillRect(x, y, this.tileX, this.tileY); |
|
} |
|
toPosition(x, y) { |
|
const column = (x - x % this.stepX) / this.stepX; |
|
const row = (y - y % this.stepY) / this.stepY; |
|
return { row, column }; |
|
} |
|
}; |
|
exports_1("View", View); |
|
} |
|
}; |
|
}); |
|
|
|
} catch(e) { console.error(e) } |
|
</script> |
|
<input type='button' id='stop' value='Stop' /> |
|
<input type='button' id='step' value='Step' /> |
|
<input type='button' id='clear' value='Clear' /> |
|
<input type='button' id='reset' value='Reset' /> |
|
<br/> |
|
<canvas id='game-canvas' width='500' height='500'></canvas> |
|
<script> |
|
System.defaultJSExtensions = true |
|
System.import('./index.js').catch(function(e) { console.error(e) }) |
|
</script> |
|
</body> |
|
|
|
</html> |