Goban 0.6
マウスをクリックすると碁石を自由に置けます。待ったはできません。[パス Pass] ボタンでパスすることができます。石を囲うと取ることができます。活路の数を表示するようにしました。
実行結果
ソース
一部のソースはリンクを張ってあります。ソースは UTF-8 でエンコードしてあります。
goban06.html
スタイルシートの部分です。活路の数を表示できるように control の高さを広げました。
<style>
</style>
実行結果を表示する部分です。活路の数を表示できるように control の一部を追加しました。
<h2>実行結果</h2>
<div style="height: 540px; width: 640; position: relative">
<canvas width="640" height="480" id="table">Goban 0.6 には HTML5 Canvas が必要です。</canvas>
<canvas width="640" height="480" id="shadow">Goban 0.6 には HTML5 Canvas が必要です。</canvas>
<canvas width="640" height="480" id="stones">Goban 0.6 には HTML5 Canvas が必要です。</canvas>
<div id="control">
<img style="vertical-align: bottom; padding-left: 10px" src="img/white22.png">
<input id="white" type="button" value="パス Pass" onclick="pass()">
<span id="pw">0</span>
<img style="vertical-align: bottom; padding-left: 10px" src="img/black22.png">
<input id="black" type="button" value="パス Pass" onclick="pass()">
<span id="pb">0</span>
<input style="margin-left: 40px" type="button" value="はじめから Restart" onclick="restart()"><br>
活路 Liberty <span id="iw">0</span>
活路 Liberty <span id="ib">0</span>
</div><!-- end of control -->
</div><!-- end of 実行結果 -->
goban06.js
バージョンを変更し、活路を表示するようにしました。
/**
* アゲハマの表示
* @param stone 石の色
* @param prisoner アゲハマの数
* @since 0.4
*/
function showPrisoner(stone, prisoner) {
if (stone == BLACK) {
var p = document.getElementById('pb');
} else {
var p = document.getElementById('pw');
}
p.firstChild.nodeValue = prisoner;
}
/**
* 活路の表示
* @param stone 石の色
* @param liberty 活路の数
* @since 0.6
*/
function showLiberty(stone, liberty) {
if (stone == BLACK) {
var p = document.getElementById('ib');
} else {
var p = document.getElementById('iw');
}
p.firstChild.nodeValue = liberty;
}
/**
* マウスイベントハンドラー
* 碁石を置きます。
* @since 0.2
*/
function onClick() {
var event = arguments[0];
var mx = event.pageX - this.parentNode.offsetLeft;
var my = event.pageY - this.parentNode.offsetTop;
var mv = brd.offsetToMove(mx, my);
if (mv.onBoard) {
brd.move(mv.col, mv.row, context3, context2);
} else {
if (brd.p.turn == BLACK)
drawObject(mx - (PX_STONE / 2), my - (PX_STONE / 2), Z2_STONE, imgb, context2, context2);
else
drawObject(mx - (PX_STONE / 2), my - (PX_STONE / 2), Z2_STONE, imgw, context2, context2);
auError.play();
}
}
/**
* [パス]ボタンの処理
* @since 0.3
*/
function pass() {
// ボタンの音を鳴らす。
auSwitch.play();
var col = PASS(ro);
var row = PASS(ro);
brd.move(col, row, context3, context2);
}
/**
* [はじめから]ボタンの処理
* @since 0.3
*/
function restart() {
// ボタンの音を鳴らす。
auSwitch.play();
// 碁石と影のレイヤーをクリア
context3.clearRect(0, 0, context3.canvas.width, context3.canvas.height);
context2.clearRect(0, 0, context2.canvas.width, context2.canvas.height);
// アゲハマのクリア
showPrisoner(BLACK, 0);
showPrisoner(WHITE, 0);
// 活路のクリア
showLiberty(BLACK, 0);
showLiberty(WHITE, 0);
// 黒番から
brd.clear();
passButton[BLACK].disabled = false;
passButton[WHITE].disabled = true;
}
board03.js
活路を表示するようにしました。
Board.prototype = {
/**
* 着手します。
* @param col 石の桁位置を指定します。
* @param row 石の行位置を指定します。
* @param context3 石を描画するコンテキスト
* @param context2 影を描画するコンテキスト
* @since 0.2
*/
move : function(col, row, context3, context2) {
passButton[this.p.turn].disabled = true;
var turn = this.p.turn;
var moved = this.p.move(col, row); // 着手禁止点は false
var mv = new Move(col, row);
if (!mv.isPass(this.ro)) {
// setWatch();
if (moved) {
this.prisoner[P_BLACK] = this.p.prisoner[P_BLACK];
this.prisoner[P_WHITE] = this.p.prisoner[P_WHITE];
// rec.move(col, row);
this.drawStone(col, row, turn, context3, context2);
auClick.play();
if (this.p.d.abs()) {
this.removeStones(this.p.d, this.p.turn, context3, context2);
showPrisoner(turn, this.prisoner[turn - 1]);
}
showLiberty(BLACK, this.p.liberty[P_BLACK]);
showLiberty(WHITE, this.p.liberty[P_WHITE]);
} else
auError.play();
}
passButton[this.p.turn].disabled = false;
return moved;
},
pos04.js
式を整理し、活路を表示するようにしました。
/*
* Copyright (C) 2012-2013 たかはしのんき. All rights reserved.
*
* History:
* 0.4 2013/03/29 式の整理、活路の表示。
* 0.3 2013/03/18 コウの処理を追加。
* 0.2 2012/05/17 SixVectors オブジェクトを外せるよう変更。メソッド clear の追加。
* 0.1 2012/05/15 新規作成。Java 版より移植。
*
* Reference:
* [1]佐藤真史,穴田浩一,堤正義:囲碁の数理モデル化とその応用,
* 第16回ゲームプログラミングワークショップ2011,Vol.2011 No.6,
* pp.100-103(2011)
*/
/**
* 囲碁の局面 (position) を B-W graph model で表したオブジェクトです。
* このオブジェクトで扱う メソッドの引数に盤面の桁位置 col と行位置 row を 指定する
* 場合は、囲碁に合わせ、col, row の順で指定します。
* 行列の行 i、 列 j を指定する場合の i, j の順と逆になるので注意してください。
* @author たかはしのんき
* @version 0.4
*/
var COL = 0; // 横座標
var ROW = 1; // 縦座標
var SPACE = 0; // 空点
var BLACK = 1; // 黒石
var WHITE = 2; // 白石
var P_BLACK = 0; // 黒石(アゲハマと活路用)
var P_WHITE = 1; // 白石(アゲハマと活路用)
var OPPOSITE = 3; // 敵石計算用定数
/**
* n 路盤の局面を表すオブジェクトです。
* @param n 路数を指定します。
* @since 0.1
*/
Pos = function(n) {
// this.h = new BVector(order); // アタリ
// this.A = new BMatrix(order, order); // 追加される連接関係
// this.D = new BMatrix(order, order) // リセットされる連接関係
// this.a = new BVector(order); // 追加される連
// this.d = new BVector(order); // リセットされる連
this.ro = n; // 路数
this.order = n * n; // ベクトルの次数
this.F0 = new BMatrix(this.order, this.order); // 隣接関係
this.initF0();
this.prisoner = new Array(2); // アゲハマ
this.liberty = new Array(2); // 活路の数
try {
this.v6 = new SixVectors(this); // 6ベクトル
} catch(e) {
this.v6 = null;
}
this.clear();
};
Pos.prototype = {
/**
* 隣接関係 F0 を初期化します。
* @since 0.1
*/
initF0 : function() {
var adj = new Array(4);
adj = [ // 隣接する(adjacent)相対座標
[0, -1],
[-1, 0], [0, 0], [1, 0],
[0, 1]
];
for (var row = 1; row <= this.ro; row++)
for (var col = 1; col <= this.ro; col++)
for (var i = 0; i < adj.length; i++) {
var ar = row + adj[i][ROW];
var ac = col + adj[i][COL];
if (ar > 0 && ar <= this.ro && ac > 0 && ac <= this.ro)
this.F0.setValue(this.toIndex(col, row), this.toIndex(ac, ar), 1);
}
},
/**
* 局面を初期化します。
* @since 0.3
*/
clear : function() {
this.F = this.F0.clone(); // 連接関係
this.b = new BVector(this.order, 1); // 黒の着点∨空点
this.w = this.b.clone(); // 白の着点∨空点
this.l = this.b.and(this.w); // 空点
this.k = new BVector(this.order); // コウ
this.ib = new BVector(this.order); // 黒石の活路
this.iw = new BVector(this.order); // 白石の活路
this.calcVectors(0, 0);
if (this.v6 != null)
this.v6.calcSixVectors(this);
this.watch = null; // 監視する BVector
this.turn = BLACK; // 手番(次の番)
this.moves = 0; // 手数
this.prisoner = [0, 0]; // アゲハマ
this.liberty = [0, 0]; // 活路の数
},
/**
* 監視する BVector を設定します。
* @param watch 監視する BVector を指定します。 null なら監視を解除します。
* @since 0.1
*/
setWatch : function(watch) {
this.watch = watch;
},
/**
* 監視する BVector を返します。
* @return 監視する BVector を返します。なければ null を返します。
* @since 0.1
*/
getWatch : function() {
return this.watch;
},
/**
* 碁盤上の点 (move) をベクトル要素の添字 (index) に変換します。
* @param col 点の横方向の座標
* @param row 点の縦方向の座標
* @return 添字を返します。(1 origin)
* @since 0.1
*/
toIndex : function(col, row) {
return (row - 1) * this.ro + col;
},
/**
* ベクトル要素の添字 (index) を碁盤上の点 (move) に変換します。
* @param index 添字を渡します。 (1 origin)
* @return 碁盤上の点の座標をクラス Move のオブジェクトとして返します。
* @since 0.1
*/
toMove : function(index) {
var mv = new Move();
mv.row = Math.floor((index - 1) / this.ro) + 1;
mv.col = (index - 1) % this.ro + 1;
return mv;
},
/**
* turn の反対のプレイヤーを返します。
* @param turn BLACK か WHITE を指定します。
* @return turn の反対のプレイヤーを返します。
* @since 0.1
*/
opposite : function(turn) {
return OPPOSITE - turn;
},
/**
* 着手により局面を更新します。 col と row のいずれかを ro+1 にするとパスできます。
* @param col 着手の横座標
* @param row 着手の縦座標
* @return 着手できたら true、着手できない手なら false を返します。
* @since 0.1
*/
move : function(col, row) {
var mv = new Move(col, row);
if (!mv.isPass(this.ro)) {
if (!this.isMovable(col, row))
return false;
this.calcVectors(col, row);
if (this.v6 != null)
this.v6.calcSixVectors(this);
}
this.turn = this.opposite(this.turn);
this.moves++;
return true;
},
/**
* 与えられた交点に着手できるかどうかを調べます。
* @param col 調べる交点の桁位置
* @param row 調べる交点の行位置
* @return 着手可能なら true を返します。
* @since 0.3
*/
isMovable : function(col, row) {
if (this.h == null) {
this.h = new BVector(this.order);
}
var tF = this.F.tran();
for (var i = 1; i <= this.order; i++) {
var ei = new BVector(this.order);
ei.setValue(i, 1);
var tFei = tF.mul(ei);
if ((tFei.and(this.l)).abs() == 1)
this.h.setValue(i, 1);
else
this.h.setValue(i, 0);
}
if (row == 0 && col == 0)
return false;
var o = new BVector(this.order);
if (this.turn == BLACK)
o = this.F.mul(this.b.xor(this.h)).and(this.l).diff(this.k);
else if (this.turn == WHITE)
o = this.F.mul(this.w.xor(this.h)).and(this.l).diff(this.k);
else
return false;
var i = this.toIndex(col, row); // 調べる着点
var ei = new BVector(this.order);
ei.setValue(i, 1);
if (o.and(ei).equals(ei))
return true;
return false;
},
/**
* BWモデルに関連するベクトルと行列を計算します。計算の対象は以下のとおり。<br>
* l - 空点を表すベクトル<br>
* h - アタリの石の集合を表すベクトル<br>
* a - 着手によって形成される連接点を表すベクトル<br>
* d - 着手によって削除される石を表すベクトル<br>
* A - 着手によって追加される連接点を表す行列<br>
* D - 着手によってリセットされる連接点を表す行列<br>
* b - 着手後の黒石∨空点を表すベクトル<br>
* w - 着手後の白石∨空点を表すベクトル<br>
* F - 着手後の連接点を表す行列<br>
* k - 着手後のコウを表すベクトル<br>
* ib - 着手後の黒石の活路を表すベクトル<br>
* iw - 着手後の白石の活路を表すベクトル
* @param col 着手した点の横座標
* @param row 着手した点の縦座標
* @since 0.3
*/
calcVectors : function(col, row) {
if (this.h == null) {
this.h = new BVector(this.order);
}
var tF = this.F.tran(); // Fの転置
for (var i = 1; i <= this.order; i++) {
var ei = new BVector(this.order);
ei.setValue(i, 1);
var tFei = tF.mul(ei);
if ((tFei.and(this.l)).abs() == 1)
this.h.setValue(i, 1);
else
this.h.setValue(i, 0);
}
if (row ==0 && col==0)
return;
var i = this.toIndex(col, row); // 着点
var ei = new BVector(this.b.order);
ei.setValue(i, 1);
var Fei = this.F.mul(ei); // 着点を連接点とする交点
var F0ei = this.F0.mul(ei); // 着点の隣接点
var z = new BVector(this.b.order); // all 0(zero)
if (this.turn == BLACK) {
this.a = (Fei.diff(this.w)).or(ei); // 着点を連接点とする黒石と着点
this.d = (Fei.and(this.h)).diff(this.b); // 着点を連接点とする白石のアタリの連
if (F0ei.diff(ei).and(this.b).abs() == 0 && this.d.abs() == 1)
this.k = this.d;
else
this.k = z;
this.b = this.b.or(this.d);
this.w = this.w.diff(ei);
this.prisoner[P_BLACK] += this.d.abs();
} else if (this.turn == WHITE) {
this.a = (Fei.diff(this.b)).or(ei); // 着点を連接点とする白石と着点
this.d = (Fei.and(this.h)).diff(this.w); // 着点を連接点とする黒石のアタリの連
if (F0ei.diff(ei).and(this.w).abs() == 0 && this.d.abs() == 1)
this.k = this.d;
else
this.k = z;
this.b = this.b.diff(ei);
this.w = this.w.or(this.d);
this.prisoner[P_WHITE] += this.d.abs();
}
this.A = this.a.cross(tF.mul(this.a));
var o = new BVector(this.b.order, 1); // all 1(one)
this.D = this.F0.or((this.d.inv()).cross(o));
this.F = (this.F.or(this.A)).and(this.D);
this.l = this.b.and(this.w);
this.ib = (tF.mul((this.w).inv())).and(this.l); // 黒石の活路
this.liberty[P_BLACK] = this.ib.abs(); // 黒石の活路の数
this.iw = (tF.mul((this.b).inv())).and(this.l); // 白石の活路
this.liberty[P_WHITE] = this.iw.abs(); // 白石の活路の数
},
/**
* 局面の座標より、石または空点を返します。エラーのときは -1 を返します。
* @param col 横座標
* @param row 縦座標
* @return SPACE, BLACK, WHITE のいずれかを返します。
* @since 0.1
*/
getStone : function(col, row) {
if (row <= 0 || row > this.ro || col <=0 || col > this.ro)
return -1;
var b1 = this.b.getValue(this.toIndex(col, row));
var w1 = this.w.getValue(this.toIndex(col, row));
var stone = ((b1 & w1) == 1) ? SPACE : ((b1 == 1) ? BLACK : WHITE);
return stone;
},
/* 局面の状態を文字列に変換します。
* @return 文字列を返します。
* @since 0.3
*/
toString : function() {
var turn = ["-", "B", "W"];
var str = new String();
str = "#" + this.moves + "\n";
str += "F'=\n" + this.F.toString();
str += "b'=" + this.b.toString() + "\n";
str += "w'=" + this.w.toString() + "\n";
str += "l=" + this.l.toString() + "\n";
str += "h=" + this.h.toString() + "\n";
str += "Σ|db|=" + this.prisoner[P_BLACK] + "\n";
str += "Σ|dw|=" + this.prisoner[P_WHITE] + "\n";
str += "k=" + this.k.toString() + "\n";
if (this.moves > 0) {
str += "a=" + this.a.toString() + "\n";
str += "d=" + this.d.toString() + "\n";
str += "A=\n" + this.A.toString();
str += "D=\n" + this.D.toString();
}
str += "turn:" + turn[this.turn] + "\n";
return str;
},
/* 局面の状態を TeX 文字列に変換します。
* @return TeX 文字列を返します。
* @since 0.3
*/
toTeX : function() {
var turn = ["-", "B", "W"];
var str = new String();
str = "#" + this.moves + "\n";
str += "$$F'=" + this.F.toTeX() +"$$\n";
str += "$$\\boldsymbol{b}'=" + this.b.toTeX() + "$$\n";
str += "$$\\boldsymbol{w}'=" + this.w.toTeX() + "$$\n";
str += "$$\\boldsymbol{l}=" + this.l.toTeX() + "$$\n";
str += "$$\\boldsymbol{h}=" + this.h.toTeX() + "$$\n";
str += "$$\\sum \\left| \\boldsymbol{d}_b \\right| =" + this.prisoner[P_BLACK] + "$$\n";
str += "$$\\sum \\left| \\boldsymbol{d}_w \\right| =" + this.prisoner[P_WHITE] + "$$\n";
str += "$$\\boldsymbol{k}=" + this.k.toTeX() + "$$\n";
if (this.moves > 0) {
str += "$$\\boldsymbol{a}=" + this.a.toTeX() + "$$\n";
str += "$$\\boldsymbol{d}=" + this.d.toTeX() + "$$\n";
str += "$$A=" + this.A.toTeX() + "$$\n";
str += "$$D=" + this.D.toTeX() + "$$\n";
}
str += "turn:" + turn[this.turn] + "\n";
return str;
},
/* 局面の状態を絵文字列に変換します。
* @return 絵文字列を返します。
* @since 0.1
*/
toPicStr : function() {
var figure = ["┼", "●", "○"];
var grid = ["┏", "┯", "┓", "┠", "┼", "┨", "┗", "┷", "┛"];
var str = new String();
str = "";
for (var row = 1; row <= this.ro; row++) {
for (var col = 1; col <= this.ro; col++) {
var stone = this.getStone(col, row);
if (stone == SPACE) {
var rx = Math.ceil((row - 1) / (this.ro - 1) * 2);
var cx = Math.ceil((col - 1) / (this.ro - 1) * 2);
str += grid[rx * this.ro + cx];
} else
str += figure[stone];
}
str += "\n";
}
return str;
}
};
move02.js
今回は変更ありません。
リンク先をご覧下さい。
bvector05.js
今回は変更ありません。
リンク先をご覧下さい。
bmatrix04.js
今回は変更ありません。
リンク先をご覧下さい。