/el-igo

Emacs Go Game(SGF) Editor

Primary LanguageEmacs Lisp

el-igo - Emacs Go Game(SGF) Editor

Emacs内で囲碁の盤面を表示し、棋譜(SGF形式)を編集します。

./screenshot/igo-org-20201227.gif

動作環境

Emacs 27.1

org-mode文書内に棋譜を埋め込む(igo-org.el)

設定

init.elに次のコードを追加してください。

(with-eval-after-load "org"
  (require 'igo-org)
  (igo-org-setup))

また、HTMLとしてエクスポートしたときに盤面を表示したい場合は後述の設定も追加してください。

使い方

org文書内にigo特殊ブロックを挿入します。(操作例: C-c C-, SPC i g o RET)

#+begin_igo
#+end_igo

ブロックの中に (;SZ[9]) と入力すると9路盤が表示されます。またはブロック内で C-c i を押すと盤面サイズを指定して初期化できるようになっています。

後は適当に石を置いたり、フリー編集モードで初期盤面を設定したり、コメントを設定したりすると、その操作毎にバッファのテキストが書き換わります。

ブロック毎のオプション

#+begin_igo の後にブロック毎のオプションを指定できます。

例えば次のようにするとブロックが盤面化されたとき(orgファイルを開いたとき等)に最初から手順番号が表示されます。

#+begin_igo :move-number t
(;FF[4]GM[1]SZ[9];B[fd];W[df];B[ff];W[dd])
#+end_igo

有効なオプションには次のものがあります。

オプション名意味
:status-barステータスバーの表示状態nil, noのとき非表示
:move-number手順番号の表示状態nil, noのとき非表示
:branch-text分岐文字(A,B,…)の表示状態nil, noのとき非表示
:editable編集可能nil, noのとき編集不可能
:read-only編集禁止(:editableの逆)nil, noのとき編集可能
:path最初に表示する盤面(ノード)盤面へたどり着く経路(後述)
:displayエクスポート時の表示方法表示方法を示す値(後述)
:grid-interval格子線の間隔ピクセル数(デフォルトは igo-board-view-grid-interval-default)

orgファイル内に #+IGO_BLOCK_DEFAULTS: を記述することで、ファイル内でのオプションのデフォルト値を設定できます。(注意:現在の所、変更時はファイルを開き直す必要があります)

例:

#+IGO_BLOCK_DEFAULTS: :grid-interval 24 :move-number t

:pathの指定方法

:path オプションは最初に表示する盤面(ゲーム木のノード)を指定します。

パス(盤面へたどり着く経路)は次の要素を並べたもので、最初の盤面(ルート)から各要素が指定する盤面を順番にたどり最終的に到達した盤面が選択されます。

数字現在の盤面から数字で指定しただけ後の盤面(途中分岐がある場合は最初の分岐(A)を選択)(無い場合は最後の盤面)
-数字現在の盤面から数字で指定しただけ前の盤面(無い場合は最初の盤面)
アルファベット二文字SGF座標とみなし、その場所に打つ現在の盤面から最も近い盤面(幅優先探索)
大文字アルファベット一文字現在の盤面以降の最初の分岐での分岐先(A:0, B:1, …)を指定したものと見なし、その分岐直後の盤面
_ (アンダーバー)現在の盤面以降の最初の分岐がある盤面(分岐が無ければ最後の盤面)

例:

  • 0 : 最初の盤面
  • 12 : 最初から12手目の盤面
  • cd : 最初に3の4に着手する盤面
  • cc/fc : 最初に左上三々(cc)に着手した後、次に最初に二間開き(fc)した盤面
  • cc/2 : 最初に着手した後の2手目
  • A/B/A : 分岐をA、B、Aの順に選択した盤面
  • _ : 最初の分岐(無ければ最後の盤面)
  • _/-1 : 最初の分岐(無ければ最後の盤面)の一つ前

SGFファイルの編集(igo-sgf-mode.el)

設定

init.elに次のコードを追加してください。

(autoload 'igo-sgf-mode "igo-sgf-mode")
(add-to-list 'auto-mode-alist '("\\.sgf$" . igo-sgf-mode))

sgfファイルを開くと自動的に盤面が表示されます。

注意: sgfファイルはオセロ、チェス、バックギャモンなど囲碁以外のゲームの棋譜も表現できます。あなたがそれらを扱う場合は、GMプロパティが1以外のときにigo-sgf-modeを起動しないようにする必要があります(未実装)。

バッファ内の任意の部分を盤面にする(igo-editor.el)

任意のSGFテキストをリージョンで囲った上で M-x igo-edit-region を実行すると、その範囲がエディタ化されます。

igo-sgf-mode.el も igo-org.el も igo-editor.el を使って実装されています。igo-sgf-mode.elはバッファ全体を、igo-org.elはbegin_igo~end_igoの間を自動的にエディタ化します。

エディタの使い方

モード

エディタは大きく分けて次のようなモードを持っています。

  • テキストモード
    • 固定モード(エラーが無くなってもテキストのまま)
    • 自動回復モード(エラーが無くなったときに自動的にグラフィカルモードに移行する)

キー操作

各モードで使えるキー操作は次の通りです。

テキストモード

操作説明関数
C-c qエディタの終了igo-editor-quit
C-c gグラフィカルモードへ移行igo-editor-graphical-mode
C-c i盤面の初期化igo-editor-init-board

グラフィカルモード共通

操作説明関数
C-c gテキストモードへ移行igo-editor-text-mode
C-x c-q編集可能状態切り替えigo-editor-toggle-editable
a, |<ボタンクリック最初へigo-editor-first-node
e, >|ボタンクリック最後へ(デフォルト選択でたどれる所まで)igo-editor-last-node
b, <ボタンクリック前へigo-editor-previous-node
f, >ボタンクリック次へ(デフォルト選択でたどれる場合)igo-editor-next-node
M-b前の分岐地点へigo-editor-previous-fork
M-f次の分岐地点へigo-editor-next-fork
n次の盤面を分岐の中から選択して表示igo-editor-select-next-node
Q着手モードigo-editor-move-mode
Fフリー編集モードigo-editor-free-edit-mode
Mマーク編集モードigo-editor-mark-edit-mode
s sステータスバー表示切り替えigo-editor-toggle-status-bar
s n手順番号表示切り替えigo-editor-toggle-move-number
s b分岐表示切り替えigo-editor-toggle-branch-text
cコメントの編集igo-editor-edit-comment
N手順番号の編集igo-editor-edit-move-number
g対局情報の編集igo-editor-edit-game-info
x盤面のSVG画像出力igo-editor-export-image
C-c i盤面の初期化igo-editor-init-board

着手モード

操作説明関数
P, Passボタンクリックパスigo-editor-pass
p石を置くigo-editor-put-stone
盤面をクリック石を置くigo-editor-move-mode-board-click
Passボタン右クリック着手「パス」に対するメニューを表示igo-editor-pass-click-r
盤面を右クリック交点(石や空点)に対するメニューを表示igo-editor-move-mode-board-click-r
\dollar現在の盤面をルートにするigo-editor-make-current-node-root

フリー編集モード

(現在の所、一番最初の盤面でのみ使用できます)

操作説明関数
Quitボタンクリック着手モードへ切り替えigo-editor-move-mode
p交点を選択中の状態にするigo-editor-free-edit-put
盤面をクリック交点を選択中の状態にするigo-editor-free-edit-board-down
B, Blackボタンクリック黒石を選択するigo-editor-free-edit-black
W, Whiteボタンクリック白石を選択するigo-editor-free-edit-white
E, Emptyボタンクリック空点を選択するigo-editor-free-edit-empty
T, Turnボタンクリック次の手番を反転させるigo-editor-free-edit-toggle-turn

マーク編集モード

操作説明関数
Quitボタンクリック着手モードへ切り替えigo-editor-move-mode
p交点を選択中の状態にするigo-editor-mark-edit-put
盤面をクリック交点を選択中の状態にするigo-editor-mark-edit-board-down
X, Xボタンクリック×マークを選択するigo-editor-mark-edit-cross
O, Oボタンクリック○マークを選択するigo-editor-mark-edit-circle
S, SQボタンクリック□マークを選択するigo-editor-mark-edit-square
T, TRボタンクリック△マークを選択するigo-editor-mark-edit-triangle
E, Textボタンクリックテキストを選択するigo-editor-mark-edit-text
D, Delボタンクリック消去を選択するigo-editor-mark-edit-del

分岐の編集

前の手に戻って別の場所に打つと自動的に分岐が作られます。エディタは全ての分岐をツリー構造で記録しています。

分岐は分岐直前の盤面でAから始まるアルファベットで表示されます。

分岐箇所を示すアルファベットを「左クリック」すると、その分岐に進みます。

「次へ進む」ボタンは最後に選んだ分岐へ進みますが、もしまだ選択していない場合は明示的に指定する必要があります。

分岐を削除したい場合や分岐の(アルファベットの)順番を変更したい場合は、アルファベットを 「右クリック」 してください。分岐に対する操作がポップアップメニューで表示されます。

org-modeでHTMLエクスポートする

org-mode文書中に棋譜を埋め込んだのならエクスポート後の文書にも盤面が表示されて欲しいと思うことでしょう。ここではHTMLでのエクスポート時に盤面を出力する方法について説明します。

org-mode標準機能だけで処理する方法

標準のHTMLバックエンドは特殊ブロックをdivタグで囲んだ形で出力します。 #+begin_igo#+end_igo も特殊ブロックなので、HTMLで出力すると <div class="igo"><p> SGFテキスト </p></div> の形で出力されます。

盤面の形で表示させたい場合は、ページ読み込み完了時にJavaScriptで一括変換すると良いでしょう。

例えば拙作のJavaScript碁盤を使用するならば misohena/js_igo: JavaScript Go Game Board より igo.js, igo_view.js, igo.css をダウンロードした上で、次のようにします。

#+HTML_HEAD: <script src="igo.js"></script>
#+HTML_HEAD: <script src="igo_view.js"></script>
#+HTML_HEAD: <link rel="stylesheet" href="igo.css" />
#+HTML_HEAD: <script>window.addEventListener("load", ev=>{ for(elem of document.querySelectorAll("div.igo")){ let sgf = elem.textContent; while(elem.hasChildNodes()){elem.removeChild(elem.firstChild);} new igo.GameView(elem, sgf, {"showBranchText": true, "showLastMoveMark": true, "showComment": true, "path":1000}); }});</script>

お互いに二連星したところ。

#+begin_igo
(;FF[4]GM[1]SZ[9];B[fd];W[df];B[ff];W[dd])
#+end_igo

エクスポータをカスタマイズする

igo特殊ブロックの出力(変換結果)自体を変える方法もあります。

igo特殊ブロックの出力を変えるためにはorg-modeのエクスポータをカスタマイズしなければなりませんが、その方法として次の三つを用意しました。

  • 既存のHTMLバックエンドを修正する
  • HTMLバックエンドから派生した新しいバックエンドを定義する
  • バッファローカル変数を書き替える

既存のHTMLバックエンドを修正する

最も使い勝手の良い方法は既存のHTMLバックエンドを修正することです。一度設定してしまえばファイル毎に設定する必要はありませんし、普段通りの操作でエクスポートできます。

次のコードを init.el に追加してください。

(with-eval-after-load "ox-html"
  (require 'igo-org-export-html)
  (igo-org-modify-html-backend))

すると org-mode のHTMLバックエンドが読み込まれた直後にそれを書き替えてigo特殊ブロック( #+begin_igo#+end_igo 部分)を特別に処理するようにします。

デフォルトは拙作のJavaScript碁盤を使うHTMLを出力するので、 misohena/js_igo: JavaScript Go Game Board より igo.js, igo_view.js, igo.css をダウンロードしてhtmlと同じ場所に配置してください。

あとは通常通りHTMLとしてエクスポートするだけです。

HTMLバックエンドから派生した新しいバックエンドを定義する

何らかの理由でHTMLバックエンドを直接修正して欲しくない場合、新しく専用のバックエンドを定義することも出来ます。

次のコードを実行すると igo-html という名前のバックエンドが登録されます。

(require 'igo-org-export-html)
(igo-org-define-html-backend t)

igo-org-define-html-backend の引数に t を指定するとメニューに項目を追加します。

C-c C-e でエクスポートのメニューを出した後、 g を押すことでこのバックエンドを指定できます。

個別のファイルにフィルタを設定する

バックエンドをカスタマイズしなくても、ファイルごとにバッファローカル変数を設定することで変換処理を変更できます。

この方法を使うには、org-mode文書の中に次のコードを追加してください。

#+begin_src emacs-lisp :exports results :results none
(require 'igo-org-export-html)
(igo-org-set-html-filters-local)
#+end_src

:exports results を指定することでエクスポートのたびにソースブロックを評価させ、 :results none を指定することで結果の出力を抑制しています。

後は通常通りHTMLとしてエクスポートしてください。

org-modeのデフォルト設定ではエクスポートするたびにソースブロックを評価するか聞いてくるので yes を入力してください。

するとバッファローカル変数に変換フィルタが設定され、igo特殊ブロックが特別に変換されます。

オプション

igo-org-export-html.el を使用して変換する場合、次のオプションが使用できます。

オプション意味デフォルト値
#+IGO_JS_PATH: <path-to-directory>スクリプトのあるディレクトリへのパスigo-org-js-pathの値 (./)
#+IGO_JS_TEMPLATE: <header-template>HTMLのHEADに挿入するテキストの雛形(displayがjsのとき)igo-org-js-templateの値
#+IGO_LAZY_JS_TEMPLATE: <block-template>igo特殊ブロックの中に挿入するテキストの雛形(displayがlazy-jsのとき)igo-org-lazy-js-templateの値
#+IGO_HEADER_TEMPLATE: <header-template>HTMLのHEADに挿入するテキストの雛形(displayがcustomのとき)igo-org-header-templateの値
#+IGO_BLOCK_TEMPLATE: <block-template>igo特殊ブロックの中に挿入するテキストの雛形(displayがcustomのとき)igo-org-block-templateの値
#+IGO_ENABLE: <boolean>igo特殊ブロックを変換するかどうかt
#+IGO_DISPLAY: <display-type>igo特殊ブロックをどのように変換するかjs

#+IGO_ENABLE: nil を指定するとファイル内で一切の変換を抑制できます。

#+IGO_DISPLAY: には次のいずれかを指定できます。

<display-type>表示方法
none非表示
noconv変換しない(SGFテキストのまま)
jsjs_igoによるJavaScript碁盤
lazy-jsjs_igoによるJavaScript碁盤(遅延読み込み型。<head></head>にスクリプトを挿入しない)
svgSVG画像埋め込み
custom#+IGO_HEADER_TEMPLATE:#+IGO_BLOCK_TEMPLATE: を使用

また、表示方法はブロック毎に #+begin_igo :display <display-type> の形でも指定できます。

例:

#+IGO_JS_PATH: ./js_igo/
#+IGO_DISPLAY: svg

#+begin_igo :move-number t :path A/A/B
....省略(SVGで表示)....
#+end_igo

#+begin_igo :read-only t :move-number t :path 5 :display js
....省略(js_igoで表示)....
#+end_igo

表示方法によってはテンプレート文字列を指定できます。

オプションの <header-template> の部分は、HTMLのHEAD要素内に挿入するテキストの雛形です。表示方法が js であるブロックが存在する場合、 #+IGO_JS_TEMPLATE: オプションで指定した雛形が使われます。また、表示方法が custom であるブロックが存在する場合、 #+IGO_HEADER_TEMPLATE: オプションで指定した雛形も使われます。

<header-template> の中では次の記法が使用できます。

% <var-name> %置き換え先
%PATH%#+IGO_JS_PATH: オプションの値

オプションの <block-template> の部分は、igo特殊ブロックの中に挿入するテキストの雛形です。表示方法が lazy-js のブロックには #+IGO_LAZY_JS_TEMPLATE: オプションで指定した雛形が使われます。また、表示方法が custom であるブロックには #+IGO_BLOCK_TEMPLATE: オプションで指定した雛形が使われます。

<header-template> の中では次の記法が使用できます。

% <var-name> %置き換え先
%PATH%#+IGO_JS_PATH: オプションの値
%SGF%SGFテキスト
%OPT_JSON%js_igo用のオプション
%SVG%盤面をSVG化したテキスト

また、%の後に次のいずれかを指定することでテキスト内の一部の文字をエスケープできます。

記法置き換える文字置き換え後の文字
%HTML_<var-name>%& < >&amp; &lt; &gt;
%ATTR_<var-name>%& < > ”&amp; &lt; &gt; &quot;
%LITERAL_<var-name>%\ ” 改行 <!– <script </script\ " \n <\!– <\script <\/script

つまり、HTMLの属性の中に記述するときは%ATTR_を、HTMLの内容部分に記述するときは%HTML_を、JavaScriptの文字列リテラル内に記述するときは%LITERAL_を使用してください。例えばSGFをJavaScriptの文字列にして解析したい場合、 parseSGF("%LITERAL_SGF%") のように記述します。