el-igo icon indicating copy to clipboard operation
el-igo copied to clipboard

Emacs Go Game(SGF) Editor

#+TITLE: el-igo - Emacs Go Game(SGF) Editor #+OPTIONS: toc:nil num:nil ^:nil

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

[[file:./screenshot/igo-org-20201227.gif]]

  • 動作環境 Emacs 27.1

  • org-mode文書内に棋譜を埋め込む(igo-org.el) ** 設定 init.elに次のコードを追加してください。

#+begin_src emacs-lisp (with-eval-after-load "org" (require 'igo-org) (igo-org-setup)) #+end_src

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

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

#+begin_src org ,#+begin_igo ,#+end_igo #+end_src

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

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

** ブロック毎のオプション

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

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

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

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

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

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

例: #+begin_src org ,#+IGO_BLOCK_DEFAULTS: :grid-interval 24 :move-number t #+end_src

*** :pathの指定方法

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

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

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

例:

  • 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に次のコードを追加してください。

#+begin_src emacs-lisp (autoload 'igo-sgf-mode "igo-sgf-mode") (add-to-list 'auto-mode-alist '("\.sgf$" . igo-sgf-mode)) #+end_src

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, \vert{}<ボタンクリック | 最初へ | igo-editor-first-node | | e, >\vert{}ボタンクリック | 最後へ(デフォルト選択でたどれる所まで) | 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エクスポートする :PROPERTIES: :CUSTOM_ID: org-export :END:

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

** org-mode標準機能だけで処理する方法 標準のHTMLバックエンドは特殊ブロックをdivタグで囲んだ形で出力します。 ~#+begin_igo~ ~ ~#+end_igo~ も特殊ブロックなので、HTMLで出力すると ~

~ /SGFテキスト/ ~

~ の形で出力されます。

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

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

#+begin_src org ,#+HTML_HEAD: ,#+HTML_HEAD: ,#+HTML_HEAD: ,#+HTML_HEAD:

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

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

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

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

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

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

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

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

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

#+begin_src emacs-lisp (with-eval-after-load "ox-html" (require 'igo-org-export-html) (igo-org-modify-html-backend)) #+end_src

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

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

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

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

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

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

#+begin_src emacs-lisp (require 'igo-org-export-html) (igo-org-define-html-backend t) #+end_src

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

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

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

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

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

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

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

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

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

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

** オプション :PROPERTIES: :CUSTOM_ID: org-export-options :END:

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

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

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

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

| // | 表示方法 | |------------------+-----------------------------------------------------------------------------------| | ~none~ | 非表示 | | ~noconv~ | 変換しない(SGFテキストのまま) | | ~js~ | js_igoによるJavaScript碁盤 | | ~lazy-js~ | js_igoによるJavaScript碁盤(遅延読み込み型。にスクリプトを挿入しない) | | ~svg~ | SVG画像埋め込み | | ~custom~ | ~#+IGO_HEADER_TEMPLATE:~ と ~#+IGO_BLOCK_TEMPLATE:~ を使用 |

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

例:

#+begin_src org ,#+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 #+end_src

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

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

// の中では次の記法が使用できます。

| % // % | 置き換え先 | |------------------+---------------------------------| | ~%PATH%~ | ~#+IGO_JS_PATH:~ オプションの値 |

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

// の中では次の記法が使用できます。

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

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

| 記法 | 置き換える文字 | 置き換え後の文字 | |------------------------+--------------------------------+-----------------------------------| | ~%HTML_%~ | & < > | & < > | | ~%ATTR_%~ | & < > " | & < > " | | ~%LITERAL_%~ | \ " 改行 <!-- <script </script | \ " \n <!-- <\script </script |

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