Last active
April 24, 2017 05:36
-
-
Save shigehiro-yanbe/9f51972c78c19f623c296a36cc87547e to your computer and use it in GitHub Desktop.
ライフゲーム
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var PIXEL_SIZE = 8; | |
var ModelEvent = { | |
Update: 0, | |
Play: 1, | |
Stop: 2, | |
SizeChange: 3, | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//============================================================================= | |
var Controller = (function(){ | |
var Controller = function() { | |
this.width = 32; | |
this.height = 32; | |
this.model = new Model(this.width, this.height); | |
this.view = new View(this.model, this); | |
this.model.Start(); | |
} | |
var p = Controller.prototype; | |
p.Stop = function() { this.model.Stop(); } | |
p.Play = function() { this.model.Start(); } | |
p.Clear = function() { this.model.Clear(); } | |
p.SetRandom = function() { this.model.SetRandom(); } | |
p.SizeChange = function(width,height) { this.model.SizeChange(width,height); } | |
p.MouseDown = function(e) { this.model.MouseDown(e); } | |
p.MouseUp = function(e) { this.model.MouseUp(e); } | |
p.MouseMove = function(e) { this.model.MouseMove(e); } | |
return Controller; | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<title>lifegame</title> | |
<script src="constants.js"></script> | |
<script src="matrix.js"></script> | |
<script src="lifegame.js"></script> | |
<script src="mousehandler.js"></script> | |
<script src="model.js"></script> | |
<script src="view.js"></script> | |
<script src="controller.js"></script> | |
</head> | |
<body onload="new Controller();"> | |
<form> | |
<input id="stop" type="button" value="停止"> | |
<input id="play" type="button" value="再生"> | |
<input id="clear" type="button" value="クリア"> | |
<input id="random" type="button" value="ランダム"> | |
幅: | |
<input id="width" type="text" size="5"> | |
高さ: | |
<input id="height" type="text" size="5"> | |
<input id="size" type="button" value="サイズ変更"> | |
</form> | |
<canvas id="canvas" style="border: solid thin #000000"> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//============================================================================= | |
// ライフゲームの状態クラス | |
var LifeGame = (function(){ | |
// コンストラクタ | |
var LifeGame = function(width, height) { | |
this.width = width; | |
this.height = height; | |
this.front = new Matrix(width+2, height+2); | |
this.back = new Matrix(width+2, height+2); | |
this.SetRandom(); | |
} | |
var p = LifeGame.prototype; | |
// ランダムに初期状態を設定する | |
p.SetRandom = function() { | |
for (var y = 1; y <= this.height; ++y) { | |
for (var x = 1; x <= this.width; ++x) { | |
this.front.set(x, y, Math.random() <= 0.25); | |
} | |
} | |
} | |
// クリア | |
p.Clear = function() { | |
this.front.Clear(); | |
} | |
// 一世代進める | |
p.NextGeneration = function() { | |
for (var y = 1; y <= this.height; ++y) { | |
for (var x = 1; x <= this.width; ++x) { | |
this.back.set(x, y, this.front.nextState(x,y)); | |
} | |
} | |
this.swap(); | |
} | |
// フロントバッファとバックバッファを入れ替える | |
p.swap = function() { | |
var tmp = this.front; | |
this.front = this.back; | |
this.back = tmp; | |
} | |
// 指定セルの状態を返す | |
p.Get = function(x, y) { | |
return this.front.get(x+1,y+1); | |
} | |
// 指定セルの状態を設定する | |
p.Set = function(x,y,onoff) { | |
this.front.set(x+1,y+1,onoff); | |
} | |
return LifeGame; | |
})(); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 一世代分の状態を保持する二次元配列クラス | |
var Matrix = (function(){ | |
// コンストラクタ | |
var Matrix = function(width, height) { | |
this.width = width; | |
this.height = height; | |
this.matrix = this.createMatrix(width, height); | |
} | |
var p = Matrix.prototype; | |
// 二次元配列を作る | |
p.createMatrix = function(width, height) { | |
var matrix = new Array(height); | |
for (var h = 0; h < height; ++h) { | |
matrix[h] = new Array(width); | |
for (var w = 0; w < width; ++w) { | |
matrix[h][w] = false; | |
} | |
} | |
return matrix; | |
} | |
// 全クリア | |
p.Clear = function() { | |
for (var y = 0; y < this.height; ++y) { | |
for (var x = 0; x < this.width; ++x) { | |
this.matrix[y][x] = false; | |
} | |
} | |
} | |
// 指定のマスの周囲のtrueの数を返す | |
p.count = function(x, y) { | |
var c = 0; | |
var xl = x - 1; | |
var xr = x + 1; | |
var yu = y - 1; | |
var yd = y + 1; | |
if (this.matrix[yu][xl]) ++c; | |
if (this.matrix[yu][x ]) ++c; | |
if (this.matrix[yu][xr]) ++c; | |
if (this.matrix[y ][xl]) ++c; | |
if (this.matrix[y ][xr]) ++c; | |
if (this.matrix[yd][xl]) ++c; | |
if (this.matrix[yd][x ]) ++c; | |
if (this.matrix[yd][xr]) ++c; | |
return c; | |
} | |
// 指定のマスの次世代の状態を返す | |
p.nextState = function(x, y) { | |
switch (this.count(x,y)) { | |
case 2: return this.get(x, y); | |
case 3: return true; | |
default: return false; | |
} | |
} | |
// 指定のマスの状態を返す | |
p.get = function(x, y) { | |
return this.matrix[y][x]; | |
} | |
// 指定のマスの状態を設定する | |
p.set = function(x, y, onoff) { | |
this.matrix[y][x] = onoff; | |
} | |
return Matrix; | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//============================================================================= | |
var Model = (function(){ | |
var Model = function() { | |
this.Width = 32; | |
this.Height = 32; | |
this.lifegame = new LifeGame(this.Width, this.Height); | |
this.isPlay = true; | |
this.listener = null; | |
this.mouseHandler = new MouseHandler_PlayMode(); | |
} | |
var p = Model.prototype; | |
p.Start = function() { | |
this.isPlay = true; | |
this.update(); | |
this.notifyEvent( ModelEvent.Play ); | |
this.mouseHandler = new MouseHandler_PlayMode(); | |
} | |
p.Stop = function() { | |
this.isPlay = false; | |
this.notifyEvent( ModelEvent.Stop ); | |
this.mouseHandler = new MouseHandler_EditMode(this); | |
} | |
p.Clear = function() { | |
this.lifegame.Clear(); | |
this.notifyEvent( ModelEvent.Update ); | |
this.Stop(); | |
} | |
p.SetRandom = function() { | |
this.lifegame.SetRandom(); | |
this.notifyEvent( ModelEvent.Update ); | |
this.Stop(); | |
} | |
p.SizeChange = function(width,height) { | |
this.Width = width; | |
this.Height = height; | |
this.lifegame = new LifeGame(width,height); | |
this.notifyEvent( ModelEvent.SizeChange ); | |
this.Stop(); | |
} | |
p.update = function() { | |
if (this.isPlay) { | |
this.lifegame.NextGeneration(); | |
this.notifyEvent( ModelEvent.Update ); | |
var self = this; | |
setTimeout( function(){ self.update(); }, 500 ); | |
} | |
} | |
p.notifyEvent = function(event) { | |
if (this.listener) { | |
this.listener(event); | |
} | |
} | |
p.Get = function(x,y) { | |
return this.lifegame.Get(x,y); | |
} | |
p.Set = function(x,y,onoff) { | |
this.lifegame.Set(x,y,onoff); | |
} | |
p.RegisterEventListener = function(listener) { | |
this.listener = listener; | |
} | |
p.MouseDown = function(e) { | |
this.mouseHandler.MouseDown(e); | |
} | |
p.MouseUp = function(e) { | |
this.mouseHandler.MouseUp(e); | |
} | |
p.MouseMove = function(e) { | |
this.mouseHandler.MouseMove(e); | |
} | |
return Model; | |
})(); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//============================================================================= | |
var MouseHandler_PlayMode = (function(){ | |
var MouseHandler_PlayMode = function() { | |
} | |
var p = MouseHandler_PlayMode.prototype; | |
p.MouseDown = function(e) {} | |
p.MouseUp = function(e) {} | |
p.MouseMove = function(e) {} | |
return MouseHandler_PlayMode; | |
})(); | |
//============================================================================= | |
var MouseHandler_EditMode = (function(){ | |
var MouseHandler_EditMode = function(model) { | |
this.model = model; | |
this.isMouseDown = false; | |
this.isDrag = false; | |
this.firstPos = undefined; | |
this.prevPos = undefined; | |
} | |
var p = MouseHandler_EditMode.prototype; | |
p.MouseDown = function(e) { | |
this.isMouseDown = true; | |
this.isDrag = false; | |
var pos = this.toPoint(e); | |
this.firstPos = this.prevPos = pos; | |
this.model.Set(pos.x, pos.y, !this.model.Get(pos.x,pos.y)); | |
this.model.notifyEvent( ModelEvent.Update ); | |
} | |
p.MouseUp = function(e) { | |
this.isMouseDown = false; | |
} | |
p.MouseMove = function(e) { | |
if (!this.isMouseDown) { return; } | |
var pos = this.toPoint(e); | |
if ((pos.x == this.prevPos.x) && (pos.y == this.prevPos.y)) { return; } | |
if (!this.isDrag) { | |
this.model.Set(this.firstPos.x, this.firstPos.y, true); | |
this.isDrag = true; | |
} | |
this.model.Set(pos.x, pos.y, true); | |
this.model.notifyEvent( ModelEvent.Update ); | |
this.prevPos = pos; | |
} | |
p.toPoint = function(e) { | |
return { | |
x:this.toCell( e.offsetX ), | |
y:this.toCell( e.offsetY ), | |
}; | |
} | |
p.toCell = function(offset) { | |
return Math.floor( offset / PIXEL_SIZE ); | |
} | |
return MouseHandler_EditMode; | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//============================================================================= | |
var View = (function(){ | |
var View = function(model, controller) { | |
this.model = model; | |
this.controller = controller; | |
this.canvas = document.getElementById('canvas'); | |
this.initElements(); | |
this.registerEvent(); | |
} | |
var p = View.prototype; | |
p.initElements = function() { | |
this.canvas.width = this.model.Width * PIXEL_SIZE; | |
this.canvas.height = this.model.Height * PIXEL_SIZE; | |
document.getElementById('width') .value = this.model.Width; | |
document.getElementById('height').value = this.model.Height; | |
} | |
p.registerEvent = function() { | |
var self = this; | |
this.model.RegisterEventListener( function(event){ self.onModelEvent(event); } ); | |
function registerClickEvent(id,handler) | |
{ | |
document.getElementById(id).addEventListener | |
('click', function(){ handler();}, false ); | |
} | |
registerClickEvent('stop', function(){ self.onClick_Stop(); }); | |
registerClickEvent('play', function(){ self.onClick_Play(); }); | |
registerClickEvent('clear', function(){ self.onClick_Clear(); }); | |
registerClickEvent('random', function(){ self.onClick_Random(); }); | |
registerClickEvent('size', function(){ self.onClick_SizeChange(); }); | |
var canvas = document.getElementById('canvas'); | |
canvas.addEventListener('mousedown', function(e){ self.onMouseDown(e); }, false); | |
canvas.addEventListener('mouseup', function(e){ self.onMouseUp(e); }, false); | |
canvas.addEventListener('mousemove', function(e){ self.onMouseMove(e); }, false); | |
} | |
p.onClick_Stop = function() { | |
this.controller.Stop(); | |
} | |
p.onClick_Play = function() { | |
this.controller.Play(); | |
} | |
p.onClick_Clear = function() { | |
this.controller.Clear(); | |
} | |
p.onClick_Random = function() { | |
this.controller.SetRandom(); | |
} | |
p.onClick_SizeChange = function() { | |
var width = document.getElementById('width') .value; | |
var height = document.getElementById('height').value; | |
this.controller.SizeChange(width, height); | |
} | |
p.onMouseDown = function(e) { | |
this.controller.MouseDown(e); | |
} | |
p.onMouseUp = function(e) { | |
this.controller.MouseUp(e); | |
} | |
p.onMouseMove = function(e) { | |
this.controller.MouseMove(e); | |
} | |
p.onSizeChange = function() { | |
this.initElements(); | |
this.render(); | |
} | |
p.onModelEvent = function(event) { | |
switch (event) { | |
case ModelEvent.Update: this.render(); break; | |
case ModelEvent.Play: this.setActive_SizeFields(false); break; | |
case ModelEvent.Stop: this.setActive_SizeFields(true); break; | |
case ModelEvent.SizeChange: this.onSizeChange(); break; | |
default: | |
alert(""); | |
throw null; | |
} | |
} | |
p.setActive_SizeFields = function(onoff) { | |
var disabled = !onoff; | |
document.getElementById('width' ).disabled = disabled; | |
document.getElementById('height').disabled = disabled; | |
document.getElementById('size' ).disabled = disabled; | |
} | |
p.render = function() { | |
var ctx = this.canvas.getContext('2d'); | |
ctx.fillStyle = "rgb(255,255,255)"; | |
ctx.fillRect(0, 0, (this.model.Width * PIXEL_SIZE), (this.model.Height * PIXEL_SIZE)); | |
ctx.fillStyle = "rgb(0,0,0)"; | |
for (var y = 0; y < this.model.Height; ++y) { | |
for (var x = 0; x < this.model.Width; ++x) { | |
if (this.model.Get(x,y)) { | |
ctx.fillRect(x*PIXEL_SIZE, y*PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE); | |
} | |
} | |
} | |
} | |
return View; | |
})(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment