Simulator 0.2
中国ルールでプレイアウトを繰り返し、勝敗の統計を取る予定ですが、今回はプレイアウトのルールのみ実装し、手動での対局となっています。
勝敗の記録は取れません。プレイアウトのルールによりアタリでない自石の1目の眼に打てなくなっています。
実行結果
ソース
後半のソースはリンクを張ってあります。ソースは UTF-8 でエンコードしてあります。
simulator02.html
スタイルシートの部分です。変更はありません。
<style>
hr.colored {
border-color: goldenrod
}
#table {
margin: 0;
color: white;
background-image: url(img/table800.jpg);
z-index: 1;
position: relative;
left: 0px;
top: 0px
}
#shadow {
margin: 0;
z-index: 2;
position: absolute;
left: 0px;
top: 0px
}
#stones {
margin: 0;
z-index: 3;
position: absolute;
left: 0px;
top: 0px
}
#control {
color: white;
height: 48px;
width: 630px;
background-color: #26130D;
padding: 5px;
border-spacing: 0;
margin: 0;
position: absolute;
left: 0px;
top: 480px
}
.list {
border: 1px solid lightgray;
max-height: 300px
}
</style>
実行結果を表示する部分です。バージョン番号以外の変更はありません。
<h2>実行結果</h2>
<div style="height: 540px; width: 640; position: relative">
<canvas width="640" height="480" id="table">Simulator 0.2 には HTML5 Canvas が必要です。</canvas>
<canvas width="640" height="480" id="shadow">Simulator 0.2 には HTML5 Canvas が必要です。</canvas>
<canvas width="640" height="480" id="stones">Simulator 0.2 には 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>
白石 White <span id="w">0</span>
黒石 Black <span id="b">0</span>
</div><!-- end of control -->
</div><!-- end of 実行結果 -->
simulator02.js
バージョン番号を変更しました。
/*
* Copyright (C) 2012-2013 たかはしのんき. All rights reserved.
*
* History:
* 0.2 2013-04-26 バージョンの変更。
* 0.1 2013-04-07 碁盤プログラム goban06.js を元に新規作成。
*/
/**
* Simulator - 囲碁対局シミュレータ
* @version 0.2
* @author たかはしのんき
*
*/
// 共通に使う定数と変数
var BLACK = 1;
var WHITE = 2;
var PX_BOWL = 134; // 碁笥の直径 [ピクセル]
var Z2_BOWL = 20; // 碁笥の高さ / 2 [ピクセル]
var PX_LID = 110; // 碁笥の蓋の直径 [ピクセル]
var Z2_LID = 8; // 碁笥の蓋の高さ / 2 [ピクセル]
var PX_STONE = 22; // 碁石の直径 [ピクセル]
var Z2_STONE = 2; // 碁石の高さ / 2 [ピクセル]
var PX_STAR = 5; // 星の直径 [ピクセル]
var PX_CHAR = 24; // 文字の高さ [ピクセル]
var Z2_BOARD = 6; // 碁盤の高さ / 2 [ピクセル]
// キャッシュにイメージを読み込んでおく
var imgbb = new Image(PX_BOWL, PX_BOWL); // 黒の碁笥 (black bowl)
imgbb.src = "img/blackbowl134.png";
var imgwb = new Image(PX_BOWL, PX_BOWL); // 白の碁笥 (white bowl)
imgwb.src = "img/whitebowl134.png";
var imgl = new Image(PX_LID, PX_LID); // 碁笥の蓋 (lid)
imgl.src = "img/lid110.png";
var imgb = new Image(PX_STONE, PX_STONE); // 黒石 (white stone)
imgb.src = "img/black22.png";
var imgw = new Image(PX_STONE, PX_STONE); // 白石 (black stone)
imgw.src = "img/white22.png";
var imgs = new Image(PX_STAR, PX_STAR); // 星 (star)
imgs.src = "img/star5.png";
// キャッシュに効果音を読み込んでおく
var ext = audioExt();
var auClick = new Audio("se/button6." + ext);
var auSwitch = new Audio("se/se_sad05." + ext);
var auError = new Audio("se/se_sad08." + ext);
var ro = 9; // 路数
var context3; // 碁石レイヤーのキャンバスのコンテキスト
var context2; // 影レイヤーのキャンバスのコンテキスト
var passButton = new Array(2); // [パス]ボタン
var brd; // 碁盤オブジェクト
var offsetBLid = new Object(); // 黒の碁笥の蓋のオフセット
var offsetWLid = new Object(); // 白の碁笥の蓋のオフセット
/**
* ロード時に碁盤イメージを描画します。
*/
window.onload = function() {
// 黒石の <input id="black"> 取得
passButton[BLACK] = document.getElementById('black');
// 白石の <input id="white"> 取得
passButton[WHITE] = document.getElementById('white');
// キャンバスとコンテキスト取得
var canvas = document.querySelector('#table');
var context = canvas.getContext('2d');
var canvas3 = document.querySelector('#stones');
context3 = canvas3.getContext('2d');
var canvas2 = document.querySelector('#shadow');
context2 = canvas2.getContext('2d');
// 座標 (270, 50) にタイトルを表示
context.fillStyle = "white";
context.font = "bold 24px Arial";
var title = "Simulator 0.2";
var x = context.canvas.width / 2 -
PX_CHAR / 1.8 * title.length / 2;
var y = PX_CHAR * 2;
context.fillText(title, x, y);
// 机の中央に 碁盤を表示
brd = new Board(ro, context);
// 碁盤の左に白の碁笥の蓋のイメージを表示
offsetWLid.x = Math.floor((brd.boardOffset.x - PX_LID) / 2);
offsetWLid.y = brd.boardOffset.y +
Math.floor((brd.boardSize.height - PX_LID) / 2);
drawObject(offsetWLid.x, offsetWLid.y, Z2_LID, imgl, context, context);
// 左上に白の碁笥のイメージを表示
var xb = offsetWLid.x - Math.floor((PX_BOWL - PX_LID) / 2);
var yb = offsetWLid.y - PX_BOWL - Z2_BOWL;
drawObject(xb, yb, Z2_BOWL, imgwb, context, context);
// 碁盤の右に黒の碁笥の蓋のイメージを表示
offsetBLid.x = offsetWLid.x + brd.boardOffset.x + brd.boardSize.width;
offsetBLid.y = offsetWLid.y;
drawObject(offsetBLid.x, offsetBLid.y, Z2_LID, imgl, context, context);
// 右下に黒の碁笥のイメージを表示
xb = offsetBLid.x - Math.floor((PX_BOWL - PX_LID) / 2);
yb = offsetBLid.y + PX_LID + Z2_BOWL;
drawObject(xb, yb, Z2_BOWL, imgbb, context, context);
// 碁盤を表示
brd.drawBoard(Z2_BOARD, context);
// 黒番から
passButton[WHITE].disabled = true;
// クリックイベント登録
canvas3.addEventListener("click", onClick, false);
};
/**
* アゲハマの表示
* @param stone 石の色
* @param prisoner アゲハマの数
* @since 0.1
*/
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.1
*/
function showLiberty(stone, liberty) {
if (stone == BLACK) {
var p = document.getElementById('ib');
} else {
var p = document.getElementById('iw');
}
p.firstChild.nodeValue = liberty;
}
/**
* 石の数の表示
* @param stone 石の色
* @param num 石の数
* @since 0.1
*/
function showNumStones(stone, num) {
if (stone == BLACK) {
var p = document.getElementById('b');
} else {
var p = document.getElementById('w');
}
p.firstChild.nodeValue = num;
}
/**
* マウスイベントハンドラー
* 碁石を置きます。
* @since 0.1
*/
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.1
*/
function pass() {
// ボタンの音を鳴らす。
auSwitch.play();
var col = PASS(ro);
var row = PASS(ro);
brd.move(col, row, context3, context2);
}
/**
* [はじめから]ボタンの処理
* @since 0.1
*/
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);
// 石の数のクリア
showNumStones(BLACK, 0);
showNumStones(WHITE, 0);
// 黒番から
brd.clear();
passButton[BLACK].disabled = false;
passButton[WHITE].disabled = true;
}
/**
* ブラウザで有効なAudioの拡張子を獲得
* @since 0.1
*/
function audioExt() {
var ext = "";
var audio = new Audio();
if (audio.canPlayType("audio/ogg") == 'maybe')
ext="ogg";
else if (audio.canPlayType("audio/mp3") == 'maybe')
ext="mp3";
else if (audio.canPlayType("audio/wav") == 'maybe')
ext="wav";
return ext;
}
/**
* 円形オブジェクトを描画します。
* @param x 左端座標
* @param y 上端座標
* @param s 影の長さ(高さ/2)
* @param img オブジェクトのイメージ
* @param context3 描画先のコンテキストを指定します。
* @param context2 影用のコンテキストを指定します。
* @since 0.1
*/
function drawObject(x, y, s, img, context3, context2) {
var r = img.width / 2;
context2.beginPath();
context2.arc(x + r + s, y + r + s, r, 0, 2 * Math.PI);
context2.fillStyle = "black";
context2.globalAlpha = 0.5;
context2.fill();
context3.globalAlpha = 1.0;
context3.drawImage(img, x, y);
}
board04.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]);
showNumStones(BLACK, this.p.w.inv().abs());
showNumStones(WHITE, this.p.b.inv().abs());
} else
auError.play();
}
passButton[this.p.turn].disabled = false;
return moved;
},
pos06.js
囲っている自石がアタリの場合は 1 目の眼にも打てるように、プレイアウトのための着手禁止点 rb, rw の計算式を変更しました。
/**
* 与えられた交点に着手できるかどうかを調べます。
* @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 (playout) {
var rb = new BVector(this.order); // プレイアウトでの黒石の着手禁止点を表すベクトル
var rw = new BVector(this.order); // プレイアウトでの白石の着手禁止点を表すベクトル
var z = new BVector(this.order); // all 0 (zero)
for (var i = 1; i <= this.order; i++) {
var ei = new BVector(this.order);
ei.setValue(i, 1);
var F0ei_ei = this.F0.mul(ei).diff(ei);
if (F0ei_ei.diff(this.w.inv().diff(this.h)).equals(z))
rb.setValue(i, 1);
if (F0ei_ei.diff(this.b.inv().diff(this.h)).equals(z))
rw.setValue(i, 1);
}
}
if (row == 0 && col == 0)
return false;
var o = new BVector(this.order); // 着手可能点を表すベクトル
if (playout) {
if (this.turn == BLACK)
o = this.F.mul(this.b.xor(this.h)).and(this.l).diff(this.k).diff(rb);
else if (this.turn == WHITE)
o = this.F.mul(this.w.xor(this.h)).and(this.l).diff(this.k).diff(rw);
else
return false;
} else {
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;
},
move02.js
変更はありません。
リンク先をご覧下さい。
bvector05.js
変更はありません。
リンク先をご覧下さい。
bmatrix04.js
変更はありません。
リンク先をご覧下さい。