From 7601acc97e5606a954255c65ba9a200d27230d51 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Mon, 26 Feb 2024 21:00:02 +0000 Subject: weiqi (26feb24) git-svn-id: svn://tug.org/texlive/trunk@70178 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/latex/weiqi/README.md | 25 + Master/texmf-dist/doc/latex/weiqi/weiqi.pdf | Bin 0 -> 345824 bytes Master/texmf-dist/source/latex/weiqi/weiqi.dtx | 2471 ++++++++++++++++++++++++ Master/texmf-dist/source/latex/weiqi/weiqi.ins | 36 + Master/texmf-dist/tex/latex/weiqi/weiqi.sty | 1329 +++++++++++++ Master/tlpkg/bin/tlpkg-ctan-check | 2 +- Master/tlpkg/tlpsrc/collection-games.tlpsrc | 1 + Master/tlpkg/tlpsrc/weiqi.tlpsrc | 0 8 files changed, 3863 insertions(+), 1 deletion(-) create mode 100644 Master/texmf-dist/doc/latex/weiqi/README.md create mode 100644 Master/texmf-dist/doc/latex/weiqi/weiqi.pdf create mode 100644 Master/texmf-dist/source/latex/weiqi/weiqi.dtx create mode 100644 Master/texmf-dist/source/latex/weiqi/weiqi.ins create mode 100644 Master/texmf-dist/tex/latex/weiqi/weiqi.sty create mode 100644 Master/tlpkg/tlpsrc/weiqi.tlpsrc (limited to 'Master') diff --git a/Master/texmf-dist/doc/latex/weiqi/README.md b/Master/texmf-dist/doc/latex/weiqi/README.md new file mode 100644 index 00000000000..8abfe40af07 --- /dev/null +++ b/Master/texmf-dist/doc/latex/weiqi/README.md @@ -0,0 +1,25 @@ +# Description + +A new package which use LaTeX3 to typeset the weiqi(go). +使用 LaTeX3 创建一个排版围棋棋谱的宏包。 + +# Copyright + +Copyright (C) 2023-2024 By Ms_yam + +It may be distributed and/or modified under the conditions of the +LaTeX Project Public License (LPPL), either version 1.3c of this +license or (at your option) any later version. The latest version +of this license is in the file + + https://www.latex-project.org/lppl.txt + +# generate + +```sh +xetex weiqi.ins +xelatex weiqi.dtx +makeindex -s gind.ist weiqi.idx +xelatex weiqi.dtx +xelatex weiqi.dtx +``` \ No newline at end of file diff --git a/Master/texmf-dist/doc/latex/weiqi/weiqi.pdf b/Master/texmf-dist/doc/latex/weiqi/weiqi.pdf new file mode 100644 index 00000000000..ed48eb673a8 Binary files /dev/null and b/Master/texmf-dist/doc/latex/weiqi/weiqi.pdf differ diff --git a/Master/texmf-dist/source/latex/weiqi/weiqi.dtx b/Master/texmf-dist/source/latex/weiqi/weiqi.dtx new file mode 100644 index 00000000000..0c7cd40516c --- /dev/null +++ b/Master/texmf-dist/source/latex/weiqi/weiqi.dtx @@ -0,0 +1,2471 @@ +% \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} +% +% \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} +% +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/weiqi/weiqi.ins b/Master/texmf-dist/source/latex/weiqi/weiqi.ins new file mode 100644 index 00000000000..bb7a63b39a6 --- /dev/null +++ b/Master/texmf-dist/source/latex/weiqi/weiqi.ins @@ -0,0 +1,36 @@ +%% +%% 版本(C) 2023-2024 by Ms_yam +%% +%% 它可以在LaTeX 项目公共许可(LPPL)1.3c 及之后的任意版本( +%% 随你的意见)下分发或修改。这个许可的最新版本在如下文件中: +%% +%% http://www.latex-project.org/lppl.txt +%% +%% 版本1.3c 及之后的版本是LaTeX 2008 及之后的版本的组成。 +%% + +\input docstrip.tex + +\keepsilent + +\preamble + +\endpreamble + +\generate{\file{weiqi.sty}{\from{weiqi.dtx}{package}}} + +\obeyspaces + +\Msg{************************************************************} +\Msg{* *} +\Msg{* 请将下列文件移动到 TeX 搜索路径以完成安装: *} +\Msg{* *} +\Msg{* weiqi.sty *} +\Msg{* *} +\Msg{* 使用 XeLaTeX 运行 weiqi.dtx 文件以生成用户文档。 *} +\Msg{* *} +\Msg{* 祝您使用TeX 愉快! *} +\Msg{* *} +\Msg{************************************************************} + +\endbatchfile \ No newline at end of file diff --git a/Master/texmf-dist/tex/latex/weiqi/weiqi.sty b/Master/texmf-dist/tex/latex/weiqi/weiqi.sty new file mode 100644 index 00000000000..3fddd04badf --- /dev/null +++ b/Master/texmf-dist/tex/latex/weiqi/weiqi.sty @@ -0,0 +1,1329 @@ +%% +%% This is file `weiqi.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% weiqi.dtx (with options: `package') +%% +%% +%% 文件:weiqi.dtx +%% +%% 版权 (C) 2023-2024 By Ms_yam +%% +%% 它可以在 LaTeX 项目公共许可(LPPL)1.3c 及之后的任意版本(随你的意见)下分发或修改。 +%% 这个许可的最新版本在如下文件中: +%% +%% https://www.latex-project.org/lppl.txt +%% +%% 本宏包为作者练习 epxl3 和编写 dtx 文件所编写,里面的接口及方法并不是最优的。 +%% 仅供参考。 +%% +\NeedsTeXFormat{LaTeX2e} +\ProvidesExplPackage{weiqi}{2024-02-22}{0.1} + {drawing weiqi using expl3} +\RequirePackage{l3draw}[2024-01-04] +\ExplSyntaxOn +\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 } +\int_const:Nn \c__weiqi_normal_size_int { 19 } +\int_const:Nn \c__weiqi_mid_size_int { 13 } +\int_const:Nn \c__weiqi_small_size_int { 9 } +\clist_const:Nn \c__weiqi_normal_star_clist + { d4, j4, p4, d10, j10, p10, d16, j16, p16 } +\clist_const:Nn \c__weiqi_mid_star_clist + { c3, g3, k3, c7, g7, k7, c11, g11, k11 } +\clist_const:Nn \c__weiqi_small_star_clist { c3, k3, c7, k7 } +\int_const:Nn \c__weiqi_max_step_int { 500 } +\str_const:Nn \c__weiqi_normal_mode_str { normal } +\str_const:Nn \c__weiqi_sgf_mode_str { sgf } +\int_new:N \g__weiqi_x_direction_int +\int_new:N \g__weiqi_y_direction_int +\bool_new:N \g__weiqi_swap_xy_bool +\fp_new:N \g__weiqi_scale_fp +\int_new:N \g__weiqi_min_width_int +\int_new:N \g__weiqi_min_hight_int +\bool_new:N \g__weiqi_show_loc_bool +\str_new:N \g__weiqi_loc_mode_str +\int_gset:Nn \g__weiqi_x_direction_int { 1 } +\int_gset:Nn \g__weiqi_y_direction_int { 1 } +\bool_gset_false:N \g__weiqi_swap_xy_bool +\fp_gset:Nn \g__weiqi_scale_fp { 1 } +\int_gset:Nn \g__weiqi_min_width_int { 3 } +\int_gset:Nn \g__weiqi_min_hight_int { 2 } +\bool_gset_true:N \g__weiqi_show_loc_bool +\str_gset_eq:NN \g__weiqi_loc_mode_str \c__weiqi_normal_mode_str +\int_new:N \l__weiqi_x_direction_int +\int_new:N \l__weiqi_y_direction_int +\bool_new:N \l__weiqi_swap_xy_bool +\fp_new:N \l__weiqi_scale_fp +\int_new:N \l__weiqi_min_width_int +\int_new:N \l__weiqi_min_hight_int +\bool_new:N \l__weiqi_show_loc_bool +\str_new:N \l__weiqi_loc_mode_str +\int_new:N \g__weiqi_default_size_int +\int_gset_eq:NN \g__weiqi_default_size_int \c__weiqi_normal_size_int +\int_new:N \g__weiqi_size_int +\int_new:N \g__weiqi_step_count_int +\intarray_new:Nn \g__weiqi_x_intarray { \c__weiqi_max_step_int } +\intarray_new:Nn \g__weiqi_y_intarray { \c__weiqi_max_step_int } +\intarray_new:Nn \g__weiqi_player_intarray { \c__weiqi_max_step_int } +\seq_new:N \g__weiqi_label_seq +\seq_new:N \g__weiqi_die_seq +\clist_new:N \g__weiqi_red_point_clist +\clist_new:N \g__weiqi_green_point_clist +\clist_new:N \g__weiqi_blue_point_clist +\int_new:N \l__weiqi_x_min_int +\int_new:N \l__weiqi_x_max_int +\int_new:N \l__weiqi_y_min_int +\int_new:N \l__weiqi_y_max_int +\bool_new:N \l__weiqi_left_bool +\bool_new:N \l__weiqi_right_bool +\bool_new:N \l__weiqi_up_bool +\bool_new:N \l__weiqi_down_bool +\fp_new:N \l__weiqi_x_min_fp +\fp_new:N \l__weiqi_x_max_fp +\fp_new:N \l__weiqi_y_min_fp +\fp_new:N \l__weiqi_y_max_fp +\str_new:N \l__weiqi_label_str +\int_new:N \l__weiqi_x_int +\int_new:N \l__weiqi_y_int +\int_new:N \l__weiqi_player_int +\fp_new:N \l__weiqi_x_fp +\fp_new:N \l__weiqi_y_fp +\clist_new:N \l__weiqi_point_clist +\int_new:N \l__weiqi_tmp_int +\str_new:N \l__weiqi_tmp_str +\bool_new:N \l__weiqi_tmp_bool +\seq_new:N \l__weiqi_tmp_seq +\cs_new:Npn \__weiqi_new_game:n #1 + { + \int_set_eq:NN \l__weiqi_x_direction_int \g__weiqi_x_direction_int + \int_set_eq:NN \l__weiqi_y_direction_int \g__weiqi_y_direction_int + \bool_set_eq:NN \l__weiqi_swap_xy_bool \g__weiqi_swap_xy_bool + \fp_set_eq:NN \l__weiqi_scale_fp \g__weiqi_scale_fp + \int_set_eq:NN \l__weiqi_min_width_int \g__weiqi_min_width_int + \int_set_eq:NN \l__weiqi_min_hight_int \g__weiqi_min_hight_int + \bool_set_eq:NN \l__weiqi_show_loc_bool \g__weiqi_show_loc_bool + \str_set_eq:NN \l__weiqi_loc_mode_str \g__weiqi_loc_mode_str + \int_gset:Ne \g__weiqi_size_int { #1 } + \int_gset:Nn \g__weiqi_step_count_int { 0 } + \intarray_gzero:N \g__weiqi_x_intarray + \intarray_gzero:N \g__weiqi_y_intarray + \intarray_gzero:N \g__weiqi_player_intarray + \seq_gclear:N \g__weiqi_label_seq + \seq_gclear:N \g__weiqi_die_seq + \clist_gclear:N \g__weiqi_red_point_clist + \clist_gclear:N \g__weiqi_green_point_clist + \clist_gclear:N \g__weiqi_blue_point_clist + } +\cs_new:Npn \__weiqi_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__weiqi_x_int { 0 } + \int_set:Nn \l__weiqi_y_int { 0 } + } + { + \int_set:Ne \l__weiqi_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__weiqi_y_int { \g__weiqi_size_int - \l_tmpa_int + 1 } + } + { + \int_set:Ne \l__weiqi_y_int + { \str_range:Nnn \l_tmpa_str { 2 } { 5 } } + } + } + } +\cs_generate_variant:Nn \__weiqi_loc_to_xy:n { V } +\cs_new:Npn \__weiqi_xy_to_loc:N #1 + { + \int_compare:nNnTF { \l__weiqi_x_int } = { 0 } + { \str_set:Nn #1 { - } } + { + \str_set:Nx \l_tmpa_str + { \int_to_alph:n { \l__weiqi_x_int } } + \str_compare:eNeTF + { \l__weiqi_loc_mode_str } = { \c__weiqi_sgf_mode_str } + { + \int_set:Nn \l_tmpa_int + { \g__weiqi_size_int - \l__weiqi_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__weiqi_y_int } } + \str_set_eq:NN #1 \l_tmpa_str + } + } +\cs_new:Npn \__weiqi_add_stone:nnn #1#2#3 + { + \int_gincr:N \g__weiqi_step_count_int + \intarray_gset:Nnn \g__weiqi_player_intarray + \g__weiqi_step_count_int { #1 } + \__weiqi_loc_to_xy:n { #2 } + \intarray_gset:Nnn \g__weiqi_x_intarray + \g__weiqi_step_count_int \l__weiqi_x_int + \intarray_gset:Nnn \g__weiqi_y_intarray + \g__weiqi_step_count_int \l__weiqi_y_int + \str_if_eq:nnTF { #3 } { 0 } + { \seq_put_right:Nn \g__weiqi_label_seq {} } + { \seq_put_right:Nn \g__weiqi_label_seq { #3 } } + } +\cs_generate_variant:Nn \__weiqi_add_stone:nnn {nnV, nVV} +\cs_new:Npn \__weiqi_add_stones:nnn #1#2#3 + { + \int_set:Nn \l__weiqi_player_int { #1 } + \clist_set:Nn \l__weiqi_position_clsit { #2 } + \bool_set_false:N \l__weiqi_tmp_bool + \str_if_empty:nTF { #3 } + { \str_set:Nn \l__weiqi_tmp_str {} } + { + \regex_match:nnTF { [^0-9]+ } { #3 } + { \str_set:Nx \l__weiqi_tmp_str { #3 } } + { + \bool_set_true:N \l__weiqi_tmp_bool + \int_set:Nn \l__weiqi_tmp_int { #3 } + } + } + \clist_map_inline:Nn \l__weiqi_position_clsit + { + \bool_if:nTF \l__weiqi_tmp_bool + { + \__weiqi_add_stone:nnV + { \l__weiqi_player_int } + { ##1 } + { \l__weiqi_tmp_int } + \int_case:nn { \l__weiqi_player_int } + { + { 1 } { \int_set:Nn \l__weiqi_player_int { 2 } } + { 2 } { \int_set:Nn \l__weiqi_player_int { 1 } } + { 3 } { \int_set:Nn \l__weiqi_player_int { 3 } } + } + \int_compare:nNnT { \l__weiqi_tmp_int } > { 0 } + { \int_incr:N \l__weiqi_tmp_int } + } + { \__weiqi_add_stone:nnV { #1 } { ##1 } { \l__weiqi_tmp_str } } + } + } +\cs_new:Npn \__weiqi_add_sgf_stones:nn #1#2 + { + \regex_extract_all:nnN { ;[BW]\[[a-z]{2}\] } { #1 } \l__weiqi_tmp_seq + \clist_set_from_seq:NN \l__weiqi_point_clist \l__weiqi_tmp_seq + \bool_set_false:N \l__weiqi_tmp_bool + \str_if_empty:nTF { #2 } + { \str_set:Nn \l__weiqi_tmp_str {} } + { + \regex_match:nnTF { [^0-9]+ } { #2 } + { \str_set:Nx \l__weiqi_tmp_str { #2 } } + { + \bool_set_true:N \l__weiqi_tmp_bool + \int_set:Nn \l__weiqi_tmp_int { #2 } + } + } + \clist_map_inline:Nn \l__weiqi_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__weiqi_player_int { 1 } } + { W } { \int_set:Nn \l__weiqi_player_int { 2 } } + } + \bool_if:nTF \l__weiqi_tmp_bool + { + \__weiqi_add_stone:nVV { \l__weiqi_player_int } + { \l_tmpb_str } { \l__weiqi_tmp_int } + \int_compare:nNnT { \l__weiqi_tmp_int } > { 0 } + { \int_incr:N \l__weiqi_tmp_int } + } + { + \__weiqi_add_stone:nVV { \l__weiqi_player_int } + { \l_tmpb_str } { \l__weiqi_tmp_str } + } + } + } +\cs_generate_variant:Nn \__weiqi_add_sgf_stones:nn { VV } +\cs_new:Npn \__weiqi_reset_stone_number:n #1 + { + \int_set:Ne \l__weiqi_tmp_int { 1 - #1 } + \int_step_inline:nn { \c__weiqi_max_step_int } + { + \bool_lazy_or:nnF + { + \int_compare_p:nNn + { \intarray_item:Nn \g__weiqi_player_intarray { ##1 } } = { 0 } + } + { + \int_compare_p:nNn + { \intarray_item:Nn \g__weiqi_player_intarray { ##1 } } = { 3 } + } + { + \int_incr:N \l__weiqi_tmp_int + \int_compare:nNnTF { \l__weiqi_tmp_int } > { 0 } + { \seq_gset_item:NnV \g__weiqi_label_seq { ##1 } { \l__weiqi_tmp_int } } + { \seq_gset_item:Nnn \g__weiqi_label_seq { ##1 } {} } + } + } + } +\cs_new:Npn \__weiqi_change_stone:n #1 + { + \int_case:nn + { \intarray_item:Nn \g__weiqi_player_intarray { #1 } } + { + { 1 } { \intarray_gset:Nnn \g__weiqi_player_intarray { #1 } { 2 } } + { 2 } { \intarray_gset:Nnn \g__weiqi_player_intarray { #1 } { 1 } } + } + } +\cs_new:Npn \__weiqi_remove_stone:n #1 + { + \intarray_gset:Nnn \g__weiqi_x_intarray { #1 } { 0 } + \intarray_gset:Nnn \g__weiqi_y_intarray { #1 } { 0 } + \intarray_gset:Nnn \g__weiqi_player_intarray { #1 } { 0 } + \seq_gset_item:Nnn \g__weiqi_label_seq { #1} { } + } +\cs_new:Npn \__weiqi_die_stone:n #1 + { + \seq_if_in:NnF \g__weiqi_die_seq { #1 } + { + \seq_put_right:Nn \g__weiqi_die_seq { #1 } + \prg_break: + } + } +\cs_new:Npn \__weiqi_modify_stone:N #1 + { + \int_step_inline:nn { \c__weiqi_max_step_int } + { + \bool_lazy_and:nnT + { + \int_compare_p:n + { \intarray_item:Nn \g__weiqi_x_intarray { ##1 } = \l__weiqi_x_int } + } + { + \int_compare_p:n + { \intarray_item:Nn \g__weiqi_y_intarray { ##1 } = \l__weiqi_y_int } + } + { #1 { ##1 } } + } + \prg_break_point: + } +\cs_new:Npn \__weiqi_modify_stones:nN #1#2 + { + \clist_set:Nn \l__weiqi_position_clsit { #1 } + \clist_map_inline:Nn \l__weiqi_position_clsit + { + \__weiqi_loc_to_xy:n { ##1 } + \int_compare:nNnF { \l__weiqi_x_int } = { 0 } + { \__weiqi_modify_stone:N { #2 } } + } + } +\cs_new:Nn \__weiqi_clear_labels: + { + \int_step_inline:nn { \c__weiqi_max_step_int } + { + \int_compare:nNnT + { \intarray_item:Nn \g__weiqi_player_intarray { ##1 } } = { 3 } + { + \intarray_gset:Nnn \g__weiqi_x_intarray { ##1 } { 0 } + \intarray_gset:Nnn \g__weiqi_y_intarray { ##1 } { 0 } + \intarray_gset:Nnn \g__weiqi_player_intarray { ##1 } { 0 } + \seq_gset_item:Nnn \g__weiqi_label_seq { ##1 } {} + } + } + } +\cs_new:Npn \__weiqi_add_points:nn #1#2 + { + \str_case:nn { #1 } + { + { red } + { \clist_gput_right:Nn \g__weiqi_red_point_clist { #2 } } + { green } + { \clist_gput_right:Nn \g__weiqi_green_point_clist { #2 } } + { blue } + { \clist_gput_right:Nn \g__weiqi_blue_point_clist { #2 } } + } + } +\cs_new:Nn \__weiqi_clear_points: + { + \clist_clear:N \g__weiqi_red_point_clist + \clist_clear:N \g__weiqi_green_point_clist + \clist_clear:N \g__weiqi_blue_point_clist + } +\cs_new:Npn \__weiqi_transform_xy:NN #1#2 + { + \int_set:Ne \l_tmpa_int { #1 * \l__weiqi_x_direction_int } + \int_set:Ne \l_tmpb_int { #2 * \l__weiqi_y_direction_int } + \bool_if:NTF \l__weiqi_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 + } + } +\cs_new:Nn \__weiqi_calc_range: + { + \int_set:Nn \l__weiqi_x_min_int { 99 } + \int_set:Nn \l__weiqi_y_min_int { 99 } + \int_set:Nn \l__weiqi_x_max_int { 0 } + \int_set:Nn \l__weiqi_y_max_int { 0 } + \int_step_inline:nn {\g__weiqi_step_count_int} + { + \int_set:Ne \l__weiqi_x_int + { \intarray_item:Nn \g__weiqi_x_intarray { ##1 } } + \int_set:Ne \l__weiqi_y_int + { \intarray_item:Nn \g__weiqi_y_intarray { ##1 } } + \int_compare:nNnF + { \l__weiqi_x_int } = { 0 } + { + \int_compare:nNnT + \l__weiqi_x_min_int > \l__weiqi_x_int + { \int_set_eq:NN \l__weiqi_x_min_int \l__weiqi_x_int } + \int_compare:nNnT + \l__weiqi_x_max_int < \l__weiqi_x_int + { \int_set_eq:NN \l__weiqi_x_max_int \l__weiqi_x_int } + \int_compare:nNnT + \l__weiqi_y_min_int > \l__weiqi_y_int + { \int_set_eq:NN \l__weiqi_y_min_int \l__weiqi_y_int } + \int_compare:nNnT + \l__weiqi_y_max_int < \l__weiqi_y_int + { \int_set_eq:NN \l__weiqi_y_max_int \l__weiqi_y_int } + } + } + \int_compare:nNnT + { \l__weiqi_x_min_int } = { 99 } + { + \int_set:Nn \l__weiqi_x_min_int { 1 } + \int_set:Nn \l__weiqi_y_min_int { 1 } + \int_set_eq:NN \l__weiqi_x_max_int \g__weiqi_size_int + \int_set_eq:NN \l__weiqi_y_max_int \g__weiqi_size_int + } + \int_set:Ne \l_tmpa_int + { \int_min:nn { \g__weiqi_size_int } { \l__weiqi_min_width_int } } + \int_compare:nNnTF + { \g__weiqi_size_int - \l__weiqi_x_max_int } > { \l__weiqi_x_min_int - 1 } + { + \int_set:Nn \l__weiqi_x_min_int { 1 } + \int_set:Ne \l__weiqi_x_max_int + { \int_max:nn { \l__weiqi_x_max_int + 1 } { \l_tmpa_int } } + } + { + \int_set_eq:NN \l__weiqi_x_max_int \g__weiqi_size_int + \int_compare:nNnF + { \l__weiqi_x_min_int } = { 1 } + { + \int_set:Ne \l__weiqi_x_min_int + { + \int_min:nn + { \l__weiqi_x_min_int - 1 } + { \g__weiqi_size_int - \l_tmpa_int + 1 } + } + } + } + \int_set:Ne \l_tmpa_int + { \int_min:nn { \g__weiqi_size_int } { \l__weiqi_min_hight_int } } + \int_compare:nNnTF + { \g__weiqi_size_int - \l__weiqi_y_max_int } > { \l__weiqi_y_min_int - 1 } + { + \int_set:Nn \l__weiqi_y_min_int { 1 } + \int_set:Ne \l__weiqi_y_max_int + { \int_max:nn { \l__weiqi_y_max_int + 1 } { \l_tmpa_int } } + } + { + \int_set_eq:NN \l__weiqi_y_max_int \g__weiqi_size_int + \int_compare:nNnF + { \l__weiqi_y_min_int } = { 1 } + { + \int_set:Ne \l__weiqi_y_min_int + { + \int_min:nn + { \l__weiqi_y_min_int - 1 } + { \g__weiqi_size_int - \l_tmpa_int + 1 } + } + } + } + \__weiqi_transform_xy:NN \l__weiqi_x_min_int \l__weiqi_y_min_int + \__weiqi_transform_xy:NN \l__weiqi_x_max_int \l__weiqi_y_max_int + } +\cs_new:Npn \__weiqi_set_range:n #1 + { + \str_compare:eNeTF + { \str_lowercase:n { #1 } } = { full } + { + \int_set:Nn \l__weiqi_x_min_int { 1 } + \int_set:Nn \l__weiqi_y_min_int { 1 } + \int_set_eq:NN \l__weiqi_x_max_int \g__weiqi_size_int + \int_set_eq:NN \l__weiqi_y_max_int \g__weiqi_size_int + } + { + \clist_set:Nn \l__weiqi_position_clsit { #1 } + \clist_pop:NN \l__weiqi_position_clsit \l_tmpa_tl + \__weiqi_loc_to_xy:V { \l_tmpa_tl } + \int_set_eq:NN \l__weiqi_x_min_int \l__weiqi_x_int + \int_set_eq:NN \l__weiqi_y_min_int \l__weiqi_y_int + \clist_pop:NN \l__weiqi_position_clsit \l_tmpa_tl + \__weiqi_loc_to_xy:V { \l_tmpa_tl } + \int_set_eq:NN \l__weiqi_x_max_int \l__weiqi_x_int + \int_set_eq:NN \l__weiqi_y_max_int \l__weiqi_y_int + } + \int_compare:nNnT { \l__weiqi_x_min_int } > { \l__weiqi_x_max_int } + { + \int_set_eq:NN \l_tmpa_int \l__weiqi_x_min_int + \int_set_eq:NN \l__weiqi_x_min_int \l__weiqi_x_max_int + \int_set_eq:NN \l__weiqi_x_max_int \l_tmpa_int + } + \int_compare:nNnT { \l__weiqi_y_min_int } > { \l__weiqi_y_max_int } + { + \int_set_eq:NN \l_tmpa_int \l__weiqi_y_min_int + \int_set_eq:NN \l__weiqi_y_min_int \l__weiqi_y_max_int + \int_set_eq:NN \l__weiqi_y_max_int \l_tmpa_int + } + \__weiqi_transform_xy:NN \l__weiqi_x_min_int \l__weiqi_y_min_int + \__weiqi_transform_xy:NN \l__weiqi_x_max_int \l__weiqi_y_max_int + } +\cs_new:Nn \__weiqi_calc_board_border: + { + \int_compare:nNnTF + { \int_abs:n { \l__weiqi_x_min_int } } = { 1 } + { + \bool_set_true:N \l__weiqi_left_bool + \fp_set:Nn \l__weiqi_x_min_fp + { \l__weiqi_x_min_int } + } + { + \bool_set_false:N \l__weiqi_left_bool + \fp_set:Nn \l__weiqi_x_min_fp + { \l__weiqi_x_min_int - 0.3 * \int_sign:n { \l__weiqi_x_min_int } } + } + \int_compare:nNnTF + { \int_abs:n { \l__weiqi_x_max_int } } = { \g__weiqi_size_int } + { + \bool_set_true:N \l__weiqi_right_bool + \fp_set:Nn \l__weiqi_x_max_fp + { \l__weiqi_x_max_int } + } + { + \bool_set_false:N \l__weiqi_right_bool + \fp_set:Nn \l__weiqi_x_max_fp + { \l__weiqi_x_max_int + 0.3 * \int_sign:n { \l__weiqi_x_max_int } } + } + \int_compare:nNnTF + { \int_abs:n { \l__weiqi_y_min_int } } = { 1 } + { + \bool_set_true:N \l__weiqi_down_bool + \fp_set:Nn \l__weiqi_y_min_fp + { \l__weiqi_y_min_int } + } + { + \bool_set_false:N \l__weiqi_down_bool + \fp_set:Nn \l__weiqi_y_min_fp + { \l__weiqi_y_min_int - 0.3 * \int_sign:n { \l__weiqi_y_min_int } } + } + \int_compare:nNnTF + { \int_abs:n { \l__weiqi_y_max_int } } = { \g__weiqi_size_int } + { + \bool_set_true:N \l__weiqi_up_bool + \fp_set:Nn \l__weiqi_y_max_fp + { \l__weiqi_y_max_int } + } + { + \bool_set_false:N \l__weiqi_up_bool + \fp_set:Nn \l__weiqi_y_max_fp + { \l__weiqi_y_max_int + 0.3 * \int_sign:n { \l__weiqi_y_max_int } } + } + } +\prg_set_conditional:Npnn \__weiqi_within_range:nn #1#2 { p, T } + { + \fp_set:Nn \l_tmpa_fp { abs( \l__weiqi_x_min_fp - #1 ) } + \fp_add:Nn \l_tmpa_fp { abs( \l__weiqi_x_max_fp - #1 ) } + \fp_sub:Nn \l_tmpa_fp { abs( \l__weiqi_x_max_fp - \l__weiqi_x_min_fp ) } + \fp_add:Nn \l_tmpa_fp { abs( \l__weiqi_y_min_fp - #2 ) } + \fp_add:Nn \l_tmpa_fp { abs( \l__weiqi_y_max_fp - #2 ) } + \fp_sub:Nn \l_tmpa_fp { abs( \l__weiqi_y_max_fp - \l__weiqi_y_min_fp ) } + \fp_compare:nNnTF + { \l_tmpa_fp } < { 0.1 } + { \prg_return_true: } + { \prg_return_false: } + } +\cs_new:Nn \__weiqi_draw_board_grid: + { + \int_set:Ne \l__weiqi_tmp_int + { \int_sign:n { \l__weiqi_x_max_int - \l__weiqi_x_min_int } } + \int_step_inline:nnnn + { \l__weiqi_x_min_int } { \l__weiqi_tmp_int } { \l__weiqi_x_max_int } + { + \draw_path_moveto:n { ##1 cm, \l__weiqi_y_min_fp cm } + \draw_path_lineto:n { ##1 cm, \l__weiqi_y_max_fp cm } + } + \int_set:Ne \l__weiqi_tmp_int + { \int_sign:n { \l__weiqi_y_max_int - \l__weiqi_y_min_int } } + \int_step_inline:nnnn + { \l__weiqi_y_min_int } { \l__weiqi_tmp_int } { \l__weiqi_y_max_int } + { + \draw_path_moveto:n { \l__weiqi_x_min_fp cm, ##1 cm } + \draw_path_lineto:n { \l__weiqi_x_max_fp cm, ##1 cm } + } + } +\cs_new:Nn \__weiqi_draw_board_border: + { + \bool_if:nT { \l__weiqi_left_bool } + { + \draw_path_moveto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_min_fp cm } + \draw_path_lineto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_max_fp cm } + } + \bool_if:nT { \l__weiqi_right_bool } + { + \draw_path_moveto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_min_fp cm } + \draw_path_lineto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_max_fp cm } + } + \bool_if:nT { \l__weiqi_down_bool } + { + \draw_path_moveto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_min_fp cm } + \draw_path_lineto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_min_fp cm } + } + \bool_if:nT { \l__weiqi_up_bool } + { + \draw_path_moveto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_max_fp cm } + \draw_path_lineto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_max_fp cm } + } + } +\cs_new:Nn \__weiqi_draw_board_corner: + { + \bool_if:nT { \l__weiqi_left_bool && \l__weiqi_down_bool } + { + \draw_path_moveto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_max_fp cm } + \draw_path_lineto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_min_fp cm } + \draw_path_lineto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_min_fp cm } + } + \bool_if:nT { \l__weiqi_right_bool && \l__weiqi_down_bool } + { + \draw_path_moveto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_max_fp cm } + \draw_path_lineto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_min_fp cm } + \draw_path_lineto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_min_fp cm } + } + \bool_if:nT { \l__weiqi_right_bool && \l__weiqi_up_bool } + { + \draw_path_moveto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_min_fp cm } + \draw_path_lineto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_max_fp cm } + \draw_path_lineto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_max_fp cm } + } + \bool_if:nT { \l__weiqi_left_bool && \l__weiqi_up_bool } + { + \draw_path_moveto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_min_fp cm } + \draw_path_lineto:n { \l__weiqi_x_min_fp cm, \l__weiqi_y_max_fp cm } + \draw_path_lineto:n { \l__weiqi_x_max_fp cm, \l__weiqi_y_max_fp cm } + } + } +\cs_new:Npn \__weiqi_draw_point:n #1 + { + \__weiqi_loc_to_xy:n { #1 } + \__weiqi_transform_xy:NN \l__weiqi_x_int \l__weiqi_y_int + \__weiqi_within_range:nnT { \l__weiqi_x_int } { \l__weiqi_y_int } + { + \draw_path_circle:nn + { \l__weiqi_x_int cm, \l__weiqi_y_int cm } { 1mm } + } + } +\cs_new:Nn \__weiqi_draw_board_star: + { + \clist_clear:N \l__weiqi_point_clist + \int_case:nn { \g__weiqi_size_int } + { + { \c__weiqi_normal_size_int } + { \clist_set_eq:NN \l__weiqi_point_clist \c__weiqi_normal_star_clist } + { \c__weiqi_mid_size_int } + { \clist_set_eq:NN \l__weiqi_point_clist \c__weiqi_mid_star_clist } + { \c__weiqi_small_size_int } + { \clist_set_eq:NN \l__weiqi_point_clist \c__weiqi_small_star_clist } + } + \clist_map_function:NN \l__weiqi_point_clist \__weiqi_draw_point:n + } +\cs_new:Npn \__weiqi_set_loc_label:nn #1#2 + { + \str_case_e:nn { #1 } + { + { A } + { \str_set:Nx \l__weiqi_label_str { \int_to_Alph:n { #2 } } } + { \c__weiqi_normal_mode_str } + { \str_set:NV \l__weiqi_label_str { #2 } } + { \c__weiqi_sgf_mode_str } + { + \int_set:Nn \l_tmpa_int { \g__weiqi_size_int - #2 + 1 } + \str_set:Nx\l__weiqi_label_str { \int_to_alph:n { \l_tmpa_int } } + } + } + } +\cs_new:Nn \__weiqi_draw_board_loc: + { + \int_gset:Nn \g_tmpa_int + { \int_sign:n { \l__weiqi_x_max_int - \l__weiqi_x_min_int } } + \int_gset:Nn \g_tmpb_int + { \int_sign:n { \l__weiqi_y_max_int - \l__weiqi_y_min_int } } + \int_step_inline:nnnn + { \l__weiqi_x_min_int } { \g_tmpa_int } { \l__weiqi_x_max_int } + { + \int_set:Ne \l__weiqi_tmp_int { \int_abs:n { ##1 } } + \bool_if:NTF \l__weiqi_swap_xy_bool + { \__weiqi_set_loc_label:nn { \l__weiqi_loc_mode_str } { \l__weiqi_tmp_int } } + { \__weiqi_set_loc_label:nn { A } { \l__weiqi_tmp_int } } + \hbox_set:Nn \l_tmpa_box { \l__weiqi_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__weiqi_up_bool + { + \draw_box_use:Nn \l_tmpa_box + { + ##1 cm - 0.5 * { \box_wd:N \l_tmpa_box }, + (\l__weiqi_y_max_fp + \l_tmpa_fp ) cm - abs(\l_tmpb_fp) + \l_tmpb_fp + } + } + \bool_if:NT \l__weiqi_down_bool + { + \draw_box_use:Nn \l_tmpa_box + { + ##1 cm - 0.5 * { \box_wd:N \l_tmpa_box }, + (\l__weiqi_y_min_fp - \l_tmpa_fp ) cm - abs(\l_tmpb_fp) - \l_tmpb_fp + } + } + } + \int_step_inline:nnnn + { \l__weiqi_y_min_int } { \g_tmpb_int } { \l__weiqi_y_max_int } + { + \int_set:Ne \l__weiqi_tmp_int { \int_abs:n { ##1 } } + \bool_if:NTF \l__weiqi_swap_xy_bool + { \__weiqi_set_loc_label:nn { A } { \l__weiqi_tmp_int } } + { \__weiqi_set_loc_label:nn { \l__weiqi_loc_mode_str } { \l__weiqi_tmp_int } } + \hbox_set:Nn \l_tmpa_box { \l__weiqi_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__weiqi_left_bool + { + \draw_box_use:Nn \l_tmpa_box + { + (\l__weiqi_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__weiqi_right_bool + { + \draw_box_use:Nn \l_tmpa_box + { + (\l__weiqi_y_max_fp + \l_tmpa_fp) cm - abs(\l_tmpb_fp) + \l_tmpb_fp, + ##1 cm - 0.5 * { \box_ht:N \l_tmpa_box } + } + } + } + } +\cs_new:Nn \__weiqi_draw_board: + { + \__weiqi_calc_board_border: + \draw_linewidth:n { 0.7 } + \color_select:n { black } + \__weiqi_draw_board_grid: + \draw_path_use_clear:n { stroke } + \draw_linewidth:n { 2 } + \__weiqi_draw_board_border: + \draw_path_use_clear:n { stroke } + \__weiqi_draw_board_corner: + \draw_path_use_clear:n { stroke } + \color_select:n { black } + \__weiqi_draw_board_star: + \draw_path_use_clear:n { draw, fill } + \color_select:n { black!50 } + \bool_if:NT \l__weiqi_show_loc_bool + { \__weiqi_draw_board_loc: } + \draw_path_use_clear:n { stroke } + } +\cs_new:Npn \__weiqi_draw_points: + { + \color_select:n { red } + \clist_map_function:NN \g__weiqi_red_point_clist \__weiqi_draw_point:n + \draw_path_use_clear:n { draw, fill } + \color_select:n { green } + \clist_map_function:NN \g__weiqi_green_point_clist \__weiqi_draw_point:n + \draw_path_use_clear:n { draw, fill } + \color_select:n { blue } + \clist_map_function:NN \g__weiqi_blue_point_clist \__weiqi_draw_point:n + \draw_path_use_clear:n { draw, fill } + } +\cs_new:Npn \__weiqi_draw_stone:nnnn #1#2#3#4 + { + \int_compare:nNnF { #1 } = { 3 } + { + \color_fill:n { white } + \draw_path_circle:nn { #2cm, #3cm } { 4.4mm } + \draw_path_use_clear:n { fill } + } + \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 } + \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 } + } + } +\cs_new:Nn \__weiqi_draw_stones: + { + \draw_linewidth:n { 1 } + \int_step_inline:nn {\g__weiqi_step_count_int} + { + \int_set:Ne \l__weiqi_x_int + { \intarray_item:Nn \g__weiqi_x_intarray { ##1 } } + \int_set:Ne \l__weiqi_y_int + { \intarray_item:Nn \g__weiqi_y_intarray { ##1 } } + \int_set:Ne \l__weiqi_player_int + { \intarray_item:Nn \g__weiqi_player_intarray { ##1 } } + \str_set:Nx \l__weiqi_tmp_str + { \seq_item:Nn \g__weiqi_label_seq { ##1 } } + \seq_if_in:NnT \g__weiqi_die_seq { ##1 } + { \int_set:Nn \l__weiqi_x_int { 0 } } + \int_if_zero:nF { \l__weiqi_x_int } + { + \__weiqi_transform_xy:NN \l__weiqi_x_int \l__weiqi_y_int + \__weiqi_within_range:nnT + { \l__weiqi_x_int } { \l__weiqi_y_int } + { + \__weiqi_draw_stone:nnnn { \l__weiqi_player_int } + { \l__weiqi_x_int } { \l__weiqi_y_int } { \l__weiqi_tmp_str } + } + } + } + } +\cs_new:Nn \__weiqi_draw_specific_stone: + { + \color_select:n { black } + \int_case:nn { \l__weiqi_player_int } + { + { 1 } { \color_fill:n { black } } + { 2 } { \color_fill:n { white } } + } + \draw_path_circle:nn{ \l__weiqi_x_fp cm, \l__weiqi_y_fp cm } { 4mm } + \draw_path_use_clear:n { draw, fill } + \int_case:nn { \l__weiqi_player_int } + { + { 1 } { \color_select:n { white } } + { 2 } { \color_select:n { black } } + } + \__weiqi_xy_to_loc:N \l_tmpa_str + \hbox_set:Nn \l_tmpa_box { \Large \textbf{ \l__weiqi_tmp_str } } + \hbox_set:Nn \l_tmpb_box { \Large \texttt{ \l_tmpa_str } } + \draw_box_use:Nn \l_tmpa_box + { + \l__weiqi_x_fp cm - 0.5 * { \box_wd:N \l_tmpa_box }, + \l__weiqi_y_fp cm - 0.5 * { \box_ht:N \l_tmpa_box } + } + \color_select:n { black } + \draw_box_use:Nn \l_tmpb_box + { + \l__weiqi_x_fp cm + 6mm, + \l__weiqi_y_fp cm - 0.5 * { \box_ht:N \l_tmpa_box } + } + \fp_set:Nn \l_tmpa_fp { min(\l__weiqi_x_min_fp, \l__weiqi_x_max_fp) } + \fp_set:Nn \l_tmpb_fp { max(\l__weiqi_x_min_fp, \l__weiqi_x_max_fp) } + \fp_add:Nn \l__weiqi_x_fp { 2 } + \fp_compare:nNnT { \l__weiqi_x_fp } > { \l_tmpb_fp } + { + \fp_set_eq:NN \l__weiqi_x_fp \l_tmpa_fp + \fp_sub:Nn \l__weiqi_y_fp { 1 } + } + } +\cs_new:Nn \__weiqi_draw_specific_stones: + { + \draw_linewidth:n { 1 } + \fp_set:Nn \l__weiqi_x_fp { min(\l__weiqi_x_min_int, \l__weiqi_x_max_int) } + \fp_set:Nn \l__weiqi_y_fp { min(\l__weiqi_y_min_int, \l__weiqi_y_max_int) - 1.2} + \int_step_inline:nn {\g__weiqi_step_count_int} + { + \int_set:Ne \l__weiqi_x_int + { \intarray_item:Nn \g__weiqi_x_intarray { ##1 } } + \int_set:Ne \l__weiqi_y_int + { \intarray_item:Nn \g__weiqi_y_intarray { ##1 } } + \int_set:Ne \l__weiqi_player_int + { \intarray_item:Nn \g__weiqi_player_intarray { ##1 } } + \str_set:Nx \l__weiqi_tmp_str + { \seq_item:Nn \g__weiqi_label_seq { ##1 } } + \seq_if_in:NnTF \g__weiqi_die_seq { ##1 } + { \int_set:Nn \l_tmpa_int { 0 } } + { \int_set_eq:NN \l_tmpa_int \l__weiqi_x_int } + \str_compare:eNeT { \l__weiqi_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__weiqi_player_int } > { 0 } } + { \int_compare_p:nNn { \l__weiqi_player_int } < { 3 } } + } + { \__weiqi_draw_specific_stone: } + } + } +\cs_new:Nn \__weiqi_show: + { + \draw_begin: + \group_begin: + \draw_transform_scale:n { \l__weiqi_scale_fp } + \__weiqi_draw_board: + \__weiqi_draw_points: + \__weiqi_draw_stones: + \__weiqi_draw_specific_stones: + \group_end: + \draw_end: + } +\NewDocumentCommand \newweiqi { s o } + { + \IfNoValueTF { #2 } + { \__weiqi_new_game:n { \g__weiqi_default_size_int } } + { + \IfBooleanT { #1 } { \int_gset:Nn \g__weiqi_default_size_int { #2 } } + \__weiqi_new_game:n { #2 } + } + } +\NewDocumentCommand \weiqisize { s m } + { + \IfBooleanT{ #1 } + { \int_gset:Nn \g__weiqi_default_size_int { #2 } } + \int_set:Nn \g__weiqi_size_int { #2 } + } +\NewDocumentCommand \weiqiblack { s o m } + { + \IfNoValueTF { #2 } + { \__weiqi_add_stones:nnn { 1 } { #3 } { } } + { \__weiqi_add_stones:nnn { 1 } { #3 } { #2 } } + } +\NewDocumentCommand \weiqiwhite { s o m } + { + \IfNoValueTF { #2 } + { \__weiqi_add_stones:nnn { 2 } { #3 } { } } + { \__weiqi_add_stones:nnn { 2 } { #3 } { #2 } } + } +\NewDocumentCommand \weiqisgf { s o m } + { + \IfNoValueTF { #2 } + { \__weiqi_add_sgf_stones:nn { #3 } { } } + { \__weiqi_add_sgf_stones:nn { #3 } { #2 } } + } +\NewDocumentCommand \inputsgf { s o m } + { + \ior_open:Nn \g_tmpa_ior { #3 } + \str_set:Nn \l__weiqi_tmp_str {} + \ior_str_map_inline:Nn \g_tmpa_ior + { + \str_put_right:Nx \l__weiqi_tmp_str { ##1 } + } + \ior_close:N \g_tmpa_ior + \regex_extract_once:nVNTF { ;GM\[1\] } { \l__weiqi_tmp_str } \l_tmpa_seq + { + \regex_extract_once:nVNTF { SZ\[[0-9]+\] } { \l__weiqi_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__weiqi_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 } } + \__weiqi_add_sgf_stones:VV { \l__weiqi_tmp_str } { \l_tmpa_int } + } + { 解析棋盘大小失败 } + } + { 不支持的棋谱 } + } +\NewDocumentCommand \resetnumber { s o } + { + \IfNoValueTF { #2 } + { \__weiqi_reset_stone_number:n { 1 } } + { \__weiqi_reset_stone_number:n { #2 } } + } +\NewDocumentCommand \weiqilabel { s o m } + { + \IfBooleanT{ #1 } { \__weiqi_clear_labels: } + \IfNoValueTF { #2 } + { \__weiqi_add_stones:nnn { 3 } { #3 } { a } } + { \__weiqi_add_stones:nnn { 3 } { #3 } { #2 } } + } +\NewDocumentCommand \clearlabel { } + { \__weiqi_clear_labels: } +\NewDocumentCommand \weiqired { s m } + { + \IfBooleanT{ #1 } { \__weiqi_clear_points: } + \__weiqi_add_points:nn { red } { #2 } + } +\NewDocumentCommand \weiqigreen { s m } + { + \IfBooleanT{ #1 } { \__weiqi_clear_points: } + \__weiqi_add_points:nn { green } { #2 } + } +\NewDocumentCommand \weiqiblue { s m } + { + \IfBooleanT{ #1 } { \__weiqi_clear_points: } + \__weiqi_add_points:nn { blue } { #2 } + } +\NewDocumentCommand \clearpoint { } + { \__weiqi_clear_points: } +\NewDocumentCommand \weiqidie { s m } + { + \__weiqi_modify_stones:nN { #2 } \__weiqi_die_stone:n + } +\NewDocumentCommand \weiqiremove { s m } + { + \__weiqi_modify_stones:nN { #2 } \__weiqi_remove_stone:n + } +\NewDocumentCommand \weiqichange { s m } + { + \__weiqi_modify_stones:nN { #2 } \__weiqi_change_stone:n + } +\NewDocumentCommand \showweiqi { s o } + { + \IfNoValueTF { #2 } + { \__weiqi_calc_range: } + { \__weiqi_set_range:n { #2 } } + \__weiqi_show: + \IfBooleanF { #1 } { \newweiqi } + } +\NewDocumentCommand \nonelocmode { s } + { + \bool_set_false:N \l__weiqi_show_loc_bool + \IfBooleanT { #1 } { \bool_gset_false:N \g__weiqi_show_loc_bool } + } +\NewDocumentCommand \normallocmode { s } + { + \bool_set_true:N \l__weiqi_show_loc_bool + \str_set_eq:NN \l__weiqi_loc_mode_str \c__weiqi_normal_mode_str + \IfBooleanT { #1 } + { + \bool_gset_true:N \g__weiqi_show_loc_bool + \str_gset_eq:NN \g__weiqi_loc_mode_str \c__weiqi_normal_mode_str + } + } +\NewDocumentCommand \sgflocmode { s } + { + \bool_set_true:N \l__weiqi_show_loc_bool + \str_set_eq:NN \l__weiqi_loc_mode_str \c__weiqi_sgf_mode_str + \IfBooleanT { #1 } + { + \bool_gset_true:N \g__weiqi_show_loc_bool + \str_gset_eq:NN \g__weiqi_loc_mode_str \c__weiqi_sgf_mode_str + } + } + +\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__weiqi_swap_xy_bool + \int_set:Ne \l_tmpb_int { \l__weiqi_x_direction_int } + \int_set:Ne \l__weiqi_x_direction_int { \l__weiqi_y_direction_int } + \int_set:Ne \l__weiqi_y_direction_int { 0 - \l_tmpb_int } + } + { 180 } + { + \int_set:Ne \l__weiqi_x_direction_int { 0 - \l__weiqi_x_direction_int } + \int_set:Ne \l__weiqi_y_direction_int { 0 - \l__weiqi_y_direction_int } + } + { 270 } + { + \bool_set_inverse:N \l__weiqi_swap_xy_bool + \int_set:Ne \l_tmpb_int { \l__weiqi_x_direction_int } + \int_set:Ne \l__weiqi_x_direction_int { 0 - \l__weiqi_y_direction_int } + \int_set:Ne \l__weiqi_y_direction_int { \l_tmpb_int } + } + } + \IfBooleanT{ #1 } + { + \bool_gset_eq:NN \g__weiqi_swap_xy_bool \l__weiqi_swap_xy_bool + \int_gset_eq:NN \g__weiqi_x_direction_int \l__weiqi_x_direction_int + \int_gset_eq:NN \g__weiqi_y_direction_int \l__weiqi_y_direction_int + } + } +\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__weiqi_x_direction_int { 0 - \l__weiqi_x_direction_int } + } + { y } + { + \int_set:Ne \l__weiqi_y_direction_int { 0 - \l__weiqi_y_direction_int } + } + { xy } + { + \int_set:Ne \l__weiqi_x_direction_int { 0 - \l__weiqi_x_direction_int } + \int_set:Ne \l__weiqi_y_direction_int { 0 - \l__weiqi_y_direction_int } + } + + } + \IfBooleanT{ #1 } + { + \bool_set_eq:NN \g__weiqi_swap_xy_bool \l__weiqi_swap_xy_bool + \int_set_eq:NN \g__weiqi_x_direction_int \l__weiqi_x_direction_int + \int_set_eq:NN \g__weiqi_y_direction_int \l__weiqi_y_direction_int + } + } +\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__weiqi_swap_xy_bool + \int_set:Nn \l__weiqi_x_direction_int { 1 } + \int_set:Nn \l__weiqi_y_direction_int { 1 } + } + { 90 } + { + \bool_set_true:N \l__weiqi_swap_xy_bool + \int_set:Nn \l__weiqi_x_direction_int { 1 } + \int_set:Nn \l__weiqi_y_direction_int { -1 } + } + { 180 } + { + \bool_set_false:N \l__weiqi_swap_xy_bool + \int_set:Nn \l__weiqi_x_direction_int { -1 } + \int_set:Nn \l__weiqi_y_direction_int { -1 } + } + { 270 } + { + \bool_set_true:N \l__weiqi_swap_xy_bool + \int_set:Nn \l__weiqi_x_direction_int { -1 } + \int_set:Nn \l__weiqi_y_direction_int { 1 } + } + } + \IfBooleanT{ #1 } + { + \bool_gset_eq:NN \g__weiqi_swap_xy_bool \l__weiqi_swap_xy_bool + \int_gset_eq:NN \g__weiqi_x_direction_int \l__weiqi_x_direction_int + \int_gset_eq:NN \g__weiqi_y_direction_int \l__weiqi_y_direction_int + } + } +\NewDocumentCommand \weiqiscale { s o } + { + \IfNoValueTF { #2 } + { \fp_set:Nn \l__weiqi_scale_fp { 1.0 } } + { \fp_set:Nn \l__weiqi_scale_fp { #2 * \l__weiqi_scale_fp } } + \IfBooleanT{ #1 } + { \fp_set_eq:NN \g__weiqi_scale_fp \l__weiqi_scale_fp } + } +\NewDocumentCommand \weiqiminsize { s m m } + { + \int_set:Nn \l__weiqi_min_width_int { #2 } + \int_set:Nn \l__weiqi_min_hight_int { #3 } + \IfBooleanT{ #1 } + { + \int_gset:Nn \g__weiqi_min_width_int { #2 } + \int_gset:Nn \g__weiqi_min_hight_int { #3 } + } + } +\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__weiqi_size_int_\l_tmpa_str } + { + \int_new:c { g__weiqi_size_int_\l_tmpa_str } + \int_new:c { g__weiqi_step_count_int_\l_tmpa_str } + \intarray_new:cn { g__weiqi_x_intarray_\l_tmpa_str } + { \c__weiqi_max_step_int } + \intarray_new:cn { g__weiqi_y_intarray_\l_tmpa_str } + { \c__weiqi_max_step_int } + \intarray_new:cn { g__weiqi_player_intarray_\l_tmpa_str } + { \c__weiqi_max_step_int } + \seq_new:c { g__weiqi_label_seq_\l_tmpa_str } + \seq_new:c { g__weiqi_die_seq_\l_tmpa_str } + } + \int_gset_eq:cN { g__weiqi_size_int_\l_tmpa_str } \g__weiqi_size_int + \int_gset_eq:cN + { g__weiqi_step_count_int_\l_tmpa_str } \g__weiqi_step_count_int + \int_step_inline:nn { \c__weiqi_max_step_int } + { + \intarray_gset:cnn { g__weiqi_x_intarray_\l_tmpa_str } { ##1 } + { \intarray_item:Nn \g__weiqi_x_intarray { ##1 } } + \intarray_gset:cnn { g__weiqi_y_intarray_\l_tmpa_str } { ##1 } + { \intarray_item:Nn \g__weiqi_y_intarray { ##1 } } + \intarray_gset:cnn { g__weiqi_player_intarray_\l_tmpa_str } { ##1 } + { \intarray_item:Nn \g__weiqi_player_intarray { ##1 } } + } + \clist_gset_eq:cN { g__weiqi_label_seq_\l_tmpa_str } \g__weiqi_label_seq + \clist_gset_eq:cN { g__weiqi_die_seq_\l_tmpa_str } \g__weiqi_die_seq + } +\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__weiqi_size_int_\l_tmpa_str } + { \__weiqi_new_game:n { \g__weiqi_default_size_int } } + { + \int_set_eq:Nc \l_tmpa_int { g__weiqi_size_int_\l_tmpa_str } + \__weiqi_new_game:n { \l_tmpa_int } + \int_gset_eq:Nc \g__weiqi_step_count_int + { g__weiqi_step_count_int_\l_tmpa_str } + \int_step_inline:nn { \c__weiqi_max_step_int } + { + \intarray_gset:Nnn \g__weiqi_x_intarray { ##1 } + { \intarray_item:cn { g__weiqi_x_intarray_\l_tmpa_str } { ##1 } } + \intarray_gset:Nnn \g__weiqi_y_intarray { ##1 } + { \intarray_item:cn { g__weiqi_y_intarray_\l_tmpa_str } { ##1 } } + \intarray_gset:Nnn \g__weiqi_player_intarray { ##1 } + { + \intarray_item:cn + { g__weiqi_player_intarray_\l_tmpa_str } { ##1 } + } + } + \clist_set_eq:Nc \g__weiqi_label_seq { g__weiqi_label_seq_\l_tmpa_str } + \clist_set_eq:Nc \g__weiqi_die_seq { g__weiqi_die_seq_\l_tmpa_str } + } + \IfBooleanT{ #1 } + { + \__weiqi_clear_labels: + \int_step_inline:nn { \g__weiqi_step_count_int } + { + \seq_gset_item:Nnn \g__weiqi_label_seq { ##1 } {} + } + } + } +\NewDocumentCommand \weiqidata { s } + { + \noindent 棋盘大小:\int_use:N \g__weiqi_size_int~ + (默认:\int_use:N \g__weiqi_default_size_int)\\ + 当前对局步数:\int_use:N \g__weiqi_step_count_int~(含纯标签及移除棋子)\\ + \int_compare:nNnT { \g__weiqi_step_count_int } > { 0 } + { 序号:($x$,~$y$),所属方,标签,备注\\ } + \int_step_inline:nn {\g__weiqi_step_count_int} + { + \int_set:Ne \l__weiqi_x_int + { \intarray_item:Nn \g__weiqi_x_intarray { ##1 } } + \int_set:Ne \l__weiqi_y_int + { \intarray_item:Nn \g__weiqi_y_intarray { ##1 } } + \int_set:Ne \l__weiqi_player_int + { \intarray_item:Nn \g__weiqi_player_intarray { ##1 } } + \str_set:Nx \l__weiqi_tmp_str + { \seq_item:Nn \g__weiqi_label_seq { ##1 } } + ##1: + (\int_use:N \l__weiqi_x_int,~\int_use:N \l__weiqi_y_int), + \int_case:nn { \l__weiqi_player_int } + { + { 1 } { B } + { 2 } { W } + { 3 } { L } + { 0 } { - } + }, + \str_if_empty:NTF \l__weiqi_tmp_str + { \meta{空} } + { \l__weiqi_tmp_str }, + \int_compare:nNnTF + { \l__weiqi_player_int } = { 0 } + { \meta{无效} } + { + \seq_if_in:NnT \g__weiqi_die_seq { ##1 } + { \meta{死子} } + { + \int_compare:nNnT + { \l__weiqi_x_int } = { 0 } + { \meta{虚着} } + } + }\\ + } + 红色指示点: + \clist_if_empty:NTF \g__weiqi_red_point_clist + { \meta{空} } + { \clist_use:Nn \g__weiqi_red_point_clist {,~} }\\ + 绿色指示点: + \clist_if_empty:NTF \g__weiqi_green_point_clist + { \meta{空} } + { \clist_use:Nn \g__weiqi_green_point_clist {,~} }\\ + 蓝色指示点: + \clist_if_empty:NTF \g__weiqi_blue_point_clist + { \meta{空} } + { \clist_use:Nn \g__weiqi_blue_point_clist {,~} }\\ + 方位信息: + \int_use:N \l__weiqi_x_direction_int,~ + \int_use:N \l__weiqi_x_direction_int,~ + \bool_to_str:N \l__weiqi_swap_xy_bool;~ + (全局: + \int_use:N \g__weiqi_x_direction_int,~ + \int_use:N \g__weiqi_x_direction_int,~ + \bool_to_str:N \g__weiqi_swap_xy_bool + )\\ + 缩放比例:\fp_use:N \l__weiqi_scale_fp~ + (全局:\fp_use:N \g__weiqi_scale_fp)\\ + 坐标刻度:\l__weiqi_loc_mode_str,~\bool_to_str:N \l__weiqi_show_loc_bool + (全局:\g__weiqi_loc_mode_str,~\bool_to_str:N \g__weiqi_show_loc_bool)\\ + 最小显示尺寸: + \int_use:N \l__weiqi_min_width_int,~ + \int_use:N \l__weiqi_min_hight_int~ + (全局: + \int_use:N \g__weiqi_min_width_int,~ + \int_use:N \g__weiqi_min_hight_int + )\\ + \IfBooleanT{ #1 } + { + 棋子区间: + (\int_use:N \l__weiqi_x_min_int,~\int_use:N \l__weiqi_y_max_int), + (\int_use:N \l__weiqi_x_max_int,~\int_use:N \l__weiqi_y_min_int)\\ + 棋盘边界: + (\fp_use:N \l__weiqi_x_min_fp,~\fp_use:N \l__weiqi_x_max_fp), + (\fp_use:N \l__weiqi_y_min_fp,~\fp_use:N \l__weiqi_y_max_fp)\\ + 是否边路: + \bool_to_str:N \l__weiqi_up_bool, + \bool_to_str:N \l__weiqi_down_bool, + \bool_to_str:N \l__weiqi_left_bool, + \bool_to_str:N \l__weiqi_right_bool(上下左右)\\ + } + } +\newweiqi +\ExplSyntaxOff +\endinput +%% +%% End of file `weiqi.sty'. diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index dbfb63ce013..3be26e7c2ba 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -911,7 +911,7 @@ my @TLP_working = qw( voss-mathcol vpe vruler vtable vwcol wadalab wallcalendar wallpaper wargame warning warpcol - was wasy wasy-type1 wasysym webguide webquiz wheelchart + was wasy wasy-type1 wasysym webguide webquiz weiqi wheelchart widetable widows-and-orphans williams willowtreebook windycity withargs witharrows wnri wnri-latex wordcloud wordcount wordle wordlike worldflags worksheet diff --git a/Master/tlpkg/tlpsrc/collection-games.tlpsrc b/Master/tlpkg/tlpsrc/collection-games.tlpsrc index 16d23109c81..39fb62c5204 100644 --- a/Master/tlpkg/tlpsrc/collection-games.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-games.tlpsrc @@ -55,6 +55,7 @@ depend thematicpuzzle depend trivialpursuit depend twoxtwogame depend wargame +depend weiqi depend wordle depend xq depend xskak diff --git a/Master/tlpkg/tlpsrc/weiqi.tlpsrc b/Master/tlpkg/tlpsrc/weiqi.tlpsrc new file mode 100644 index 00000000000..e69de29bb2d -- cgit v1.2.3