Viewer 0.1

囲碁の棋譜フォーマット SGF (Smart Game Format) の構文から、その構文解析クラス SGFParser を作成し、 この機能を利用して棋譜を再生するプログラムを作成しました。

クラス SGFParser の生成のための入力に使用した SGF の構文は以下の通りです。SGF Parser 0.1 の Property を具体的な定義に変更しました。

生成された SGFParser のコードは以下の通りです。字下げは Aptana Studio 等のツールで簡単にできるので行っていません。

上記のコードに、読み込んだ棋譜を碁盤の内部情報に変換するコードを加え、棋譜を盤上で再生できるようにしました。

実行結果

以下に実行結果を示します。利用した棋譜は Small Basic の Go Simulator 0.4 で作成したものです。対局の終盤で三コウ(三劫)が発生しています。

SGF Viewer 0.1 には HTML5 Canvas が必要です。 SGF Viewer 0.1 には HTML5 Canvas が必要です。 SGF Viewer 0.1 には HTML5 Canvas が必要です。
0 0
得点 Score 0 得点 Score 0 間隔 Interval 300
(;GM[1]FF[1]SZ[9]PB[Random]PW[Random]RE[W+10]
DT[2013-03-10]KM[0.0]RU[Japanese]
AP[Go Simulator:0.4]CA[UTF-8]
;B[id];W[fd];B[ee];W[eg];B[hf];W[ac];B[fg];W[df];B[bh];W[fa]
;B[cf];W[hb];B[gf];W[be];B[af];W[cc];B[fc];W[cd];B[bd];W[if]
;B[dd];W[di];B[hc];W[fh];B[gd];W[eb];B[ie];W[hh];B[ed];W[ae]
;B[bi];W[bb];B[aa];W[eh];B[ga];W[ai];B[ab];W[ib];B[gh];W[dc]
;B[ic];W[ff];B[ei];W[bf];B[cg];W[de];B[dh];W[gg];B[ea];W[fb]
;B[ba];W[ii];B[hi];W[ci];B[cb];W[ah];B[ig];W[ca];B[ab];W[aa]
;B[ad];W[hg];B[hd];W[bc];B[db];W[gc];B[ag];W[gb];B[dg];W[gi]
;B[ch];W[di];B[ai];W[ha];B[fe];W[ad];B[ge];W[ih];B[bg];W[if]
;B[ef];W[ec];B[fg];W[fd];B[ci];W[fi];B[ce];W[de];B[df];W[ff]
;B[fc];W[di];B[fg];W[fd];B[ei];W[ff];B[fc];W[di];B[fg];W[fd]
;B[ei];W[ff];B[fc];W[di];B[fg];W[da];B[ff];W[db];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di]
;B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di]
;B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di]
;B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di]
;B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[];B[])

ドキュメント

JsDoc Toolkit で作成したドキュメントはこちら

ソース

expand source と表示されている場合はその文字をクリックするとソースが展開表示されます。 展開したソースを元に戻すにはブラウザーの再読み込みボタンを押してください。

viewer01.html

(1) ヘッダー部

このソースコードは Jasmine のサンプル SpecRunner.html から大部分を持ってきました。前半はスタイルシートとスクリプトを読み込んでいる部分です。

スタイルシートの shThemeAptana.css は shThemeEclipse.css を元に新たに作成しました。詳細は shThemeAptana.css の項を参照下さい。

<head>
<meta charset="UTF-8">
<title>JavaScriptでプログラミング - Viewer 0.1</title>

<link type="text/css" rel="stylesheet" href="css/javascript.css">
<link type="text/css" rel="stylesheet" href="css/shCoreEclipse.css">
<link type="text/css" rel="stylesheet" href="css/shThemeAptana.css">
<script type="text/javascript" src="js/XRegExp.js"></script>
<script type="text/javascript" src="js/shCore.js"></script>
<script type="text/javascript" src="js/shBrushJScript.js"></script>
<script type="text/javascript" src="js/shBrushXml.js"></script>
<script type="text/javascript" src="js/shBrushCss.js"></script>

<!-- include source files here... -->
<script type="text/javascript" src="js/viewer01/viewer01.js"></script>
<script type="text/javascript" src="js/viewer01/board06.js"></script>
<script type="text/javascript" src="js/viewer01/pos10.js"></script>
<script type="text/javascript" src="js/viewer01/move05.js"></script>
<script type="text/javascript" src="js/viewer01/bvector07.js"></script>
<script type="text/javascript" src="js/viewer01/bmatrix05.js"></script>
<script type="text/javascript" src="js/generator03/source01.js"></script>
<script type="text/javascript" src="js/viewer01/lex04.js"></script>
<script type="text/javascript" src="js/generator03/generator03.js"></script>
<script type="text/javascript" src="js/viewer01/sgfparser02.js"></script>

<!-- include spec files here... -->

(2) 冒頭の SGF Parser 生成部

後半の SGF の構文の定義で抜け落ちていた Node の定義と Property の具体例を追加しました。また、 ValueType の定義の順番を変更しました。

最後の部分は Jasmine によるテスト結果を HTML 上で展開するレポーターと呼ばれる部分です。前回から変更ありません。

<script type="text/javascript">
  // define SGF syntax
  var gapFree = ["PropIdent", "Number", "Real", "Text", "SimpleText", "Move"];
  var sgfSyntax = "Collection = GameTree, {GameTree}.\n";
  sgfSyntax += "GameTree = '(', Sequence, {GameTree}, ')'.\n";
  sgfSyntax += "Sequence = Node, {Node}.\n";
  sgfSyntax += "Node = ';', {Property}.\n";
  sgfSyntax += "Property = Game | Size | Player | Handy | Komi | BW | Other.\n";
  sgfSyntax += "Game = 'GM[1]'.\n";                 // GM[1]
  sgfSyntax += "Size = 'SZ[', Number, ']'.\n";      // SZ[6]
  sgfSyntax += "Player = ('PB'|'PW'), '[', SimpleText, ']'.\n"; // PB[black player] | PW[white player]
  sgfSyntax += "Handy = 'HA[', Number, ']'.\n";     // HA[handy]
  sgfSyntax += "Komi = 'KM[', Real, ']'.\n";        // KM[0.0]
  sgfSyntax += "BW = Color, '[', [Move], ']'.\n";   // B[xy] | W[xy]
  sgfSyntax += "Other = PropIdent, PropValue, {PropValue}.\n";
  sgfSyntax += "PropIdent = upper, {upper}.\n";
  sgfSyntax += "PropValue = '[', CValueType, ']'.\n";
  sgfSyntax += "CValueType = ValueType | Compose.\n";
  sgfSyntax += "ValueType = Text | None | Number | Real | Double | Color | SimpleText | Move.\n";
  sgfSyntax += "None = [sp].\n";
  sgfSyntax += "Number = ['+' | '-'], digit, {digit}.\n";
  sgfSyntax += "Real = Number, ['.', digit, {digit}].\n";
  sgfSyntax += "Double = '1' | '2'.\n";
  sgfSyntax += "Color = 'B' | 'W'.\n";
  sgfSyntax += "Move = (lower | upper), (lower | upper).\n";
  sgfSyntax += "Compose = ValueType, ':', ValueType.\n";
  var ebnf = new EBNFParser(sgfSyntax, gapFree, "SGF", "0.2");
  SyntaxHighlighter.all();
</script>
また、SGF Parser 0.1 のとき <body> タグの実行結果の直後にあったスクリプトを今回は実行結果の直前に持ってきました。スクリプトの内容自体は変更ありません。

クラス SGFParser の生成のための入力に使用した SGF の構文は以下の通りです。SGF Parser 0.1 の Property を具体的な定義に変更しました。

<script type="text/javascript"> // get element from HTML and set text (code) var html = '<pre class="code">\n'; html += sgfSyntax; html += '</pre>\n'; document.writeln(html); </script>

生成された SGFParser のコードは以下の通りです。字下げは Aptana Studio 等のツールで簡単にできるので行っていません。

<script type="text/javascript"> // get element from HTML and set text (code) var html = "<pre class=\"brush: js; class-name: 'list'\">\n"; html += ebnf.syntax(); html += "</pre>\n"; document.writeln(html); </script>

上記のコードに、読み込んだ棋譜を碁盤の内部情報に変換するコードを加え、棋譜を盤上で再生できるようにしました。

(3) 実行結果 - SGF の棋譜から盤面を再生する部分

Simulator 0.4 のプレイアウトボタンを再生ボタンに変更し、再生スピードを変更できるようスライダー(171行目)を追加しました。
<h2>実行結果</h2>
<p>以下に実行結果を示します。利用した棋譜は Small Basic の Go Simulator 0.4 で作成したものです。対局の終盤で三コウ(三劫)が発生しています。</p>
<div style="height: 640px; width: 640; position: relative">
<canvas width="640" height="480" id="table">SGF Viewer 0.1 には HTML5 Canvas が必要です。</canvas>
<canvas width="640" height="480" id="shadow">SGF Viewer 0.1 には HTML5 Canvas が必要です。</canvas>
<canvas width="640" height="480" id="stones">SGF Viewer 0.1 には HTML5 Canvas が必要です。</canvas>
<form id="control">
<img style="vertical-align: bottom; padding-left: 10px" src="img/white22.png">
<input id="white" type="button" value="パス Pass" onclick="onPass()">
<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="onPass()">
<span id="pb">0</span>
<input style="margin-left: 40px" type="button" value="再生 Play" onclick="onPlay()">
<br>
<span style="margin-left: 10px">得点 Score</span> <span id="sw">0</span>
<span style="margin-left: 30px">得点 Score</span> <span id="sb">0</span>
<span style="margin-left: 40px">間隔 Interval</span>
<input id="interval" style="margin-left: 10px" type="range" min="0" max="600" step="10">
<output for="interval" style="margin-left: 10px">300</output>
<pre id="sgf">(;GM[1]FF[1]SZ[9]PB[Random]PW[Random]RE[W+10]
DT[2013-03-10]KM[0.0]RU[Japanese]
AP[Go Simulator:0.4]CA[UTF-8]
;B[id];W[fd];B[ee];W[eg];B[hf];W[ac];B[fg];W[df];B[bh];W[fa]
;B[cf];W[hb];B[gf];W[be];B[af];W[cc];B[fc];W[cd];B[bd];W[if]
;B[dd];W[di];B[hc];W[fh];B[gd];W[eb];B[ie];W[hh];B[ed];W[ae]
;B[bi];W[bb];B[aa];W[eh];B[ga];W[ai];B[ab];W[ib];B[gh];W[dc]
;B[ic];W[ff];B[ei];W[bf];B[cg];W[de];B[dh];W[gg];B[ea];W[fb]
;B[ba];W[ii];B[hi];W[ci];B[cb];W[ah];B[ig];W[ca];B[ab];W[aa]
;B[ad];W[hg];B[hd];W[bc];B[db];W[gc];B[ag];W[gb];B[dg];W[gi]
;B[ch];W[di];B[ai];W[ha];B[fe];W[ad];B[ge];W[ih];B[bg];W[if]
;B[ef];W[ec];B[fg];W[fd];B[ci];W[fi];B[ce];W[de];B[df];W[ff]
;B[fc];W[di];B[fg];W[fd];B[ei];W[ff];B[fc];W[di];B[fg];W[fd]
;B[ei];W[ff];B[fc];W[di];B[fg];W[da];B[ff];W[db];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di]
;B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di]
;B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di]
;B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di]
;B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if];B[ei];W[fd]
;B[ig];W[di];B[fc];W[if];B[ei];W[fd];B[ig];W[di];B[fc];W[if]
;B[ei];W[fd];B[ig];W[];B[])
</pre>
</form><!-- end of control -->
</div><!-- end of 実行結果 -->

shThemeAptana.css

今回 SyntaxHighlighter のテーマを変更しました。Aptana Studio 3 の色になるべく近くなるようにしました。 shThemeEclipse.css を元に作成しました。
/**
 * SyntaxHighlighter
 * http://alexgorbatchev.com/SyntaxHighlighter
 *
 * SyntaxHighlighter is donationware. If you are using it, please donate.
 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
 *
 * @version
 * 3.0.83 (July 02 2010)
 * 
 * @copyright
 * Copyright (C) 2004-2010 Alex Gorbatchev.
 * Copyright (c) 2014 Nonki Takahashi.
 *
 * @license
 * Dual licensed under the MIT and GPL licenses.
 */
.syntaxhighlighter {
  background-color: #141414 !important;
}
.syntaxhighlighter .line.alt1 {
  background-color: black !important;
}
.syntaxhighlighter .line.alt2 {
  background-color: black !important;
}
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
  background-color: #3c4043 !important;
}
.syntaxhighlighter .line.highlighted.number {
  color: black !important;
}
.syntaxhighlighter table caption {
  color: #f8f8f8 !important;
}
.syntaxhighlighter .gutter {
  color: #787878 !important;
}
.syntaxhighlighter .gutter .line {
  border-right: 3px solid #d4d0c8 !important;
}
.syntaxhighlighter .gutter .line.highlighted {
  background-color: #d4d0c8 !important;
  color: black !important;
}
.syntaxhighlighter.printing .line .content {
  border: none !important;
}
.syntaxhighlighter.collapsed {
  overflow: visible !important;
}
.syntaxhighlighter.collapsed .toolbar {
  color: #7587a6 !important;
  background: black !important;
  border: 1px solid #d4d0c8 !important;
}
.syntaxhighlighter.collapsed .toolbar a {
  color: #7587a6 !important;
}
.syntaxhighlighter.collapsed .toolbar a:hover {
  color: #f9ee98 !important;
}
.syntaxhighlighter .toolbar {
  color: #a0a0a0 !important;
  background: #d4d0c8 !important;
  border: none !important;
}
.syntaxhighlighter .toolbar a {
  color: #a0a0a0 !important;
}
.syntaxhighlighter .toolbar a:hover {
  color: black !important;
}
.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
  color: #f8f8f8 !important;
}
.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
  color: #5f5a60 !important;
}
.syntaxhighlighter .string, .syntaxhighlighter .string a {
  color: #8f9d6a !important;
}
.syntaxhighlighter .keyword {
  color: #cda869 !important;
}
.syntaxhighlighter .preprocessor {
  color: #646464 !important;
}
.syntaxhighlighter .variable {
  color: #f8f8f8 !important;
}
.syntaxhighlighter .value {
  color: #cf6a4d !important;
}
.syntaxhighlighter .functions {
  color: #9b859e !important;
}
.syntaxhighlighter .constants {
  color: #cf6a4d !important;
}
.syntaxhighlighter .script {
  font-weight: bold !important;
  color: #9b703f !important;
  background-color: none !important;
}
.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
  color: #9b703f !important;
}
.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
  color: #f9ee98 !important;
}
.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
  color: #cf6a4d !important;
}

.syntaxhighlighter .keyword {
  font-weight: bold !important;
}
.syntaxhighlighter .xml .keyword {
  color: #9b703f !important;
  font-weight: normal !important;
}
.syntaxhighlighter .xml .color1, .syntaxhighlighter .xml .color1 a {
  color: #9b703f !important;
}
.syntaxhighlighter .xml .string {
  font-style: italic !important;
  color: #8f9d6a !important;
}

viewer01.js

SGF Viewer 0.1 のソースコードです。 リンク先をご覧下さい。

board06.js

碁盤クラス Borard のソースコードです。Simulator 0.4 からコメントを英語に変更した他、クラス Move のインタフェースの変更に対応しました。 リンク先をご覧下さい。

pos09.js

BWモデルで局面を表すクラス Pos のソースコードです。Simulator 0.4 からコメントを英語に変更した他、クラス Move のインタフェースの変更に対応しました。 リンク先をご覧下さい。

move04.js

着手クラス Move のソースコードです。Simulator 0.4 からコメントを英語に変更した他、クラス Move のインタフェースの変更に対応しました。 リンク先をご覧下さい。

bvector07.js

2進ベクトルクラス BVector のソースコードです。Simulator 0.4 から処理内容に変更ありませんが、コメントを英語に変更しました。 リンク先をご覧下さい。

bmatrix05.js

2進行列クラス BMatrix のソースコードです。Simulator 0.4 から処理内容に変更ありませんが、コメントを英語に変更しました。 リンク先をご覧下さい。

generator03.js

クラス EBNFParser のソースコードです。パーサーを生成するためのツールです。 前回から終端記号 symbol にコロンとセミコロンを追加しました。
/**
 * symbol = '=' | ',' | '.' | '|' | '+' | '-' | '*' | '/' |
 *          ':' | ';' | '[' | ']' | '{' | '}' | '(' | ')'.
 * @return {String} code generated if matched, null if not matched
 * @since 0.31
 */
EBNFParser.prototype.symbol = function() {
	var match = [];
	var save = this.ptr;
	var n = -1;
	this.sp();
	match[++n] = this.text('=');
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text(',');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('.');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('|');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('+');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('-');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('*');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('/');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text(':');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text(';');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('[');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text(']');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('{');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('}');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text('(');
	}
	if (!match[n]) {
		n--;
		this.sp();
		match[++n] = this.text(')');
	}
	if (!match[n]) {
		this.ptr = save;
		return null;
	}
	return this.run(n, match, "symbol");
};
ファイル全体はリンク先をご覧下さい。 フォルダの関係でリンク先のソースは前回のままです。

source01.js

クラス Source のソースコードです。Lex, Parser の対象となるテキストを格納するクラスです。前回から変更ありません。 リンク先をご覧下さい。

lex04.js

クラス Lex のソースコードです。字句解析のためのツールです。前回から変更ありません。 リンク先をご覧下さい。

sgfparser02.js

クラス SGFParser のソースコードです。SGF を構文解析するためのツールです。このページの最初で生成したものに手を加えました。 リンク先をご覧下さい。
Copyright © 2012-2017 たかはしのんき. All rights reserved.