% \iffalse meta-comment
%%
%% 文件：weiqi.dtx
%%
%% 版权 (C) 2023-2024 By Ms_yam
%%
%% 它可以在 LaTeX 项目公共许可（LPPL）1.3c 及之后的任意版本（随你的意见）下分发或修改。
%% 这个许可的最新版本在如下文件中：
%%
%%   https://www.latex-project.org/lppl.txt
%%
%% 本宏包为作者练习 epxl3 和编写 dtx 文件所编写，里面的接口及方法并不是最优的。
%% 仅供参考。
%%
% \fi
%
% \iffalse
%<*driver>
\documentclass[full]{l3doc}

\usepackage{weiqi}

% 创建代码示例
\usepackage{listings}
\ExplSyntaxOn
\makeatletter
\lst@RequireAspects{writefile}
\box_new:N \l__demo_box
\lstnewenvironment{demo}[1][code and example]
  {
    \use:c { demo_#1: }
  }
  { \use:c { demo_#1_end: } }
\cs_new:Nn \__demo_common:
  {
    \setkeys{lst}
      {
        basicstyle   = \ttfamily,
        gobble       = 2,
        language     = [LaTeX]{TeX},
      }
  }
\cs_new:Nn \__demo_input:
  {
    \catcode`\^^M = 10\relax
    \catcode`\% = 14\relax
    \input{\jobname.tmp}
  }  
\cs_new:Npn \__demo_init:nnn #1#2#3
  {
    \cs_set:cn {demo_#1:} { #2 }
    \cs_set:cn {demo_#1_end:} { #3 }
  }
   
\__demo_init:nnn{code and example}
  {%
    \hbox_set:Nw \l__demo_box
      \__demo_common:
      \lst@BeginAlsoWriteFile{\jobname.tmp}%
  }
  {%
      \lst@EndWriteFile    
    \hbox_set_end:    
    %\begin{center}
      \fp_compare:nNnTF
        { \box_wd:N \l__demo_box  } > {  0.6 * \linewidth }
        {
          \begin{minipage}{\linewidth}
            \box_use:N \l__demo_box
          \end{minipage}%
          \par
          \begin{minipage}{\linewidth}
            \__demo_input:
          \end{minipage}
      }
      {
          \begin{minipage}{0.40\linewidth}
            \__demo_input:
          \end{minipage}%
          %\hfil
          \begin{minipage}{0.54\linewidth}
            \box_use:N \l__demo_box
          \end{minipage}%
      }
    %\end{center}
  }
\makeatother
\ExplSyntaxOff
 
% ^^A 添加中文支持及设置超级链接
\usepackage[UTF8,hyperref]{ctex} 
\hypersetup{ 
  colorlinks,
  linkcolor=blue,
  hyperindex,
  pdfstartview=FitH,
  plainpages=false,
  backref,
}

% ^^A 引用待办包
\usepackage{todo}

% ^^A 汉化 l3doc 的部分定义
\NewDocumentEnvironment { texnote } { }% 不能用 Renew...，原因未知
{
  \endgraf
  \vspace{0.5em}% 3mm => 0.5em
  \small\textbf{\TeX{} 黑客笔记：}% \TeX~hackers~note:
}
{
  \vspace{0.5em}% 3mm => 0.5em
}

\begin{document}
  \DocInput{\jobname.dtx}
  \todos % ^^A 列出待办事宜
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   \pkg{weiqi}宏包：绘制围棋棋谱^^A
% }
%
% \author{Ms\_yam\thanks
%     {^^A
%       本宏包是作者练习 \LaTeX3 和编写 dtx 文件的作品，里面的接口及方法并未优化；但宏包漏洞会尽力修复。
%     }^^A
%   \  （\href{mailto:Ms_yam@163.com}{Ms\_yam@163.com}）^^A
% }
% \date{\zhdigits*{2024}年\zhnumber{02}月\zhnumber{22}日}
%
% \maketitle
%
% \DoNotIndex{\[,\\,\]}
% \DoNotIndex{\Large, \meta, \noindent, \textbf, \texttt}
% \DoNotIndex{\ExplSyntaxOn, \ExplSyntaxOff, \NeedsTeXFormat, \RequirePackage, \ProvidesExplPackage, \NewDocumentCommand}
% \DoNotIndex{\IfBooleanT, \IfBooleanF, \IfNoValueTF}
% \DoNotIndex{\bool_new:N, \bool_set_eq:NN, \bool_set_false:N, \bool_set_inverse:N, \bool_set_true:N, \bool_to_str:N}
% \DoNotIndex{\bool_gset_eq:NN, \bool_gset_false:N, \bool_gset_true:N}
% \DoNotIndex{\bool_if:nT, \bool_if:NT, \bool_if:nTF, \bool_if:NTF}
% \DoNotIndex{\bool_lazy_all:nT, \bool_lazy_all:nTF, \bool_lazy_and:nnT, \bool_lazy_and:nnTF}
% \DoNotIndex{\bool_lazy_any:nTF, \bool_lazy_or:nnT, \bool_lazy_or:nnF, \bool_lazy_or:nnTF}
% \DoNotIndex{\box_ht:N, \box_wd:N}
% \DoNotIndex{\clist_new:N, \clist_const:Nn, \clist_clear:N, \clist_set:Nn, \clist_set_eq:NN, \clist_set_from_seq:NN, \clist_pop:NN, \clist_use:Nn}
% \DoNotIndex{\clist_gclear:N, \clist_gput_right:Nn, \clist_set_eq:Nc, \clist_gset_eq:NN, \clist_gset_eq:cN}
% \DoNotIndex{\clist_if_empty:NTF, \clist_map_function:NN, \clist_map_inline:Nn}
% \DoNotIndex{\color_fill:n, \color_select:n}
% \DoNotIndex{\cs_new:Nn, \cs_new:Npn, \cs_generate_variant:Nn, \cs_if_free:cT, \cs_if_free:cTF}
% \DoNotIndex{\draw_begin:, \draw_end:, \draw_linewidth:n, \draw_path_circle:nn, \draw_path_lineto:n, \draw_path_moveto:n}
% \DoNotIndex{\draw_box_use:Nn, \draw_path_use_clear:n, \draw_transform_scale:n}
% \DoNotIndex{\fp_new:N, \fp_set_eq:NN, \fp_set:Nn, \fp_add:Nn,\fp_sub:Nn, \fp_compare:nNnT, \fp_compare:nNnTF, \fp_gset:Nn, \fp_use:N}
% \DoNotIndex{\group_begin:, \group_end:}
% \DoNotIndex{\hbox_set:Nn}
% \DoNotIndex{\int_new:N, \int_new:c, \int_const:Nn, \int_set_eq:NN, \int_set_eq:Nc, \int_set:Nn, \int_set:Ne, \int_add:Nn, \int_incr:N, \int_use:N} 
% \DoNotIndex{\int_gset:Nn, \int_gset:Ne, \int_gincr:N, \int_gset_eq:NN, \int_gset_eq:Nc, \int_gset_eq:cN}
% \DoNotIndex{\int_max:nn, \int_min:nn,  \int_sign:n, \int_abs:n, \int_from_alph:n, \int_from_alph:e, \int_to_alph:n, \int_to_Alph:n}
% \DoNotIndex{\int_case:nn, \int_compare_p:n, \int_compare_p:nNn, \int_compare:nNnT, \int_compare:nNnF, \int_compare:nNnTF}
% \DoNotIndex{\int_if_zero:nF, \int_if_zero:nTF, \int_step_inline:nn, \int_step_inline:nnnn}
% \DoNotIndex{\intarray_new:Nn, \intarray_new:cn, \intarray_gset:Nnn, \intarray_gset:cnn, \intarray_gzero:N, \intarray_item:Nn, \intarray_item:cn}
% \DoNotIndex{\ior_open:Nn, \ior_close:N, \ior_str_map_inline:Nn}
% \DoNotIndex{\prg_set_conditional:Npnn, \prg_return_false:, \prg_return_true:, \prg_generate_conditional_variant:Nnn, \prg_break_point:, \prg_break:}
% \DoNotIndex{\regex_match:nn, \regex_match:nnTF, \regex_match:nVTF, \regex_extract_all:nnN}
% \DoNotIndex{\regex_extract_once:nnN, \regex_extract_once:nVN, \regex_extract_once:nnNTF, \regex_extract_once:nVNTF}
% \DoNotIndex{\seq_new:N, \seq_new:c, \seq_put_right:Nn, \seq_item:Nn, \seq_gclear:N, \seq_gset_item:Nnn, \seq_gset_item:NnV}
% \DoNotIndex{\seq_if_in:NnT, \seq_if_in:NnF, \seq_if_in:NnTF}
% \DoNotIndex{\str_new:N, \str_const:Nn, \str_set:Nn, \str_set:NV, \str_set:Nx, \str_set_eq:NN}
% \DoNotIndex{\str_put_right:Nn, \str_put_right:NV, \str_put_right:Nx}
% \DoNotIndex{\str_gset_eq:NN}
% \DoNotIndex{\str_head:N, \str_item:Nn, \str_range:Nnn, \str_range:nnn, \str_tail:N, \str_lowercase:n}
% \DoNotIndex{\str_if_empty_p:N, \str_if_empty:NTF, \str_if_empty:nTF, \str_if_eq_p:nn, \str_if_eq_p:Vn, \str_if_eq:nnTF}
% \DoNotIndex{\str_case:nn, \str_case_e:nn, \str_compare:eNeT, \str_compare:nNnTF, \str_compare:eNeTF}
%
% \begin{documentation}
%
% \section{\pkg{weiqi} 文档}
%
% 本宏包提供了绘制围棋棋谱功能。本宏包参考（或延用）了 \pkg{igo} 宏包的部分命令，
% 但本宏包的实现完全采用 \pkg{expl3} 方式。
%
% 本宏包的绘图采用 \pkg{l3draw} 宏包（2024-01-04 版）实现，因前者具有\emph{高度}实验性，因些本
% 宏包也同样具体\emph{高度}实验性。
%
%
% \subsection{相关概念}^^A
%
%
% \subsubsection{尺寸}
%
% 本宏包中的 \meta{尺寸} 特指棋盘尺寸（即一个方向包含几路），棋盘大小为 \meta{尺寸} x \meta{尺寸}。
% 本宏包支持的 \meta{尺寸} 取值为 $2$\~{}$26$，但通常建议使用 $9$、$13$ 和 $19$ 三种尺寸。
% 其中，$19$x$19$ 为标准棋盘大小（也是默认大小）。
%
%
% \subsubsection{坐标}
% 
% 为方便描述落子位置，本宏包依惯例采用 \meta{坐标} 的概念。
% 本宏包支持两种形式的 \meta{坐标}：以左下角为起点（常规模式）和左上角为起点（$SGF$ 模式）。
%
% 两种形式的横坐标相同，从左往右依次为 $a$、$b$、\dots。它们的区别在于：
% 前者纵坐标从下往上依次为 $1$、$2$、\dots；而后者的纵坐标从上往下依次为 $a$、$b$、\dots。
% 前者是为便于人员交互设计，后者是为支持 $sgf$ 棋谱坐标而设计。
%
% 横坐标与纵坐标组合形成 \meta{坐标}，如 |a1|、|dp| 等。
% 通常需要 \meta{坐标} 的地方，也支持逗号列表形式的 \meta{坐标} 集合，如 “|a2, b2, dp|”。
%
% \begin{minipage}{0.45\linewidth}
%   \newweiqi
%   \showweiqi[a1,e4]
% \end{minipage}%
% \begin{minipage}{0.45\linewidth}
%   \sgflocmode
%   \showweiqi[aa,ed]
% \end{minipage}\\
%
%
% \subsubsection{虚着}
%
% 围棋有一个比较特殊的规则：它允许一方停一手（也叫虚着），另一方继续下。
% 为了以统一的方式记录每一手棋，特将虚着的 \meta{坐标} 定义为 |-| 或 |pass|。
%
% \subsection{基本命令}^^A 
%
%
% \begin{function}{\newweiqi}
%   \begin{syntax}
%     \cs{newweiqi} [\meta{尺寸}]
%   \end{syntax}
%   初始化新对局，\meta{尺寸}用于指定棋盘大小（默认为 $19$）。
%   带星号版本同时更改 \meta{尺寸} 的默认值。
% \end{function}
%
%
% \begin{function}{\weiqisize}
%   \begin{syntax}
%     \cs{weiqisize} \Arg{尺寸}
%   \end{syntax}
%   修改棋盘大小为 \meta{尺寸}。
%   带星号版本同时更改 \meta{尺寸} 的默认值。
%   \begin{texnote}
%     修改棋盘尺寸不会检查已有棋子是否越界。
%     同时还会引发已有的 \meta{坐标}为 $SGF$ 模式的棋子的位置错乱。
%   \end{texnote}
% \end{function}
%
%
% \begin{function}{\weiqiblack, \weiqiwhite}
%   \begin{syntax}
%     \cs{weiqiblack} [\meta{标签}] \Arg{坐标}
%   \end{syntax}
%   向当前对局中添加棋子。
%   其中，如果 \meta{标签} 为手数，则会自动递增且切换黑白方。
%   如果 \meta{标签} 为 $0$，则不显示标签但仍切换黑白方。
%   \meta{坐标} 是一组表示棋子位置的逗号分隔列表，每一项表示一手棋；
%   默认以左下角的 \meta{坐标} 为 $a1$；虚着请使用 $-$、|pass| 或留空。
% \end{function}
%
%
% \begin{function}{\weiqidie}
%   \begin{syntax}
%     \cs{weiqidie} \Arg{坐标}
%   \end{syntax}
%   设置指定位置的棋子为死子。
%   \meta{坐标} 是一组表示棋子位置的逗号分隔列表，每一项表示一个位置。
%   \begin{texnote}
%     死子是之前已经下过的棋子，因为没有气，所以需要从棋盘拿走。
%     将没有标签的棋子标记为死子是没有意义的。
%   \end{texnote}
% \end{function}
%
%
% \begin{function}{\showweiqi}
%   \begin{syntax}
%     \cs{showweiqi} [\meta{区间}] 
%   \end{syntax}
%   绘制对局。如果指定 \meta{区间}，则 \meta{区间} 应由两个角点坐标或 |full| 组成，以示指定区间内的信息；
%   如未指定区间，则会自动计算范围，该范围可保证至少包含一个角，其余边至少余一路。
%   默认情况显示完成后会清除对局，使用星号命令可保留对局。
%   \begin{texnote}
%     自动计算的范围会考虑最小显示大小；如果指定区间，则不受此限制。区间外内容不会显示。
%   \end{texnote}
% \end{function}
%
% \begin{demo}
%   \newweiqi
%   \weiqiblack[0]{bq,dq,-}
%   \weiqiwhite[1]{b2,c2,c3,a2,d2,b1}
%   \weiqiwhite[7]{-,b2}
%   \weiqidie{b2}
%   \showweiqi
% \end{demo}\\
%
%
% 死子和带标签（通常为手数）虚着会绘制在棋盘下方；不带标签的虚着则不会绘制（因为它没有任意实际意义）。
%
% \subsection{标签与指示点}^^A 
%
%
% \begin{function}{\weiqilabel, \clearlabel}
%   \begin{syntax}
%     \cs{weiqilabel} [\meta{标签}] \Arg{坐标}\\
%     \cs{clearlabel}
%   \end{syntax}
%   向当前对局中添加标签，或清除对局中的所有标签。
%   其中，如果 \meta{标签} 为手数，则会自动递增。\meta{标签} 默认为 $a$。
%   \meta{坐标} 是一组表示棋子位置的逗号分隔列表，每一项表示一个标签。
%   带星号版本在添加标签的同时会删除旧的标签。
%   \begin{texnote}
%     如果 \meta{标签} 为 $0$ 或为空（|[]|），则显示实心空白圆。
%     \meta{坐标} 规则与棋子一致，本规则在所有 \meta{坐标} 中生效。
%   \end{texnote}
% \end{function}
%
%
% \begin{function}{\weiqired, \weiqigreen, \weiqiblue, \clearpoint}
%   \begin{syntax}
%     \cs{weiqired} \Arg{坐标}\\
%     \cs{clearpoint} 
%   \end{syntax}
%   向当前对局中添加指示点，或清除所有指示点。
%   \meta{坐标} 是一组表示棋子位置的逗号分隔列表，每一项表示一个点。
%   带星号版本在添加标签的同时会删除旧的指示点（含其它颜色）。
% \end{function}
%
%
% \begin{demo}
%   \newweiqi
%   \weiqiblack{a2,-,b1,cq}
%   \weiqilabel[1]{c2,dq,-}
%   \weiqired{d2,e3,-}
%   \weiqigreen{b3}
%   \showweiqi[a1,e3]
% \end{demo}
%
%
% \subsection{棋盘设置}^^A 
%  
%
% \begin{function}{\weiqirotate, \weiqimirror, \weiqiposition}
%   \begin{syntax}
%     \cs{weiqirotate} [\meta{角度}]\\
%     \cs{weiqimirror} [\meta{镜像轴}]\\
%     \cs{weiqiposition} [\meta{角度}]
%   \end{syntax}
%   这三个命令用于设置棋盘的方位（旋转、镜像及指定方向）。
%   其中，前两个命令是基于已有方位的，最后一个则不考虑当前方位。\\
%   \meta{角度}以度为单位（逆时针方向），如未指定，默认分别为 $90$ 度（旋转）和 $0$ 度（指定方向）。
%   \meta{镜像轴} 应当为 $x$、$y$ 或 $xy$（默认） 三者之一。\\
%   使用星号命令可使当前棋盘方位为默认方位。
% \end{function}
%
%
% \begin{function}{\weiqiscale}
%   \begin{syntax}
%     \cs{weiqiscale} [\meta{比例}] 
%   \end{syntax}
%   按 \meta{比例} 缩放棋盘。 如未指定，则恢复默认比例。
%   使用星号命令可使当前缩放比例为默认缩放比例。缩放是基于原有比例的。
% \end{function}
%
%
% \begin{function}{\weiqiminsize}
%   \begin{syntax}
%     \cs{weiqiminsize} \meta{宽度} \meta{高度} 
%   \end{syntax}
%   棋盘最小显示大小（以格子计），使用星号命令可使当前大小为默认值。
% \end{function}
%
%
% \begin{function}{\nonelocmode, \normallocmode, \sgflocmode}
%   \begin{syntax}
%     \cs{nonelocmode}
%   \end{syntax}
%   将棋盘坐标显示方式设置为：不显示坐标、常规模式坐标和 $SGF$ 模式坐标之一。
%   其中，默认为常规模式，使用星号命令可使当前设置为默认值。 
% \end{function}
%
% ~\\
% \begin{demo}
%   \newweiqi
%   \weiqiblack[1]{a2,b2,c3,-,dr}
%   \weiqilabel[A]{dq}
%   \weiqirotate[180]
%   \weiqiscale[0.8]
%   \weiqiminsize{6}{5}
%   \sgflocmode
%   \showweiqi
% \end{demo}
%
%
% \subsection{棋局复用}^^A 
%
% \begin{function}{\saveweiqi, \useweiqi}
%   \begin{syntax}
%     \cs{saveweiqi} [\meta{序号}] 
%   \end{syntax}
%   保存/使用对局（只保留对局信息，棋盘方位等信息不保存）。
%   \meta{序号} 是保存的位置序号（自然数，推荐 $0$\~{}$26$）。
%   星号版使用对局会删除所有棋子标签及标签。
% \end{function}
%
%
% \begin{function}{\weiqichange}
%   \begin{syntax}
%     \cs{weiqichange} \Arg{坐标}
%   \end{syntax}
%   切换指定位置的棋子的所属方（黑白方）。
%   \meta{坐标} 是一组表示棋子位置的逗号分隔列表，每一项表示一个位置。
% \end{function}
%
%
% \begin{demo}
%   \newweiqi
%   \weiqiblack[1]{a2,b2,c3,-,dr}
%   \weiqilabel[A]{dq}
%   \saveweiqi[1]
%   \newweiqi
%   \useweiqi*[1]
%   \weiqichange{dr}
%   \showweiqi
% \end{demo}
%
%
% \begin{function}{\weiqiremove}
%   \begin{syntax}
%     \cs{weiqiremove} \Arg{坐标}
%   \end{syntax}
%   移除指定位置的所有棋子，移除后相当于没有这一手棋。
%   \meta{坐标} 是一组表示棋子位置的逗号分隔列表，每一项表示一个位置。
%   \begin{texnote}
%     这与 \cs{weiqidie} 有本质的区别：\cs{weiqidie} 旨在标记死子（这手棋是真实存在的）；
%     而本命令是直接移除这手棋，主要是以复用棋局而设置。
%   \end{texnote}
% \end{function}
%
%
% \begin{demo}
%   \newweiqi
%   \weiqiblack[0]{bq,dq,-}
%   \weiqiwhite[1]{b2,c2,c3,a2,d2,b1}
%   \weiqidie{b2}
%   \weiqiremove{d2}
%   \weiqiwhite[5]{b4}
%   \sgflocmode
%   \showweiqi
% \end{demo}
%
%
% \begin{function}{\resetnumber}
%   \begin{syntax}
%     \cs{resetnumber} [\meta{起点}]
%   \end{syntax}
%   重置围棋手数，\meta{起点} 所在位置的标签设置为 $1$，之后标签依次递增，之前无标签；默认以第 $1$ 手为起点。
% \end{function}
%
%
% \begin{demo}
%   \useweiqi*[1]
%   \resetnumber[2]
%   \showweiqi
% \end{demo}
% 
% \subsection{sgf 棋谱支持}^^A 
%
%
% \begin{function}{\weiqisgf}
%   \begin{syntax}
%     \cs{weiqisgf} [\meta{标签}] \Arg{文本}
%   \end{syntax}
%   使用 |sgf| 棋谱 \Arg{文本} 来指定棋子。如果 \meta{标签} 为手数，则会自动递增。
% \end{function}
%
% ~\\
% \begin{demo}
%   \newweiqi
%   \weiqisgf{;B[cc];W[dd]}
%   \weiqisgf[1]{;B[cd];W[dc];B[cb]}
%   \showweiqi
% \end{demo}
%
% \begin{function}{\inputsgf}
%   \begin{syntax}
%     \cs{weiqisgf} [\meta{起点}] \Arg{文件}
%   \end{syntax}
%   新建对局并输入指定棋谱。\meta{起点} 所在位置的标签设置为 $1$，之后标签依次递增，之前无标签；默认以第 $1$ 手为起点。
% \end{function}
%
%
% \subsection{调试支持}^^A
%
% \begin{function}{\weiqidata}
%   \begin{syntax}
%     \cs{weiqidata} 
%   \end{syntax}
%   格式化输出内部变量数据。带星号版本会额外输出边界变量信息。
% \end{function}
%
% \newweiqi
% \weiqiblack[0]{bq,dq,-}
% \weiqiwhite[1]{b2,c2,c3,a2,d2,b1}
% \weiqidie{b2}
% \weiqiremove{d2}
% \weiqiwhite[5]{b4}
% \weiqidata*
%
% \subsection{下一步计划}^^A 
%
% 中文标签的支持。
%
% \end{documentation}
%
% \begin{implementation}
%
% \newpage
%
% \section{\pkg{weiqi}实现}
%
% \subsection{初始化信息}
%
%    \begin{macrocode}
%<*package>
%<@@=weiqi>
%    \end{macrocode}
%
% 宏包基本信息：
%    \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}
\ProvidesExplPackage{weiqi}{2024-02-22}{0.1}
  {drawing weiqi using expl3}
%    \end{macrocode}
%
% 需要 l3draw 宏包，以支持绘图：
%    \begin{macrocode}
\RequirePackage{l3draw}[2024-01-04]
%    \end{macrocode}
%
% 开启 expl3 模式：
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
%
% \subsection{声明系统函数的变体}
%
%    \begin{macrocode}
\cs_generate_variant:Nn \int_set:Nn { Ne }
\cs_generate_variant:Nn \int_gset:Nn { Ne }
\cs_generate_variant:Nn \int_from_alph:n { e }
\cs_generate_variant:Nn \seq_gset_item:Nnn { NnV }
\cs_generate_variant:Nn \regex_extract_once:nnN { nVN }
\prg_generate_conditional_variant:Nnn \regex_match:nn { nV } { T, F, TF }
\prg_generate_conditional_variant:Nnn \regex_extract_once:nnN { nVN } { T, F, TF }
%    \end{macrocode}
%
% \subsection{声明选项}
% 
%    \begin{macrocode}
% 待实现
%    \end{macrocode}
%
%
% \subsection{定义常量}
%
% \begin{variable}{\c_@@_normal_size_int, \c_@@_mid_size_int, \c_@@_small_size_int, \c_@@_normal_star_clist, 
%    \c_@@_mid_star_clist, \c_@@_small_star_clist }
% 棋盘尺寸及对应星位坐标：
%    \begin{macrocode}
\int_const:Nn \c_@@_normal_size_int { 19 }
\int_const:Nn \c_@@_mid_size_int { 13 }
\int_const:Nn \c_@@_small_size_int { 9 }
\clist_const:Nn \c_@@_normal_star_clist 
  { d4, j4, p4, d10, j10, p10, d16, j16, p16 }
\clist_const:Nn \c_@@_mid_star_clist 
  { c3, g3, k3, c7, g7, k7, c11, g11, k11 }
\clist_const:Nn \c_@@_small_star_clist { c3, k3, c7, k7 }
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\c_@@_max_step_int, \c_@@_normal_mode_str, \c_@@_sgf_mode_str }
% 支持的最大步数及坐标显示模式：
%    \begin{macrocode}
\int_const:Nn \c_@@_max_step_int { 500 }
\str_const:Nn \c_@@_normal_mode_str { normal }
\str_const:Nn \c_@@_sgf_mode_str { sgf }
%    \end{macrocode}
% \end{variable}
%
%
% \subsection{定义变量}
%
% \subsubsection{棋盘信息}
%
% 棋盘信息包含方位（$x/y$方向及是否互换三者决定）、比例、最小显示大小（长与宽）及坐标控制（是否显示及坐标模式）。
% 共有 $8$ 个变量控制，且均具有全局及本地之分。全局变量为默认值，本地为当前对局的设置。
%
% \begin{variable}{\g_@@_x_direction_int, \g_@@_y_direction_int, \g_@@_swap_xy_bool, 
%    \g_@@_scale_fp, \g_@@_min_width_int, \g_@@_min_hight_int, \g_@@_show_loc_bool,
%    \g_@@_loc_mode_str}
% 全局棋盘信息：
%    \begin{macrocode}
\int_new:N \g_@@_x_direction_int
\int_new:N \g_@@_y_direction_int
\bool_new:N \g_@@_swap_xy_bool
\fp_new:N \g_@@_scale_fp
\int_new:N \g_@@_min_width_int
\int_new:N \g_@@_min_hight_int
\bool_new:N \g_@@_show_loc_bool
\str_new:N \g_@@_loc_mode_str
%    \end{macrocode}
%    \begin{macrocode}
\int_gset:Nn \g_@@_x_direction_int { 1 }
\int_gset:Nn \g_@@_y_direction_int { 1 }
\bool_gset_false:N \g_@@_swap_xy_bool
\fp_gset:Nn \g_@@_scale_fp { 1 }
\int_gset:Nn \g_@@_min_width_int { 3 }
\int_gset:Nn \g_@@_min_hight_int { 2 }
\bool_gset_true:N \g_@@_show_loc_bool
\str_gset_eq:NN \g_@@_loc_mode_str \c_@@_normal_mode_str
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_x_direction_int, \l_@@_y_direction_int, \l_@@_swap_xy_bool, 
%    \l_@@_scale_fp, \l_@@_min_width_int, \l_@@_min_hight_int, \l_@@_show_loc_bool,
%    \l_@@_loc_mode_str}
% 本地棋盘信息：
%    \begin{macrocode}
\int_new:N \l_@@_x_direction_int
\int_new:N \l_@@_y_direction_int
\bool_new:N \l_@@_swap_xy_bool
\fp_new:N \l_@@_scale_fp
\int_new:N \l_@@_min_width_int
\int_new:N \l_@@_min_hight_int
\bool_new:N \l_@@_show_loc_bool
\str_new:N \l_@@_loc_mode_str
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{对局信息}
%
% 对局信息包括棋盘大小、步数、棋子/标签的信息集（$x/y$ 坐标，棋手，标签）、死子集（索引）及指示点集（三色）组成。
% 共 $10$ 个变量，另加一个默认棋盘大小。本小节的变量的取值均为原始方位的取值。
%
% \begin{variable}{\g_@@_default_size_int}
% 默认对局大小：
%    \begin{macrocode}
\int_new:N \g_@@_default_size_int
\int_gset_eq:NN \g_@@_default_size_int \c_@@_normal_size_int
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_size_int, \g_@@_step_count_int, \g_@@_x_intarray, 
%   \g_@@_y_intarray, \g_@@_player_intarray, \g_@@_label_seq, \g_@@_die_seq}
% 对局内容：
%    \begin{macrocode}
\int_new:N \g_@@_size_int
\int_new:N \g_@@_step_count_int
\intarray_new:Nn \g_@@_x_intarray { \c_@@_max_step_int }
\intarray_new:Nn \g_@@_y_intarray { \c_@@_max_step_int }
\intarray_new:Nn \g_@@_player_intarray { \c_@@_max_step_int }
\seq_new:N \g_@@_label_seq
\seq_new:N \g_@@_die_seq
%    \end{macrocode}
% \end{variable}
%
%
% \begin{variable}{\g_@@_red_point_clist, \g_@@_green_point_clist,\g_@@_blue_point_clist}
% 对局辅助指示点：
%    \begin{macrocode}
\clist_new:N \g_@@_red_point_clist
\clist_new:N \g_@@_green_point_clist
\clist_new:N \g_@@_blue_point_clist
%    \end{macrocode}
% \end{variable}
%
%
% \subsubsection{边界信息}
%
% 本小节的变量为绘图过程中使用的边界信息变量。其是坐标是考虑方位信息的，但左右、上下及大小不考虑。
%
% 棋子区间（不考虑延伸的信息）：
%    \begin{macrocode}
\int_new:N \l_@@_x_min_int
\int_new:N \l_@@_x_max_int
\int_new:N \l_@@_y_min_int
\int_new:N \l_@@_y_max_int
%    \end{macrocode}
%
% 棋盘边界（考虑延伸的信息）：
%    \begin{macrocode}
\bool_new:N \l_@@_left_bool
\bool_new:N \l_@@_right_bool
\bool_new:N \l_@@_up_bool
\bool_new:N \l_@@_down_bool
\fp_new:N \l_@@_x_min_fp
\fp_new:N \l_@@_x_max_fp
\fp_new:N \l_@@_y_min_fp
\fp_new:N \l_@@_y_max_fp
%    \end{macrocode}
%
% \subsubsection{其它变量}
% 
% 通用信息变量：
%    \begin{macrocode}
\str_new:N \l_@@_label_str
\int_new:N \l_@@_x_int
\int_new:N \l_@@_y_int
\int_new:N \l_@@_player_int
\fp_new:N \l_@@_x_fp
\fp_new:N \l_@@_y_fp
\clist_new:N \l_@@_point_clist
%    \end{macrocode}
%
% 其它临时变量：
%    \begin{macrocode}
\int_new:N \l_@@_tmp_int
\str_new:N \l_@@_tmp_str
\bool_new:N \l_@@_tmp_bool
\seq_new:N \l_@@_tmp_seq
%    \end{macrocode}
%
%
% \subsection{设置棋局的函数}
%
% \subsubsection{对局准备}
%
% 指定围棋大小、初始化对局的其余 $9$ 个变量（清空对局所有对局信息）及棋盘信息的 $8$ 个变量（使用默认值[全局变量]）。
%
% \begin{macro}{\@@_new_game:n}
% 初始化对局信息（|#1| 棋盘大小）。
%    \begin{macrocode}
\cs_new:Npn \@@_new_game:n #1 
  { 
    \int_set_eq:NN \l_@@_x_direction_int \g_@@_x_direction_int
    \int_set_eq:NN \l_@@_y_direction_int \g_@@_y_direction_int
    \bool_set_eq:NN \l_@@_swap_xy_bool \g_@@_swap_xy_bool
    \fp_set_eq:NN \l_@@_scale_fp \g_@@_scale_fp
    \int_set_eq:NN \l_@@_min_width_int \g_@@_min_width_int
    \int_set_eq:NN \l_@@_min_hight_int \g_@@_min_hight_int
    \bool_set_eq:NN \l_@@_show_loc_bool \g_@@_show_loc_bool
    \str_set_eq:NN \l_@@_loc_mode_str \g_@@_loc_mode_str 
%    \end{macrocode}
%    \begin{macrocode}    
    \int_gset:Ne \g_@@_size_int { #1 }
    \int_gset:Nn \g_@@_step_count_int { 0 }
    \intarray_gzero:N \g_@@_x_intarray 
    \intarray_gzero:N \g_@@_y_intarray 
    \intarray_gzero:N \g_@@_player_intarray
    \seq_gclear:N \g_@@_label_seq  
    \seq_gclear:N \g_@@_die_seq 
%    \end{macrocode}
%    \begin{macrocode}   
    \clist_gclear:N \g_@@_red_point_clist
    \clist_gclear:N \g_@@_green_point_clist
    \clist_gclear:N \g_@@_blue_point_clist
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{坐标转换函数}
%
% 实现棋子坐标的坐标对形式与字符串形式（虚着使用 |-| ）两者之间的转换。
%
% \begin{macro}{\@@_loc_to_xy:n, \@@_loc_to_xy:V}
% 设置 $x$、$y$ 坐标变量（|#1| 坐标，支持两种模式）。
%    \begin{macrocode}
\cs_new:Npn \@@_loc_to_xy:n #1
  { 
    \str_set:Nx \l_tmpa_str { \str_lowercase:n { #1 } }
    \bool_lazy_any:nTF
      {
        { \str_if_empty_p:N \l_tmpa_str }
        { \str_if_eq_p:Vn { \l_tmpa_str } { - } }
        { \str_if_eq_p:Vn { \l_tmpa_str } { pass } }
      }
      {
        \int_set:Nn \l_@@_x_int { 0 }
        \int_set:Nn \l_@@_y_int { 0 }
      }
      {      
        \int_set:Ne \l_@@_x_int 
          { \int_from_alph:e { \str_head:N \l_tmpa_str } }
        \regex_match:nVTF { [a-z]{2} } { \l_tmpa_str }
          { 
            \int_set:Ne \l_tmpa_int 
              { \int_from_alph:e { \str_tail:N \l_tmpa_str } } 
            \int_set:Nn \l_@@_y_int { \g_@@_size_int - \l_tmpa_int + 1 }
          } 
          { 
            \int_set:Ne \l_@@_y_int 
              { \str_range:Nnn \l_tmpa_str { 2 } { 5 } } 
          }
      }
  }
%    \end{macrocode}
%    \begin{macrocode}
\cs_generate_variant:Nn \@@_loc_to_xy:n { V }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_xy_to_loc:N}
% 将指定变量设置为当前坐标的字符串形式（|#1| 指定的存储变量）。
%    \begin{macrocode}
\cs_new:Npn \@@_xy_to_loc:N #1
  { 
    \int_compare:nNnTF { \l_@@_x_int } = { 0 }
      { \str_set:Nn #1 { - } }
      {
        \str_set:Nx \l_tmpa_str 
          { \int_to_alph:n { \l_@@_x_int } }
        \str_compare:eNeTF 
          { \l_@@_loc_mode_str } = { \c_@@_sgf_mode_str }
          { 
            \int_set:Nn \l_tmpa_int 
              { \g_@@_size_int - \l_@@_y_int + 1 } 
            \str_set:Nx \l_tmpb_str 
              { \int_to_alph:n { \l_tmpa_int } }   
            \str_put_right:NV \l_tmpa_str { \l_tmpb_str } 
          }
          { \str_put_right:NV \l_tmpa_str { \l_@@_y_int } }
        \str_set_eq:NN #1 \l_tmpa_str 
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{添加棋子或纯标签}
%
% 向对局中添加棋子或纯标签，它们使用相同的结构存储。除了所属方不一样外，它们内部添加方式完全相同。
% 其中，所属方用 $0$ 表示未使用\footnote{新局开始，所属方均初始化为 $0$；移除状态的棋子，也会设置为零（同时坐标也为零）。}，
% $1$ 表示黑方，$2$ 表示白方，$3$ 表示纯标签。
%
% 棋子可以含标签（如手数或特殊字符等），棋子|+| 纯标签不等于带标签的棋子。
% 因为前者是两条记录，后者是一条记录，后续处理也不一样。
%
% \begin{macro}{\@@_add_stone:nnn, \@@_add_stone:nnV,  \@@_add_stone:nVV}
% 向对局中添加一步棋（|#1| 黑白方 ；|#2| 坐标；|#3| 标签）。
%    \begin{macrocode}
\cs_new:Npn \@@_add_stone:nnn #1#2#3
  {     
    \int_gincr:N \g_@@_step_count_int
    \intarray_gset:Nnn \g_@@_player_intarray 
      \g_@@_step_count_int { #1 }
%    \end{macrocode}
%    \begin{macrocode}
    \@@_loc_to_xy:n { #2 }
    \intarray_gset:Nnn \g_@@_x_intarray 
      \g_@@_step_count_int \l_@@_x_int 
    \intarray_gset:Nnn \g_@@_y_intarray 
      \g_@@_step_count_int \l_@@_y_int
%    \end{macrocode}
%    \begin{macrocode}
    \str_if_eq:nnTF { #3 } { 0 }  
      { \seq_put_right:Nn \g_@@_label_seq {} }
      { \seq_put_right:Nn \g_@@_label_seq { #3 } }
  }
%    \end{macrocode}
%    \begin{macrocode}
\cs_generate_variant:Nn \@@_add_stone:nnn {nnV, nVV}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_add_stones:nnn}
% 批量向对局中添加棋子（|#1| 黑白方 ；|#2| 坐标序列；|#3| 标签）。
%    \begin{macrocode}
\cs_new:Npn \@@_add_stones:nnn #1#2#3
  { 
    \int_set:Nn \l_@@_player_int { #1 }
    \clist_set:Nn \l_@@_position_clsit { #2 }
    \bool_set_false:N \l_@@_tmp_bool
    \str_if_empty:nTF { #3 }
      { \str_set:Nn \l_@@_tmp_str {} } 
      {
        \regex_match:nnTF { [^0-9]+ } { #3 } 
          { \str_set:Nx \l_@@_tmp_str { #3 } } 
          { 
            \bool_set_true:N \l_@@_tmp_bool
            \int_set:Nn \l_@@_tmp_int { #3 }
          }
      }
    \clist_map_inline:Nn \l_@@_position_clsit
      {
        \bool_if:nTF \l_@@_tmp_bool
          {
            \@@_add_stone:nnV 
              { \l_@@_player_int } 
              { ##1 }
              { \l_@@_tmp_int }
            \int_case:nn { \l_@@_player_int } 
              {
                { 1 } { \int_set:Nn \l_@@_player_int { 2 } }
                { 2 } { \int_set:Nn \l_@@_player_int { 1 } }
                { 3 } { \int_set:Nn \l_@@_player_int { 3 } }
              }
            \int_compare:nNnT { \l_@@_tmp_int } > { 0 }
              { \int_incr:N \l_@@_tmp_int }
          }
          { \@@_add_stone:nnV { #1 } { ##1 } { \l_@@_tmp_str } }    
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_add_sgf_stones:nn, \@@_add_sgf_stones:VV}
% 批量向对局中添加 sgf 格式棋子（|#1| 带黑白方的坐标序列；|#2| 标签）。
%    \begin{macrocode}
\cs_new:Npn \@@_add_sgf_stones:nn #1#2
  { 
    \regex_extract_all:nnN { ;[BW]\[[a-z]{2}\] } { #1 } \l_@@_tmp_seq
    \clist_set_from_seq:NN \l_@@_point_clist \l_@@_tmp_seq
    \bool_set_false:N \l_@@_tmp_bool
    \str_if_empty:nTF { #2 }
      { \str_set:Nn \l_@@_tmp_str {} } 
      {
        \regex_match:nnTF { [^0-9]+ } { #2 } 
          { \str_set:Nx \l_@@_tmp_str { #2 } } 
          { 
            \bool_set_true:N \l_@@_tmp_bool
            \int_set:Nn \l_@@_tmp_int { #2 }
          }
      }
    \clist_map_inline:Nn \l_@@_point_clist
      {
        \str_set:Nx \l_tmpa_str { \str_item:Nn { ##1 } { 2 } }
        \str_set:Nx \l_tmpb_str { \str_range:nnn { ##1 } { 4 } { -2 } }
        \str_case_e:nn { \l_tmpa_str }
        {
          { B } { \int_set:Nn \l_@@_player_int { 1 } }
          { W } { \int_set:Nn \l_@@_player_int { 2 } }
        }
        \bool_if:nTF \l_@@_tmp_bool
          {
            \@@_add_stone:nVV { \l_@@_player_int } 
              { \l_tmpb_str } { \l_@@_tmp_int }
            \int_compare:nNnT { \l_@@_tmp_int } > { 0 }
              { \int_incr:N \l_@@_tmp_int }
          }
          { 
            \@@_add_stone:nVV { \l_@@_player_int } 
              { \l_tmpb_str } { \l_@@_tmp_str } 
          }    
      }
  }
%    \end{macrocode}
%    \begin{macrocode}
\cs_generate_variant:Nn  \@@_add_sgf_stones:nn { VV }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{修改对局}
%
% 修改对局中的棋子信息（所有方、标签等）、移除棋子 或设置死子等。
% 其中，移除棋子相当于没有输入这个棋子\footnote{
% 移除棋子是通过把该手棋全部设置为零来实现；这与虚着不一样，后者仍有所属方。}；
% 而设置死子则用于棋子被吃的情况\footnote{
% 设置死子是通过将棋加入死子列表中来实现，其坐标信息全部不变。}。
%
% \begin{macro}{\@@_reset_stone_number:n}
% 重置所有棋子的标签，移除所有棋子标签（不含纯标签）并按手数（以 |#1| 起为第 $1$ 手）设置新标签。
%    \begin{macrocode}
\cs_new:Npn \@@_reset_stone_number:n #1
  { 
    \int_set:Ne \l_@@_tmp_int { 1 - #1 }
    \int_step_inline:nn { \c_@@_max_step_int } 
      {
        \bool_lazy_or:nnF
          {
            \int_compare_p:nNn
              { \intarray_item:Nn \g_@@_player_intarray { ##1 } } = { 0 }
          }
          {
            \int_compare_p:nNn
              { \intarray_item:Nn \g_@@_player_intarray { ##1 } } = { 3 }
          }          
          {            
            \int_incr:N \l_@@_tmp_int 
            \int_compare:nNnTF { \l_@@_tmp_int } > { 0 }
              { \seq_gset_item:NnV \g_@@_label_seq { ##1 } { \l_@@_tmp_int } }
              { \seq_gset_item:Nnn \g_@@_label_seq { ##1 } {} }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_change_stone:n}
% 切换指定索引的棋子的黑白方（|#1| 索引）。
%    \begin{macrocode}
\cs_new:Npn \@@_change_stone:n #1
  { 
    \int_case:nn 
      { \intarray_item:Nn \g_@@_player_intarray { #1 } }
      {
        { 1 } { \intarray_gset:Nnn \g_@@_player_intarray { #1 } { 2 } }
        { 2 } { \intarray_gset:Nnn \g_@@_player_intarray { #1 } { 1 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_remove_stone:n}
% 删除指定索引的棋子（|#1| 索引）。
%    \begin{macrocode}
\cs_new:Npn \@@_remove_stone:n #1
  { 
    \intarray_gset:Nnn \g_@@_x_intarray  { #1 } { 0 }
    \intarray_gset:Nnn \g_@@_y_intarray  { #1 } { 0 }
    \intarray_gset:Nnn \g_@@_player_intarray  { #1 } { 0 }
    \seq_gset_item:Nnn \g_@@_label_seq { #1} { }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_die_stone:n}
% 设置指定索引的棋子为死子（|#1| 索引）。
%    \begin{macrocode}
\cs_new:Npn \@@_die_stone:n #1
  { 
    \seq_if_in:NnF \g_@@_die_seq { #1 }
      {
        \seq_put_right:Nn \g_@@_die_seq { #1 }
        \prg_break:
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_modify_stone:N}
% 使用指定函数（|#1|）修改指定位置的棋子（由 $x$, $y$ 坐标指定）。
%    \begin{macrocode}
\cs_new:Npn \@@_modify_stone:N #1
  { 
    \int_step_inline:nn { \c_@@_max_step_int } 
      {
        \bool_lazy_and:nnT
        { 
          \int_compare_p:n 
            { \intarray_item:Nn \g_@@_x_intarray { ##1 } = \l_@@_x_int } 
        }
        {
          \int_compare_p:n 
            { \intarray_item:Nn \g_@@_y_intarray { ##1 } = \l_@@_y_int } 
        }
        { #1 { ##1 } }
      }
      \prg_break_point:
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_modify_stones:nN}
% 批量修改当前对局中的棋子（|#1| 坐标序列，|#2| 修改函数）。
%    \begin{macrocode}
\cs_new:Npn \@@_modify_stones:nN #1#2
  { 
    \clist_set:Nn \l_@@_position_clsit { #1 }
    \clist_map_inline:Nn \l_@@_position_clsit
      {
        \@@_loc_to_xy:n { ##1 }
        \int_compare:nNnF { \l_@@_x_int } = { 0 }
          { \@@_modify_stone:N { #2 } }
      } 
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_clear_labels:}
% 清除所有纯标签。
%    \begin{macrocode}
\cs_new:Nn \@@_clear_labels:
  { 
    \int_step_inline:nn { \c_@@_max_step_int } 
      {
        \int_compare:nNnT
          { \intarray_item:Nn \g_@@_player_intarray { ##1 } } = { 3 }
          {
            \intarray_gset:Nnn \g_@@_x_intarray  { ##1 } { 0 }
            \intarray_gset:Nnn \g_@@_y_intarray  { ##1 } { 0 }
            \intarray_gset:Nnn \g_@@_player_intarray  { ##1 } { 0 }
            \seq_gset_item:Nnn \g_@@_label_seq { ##1 } {}
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \subsubsection{指示点}
%
% 指示点是棋盘上的特殊圆点，它支持红绿蓝三种颜色。旨在用于在某个特定情况下的特殊指示。
% 指示点的实现原理与纯标签完全不一样，侧重点也不一样。
%
% \begin{macro}{\@@_add_points:nn}
% 批量向对局中添加指示点（|#1| 颜色 ；|#2| 坐标序列）。
%    \begin{macrocode}
\cs_new:Npn \@@_add_points:nn #1#2
  { 
    \str_case:nn { #1 }
      {
        { red }   
        { \clist_gput_right:Nn \g_@@_red_point_clist { #2 } }
        { green } 
        { \clist_gput_right:Nn \g_@@_green_point_clist { #2 } }
        { blue }  
        { \clist_gput_right:Nn \g_@@_blue_point_clist { #2 } }
      }  
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_clear_points:}
% 清除所有指示点。
%    \begin{macrocode}
\cs_new:Nn \@@_clear_points:
  { 
    \clist_clear:N \g_@@_red_point_clist 
    \clist_clear:N \g_@@_green_point_clist
    \clist_clear:N \g_@@_blue_point_clist
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{绘制棋局的函数}
%
% \subsubsection{坐标变换}
%
% 由于对局中的坐标以原始方位输入与保存，而显示时需要按指定的方位来显示，
% 因此在显示（绘图）前需要根据棋盘方位信息来进行坐标变换。
%
% \begin{macro}{\@@_transform_xy:NN}
% 转换坐标（|#1|、|#2| 分别为 $x,y$ 坐标）。
%    \begin{macrocode}
\cs_new:Npn \@@_transform_xy:NN #1#2
  {
    \int_set:Ne \l_tmpa_int { #1 * \l_@@_x_direction_int }
    \int_set:Ne \l_tmpb_int { #2 * \l_@@_y_direction_int }
    \bool_if:NTF \l_@@_swap_xy_bool
      {
        \int_set_eq:NN #1 \l_tmpb_int
        \int_set_eq:NN #2 \l_tmpa_int
      }
      {
        \int_set_eq:NN #1 \l_tmpa_int
        \int_set_eq:NN #2 \l_tmpb_int
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{边界函数}
%
% 绘制棋局时，需要确认要显示的区域（显示整个棋盘通常不是最优方案），
% 本小节提供一系列函数，用于确认显示边界。
%
% \begin{macro}{\@@_calc_range:}
% 计算棋子所在区间边界。
%    \begin{macrocode}
\cs_new:Nn \@@_calc_range:
  {
    \int_set:Nn \l_@@_x_min_int { 99 }
    \int_set:Nn \l_@@_y_min_int { 99 }
    \int_set:Nn \l_@@_x_max_int { 0 }
    \int_set:Nn \l_@@_y_max_int { 0 }
%    \end{macrocode} 
% 遍历生成自然边界：
%    \begin{macrocode}
    \int_step_inline:nn  {\g_@@_step_count_int} 
      {
        \int_set:Ne \l_@@_x_int 
          { \intarray_item:Nn \g_@@_x_intarray { ##1 } }
        \int_set:Ne \l_@@_y_int 
          { \intarray_item:Nn \g_@@_y_intarray { ##1 } }
        \int_compare:nNnF
          { \l_@@_x_int } = { 0 }
          {
            \int_compare:nNnT  
              \l_@@_x_min_int > \l_@@_x_int 
              { \int_set_eq:NN \l_@@_x_min_int \l_@@_x_int } 
            \int_compare:nNnT
              \l_@@_x_max_int < \l_@@_x_int 
              { \int_set_eq:NN \l_@@_x_max_int \l_@@_x_int } 
            \int_compare:nNnT
              \l_@@_y_min_int > \l_@@_y_int 
              { \int_set_eq:NN \l_@@_y_min_int \l_@@_y_int } 
            \int_compare:nNnT
              \l_@@_y_max_int < \l_@@_y_int 
              { \int_set_eq:NN \l_@@_y_max_int \l_@@_y_int }
          }
      }
%    \end{macrocode} 
% 无有效棋子的情况下，显示整个棋盘：
%    \begin{macrocode}
  \int_compare:nNnT
    { \l_@@_x_min_int } = { 99 }
    {
      \int_set:Nn \l_@@_x_min_int { 1 }
      \int_set:Nn \l_@@_y_min_int { 1 }
      \int_set_eq:NN \l_@@_x_max_int \g_@@_size_int
      \int_set_eq:NN \l_@@_y_max_int \g_@@_size_int  
    }
%    \end{macrocode} 
% 向外延伸，以保证至少有一个角：
%    \begin{macrocode}
    \int_set:Ne \l_tmpa_int 
      { \int_min:nn { \g_@@_size_int } { \l_@@_min_width_int } }
    \int_compare:nNnTF
      { \g_@@_size_int - \l_@@_x_max_int } > { \l_@@_x_min_int - 1 } 
      { 
        \int_set:Nn \l_@@_x_min_int { 1 }
        \int_set:Ne \l_@@_x_max_int
          { \int_max:nn { \l_@@_x_max_int + 1 } { \l_tmpa_int } }
      } 
      { 
        \int_set_eq:NN \l_@@_x_max_int \g_@@_size_int 
        \int_compare:nNnF
          { \l_@@_x_min_int } = { 1 }
          {
            \int_set:Ne \l_@@_x_min_int 
              { 
                \int_min:nn 
                  { \l_@@_x_min_int - 1 } 
                  { \g_@@_size_int -  \l_tmpa_int + 1 }
              }
          }
      } 
    \int_set:Ne \l_tmpa_int 
      { \int_min:nn { \g_@@_size_int } { \l_@@_min_hight_int } }
    \int_compare:nNnTF
      { \g_@@_size_int - \l_@@_y_max_int } > { \l_@@_y_min_int - 1 }  
      { 
        \int_set:Nn \l_@@_y_min_int { 1 } 
        \int_set:Ne \l_@@_y_max_int
          { \int_max:nn { \l_@@_y_max_int + 1 } { \l_tmpa_int } }
      } 
      { 
        \int_set_eq:NN \l_@@_y_max_int \g_@@_size_int 
        \int_compare:nNnF
          { \l_@@_y_min_int } = { 1 }
          {
            \int_set:Ne \l_@@_y_min_int 
              { 
                \int_min:nn 
                  { \l_@@_y_min_int - 1 } 
                  { \g_@@_size_int - \l_tmpa_int + 1 } 
              }
          }
      } 
%    \end{macrocode} 
% 变换坐标：
%    \begin{macrocode}
    \@@_transform_xy:NN \l_@@_x_min_int \l_@@_y_min_int
    \@@_transform_xy:NN \l_@@_x_max_int \l_@@_y_max_int      
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_set_range:n}
% 指定棋子区间边界（边界外棋子不显示），支持 |full|。
%    \begin{macrocode}
\cs_new:Npn \@@_set_range:n #1
  {
    \str_compare:eNeTF
      { \str_lowercase:n { #1 } } = { full }
      {
        \int_set:Nn \l_@@_x_min_int { 1 }
        \int_set:Nn \l_@@_y_min_int { 1 }
        \int_set_eq:NN \l_@@_x_max_int \g_@@_size_int
        \int_set_eq:NN \l_@@_y_max_int \g_@@_size_int
      }
      {
        \clist_set:Nn \l_@@_position_clsit { #1 }    
        \clist_pop:NN \l_@@_position_clsit \l_tmpa_tl
        \@@_loc_to_xy:V { \l_tmpa_tl }
        \int_set_eq:NN \l_@@_x_min_int \l_@@_x_int
        \int_set_eq:NN \l_@@_y_min_int \l_@@_y_int
        \clist_pop:NN \l_@@_position_clsit \l_tmpa_tl
        \@@_loc_to_xy:V { \l_tmpa_tl }
        \int_set_eq:NN \l_@@_x_max_int \l_@@_x_int
        \int_set_eq:NN \l_@@_y_max_int \l_@@_y_int      
      }
%    \end{macrocode}
% 生成标准对角点，变换坐标：
%    \begin{macrocode}
    \int_compare:nNnT { \l_@@_x_min_int } > { \l_@@_x_max_int }
    {
      \int_set_eq:NN \l_tmpa_int \l_@@_x_min_int
      \int_set_eq:NN \l_@@_x_min_int \l_@@_x_max_int
      \int_set_eq:NN \l_@@_x_max_int \l_tmpa_int
    }
    \int_compare:nNnT { \l_@@_y_min_int } > { \l_@@_y_max_int }
    {
      \int_set_eq:NN \l_tmpa_int \l_@@_y_min_int
      \int_set_eq:NN \l_@@_y_min_int \l_@@_y_max_int
      \int_set_eq:NN \l_@@_y_max_int \l_tmpa_int
    }
    \@@_transform_xy:NN \l_@@_x_min_int \l_@@_y_min_int
    \@@_transform_xy:NN \l_@@_x_max_int \l_@@_y_max_int      
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_calc_board_border:}
% 计算棋盘的显示边界。
%    \begin{macrocode}
\cs_new:Nn \@@_calc_board_border:
  {    
    \int_compare:nNnTF
      { \int_abs:n { \l_@@_x_min_int } } = { 1 }
      {
        \bool_set_true:N \l_@@_left_bool
        \fp_set:Nn \l_@@_x_min_fp 
          { \l_@@_x_min_int }
      }
      { 
        \bool_set_false:N \l_@@_left_bool
        \fp_set:Nn \l_@@_x_min_fp 
          { \l_@@_x_min_int - 0.3 * \int_sign:n { \l_@@_x_min_int } }           
      } 
    \int_compare:nNnTF
      { \int_abs:n { \l_@@_x_max_int } } = { \g_@@_size_int }
      {
        \bool_set_true:N \l_@@_right_bool
        \fp_set:Nn \l_@@_x_max_fp 
          { \l_@@_x_max_int }
      }
      { 
        \bool_set_false:N \l_@@_right_bool
        \fp_set:Nn \l_@@_x_max_fp 
          { \l_@@_x_max_int + 0.3 * \int_sign:n { \l_@@_x_max_int } }
      }     
    \int_compare:nNnTF
      { \int_abs:n { \l_@@_y_min_int } } = { 1 }
      {
        \bool_set_true:N \l_@@_down_bool
        \fp_set:Nn \l_@@_y_min_fp 
          { \l_@@_y_min_int }
      }
      { 
        \bool_set_false:N \l_@@_down_bool
        \fp_set:Nn \l_@@_y_min_fp 
          { \l_@@_y_min_int - 0.3 * \int_sign:n { \l_@@_y_min_int } }           
      } 
    \int_compare:nNnTF
      { \int_abs:n { \l_@@_y_max_int } } = { \g_@@_size_int }
      {
        \bool_set_true:N \l_@@_up_bool
        \fp_set:Nn \l_@@_y_max_fp 
          { \l_@@_y_max_int }
      }
      { 
        \bool_set_false:N \l_@@_up_bool
        \fp_set:Nn \l_@@_y_max_fp 
          { \l_@@_y_max_int + 0.3 * \int_sign:n { \l_@@_y_max_int } }           
      }
  }  
%    \end{macrocode}
% \end{macro} 
%
%
% \begin{macro}{\@@_within_range_p:nn, \@@_within_range:nnT}
% 判定点是否在范围内（|#1| $x$坐标；|#2| $y$ 坐标）。
% 坐标是变换后的坐标。
%    \begin{macrocode}
\prg_set_conditional:Npnn \@@_within_range:nn #1#2 { p, T }
  {
    \fp_set:Nn \l_tmpa_fp { abs( \l_@@_x_min_fp - #1 ) }
    \fp_add:Nn \l_tmpa_fp { abs( \l_@@_x_max_fp - #1 ) }
    \fp_sub:Nn \l_tmpa_fp { abs( \l_@@_x_max_fp - \l_@@_x_min_fp ) }
    \fp_add:Nn \l_tmpa_fp { abs( \l_@@_y_min_fp - #2 ) }
    \fp_add:Nn \l_tmpa_fp { abs( \l_@@_y_max_fp - #2 ) }
    \fp_sub:Nn \l_tmpa_fp { abs( \l_@@_y_max_fp - \l_@@_y_min_fp ) }
    \fp_compare:nNnTF
      { \l_tmpa_fp } < { 0.1 }
      { \prg_return_true: }
      { \prg_return_false: }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{绘制函数}
%
% 绘制对局包括绘制棋盘、棋子与纯标签、标记点及死子几个步骤。
% 其中，棋盘包括网格线、边界线、角、星位及坐标标签。
% 绘制前需要设置好棋子区间边界\footnote{棋盘边界在绘制棋盘时内部调用，因此不需要额外设置。}。
%
%
% \begin{macro}{\@@_draw_board_grid:}
% 绘制棋盘的网格线（路径）。
%    \begin{macrocode}  
\cs_new:Nn \@@_draw_board_grid:
  {
    \int_set:Ne \l_@@_tmp_int 
      { \int_sign:n { \l_@@_x_max_int - \l_@@_x_min_int } }
    \int_step_inline:nnnn
      { \l_@@_x_min_int } { \l_@@_tmp_int } { \l_@@_x_max_int }
      {
        \draw_path_moveto:n { ##1 cm, \l_@@_y_min_fp cm }
        \draw_path_lineto:n { ##1 cm, \l_@@_y_max_fp cm }
      }      
    \int_set:Ne \l_@@_tmp_int 
      { \int_sign:n { \l_@@_y_max_int - \l_@@_y_min_int } }
    \int_step_inline:nnnn 
      { \l_@@_y_min_int } { \l_@@_tmp_int } { \l_@@_y_max_int }
      {
        \draw_path_moveto:n { \l_@@_x_min_fp cm, ##1 cm }
        \draw_path_lineto:n { \l_@@_x_max_fp cm, ##1 cm }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_board_border:}
% 绘制棋盘的边界线（路径）。
%    \begin{macrocode}  
\cs_new:Nn \@@_draw_board_border:
  {
    \bool_if:nT { \l_@@_left_bool } 
      {
        \draw_path_moveto:n { \l_@@_x_min_fp cm, \l_@@_y_min_fp cm }
        \draw_path_lineto:n { \l_@@_x_min_fp cm, \l_@@_y_max_fp cm }
      }
    \bool_if:nT { \l_@@_right_bool } 
      {
        \draw_path_moveto:n { \l_@@_x_max_fp cm, \l_@@_y_min_fp cm }
        \draw_path_lineto:n { \l_@@_x_max_fp cm, \l_@@_y_max_fp cm }
      }
    \bool_if:nT { \l_@@_down_bool } 
      {
        \draw_path_moveto:n { \l_@@_x_min_fp cm, \l_@@_y_min_fp cm }
        \draw_path_lineto:n { \l_@@_x_max_fp cm, \l_@@_y_min_fp cm }
      }
    \bool_if:nT { \l_@@_up_bool } 
      {
        \draw_path_moveto:n { \l_@@_x_min_fp cm, \l_@@_y_max_fp cm }
        \draw_path_lineto:n { \l_@@_x_max_fp cm, \l_@@_y_max_fp cm }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_board_corner:}
% 绘制棋盘的角（路径）。
%    \begin{macrocode}  
\cs_new:Nn \@@_draw_board_corner:
  {
    \bool_if:nT { \l_@@_left_bool && \l_@@_down_bool }     
      {
        \draw_path_moveto:n { \l_@@_x_min_fp cm, \l_@@_y_max_fp cm }
        \draw_path_lineto:n { \l_@@_x_min_fp cm, \l_@@_y_min_fp cm }
        \draw_path_lineto:n { \l_@@_x_max_fp cm, \l_@@_y_min_fp cm }
      }
    \bool_if:nT { \l_@@_right_bool && \l_@@_down_bool }         
      {
        \draw_path_moveto:n { \l_@@_x_max_fp cm, \l_@@_y_max_fp cm }
        \draw_path_lineto:n { \l_@@_x_max_fp cm, \l_@@_y_min_fp cm }
        \draw_path_lineto:n { \l_@@_x_min_fp cm, \l_@@_y_min_fp cm }
      }
    \bool_if:nT { \l_@@_right_bool && \l_@@_up_bool }      
      {
        \draw_path_moveto:n { \l_@@_x_max_fp cm, \l_@@_y_min_fp cm }
        \draw_path_lineto:n { \l_@@_x_max_fp cm, \l_@@_y_max_fp cm }
        \draw_path_lineto:n { \l_@@_x_min_fp cm, \l_@@_y_max_fp cm }
      }
    \bool_if:nT { \l_@@_left_bool && \l_@@_up_bool }           
      {
        \draw_path_moveto:n { \l_@@_x_min_fp cm, \l_@@_y_min_fp cm }
        \draw_path_lineto:n { \l_@@_x_min_fp cm, \l_@@_y_max_fp cm }
        \draw_path_lineto:n { \l_@@_x_max_fp cm, \l_@@_y_max_fp cm }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_draw_point:n}
% 绘制单个点（路径）（|#1| 坐标）。
%    \begin{macrocode}  
\cs_new:Npn \@@_draw_point:n #1
  {
    \__weiqi_loc_to_xy:n { #1 }
    \@@_transform_xy:NN \l_@@_x_int \l_@@_y_int 
    \@@_within_range:nnT { \l_@@_x_int } { \l_@@_y_int } 
      { 
        \draw_path_circle:nn 
          { \l_@@_x_int  cm, \l_@@_y_int cm } { 1mm }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_board_star:}
% 绘制棋盘的星位（路径）。
%    \begin{macrocode}  
\cs_new:Nn \@@_draw_board_star:
  {
    \clist_clear:N \l_@@_point_clist
    \int_case:nn { \g_@@_size_int }
      {
        { \c_@@_normal_size_int }
        { \clist_set_eq:NN \l_@@_point_clist \c_@@_normal_star_clist }
        { \c_@@_mid_size_int }
        { \clist_set_eq:NN \l_@@_point_clist \c_@@_mid_star_clist }
        { \c_@@_small_size_int }
        { \clist_set_eq:NN \l_@@_point_clist \c_@@_small_star_clist }
      }
    \clist_map_function:NN \l_@@_point_clist \@@_draw_point:n
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_set_loc_label:nn}
% 设置坐标标签（|#1| 标签方案；|#2| 单轴坐标）。
%    \begin{macrocode}  
\cs_new:Npn \@@_set_loc_label:nn #1#2
  {
    \str_case_e:nn { #1 }
    {
      { A }
      { \str_set:Nx \l_@@_label_str { \int_to_Alph:n { #2 } } }
      { \c_@@_normal_mode_str }
      { \str_set:NV \l_@@_label_str { #2 } }      
      { \c_@@_sgf_mode_str }
      { 
        \int_set:Nn \l_tmpa_int { \g_@@_size_int - #2 + 1 }
        \str_set:Nx\l_@@_label_str { \int_to_alph:n { \l_tmpa_int } } 
      }
    }    
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_board_loc:}
% 绘制棋盘的坐标（路径）。
%    \begin{macrocode}  
\cs_new:Nn \@@_draw_board_loc:
  {
    \int_gset:Nn \g_tmpa_int 
      { \int_sign:n { \l_@@_x_max_int - \l_@@_x_min_int } }   
    \int_gset:Nn \g_tmpb_int 
      { \int_sign:n { \l_@@_y_max_int - \l_@@_y_min_int } }       
    \int_step_inline:nnnn
      { \l_@@_x_min_int } { \g_tmpa_int } { \l_@@_x_max_int }
      {
        \int_set:Ne \l_@@_tmp_int { \int_abs:n { ##1 } }
        \bool_if:NTF \l_@@_swap_xy_bool
          { \@@_set_loc_label:nn { \l_@@_loc_mode_str } { \l_@@_tmp_int } }
          { \@@_set_loc_label:nn { A } { \l_@@_tmp_int } }        
        \hbox_set:Nn \l_tmpa_box { \l_@@_label_str } 
        \fp_set:Nn \l_tmpa_fp { 0.2 * \g_tmpb_int }
        \fp_set:Nn \l_tmpb_fp { 0.5 * { \box_ht:N \l_tmpa_box } * \g_tmpb_int }
        \bool_if:NT \l_@@_up_bool
          {
            \draw_box_use:Nn \l_tmpa_box 
              {
                ##1 cm - 0.5 * { \box_wd:N \l_tmpa_box },
                (\l_@@_y_max_fp + \l_tmpa_fp ) cm - abs(\l_tmpb_fp) + \l_tmpb_fp
              } 
          }
        \bool_if:NT \l_@@_down_bool
          {
            \draw_box_use:Nn \l_tmpa_box 
              {
                ##1 cm - 0.5 * { \box_wd:N \l_tmpa_box },
                (\l_@@_y_min_fp - \l_tmpa_fp ) cm - abs(\l_tmpb_fp) - \l_tmpb_fp 
              } 
          } 
      }
    \int_step_inline:nnnn
      { \l_@@_y_min_int } { \g_tmpb_int } { \l_@@_y_max_int }
      {
        \int_set:Ne \l_@@_tmp_int { \int_abs:n { ##1 } }
        \bool_if:NTF \l_@@_swap_xy_bool
          { \@@_set_loc_label:nn { A } { \l_@@_tmp_int } }
          { \@@_set_loc_label:nn { \l_@@_loc_mode_str } { \l_@@_tmp_int } }    
        \hbox_set:Nn \l_tmpa_box { \l_@@_label_str } 
        \fp_set:Nn \l_tmpa_fp { 0.2 * \g_tmpa_int }
        \fp_set:Nn \l_tmpb_fp { 0.5 * { \box_wd:N \l_tmpa_box } * \g_tmpa_int }
        \bool_if:NT \l_@@_left_bool
          {
            \draw_box_use:Nn \l_tmpa_box 
              {               
                (\l_@@_x_min_fp - \l_tmpa_fp) cm  - abs(\l_tmpb_fp) - \l_tmpb_fp,
                 ##1 cm - 0.5 * { \box_ht:N \l_tmpa_box }
              } 
          } 
        \bool_if:NT \l_@@_right_bool
          {
            \draw_box_use:Nn \l_tmpa_box 
              {                
                (\l_@@_y_max_fp + \l_tmpa_fp) cm  - abs(\l_tmpb_fp) + \l_tmpb_fp,
                ##1 cm - 0.5 * { \box_ht:N \l_tmpa_box }
              } 
          }   
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_board:}
% 绘制完整的棋盘元素。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_board:
  {
    \@@_calc_board_border:
%    \end{macrocode} 
%
%    \begin{macrocode}     
    \draw_linewidth:n { 0.7 }
    \color_select:n { black }
    \@@_draw_board_grid:
    \draw_path_use_clear:n { stroke }
%    \end{macrocode} 
%
%    \begin{macrocode} 
    \draw_linewidth:n { 2 }
    \@@_draw_board_border:
    \draw_path_use_clear:n { stroke }
    \@@_draw_board_corner:
    \draw_path_use_clear:n { stroke }
%    \end{macrocode} 
%
%    \begin{macrocode}     
    \color_select:n { black }
    \@@_draw_board_star:
    \draw_path_use_clear:n { draw, fill }
%    \end{macrocode} 
%
%    \begin{macrocode} 
    \color_select:n { black!50 }
    \bool_if:NT \l_@@_show_loc_bool
      { \@@_draw_board_loc: }
    \draw_path_use_clear:n { stroke }  
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_points:}
% 绘制完整的指示点。
%    \begin{macrocode}
\cs_new:Npn \@@_draw_points:
  {
    \color_select:n { red }
    \clist_map_function:NN \g_@@_red_point_clist \@@_draw_point:n
    \draw_path_use_clear:n { draw, fill }
    \color_select:n { green }
    \clist_map_function:NN \g_@@_green_point_clist \@@_draw_point:n
    \draw_path_use_clear:n { draw, fill }
    \color_select:n { blue }
    \clist_map_function:NN \g_@@_blue_point_clist \@@_draw_point:n
    \draw_path_use_clear:n { draw, fill }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_draw_stone:nnnn}
% 绘制一手棋或纯标签（|#1| 黑白方；|#2| $x$坐标；|#3| $y$ 坐标；|#4| 标签）。\\
% 坐标是变换后的坐标。
%    \begin{macrocode}
\cs_new:Npn \@@_draw_stone:nnnn #1#2#3#4
  {
%    \end{macrocode}
% 绘制外围空白，如果是纯标签则不绘制：
%    \begin{macrocode}
    \int_compare:nNnF { #1 } = { 3 }
      {
        \color_fill:n { white }
        \draw_path_circle:nn { #2cm, #3cm } { 4.4mm }
        \draw_path_use_clear:n { fill }
      }
%    \end{macrocode}
% 绘制棋子（不含标签）；如果为纯标签，则绘制空白：
%    \begin{macrocode}
    \color_select:n { black }
    \int_case:nn { #1 }
      {
        { 1 } { \color_fill:n { black } } 
        { 2 } { \color_fill:n { white } }
        { 3 } { \color_select:n { white } }
      }
    \draw_path_circle:nn{ #2cm, #3cm } { 4mm }
    \draw_path_use_clear:n { draw, fill }
%    \end{macrocode}
% 绘制棋子标签：
%    \begin{macrocode}
    \int_case:nn { #1 }
      {
        { 1 } { \color_select:n { white } } 
        { 2 } { \color_select:n { black } }
        { 3 } { \color_select:n { blue } }
      }
    \hbox_set:Nn \l_tmpa_box { \Large \textbf{ #4 } } 
    \draw_box_use:Nn \l_tmpa_box 
      {
        #2cm - 0.5 * { \box_wd:N \l_tmpa_box },
        #3cm - 0.5 * { \box_ht:N \l_tmpa_box }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_stones:}
% 绘制完整的常规棋子。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_stones:
  {
    \draw_linewidth:n { 1 }
    \int_step_inline:nn  {\g_@@_step_count_int} 
      {
        \int_set:Ne \l_@@_x_int 
          { \intarray_item:Nn \g_@@_x_intarray { ##1 } }
        \int_set:Ne \l_@@_y_int 
          { \intarray_item:Nn \g_@@_y_intarray { ##1 } }
        \int_set:Ne \l_@@_player_int
          { \intarray_item:Nn \g_@@_player_intarray { ##1 } }
        \str_set:Nx \l_@@_tmp_str 
          { \seq_item:Nn \g_@@_label_seq { ##1 } }
        \seq_if_in:NnT \g_@@_die_seq { ##1 } 
          { \int_set:Nn \l_@@_x_int { 0 } }
        \int_if_zero:nF { \l_@@_x_int }
          {
            \@@_transform_xy:NN \l_@@_x_int \l_@@_y_int 
            \@@_within_range:nnT 
              { \l_@@_x_int } { \l_@@_y_int }
              {
                \@@_draw_stone:nnnn { \l_@@_player_int }
                  { \l_@@_x_int } { \l_@@_y_int } { \l_@@_tmp_str }
              }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_specific_stone:}
% 绘制指定的一个特殊的棋子（死子、虚着）。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_specific_stone:
  {
    \color_select:n { black }
    \int_case:nn { \l_@@_player_int }
      {
        { 1 } { \color_fill:n { black } } 
        { 2 } { \color_fill:n { white } }
      }
    \draw_path_circle:nn{ \l_@@_x_fp cm, \l_@@_y_fp cm } { 4mm }
    \draw_path_use_clear:n { draw, fill }
%    \end{macrocode}
%    \begin{macrocode}
    \int_case:nn { \l_@@_player_int }
      {
        { 1 } { \color_select:n { white } } 
        { 2 } { \color_select:n { black } }
      }  
    \@@_xy_to_loc:N \l_tmpa_str
    \hbox_set:Nn \l_tmpa_box { \Large \textbf{ \l_@@_tmp_str } } 
    \hbox_set:Nn \l_tmpb_box { \Large \texttt{ \l_tmpa_str } } 
    \draw_box_use:Nn \l_tmpa_box 
      {
        \l_@@_x_fp cm - 0.5 * { \box_wd:N \l_tmpa_box },
        \l_@@_y_fp cm - 0.5 * { \box_ht:N \l_tmpa_box }
      }
    \color_select:n { black }
    \draw_box_use:Nn \l_tmpb_box 
      {
        \l_@@_x_fp cm + 6mm,
        \l_@@_y_fp cm - 0.5 * { \box_ht:N \l_tmpa_box }
      }
%    \end{macrocode}
%    \begin{macrocode}
    \fp_set:Nn \l_tmpa_fp { min(\l_@@_x_min_fp, \l_@@_x_max_fp) }
    \fp_set:Nn \l_tmpb_fp { max(\l_@@_x_min_fp, \l_@@_x_max_fp) }
    \fp_add:Nn \l_@@_x_fp { 2 }
    \fp_compare:nNnT { \l_@@_x_fp } > { \l_tmpb_fp }
      {
        \fp_set_eq:NN \l_@@_x_fp \l_tmpa_fp
        \fp_sub:Nn \l_@@_y_fp { 1 }
      }
  } 
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_draw_specific_stones:}
% 绘制完整的特殊棋子（死子、虚着）。
%    \begin{macrocode}
\cs_new:Nn \@@_draw_specific_stones:
  {
    \draw_linewidth:n { 1 }
    \fp_set:Nn \l_@@_x_fp { min(\l_@@_x_min_int, \l_@@_x_max_int) }
    \fp_set:Nn \l_@@_y_fp { min(\l_@@_y_min_int, \l_@@_y_max_int) - 1.2}
    \int_step_inline:nn  {\g_@@_step_count_int} 
      {
        \int_set:Ne \l_@@_x_int 
          { \intarray_item:Nn \g_@@_x_intarray { ##1 } }
        \int_set:Ne \l_@@_y_int 
          { \intarray_item:Nn \g_@@_y_intarray { ##1 } }
        \int_set:Ne \l_@@_player_int
          { \intarray_item:Nn \g_@@_player_intarray { ##1 } }
        \str_set:Nx \l_@@_tmp_str 
          { \seq_item:Nn \g_@@_label_seq { ##1 } }
%    \end{macrocode}     
%    \begin{macrocode}     
        \seq_if_in:NnTF \g_@@_die_seq { ##1 } 
          { \int_set:Nn \l_tmpa_int { 0 } }
          { \int_set_eq:NN \l_tmpa_int \l_@@_x_int }
        \str_compare:eNeT { \l_@@_tmp_str } = {}
          { \int_set:Nn \l_tmpa_int { 1 } }
        \bool_lazy_all:nT
          {
            { \int_compare_p:nNn { \l_tmpa_int } = { 0 } }
            { \int_compare_p:nNn { \l_@@_player_int } > { 0 } }
            { \int_compare_p:nNn { \l_@@_player_int } < { 3 } }
          }
          { \@@_draw_specific_stone: }
      } 
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_show:}
% 显示完整对局。
%    \begin{macrocode}
\cs_new:Nn \@@_show:
  {
    \draw_begin:
      \group_begin:
        \draw_transform_scale:n { \l_@@_scale_fp }
        \@@_draw_board:   
        \@@_draw_points:   
        \@@_draw_stones:
        \@@_draw_specific_stones:
      \group_end:
    \draw_end:
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{定义文档命令}
%
% 本节定义了一些供宏包外使用的文档命令。
%
% \begin{macro}{\newweiqi}
% 开始新对局。
%    \begin{macrocode}
\NewDocumentCommand \newweiqi { s o }
  {
     \IfNoValueTF { #2 }
       { \@@_new_game:n { \g_@@_default_size_int } }
       { 
         \IfBooleanT { #1 } { \int_gset:Nn \g_@@_default_size_int { #2 } }
         \@@_new_game:n { #2 } 
       }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqisize}
% 更改棋盘大小。
%    \begin{macrocode}
\NewDocumentCommand \weiqisize { s m }
  {
    \IfBooleanT{ #1 }
      { \int_gset:Nn \g_@@_default_size_int { #2 } }
    \int_set:Nn \g_@@_size_int { #2 }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqiblack, \weiqiwhite}
% 添加黑/白棋子。星号版本命令无区别。
%    \begin{macrocode}
\NewDocumentCommand \weiqiblack { s o m }
  { 
    \IfNoValueTF { #2 }
      { \@@_add_stones:nnn { 1 } { #3 } { } }
      { \@@_add_stones:nnn { 1 } { #3 } { #2 } }
  }
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand \weiqiwhite { s o m }
  { 
    \IfNoValueTF { #2 }
      { \@@_add_stones:nnn { 2 } { #3 } { } }
      { \@@_add_stones:nnn { 2 } { #3 } { #2 } }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqisgf}
% 使用 sgf 文本添加黑/白棋子。星号版本命令无区别。
%    \begin{macrocode}
\NewDocumentCommand \weiqisgf { s o m }
  { 
    \IfNoValueTF { #2 }
      { \@@_add_sgf_stones:nn { #3 } { } }
      { \@@_add_sgf_stones:nn { #3 } { #2 } }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\inputsgf}
% 读取 sgf 棋谱。星号版本命令无区别。
%    \begin{macrocode}
\NewDocumentCommand \inputsgf { s o m }
  { 
    \ior_open:Nn \g_tmpa_ior { #3 }
    \str_set:Nn \l_@@_tmp_str {}
    \ior_str_map_inline:Nn \g_tmpa_ior 
      {
        \str_put_right:Nx \l_@@_tmp_str { ##1 }
      }
    \ior_close:N \g_tmpa_ior
%    \end{macrocode}  
%    \begin{macrocode}  
    \regex_extract_once:nVNTF { ;GM\[1\] } { \l_@@_tmp_str } \l_tmpa_seq
      {
        \regex_extract_once:nVNTF { SZ\[[0-9]+\] } { \l_@@_tmp_str } \l_tmpa_seq
          {
            \str_set:Nx \l_tmpa_str { \seq_item:Nn \l_tmpa_seq { 1 } }
            \str_set:Nx \l_tmpa_str { \str_range:Nnn \l_tmpa_str { 4 } { -2 } }
            \int_set:Ne \l_tmpa_int { \l_tmpa_str }
            \newweiqi [ \l_tmpa_int ]
            \regex_extract_once:nVN { HA\[[0-9]+\] } { \l_@@_tmp_str } \l_tmpa_seq
            \str_set:Nx \l_tmpa_str { \seq_item:Nn \l_tmpa_seq { 1 } }
            \str_set:Nx \l_tmpa_str {\str_range:Nnn \l_tmpa_str { 4 } { -2 } }
            \int_set:Ne \l_tmpa_int { \l_tmpa_str }
            \IfNoValueTF { #2 } 
              { \int_add:Nn \l_tmpa_int { 1 } }
              { \int_add:Nn \l_tmpa_int { #2 } }
            \@@_add_sgf_stones:VV { \l_@@_tmp_str } { \l_tmpa_int }  
          }
          { 解析棋盘大小失败 }
      }
      { 不支持的棋谱 }  
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\resetnumber}
% 重新修改棋子手数。星号版本命令无区别。
%    \begin{macrocode}
\NewDocumentCommand \resetnumber { s o }
  { 
    \IfNoValueTF { #2 }
      { \@@_reset_stone_number:n { 1 } }
      { \@@_reset_stone_number:n { #2 } }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqilabel, \clearlabel}
% 添加/删除标签。
%    \begin{macrocode}
\NewDocumentCommand \weiqilabel { s o m }
  { 
    \IfBooleanT{ #1 } { \@@_clear_labels: } 
    \IfNoValueTF { #2 }
      { \@@_add_stones:nnn { 3 } { #3 } { a } }
      { \@@_add_stones:nnn { 3 } { #3 } { #2 } }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentCommand \clearlabel { }
  { \@@_clear_labels: }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqired, \weiqigreen, \weiqiblue, \clearpoint}
% 添加红绿蓝点。
%    \begin{macrocode}
\NewDocumentCommand \weiqired { s m }
  { 
    \IfBooleanT{ #1 } { \@@_clear_points: } 
    \@@_add_points:nn { red } { #2 } 
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentCommand \weiqigreen { s m }
  { 
    \IfBooleanT{ #1 } { \@@_clear_points: } 
    \@@_add_points:nn { green } { #2 } 
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentCommand \weiqiblue { s m }
  { 
    \IfBooleanT{ #1 } { \@@_clear_points: } 
    \@@_add_points:nn { blue } { #2 } 
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentCommand \clearpoint { }
  { \@@_clear_points: }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqidie}
% 标记死子。
%    \begin{macrocode}
\NewDocumentCommand \weiqidie { s m }
  {
    \@@_modify_stones:nN { #2 } \@@_die_stone:n
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqiremove}
% 移除棋子。
%    \begin{macrocode}
\NewDocumentCommand \weiqiremove { s m }
  {
    \@@_modify_stones:nN { #2 } \@@_remove_stone:n
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqichange}
% 切换棋子黑白方。
%    \begin{macrocode}
\NewDocumentCommand \weiqichange { s m }
  {
    \@@_modify_stones:nN { #2 } \@@_change_stone:n
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\showweiqi}
% 显示棋盘。
%    \begin{macrocode}
\NewDocumentCommand \showweiqi { s o }
  {
    \IfNoValueTF { #2 }
      { \@@_calc_range: }
      { \@@_set_range:n { #2 } }
    \@@_show:
    \IfBooleanF { #1 } { \newweiqi }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\nonelocmode, \normallocmode, \sgflocmode}
% 设置围棋坐标显示模式。
%    \begin{macrocode}
\NewDocumentCommand \nonelocmode { s }
  {
    \bool_set_false:N \l_@@_show_loc_bool
    \IfBooleanT { #1 } { \bool_gset_false:N \g_@@_show_loc_bool }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentCommand \normallocmode { s }
  {
    \bool_set_true:N \l_@@_show_loc_bool
    \str_set_eq:NN \l_@@_loc_mode_str \c_@@_normal_mode_str   
    \IfBooleanT { #1 } 
      {
        \bool_gset_true:N \g_@@_show_loc_bool
        \str_gset_eq:NN \g_@@_loc_mode_str \c_@@_normal_mode_str
      }  
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentCommand \sgflocmode { s } 
  { 
    \bool_set_true:N \l_@@_show_loc_bool
    \str_set_eq:NN \l_@@_loc_mode_str \c_@@_sgf_mode_str
    \IfBooleanT { #1 } 
      {
        \bool_gset_true:N \g_@@_show_loc_bool
        \str_gset_eq:NN \g_@@_loc_mode_str \c_@@_sgf_mode_str
      }  
  }
%    \end{macrocode}
% \end{macro}
%

%
% \begin{macro}{\weiqirotate, \weiqimirror, \weiqiposition}
% 旋转棋盘、镜像棋盘或指定棋盘方位。
%    \begin{macrocode}
\NewDocumentCommand \weiqirotate { s o }
  {    
    \IfNoValueTF { #2 }
      { \int_set:Nn \l_tmpa_int { 90 } }
      { \int_set:Ne \l_tmpa_int { #2 } }
    \int_compare:nNnT { \l_tmpa_int } < { 0 }
      { \int_add:Nn \l_tmpa_int { 360 } }
    \int_case:nn { \l_tmpa_int }
      {
        { 90 }  
        { 
          \bool_set_inverse:N \l_@@_swap_xy_bool
          \int_set:Ne \l_tmpb_int { \l_@@_x_direction_int }
          \int_set:Ne \l_@@_x_direction_int { \l_@@_y_direction_int }
          \int_set:Ne \l_@@_y_direction_int { 0 - \l_tmpb_int }
        }  
        { 180 } 
        {
          \int_set:Ne \l_@@_x_direction_int { 0 - \l_@@_x_direction_int }
          \int_set:Ne \l_@@_y_direction_int { 0 - \l_@@_y_direction_int }
        }
        { 270 } 
        { 
          \bool_set_inverse:N \l_@@_swap_xy_bool
          \int_set:Ne \l_tmpb_int { \l_@@_x_direction_int }
          \int_set:Ne \l_@@_x_direction_int { 0 - \l_@@_y_direction_int }
          \int_set:Ne \l_@@_y_direction_int { \l_tmpb_int }
        } 
      }
    \IfBooleanT{ #1 }
      { 
        \bool_gset_eq:NN \g_@@_swap_xy_bool \l_@@_swap_xy_bool
        \int_gset_eq:NN \g_@@_x_direction_int \l_@@_x_direction_int
        \int_gset_eq:NN \g_@@_y_direction_int \l_@@_y_direction_int
      }
  }
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand \weiqimirror { s o }
  {    
    \IfNoValueTF { #2 }
      { \str_set:Nn \l_tmpa_str { xy } }
      { \str_set:Nx \l_tmpa_str { #2 } }
    \str_case_e:nn { \l_tmpa_str }
    {
      { x }
      {
        \int_set:Ne \l_@@_x_direction_int { 0 - \l_@@_x_direction_int }
      }
      { y }
      {
        \int_set:Ne \l_@@_y_direction_int { 0 - \l_@@_y_direction_int }
      }
      { xy }
      {
        \int_set:Ne \l_@@_x_direction_int { 0 - \l_@@_x_direction_int }
        \int_set:Ne \l_@@_y_direction_int { 0 - \l_@@_y_direction_int }
      }
    
    }
    \IfBooleanT{ #1 }
      { 
        \bool_set_eq:NN \g_@@_swap_xy_bool \l_@@_swap_xy_bool
        \int_set_eq:NN \g_@@_x_direction_int \l_@@_x_direction_int
        \int_set_eq:NN \g_@@_y_direction_int \l_@@_y_direction_int
      }
  }
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand \weiqiposition { s o }
  {    
    \IfNoValueTF { #2 }
      { \int_set:Nn \l_tmpa_int { 0 } }
      { \int_set:Ne \l_tmpa_int { #2 } }
    \int_compare:nNnT { \l_tmpa_int } < { 0 }
      { \int_add:Nn \l_tmpa_int { 360 } }
    \int_case:nn { \l_tmpa_int }
      {
        { 0 }
        {
          \bool_set_false:N \l_@@_swap_xy_bool
          \int_set:Nn \l_@@_x_direction_int { 1 }
          \int_set:Nn \l_@@_y_direction_int { 1 }
        }
        { 90 }  
        { 
          \bool_set_true:N \l_@@_swap_xy_bool
          \int_set:Nn \l_@@_x_direction_int { 1 }
          \int_set:Nn \l_@@_y_direction_int { -1 }
        }  
        { 180 } 
        {
          \bool_set_false:N \l_@@_swap_xy_bool
          \int_set:Nn \l_@@_x_direction_int { -1 }
          \int_set:Nn \l_@@_y_direction_int { -1 }
        }
        { 270 } 
        { 
          \bool_set_true:N \l_@@_swap_xy_bool
          \int_set:Nn \l_@@_x_direction_int { -1 }
          \int_set:Nn \l_@@_y_direction_int { 1 }
        } 
      }
    \IfBooleanT{ #1 }
      { 
        \bool_gset_eq:NN \g_@@_swap_xy_bool \l_@@_swap_xy_bool
        \int_gset_eq:NN \g_@@_x_direction_int \l_@@_x_direction_int
        \int_gset_eq:NN \g_@@_y_direction_int \l_@@_y_direction_int
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqiscale}
% 缩放棋盘。
%    \begin{macrocode}
\NewDocumentCommand \weiqiscale { s o }
  {
    \IfNoValueTF { #2 }
      { \fp_set:Nn \l_@@_scale_fp { 1.0 } }
      { \fp_set:Nn \l_@@_scale_fp { #2 * \l_@@_scale_fp } }
    \IfBooleanT{ #1 }
      { \fp_set_eq:NN \g_@@_scale_fp \l_@@_scale_fp }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqiminsize}
% 最小显示尺寸。
%    \begin{macrocode}
\NewDocumentCommand \weiqiminsize { s m m }
  {
    \int_set:Nn \l_@@_min_width_int { #2 }
    \int_set:Nn \l_@@_min_hight_int { #3 }
    \IfBooleanT{ #1 }
      {
        \int_gset:Nn \g_@@_min_width_int { #2 }
        \int_gset:Nn \g_@@_min_hight_int { #3 }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\saveweiqi}
% 保存对局。
%    \begin{macrocode}
\NewDocumentCommand \saveweiqi { s o }
  {
    \IfNoValueTF { #2 }
      { \str_set:Nx \l_tmpa_str { Default } }
      { \str_set:Nx \l_tmpa_str { \int_to_alph:n { #2 } } }
    \cs_if_free:cT { g_@@_size_int_\l_tmpa_str }
      {
        \int_new:c { g_@@_size_int_\l_tmpa_str }
        \int_new:c { g_@@_step_count_int_\l_tmpa_str }
        \intarray_new:cn { g_@@_x_intarray_\l_tmpa_str } 
          { \c_@@_max_step_int }
        \intarray_new:cn { g_@@_y_intarray_\l_tmpa_str } 
          { \c_@@_max_step_int }
        \intarray_new:cn { g_@@_player_intarray_\l_tmpa_str }
          { \c_@@_max_step_int }
        \seq_new:c { g_@@_label_seq_\l_tmpa_str }
        \seq_new:c { g_@@_die_seq_\l_tmpa_str }
      }    
    \int_gset_eq:cN { g_@@_size_int_\l_tmpa_str } \g_@@_size_int
    \int_gset_eq:cN 
      { g_@@_step_count_int_\l_tmpa_str } \g_@@_step_count_int 
    \int_step_inline:nn { \c_@@_max_step_int }
      { 
        \intarray_gset:cnn { g_@@_x_intarray_\l_tmpa_str } { ##1 }
          { \intarray_item:Nn \g_@@_x_intarray  { ##1 } }
        \intarray_gset:cnn { g_@@_y_intarray_\l_tmpa_str } { ##1 }
          { \intarray_item:Nn \g_@@_y_intarray  { ##1 } }
        \intarray_gset:cnn { g_@@_player_intarray_\l_tmpa_str } { ##1 }
          { \intarray_item:Nn \g_@@_player_intarray  { ##1 } }
      }
    \clist_gset_eq:cN { g_@@_label_seq_\l_tmpa_str } \g_@@_label_seq  
    \clist_gset_eq:cN { g_@@_die_seq_\l_tmpa_str } \g_@@_die_seq  
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\useweiqi}
% 使用对局。
%    \begin{macrocode}
\NewDocumentCommand \useweiqi { s o }
  {
    \IfNoValueTF { #2 }
      { \str_set:Nx \l_tmpa_str { Default } }
      { \str_set:Nx \l_tmpa_str { \int_to_alph:n { #2 } } }
    \cs_if_free:cTF { g_@@_size_int_\l_tmpa_str }
      { \@@_new_game:n { \g_@@_default_size_int } }  
      {
        \int_set_eq:Nc \l_tmpa_int { g_@@_size_int_\l_tmpa_str }
        \@@_new_game:n { \l_tmpa_int }
        \int_gset_eq:Nc \g_@@_step_count_int 
          { g_@@_step_count_int_\l_tmpa_str }
        \int_step_inline:nn { \c_@@_max_step_int }
          { 
            \intarray_gset:Nnn \g_@@_x_intarray { ##1 }
              { \intarray_item:cn { g_@@_x_intarray_\l_tmpa_str }  { ##1 } }
            \intarray_gset:Nnn \g_@@_y_intarray { ##1 }
              { \intarray_item:cn { g_@@_y_intarray_\l_tmpa_str }  { ##1 } }
            \intarray_gset:Nnn \g_@@_player_intarray { ##1 }
              { 
                \intarray_item:cn 
                  { g_@@_player_intarray_\l_tmpa_str }  { ##1 } 
              }
          }
        \clist_set_eq:Nc \g_@@_label_seq { g_@@_label_seq_\l_tmpa_str }
        \clist_set_eq:Nc \g_@@_die_seq { g_@@_die_seq_\l_tmpa_str }
      }
    \IfBooleanT{ #1 }
      {
        \@@_clear_labels:
        \int_step_inline:nn { \g_@@_step_count_int } 
          {
            \seq_gset_item:Nnn \g_@@_label_seq { ##1 } {}
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\weiqidata}
% 查询内部数据。
%    \begin{macrocode}
\NewDocumentCommand \weiqidata { s }
  {
    \noindent 棋盘大小：\int_use:N \g_@@_size_int~
    （默认：\int_use:N \g_@@_default_size_int）\\
    当前对局步数：\int_use:N \g_@@_step_count_int~（含纯标签及移除棋子）\\
    \int_compare:nNnT { \g_@@_step_count_int } > { 0 }
      { 序号：($x$,~$y$)，所属方，标签，备注\\ }
    \int_step_inline:nn  {\g_@@_step_count_int} 
      {
        \int_set:Ne \l_@@_x_int 
          { \intarray_item:Nn \g_@@_x_intarray { ##1 } }
        \int_set:Ne \l_@@_y_int 
          { \intarray_item:Nn \g_@@_y_intarray { ##1 } }
        \int_set:Ne \l_@@_player_int
          { \intarray_item:Nn \g_@@_player_intarray { ##1 } }
        \str_set:Nx \l_@@_tmp_str 
          { \seq_item:Nn \g_@@_label_seq { ##1 } }          
        ##1：
        (\int_use:N \l_@@_x_int,~\int_use:N \l_@@_y_int)，
        \int_case:nn { \l_@@_player_int }
          {
            { 1 } { B }
            { 2 } { W }
            { 3 } { L }
            { 0 } { - }
          }，
        \str_if_empty:NTF \l_@@_tmp_str  
          { \meta{空} }  
          { \l_@@_tmp_str }，
        \int_compare:nNnTF 
          { \l_@@_player_int } = { 0 }
          { \meta{无效} }
          {
            \seq_if_in:NnT \g_@@_die_seq { ##1 } 
              {  \meta{死子} }
              { 
                \int_compare:nNnT
                  { \l_@@_x_int } = { 0 }
                  {  \meta{虚着} }
              }
          }\\
      } 
    红色指示点：
      \clist_if_empty:NTF \g_@@_red_point_clist
        { \meta{空} }
        { \clist_use:Nn \g_@@_red_point_clist {,~} }\\
    绿色指示点：
      \clist_if_empty:NTF \g_@@_green_point_clist
        { \meta{空} }
        { \clist_use:Nn \g_@@_green_point_clist {,~} }\\
    蓝色指示点：
      \clist_if_empty:NTF \g_@@_blue_point_clist
        { \meta{空} }
        { \clist_use:Nn \g_@@_blue_point_clist {,~} }\\
    方位信息：
      \int_use:N \l_@@_x_direction_int,~
      \int_use:N \l_@@_x_direction_int,~ 
      \bool_to_str:N \l_@@_swap_xy_bool；~
    （全局：
      \int_use:N \g_@@_x_direction_int,~ 
      \int_use:N \g_@@_x_direction_int,~ 
      \bool_to_str:N \g_@@_swap_xy_bool
    ）\\
    缩放比例：\fp_use:N \l_@@_scale_fp~
    （全局：\fp_use:N \g_@@_scale_fp）\\
    坐标刻度：\l_@@_loc_mode_str,~\bool_to_str:N \l_@@_show_loc_bool
    （全局：\g_@@_loc_mode_str,~\bool_to_str:N \g_@@_show_loc_bool）\\
    最小显示尺寸：
      \int_use:N \l_@@_min_width_int,~
      \int_use:N \l_@@_min_hight_int~
    （全局：
      \int_use:N \g_@@_min_width_int,~
      \int_use:N \g_@@_min_hight_int
    ）\\
    \IfBooleanT{ #1 }
      {
        棋子区间：
        (\int_use:N \l_@@_x_min_int,~\int_use:N \l_@@_y_max_int)，
        (\int_use:N \l_@@_x_max_int,~\int_use:N \l_@@_y_min_int)\\
        棋盘边界：
        (\fp_use:N \l_@@_x_min_fp,~\fp_use:N \l_@@_x_max_fp)，
        (\fp_use:N \l_@@_y_min_fp,~\fp_use:N \l_@@_y_max_fp)\\
        是否边路：
        \bool_to_str:N \l_@@_up_bool，
        \bool_to_str:N \l_@@_down_bool，
        \bool_to_str:N \l_@@_left_bool，
        \bool_to_str:N \l_@@_right_bool（上下左右）\\
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{扫尾}
%
% 初始新对局
%    \begin{macrocode}
\newweiqi
%    \end{macrocode}
%
% 关闭 expl3 模式
%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
