Skip to content

Instantly share code, notes, and snippets.

@cobodo
Last active August 29, 2015 14:22
Show Gist options
  • Save cobodo/d91070a2407eac55346a to your computer and use it in GitHub Desktop.
Save cobodo/d91070a2407eac55346a to your computer and use it in GitHub Desktop.
昔書いたやつ。最終更新は 2008-05-22 00:53:58。"ASV"はAdobe SVG Viewerプラグインのこと。
Display the source blob
Display the rendered blob
Raw
<?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