Last active
August 29, 2015 14:22
-
-
Save cobodo/d91070a2407eac55346a to your computer and use it in GitHub Desktop.
昔書いたやつ。最終更新は 2008-05-22 00:53:58。"ASV"はAdobe SVG Viewerプラグインのこと。
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
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |
<title>Conway's Game of Life</title> | |
<g id="field" /> | |
<g id="control" /> | |
<script type="text/ecmascript"> | |
<![CDATA[ | |
// 定数定義 | |
var SVG_NS = "http://www.w3.org/2000/svg"; // 名前空間 | |
var XMAX = 40; // x軸の数 | |
var YMAX = 40; // y軸の数 | |
var r = 10; // 半径 | |
var stroke_width = 0.8; // 線の太さ | |
var stroke = "black"; // 線の色 | |
var fill = ["white", "black"]; // □,■の色 | |
var offsetx = 10; // 表示位置のオフセット(X) | |
var offsety = 10; // 表示位置のオフセット(Y) | |
var interval = 300; // シミュレーションの時間間隔(ms) | |
var birth = 0.2; // ランダム生成時の誕生確率 | |
var Error = 0.0; // エラー発生率。0.001程度だとおもしろいかも | |
var ELEMENT_NODE = 1; // Node.ELEMENT_NODE値。ASVはNodeインターフェイスを内部に持っていないため。 | |
var HighLife = false; // trueでHighLife[23/36]に | |
// グローバル変数 | |
var browser; // ブラウザ種別 | |
var g; // □を加えるグループ | |
var control; // ボタン群を配置するコントローラ | |
var field; // Model | |
var field2; // Model(buffer) | |
var timer = 0; // タイマー | |
var animate = false; // アニメーション実行フラグ | |
var squares; // SVGオブジェクトの配列 | |
var mutex = 0; // Mutexもどき。ただのフラグ。タイマーで書き換え中はnextを無効化。 | |
var num_buttons = 0; // ボタンの数 | |
// 初期化 | |
function init () { | |
// ブラウザ判別 | |
if (window.getDocument) { | |
browser = "ASV"; | |
} else { | |
browser = "Mozilla"; | |
ELEMENT_NODE = Node.ELEMENT_NODE; // 一応 | |
} | |
// 表示フィールドの取得 | |
g = document.getElementById("field"); | |
// コントローラの設定 | |
control = document.getElementById("control"); | |
// ボタンの追加 | |
add_button("start", "start", start); | |
//add_button("stop", "stop", stop); | |
add_button("next", "next", function(evt){if (mutex == 0) next(evt);}); | |
add_button("random", "random", random); | |
add_button("highlife", "HighLife", highlife); | |
add_button("error", "Error", error); | |
// 位置決め | |
control.setAttribute("transform", "translate(" + (offsetx * 2 + XMAX * r) + ", 10)"); | |
// Animation Generator | |
if (browser == "ASV") { | |
var line = document.createElementNS(SVG_NS, "line"); | |
line.setAttribute("x1", 0); | |
line.setAttribute("y1", 0); | |
line.setAttribute("x2", 1); | |
line.setAttribute("y2", 1); | |
line.setAttribute("display", "none"); | |
var anim = document.createElementNS(SVG_NS, "animate"); | |
anim.setAttribute("attributeName", "y2"); | |
anim.setAttribute("values", "0;100"); | |
anim.setAttribute("begin", "0s"); | |
anim.setAttribute("dur", interval + "ms"); | |
anim.setAttribute("fill", "remove"); | |
anim.setAttribute("repeatCount", "indefinite"); | |
anim.addEventListener("repeat", animation_generator, false); | |
line.appendChild(anim); | |
control.appendChild(line); | |
} else { | |
timer = setInterval(animation_generator, interval); | |
} | |
// cell imageの作成 | |
squares = new Array(XMAX); | |
for (var i=0; i<XMAX; i++) { | |
squares[i] = new Array(YMAX); | |
} | |
var c = document.createElementNS(SVG_NS, "rect"); | |
c.setAttribute("width", r); | |
c.setAttribute("height", r); | |
c.setAttribute("fill", fill[0]); | |
c.setAttribute("stroke", stroke); | |
c.setAttribute("stroke-width", stroke_width); | |
c.setAttribute("onclick", "click_handler(evt)"); | |
for (var i=0; i<XMAX; i++) { | |
for (var j=0; j<YMAX; j++) { | |
var node = c.cloneNode(false); | |
node.setAttribute("x", offsetx + i*r); | |
node.setAttribute("y", offsety + j*r); | |
squares[i][j] = node; | |
g.appendChild(node); | |
} | |
} | |
// cell modelの作成(現在と直前で2つ) | |
field = new Array(XMAX); | |
for (var i=0; i<XMAX; i++) { | |
field[i] = new Array(YMAX); | |
} | |
field2 = new Array(XMAX); | |
for (var i=0; i<XMAX; i++) { | |
field2[i] = new Array(YMAX); | |
} | |
for (var i=0; i<XMAX; i++) { | |
for (var j=0; j<YMAX; j++) { | |
field[i][j] = 0; | |
} | |
} | |
} | |
function add_button (id, text, func) { | |
var g = document.createElementNS(SVG_NS, "g"); | |
g.setAttribute("id", id); | |
g.setAttribute("transform", "translate(0," + num_buttons*40 + ")"); | |
num_buttons++; | |
g.addEventListener("click", func, false); | |
var r = document.createElementNS(SVG_NS, "rect"); | |
r.setAttribute("width", 60); | |
r.setAttribute("height", 30); | |
r.setAttribute("fill", "white"); | |
r.setAttribute("stroke", "black"); | |
r.setAttribute("stroke-width", 2); | |
r.setAttribute("x", 0); | |
r.setAttribute("y", 0); | |
g.appendChild(r); | |
var t = document.createElementNS(SVG_NS, "text"); | |
t.setAttribute("x", 5); | |
t.setAttribute("y", 20); | |
t.setAttribute("fill", "black"); | |
t.setAttribute("font-family", "Tahoma"); | |
t.setAttribute("font-size", 13); | |
var tx = document.createTextNode(text); | |
t.appendChild(tx); | |
g.appendChild(t); | |
control.appendChild(g); | |
} | |
// アニメーション開始・終了 | |
function start (evt) { | |
if (!animate) { | |
// 開始 | |
animate = true; | |
var st_button = document.getElementById("start"); | |
for (var i=st_button.firstChild; i != null; i = i.nextSibling) { | |
if (i.nodeName == "rect") { | |
i.setAttribute("stroke", "blue"); | |
} else if (i.nodeName == "text") { | |
i.firstChild.nodeValue = "stop"; | |
} | |
} | |
} else { | |
// 終了 | |
animate = false; | |
var st_button = document.getElementById("start"); | |
for (var i=st_button.firstChild; i != null; i = i.nextSibling) { | |
if (i.nodeName == "rect") { | |
i.setAttribute("stroke", "black"); | |
} else if (i.nodeName == "text") { | |
i.firstChild.nodeValue = "start"; | |
} | |
} | |
} | |
} | |
// 次の状態を計算 | |
function next (evt) { | |
if (mutex != 0) { | |
return; | |
} | |
mutex = 1; | |
for (var i=0; i<XMAX; i++) { | |
for (var j=0; j<YMAX; j++) { | |
var s = 0; | |
for (var k=i-1; k<=i+1; k++) { | |
for (var l=j-1; l<=j+1; l++) { | |
if (k==i && l==j) continue; | |
var epsx = 0; | |
var epsy = 0; | |
if (field[k] == undefined) { | |
epsx = (k < 0) ? XMAX : -XMAX; | |
} | |
if (field[k+epsx][l] == undefined) { | |
epsy = (l < 0) ? YMAX : -YMAX; | |
} | |
s += field[k+epsx][l+epsy]; | |
} | |
} | |
if (s == 3 || (HighLife && s == 6)) { | |
field2[i][j] = 1; | |
} else if (s == 2) { | |
field2[i][j] = field[i][j]; | |
} else { | |
field2[i][j] = 0; | |
} | |
if (s>0 && Math.random() < Error) { | |
if (field2[i][j] == 0) { | |
field2[i][j] = 1; | |
} | |
else field2[i][j] = 0; | |
} | |
} | |
} | |
var swap = field; | |
field = field2; | |
field2 = swap | |
repaint(); | |
mutex = 0; | |
} | |
// 状態を描画 | |
// 処理の高速化のため、変化部分しか再描画しない。 | |
function repaint () { | |
for (var i=0; i<XMAX; i++) { | |
for (var j=0; j<YMAX; j++) { | |
if (field[i][j] != field2[i][j]) { | |
squares[i][j].setAttribute("fill", fill[field[i][j]]); | |
} | |
} | |
} | |
} | |
// 全体をランダムに埋める | |
function random (evt) { | |
for (var i=0; i<XMAX; i++) { | |
for (var j=0; j<YMAX; j++) { | |
if (Math.random() < birth) { | |
field[i][j] = 1; | |
field2[i][j] = 0; // すべて再描画するため | |
} else { | |
field[i][j] = 0; | |
field2[i][j] = 1; // すべて再描画するため | |
} | |
} | |
} | |
repaint(); | |
} | |
// イベントハンドラ群 | |
// タイマーからアニメーション発生 | |
function animation_generator (evt) { | |
if (animate == 1) { | |
next(); | |
} | |
} | |
// HighLife切り替え | |
function highlife (evt) { | |
if (confirm("HighLifeを" + !HighLife + "にしますか?")) { | |
HighLife = !HighLife; | |
var hl_button = document.getElementById("highlife"); | |
for (var i=hl_button.firstChild; i.nextSibling != null; i = i.nextSibling) { | |
if (i.nodeName == "rect") { | |
if (HighLife) { | |
i.setAttribute("stroke", "blue"); | |
} else { | |
i.setAttribute("stroke", "black"); | |
} | |
break; | |
} | |
} | |
} | |
} | |
// エラー発生率の設定 | |
function error (evt) { | |
var e = prompt("エラー発生率 e (0 <= e <= 1)を入力してください。", 0.001); | |
if (e == null) return; | |
if (e > 1 || e < 0) { | |
alert("エラー発生率 e は 0 <= e <= 1 にしてください。"); | |
return; | |
} | |
Error = e; | |
var er_button = document.getElementById("error"); | |
for (var i=er_button.firstChild; i.nextSibling != null; i = i.nextSibling) { | |
if (i.nodeName == "text") { | |
var text = ""; | |
if (e == 0) { | |
text = "Error"; | |
} else { | |
text = e; | |
} | |
var t = document.createTextNode(text); | |
i.replaceChild(t, i.firstChild); | |
} | |
} | |
} | |
// クリックによる生死反転 | |
function click_handler (evt) { | |
if (evt.button == 0) { | |
var t; | |
if (browser == "ASV") { | |
t = evt.getTarget(); | |
} else { | |
t = evt.target; | |
} | |
var x = (t.getAttribute("x") - offsetx) / r; | |
var y = (t.getAttribute("y") - offsety) / r; | |
if (field[x][y] == 0) { | |
field[x][y] = 1; | |
t.setAttribute("fill", fill[1]); | |
} else { | |
field[x][y] = 0; | |
t.setAttribute("fill", fill[0]); | |
} | |
} | |
} | |
init(); | |
]]> | |
</script> | |
</svg> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment