囲碁の棋譜フォーマット SGF (Smart Game Format) の構文から、その構文解析クラス SGFParser を作成し、 この機能を利用して棋譜を再生するプログラムを作成しました。
クラス SGFParser の生成のための入力に使用した SGF の構文は以下の通りです。SGF Parser 0.1 の Property を具体的な定義に変更しました。
生成された SGFParser のコードは以下の通りです。字下げは Aptana Studio 等のツールで簡単にできるので行っていません。
上記のコードに、読み込んだ棋譜を碁盤の内部情報に変換するコードを加え、棋譜を盤上で再生できるようにしました。
以下に実行結果を示します。利用した棋譜は Small Basic の Go Simulator 0.4 で作成したものです。対局の終盤で三コウ(三劫)が発生しています。
このソースコードは 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... -->
後半の 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>上記のコードに、読み込んだ棋譜を碁盤の内部情報に変換するコードを加え、棋譜を盤上で再生できるようにしました。
<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 実行結果 -->
/**
* 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;
}
/**
* 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");
};
ファイル全体はリンク先をご覧下さい。
フォルダの関係でリンク先のソースは前回のままです。