diff options
Diffstat (limited to 'macros/latex/contrib/chinesechess')
-rw-r--r-- | macros/latex/contrib/chinesechess/chinesechess.pdf | bin | 4072654 -> 4096186 bytes | |||
-rw-r--r-- | macros/latex/contrib/chinesechess/chinesechess.sty | 539 | ||||
-rw-r--r-- | macros/latex/contrib/chinesechess/chinesechess.tex | 137 |
3 files changed, 445 insertions, 231 deletions
diff --git a/macros/latex/contrib/chinesechess/chinesechess.pdf b/macros/latex/contrib/chinesechess/chinesechess.pdf Binary files differindex 22951bd3db..a965c4fe30 100644 --- a/macros/latex/contrib/chinesechess/chinesechess.pdf +++ b/macros/latex/contrib/chinesechess/chinesechess.pdf diff --git a/macros/latex/contrib/chinesechess/chinesechess.sty b/macros/latex/contrib/chinesechess/chinesechess.sty index 6ddb58b836..2a2db971ed 100644 --- a/macros/latex/contrib/chinesechess/chinesechess.sty +++ b/macros/latex/contrib/chinesechess/chinesechess.sty @@ -19,21 +19,18 @@ %% \NeedsTeXFormat{LaTeX2e}[2020/10/01] \RequirePackage{expl3} -\ProvidesExplPackage{chinesechess}{2022-04-29}{v1.0.0} +\ProvidesExplPackage{chinesechess}{2022-05-06}{v1.1.0} {Typeset Chinese chess with l3draw} \RequirePackage { l3keys2e, l3draw, xparse } -% 保证TeXLive的向下兼容 +% 测量盒子总高度(保证TeXLive的向下兼容) \cs_if_free:NT \box_ht_plus_dp:N { \cs_new_protected:Npn \box_ht_plus_dp:N #1 { \tex_dimexpr:D \box_ht:N #1 + \box_dp:N #1 \scan_stop: } } -% 可以使用>{\SplitArgument{1}{~}}分割参数,如: -% \NewDocumentCommand{\cchessboard}{ s >{\SplitArgument{1}{,}}O{10mm,10mm} } -% % 棋盘排版命令用户接口 % #1 星号命令,是否输出棋子 % #2 棋盘类型、棋子类型等外观选项 @@ -56,10 +53,10 @@ % 棋谱排版命令用户接口 % #1 棋盘类型、棋子类型等外观选项 % #2 棋子位置列表 -% 棋子字母汉字对照表(取xq.sty中的定义) -% K=帅,A=仕,E=相,R=车,C=砲,H=马,P=兵, k=将,a=士,e=象,r=車,c=炮,h=馬,p=卒 -% 水平定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) -% 垂直定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) +% 红棋:K=帅,A=仕,E/B=相,R=车,C=砲,N/H=马,P=兵, +% 黑棋:k=将,a=士,e/b=象,r=車,c=炮,n/h=馬,p=卒 +% 横向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) +% 纵向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) \NewDocumentCommand{\cchessman}{ O{} m } { \group_begin: @@ -75,29 +72,43 @@ % 定义棋子字符常量 \clist_map_inline:nn { - { K } {\__cchess_symbol:n {"5E25} }, % 帥 - { A } {\__cchess_symbol:n {"4ED5} }, % 仕 - { E } {\__cchess_symbol:n {"76F8} }, % 相 - { H } {\__cchess_symbol:n {"9A6C} }, % 马 - { R } {\__cchess_symbol:n {"8F66} }, % 车 - { C } {\__cchess_symbol:n {"7832} }, % 砲 - { P } {\__cchess_symbol:n {"5175} }, % 兵 - { k } {\__cchess_symbol:n {"5C07} }, % 將 - { a } {\__cchess_symbol:n {"58EB} }, % 士 - { e } {\__cchess_symbol:n {"8C61} }, % 象 - { h } {\__cchess_symbol:n {"99AC} }, % 馬 - { r } {\__cchess_symbol:n {"8ECA} }, % 車 - { c } {\__cchess_symbol:n {"70AE} }, % 炮 - { p } {\__cchess_symbol:n {"5352} }, % 卒 + { K } { 帥 }, % 帥\__cchess_symbol:n {"5E25} + { A } { 仕 }, % 仕\__cchess_symbol:n {"4ED5} + { E } { 相 }, % 相\__cchess_symbol:n {"76F8} + { B } { 相 }, % 相\__cchess_symbol:n {"76F8} + { H } { 马 }, % 马\__cchess_symbol:n {"9A6C} + { N } { 马 }, % 马\__cchess_symbol:n {"9A6C} + { R } { 车 }, % 车\__cchess_symbol:n {"8F66} + { C } { 砲 }, % 砲\__cchess_symbol:n {"7832} + { P } { 兵 }, % 兵\__cchess_symbol:n {"5175} + { k } { 將 }, % 將\__cchess_symbol:n {"5C07} + { a } { 士 }, % 士\__cchess_symbol:n {"58EB} + { e } { 象 }, % 象\__cchess_symbol:n {"8C61} + { b } { 象 }, % 象\__cchess_symbol:n {"8C61} + { h } { 馬 }, % 馬\__cchess_symbol:n {"99AC} + { n } { 馬 }, % 馬\__cchess_symbol:n {"99AC} + { r } { 車 }, % 車\__cchess_symbol:n {"8ECA} + { c } { 炮 }, % 炮\__cchess_symbol:n {"70AE} + { p } { 卒 }, % 卒\__cchess_symbol:n {"5352} } { \__cchess_piece_char_setup:nn ##1 } } + +% 棋子字符设置命令 +% #1 棋子编号及字符 +% K=帅,A=仕,B/E=相,R=车,C=砲,N/H=马,P=兵 +% k=将,a=士,b/e=象,r=車,c=炮,n/h=馬,p=卒 +\NewDocumentCommand{\piecechar}{ m m } + { + \__cchess_piece_char_setup:nn { #1 } { #2 } + } + % 打谱环境初始化(仅用于setcchessman环境中) % #1 棋子位置列表 -% 棋子字母汉字对照表(取xq.sty中的定义) -% K=帅,A=仕,E=相,R=车,C=砲,H=马,P=兵, k=将,a=士,e=象,r=車,c=炮,h=馬,p=卒 -% 水平定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) -% 垂直定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) +% 红棋:K=帅,A=仕,E/B=相,R=车,C=砲,N/H=马,P=兵, +% 黑棋:k=将,a=士,e/b=象,r=車,c=炮,n/h=馬,p=卒 +% 横向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) +% 纵向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) \NewDocumentCommand{\init}{ m } { % 临时clist @@ -110,20 +121,20 @@ % 打谱环境中的棋子布置命令(仅用于setcchessman环境中) % #1 棋子位置 -% #2 棋子名称(单个英文字母) -% 棋子字母汉字对照表(取xq.sty中的定义) -% K=帅,A=仕,E=相,R=车,C=砲,H=马,P=兵, k=将,a=士,e=象,r=車,c=炮,h=馬,p=卒 -% 水平定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) -% 垂直定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) +% #2 棋子位置列表 +% 红棋:K=帅,A=仕,E/B=相,R=车,C=砲,N/H=马,P=兵, +% 黑棋:k=将,a=士,e/b=象,r=車,c=炮,n/h=馬,p=卒 +% 横向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) +% 纵向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) \NewDocumentCommand{\set}{ m m } { \__cchess_piece_replace_handle:nn { #1 } { #2 } } % 删除打谱环境中的棋子(仅用于setcchessman环境中) -% #1 棋子位置 -% 水平定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) -% 垂直定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) +% #1 棋子位置列表 +% 横向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) +% 纵向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) \NewDocumentCommand{\del}{ m } { \__cchess_piece_remove_handle:n { #1 } @@ -133,9 +144,10 @@ % #1 棋子名称(单个英文字母) % #2 棋子当前位置 % #3 棋子目的位置 -% K=帅,A=仕,E=相,R=车,C=砲,H=马,P=兵, k=将,a=士,e=象,r=車,c=炮,h=馬,p=卒 -% 水平定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) -% 垂直定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) +% 红棋:K=帅,A=仕,E/B=相,R=车,C=砲,N/H=马,P=兵, +% 黑棋:k=将,a=士,e/b=象,r=車,c=炮,n/h=馬,p=卒 +% 横向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8) +% 纵向定位: a(0),b(1),c(2),d(3),e(4),f(5),g(6),h(7),i(8),j(9) \NewDocumentCommand{\mov}{ m m m } { \__cchess_piece_move_handle:nnn { #1 } { #2 } { #3 } @@ -167,13 +179,37 @@ \group_end: } +% 打谱棋谱输出用户接口 +% #1 每行输出步数 +% #2 棋谱交叉引用label +% 参考雾月的回复:https://ask.latexstudio.net/ask/question/7430.html +\NewDocumentCommand{\printman}{ O{} >{\TrimSpaces} m } % 去掉两侧空格 + { + \group_begin: + \keys_set:nn { cchess } { #1 } + \__cchess_setman_print:n { #2 } + \group_end: + } + +% 棋子输出用户接口 +% #1 棋子字体字号 +% #2 棋子编码 +% 红棋:K=帅,A=仕,E/B=相,R=车,C=砲,N/H=马,P=兵, +% 黑棋:k=将,a=士,e/b=象,r=車,c=炮,n/h=馬,p=卒 +\NewDocumentCommand{\getpiece}{ O{\normalsize} m } + { + \group_begin: + \__cchess_getpiece_handle:nn {#1} { #2 } + \group_end: + } -% ==========棋子字符定义===================== +% ==========棋子字符常量定义===================== % 读取符号 \cs_new:Npn \__cchess_symbol:n #1 { - \tex_char:D #1 - \scan_stop: + #1 + % \tex_char:D #1 + % \scan_stop: } % 棋子符号定义 @@ -233,30 +269,39 @@ % 出于对国际象棋棋手意识习惯的兼容性设计 % 相 B ,也可兼容使用 E, % 马N, 也可兼容使用 H 代替 +% 在此,为兼容性考虑使用B/E同时表示相,使用H/N同时表示马 +% 在使用时,可以任意选择习惯的名称 + % 判断红黑棋子英文单字母名称的正则表达式 \regex_new:N \l__capital_regex -\regex_set:Nn \l__capital_regex { [KAERCHP] } -% 判断棋子英文单字母名称的正则表达式 -\clist_const:Nn \c__cchess_pieces_name_clist { K,A,E,R,C,H,P,k,a,e,r,c,h,p } +\regex_set:Nn \l__capital_regex { [KAEBRCHNP] } + +% 棋子英文单字母名称列表 +\clist_const:Nn \c__cchess_pieces_name_clist { K,A,E,B,R,C,H,N,P,k,a,e,b,r,c,h,n,p } \msg_new:nnn { cchess } { piecename-exists } { The~ piece~ name~ `#1~ not~ exists. } % 定义棋子字符常量 +% 注意相和马分别用两个符号以适配不同习惯 \clist_map_inline:nn { - { K } { "5E25 }, % 帥 - { A } { "4ED5 }, % 仕 - { E } { "76F8 }, % 相 - { H } { "9A6C }, % 马 - { R } { "8F66 }, % 车 - { C } { "7832 }, % 砲 - { P } { "5175 }, % 兵 - { k } { "5C07 }, % 將 - { a } { "58EB }, % 士 - { e } { "8C61 }, % 象 - { h } { "99AC }, % 馬 - { r } { "8ECA }, % 車 - { c } { "70AE }, % 炮 - { p } { "5352 }, % 卒 + { K } { 帥 }, % 帥"5E25 + { A } { 仕 }, % 仕"4ED5 + { E } { 相 }, % 相"76F8 + { B } { 相 }, % 相"76F8 + { H } { 马 }, % 马"9A6C + { N } { 马 }, % 马"9A6C + { R } { 车 }, % 车"8F66 + { C } { 砲 }, % 砲"7832 + { P } { 兵 }, % 兵"5175 + { k } { 將 }, % 將"5C07 + { a } { 士 }, % 士"58EB + { e } { 象 }, % 象"8C61 + { b } { 象 }, % 象"8C61 + { h } { 馬 }, % 馬"99AC + { n } { 馬 }, % 馬"99AC + { r } { 車 }, % 車"8ECA + { c } { 炮 }, % 炮"70AE + { p } { 卒 }, % 卒"5352 } { \__cchess_piece_define:nn #1 } @@ -268,8 +313,8 @@ { #1 } { \use:c { c__cchess_ #1 _tl } } } -% 在棋子编码列表中添加n表示空(null)棋子 -\clist_push:Nn \c__cchess_pieces_name_clist { n } +% 在棋子编码列表中添加z表示空棋子 +\clist_push:Nn \c__cchess_pieces_name_clist { z } % 定义棋子盒子容器 \clist_map_inline:Nn \c__cchess_pieces_name_clist @@ -277,7 +322,7 @@ \coffin_new:c { l__cchess_piece_ #1 _coffin } } % 将空棋子盒子容器置空 -\hcoffin_gset:Nn \l__cchess_piece_n_coffin { \phantom{空} } +\hcoffin_gset:Nn \l__cchess_piece_z_coffin { \phantom{a} } % 棋盘盒子容器 \coffin_new:N \l__cchess_board_coffin @@ -311,11 +356,11 @@ 5 = f, 6 = g, 7 = h, 8 = i, 9 = j } -% 判断是水平方向位置合法性的正则表达式 +% 判断是横向位置合法性的列表 \clist_const:Nn \c__cchess_pos_x_index_clist { a,b,c,d,e,f,g,h,i,0,1,2,3,4,5,6,7,8 } \msg_new:nnn { cchess } { posx-exists } { The~ x~ index~ `#1~ not~ exists. } -% 判断是垂直方向位置合法性的正则表达式 +% 判断是纵向位置合法性的列表 \clist_const:Nn \c__cchess_pos_y_index_clist { a,b,c,d,e,f,g,h,i,j,0,1,2,3,4,5,6,7,8,9 } \msg_new:nnn { cchess } { posy-exists } { The~ y~ index~ `#1~ not~ exists. } @@ -331,20 +376,20 @@ { \coffin_new:c { l__cchess_board_piece_ #1 _ ##1 _coffin } \hcoffin_gset:cn { l__cchess_board_piece_ #1 _ ##1 _coffin } - { \phantom{空} } + { \phantom{a} } } } -\coffin_new:N \l__cchess_board_piece_n_coffin -\hcoffin_gset:Nn \l__cchess_board_piece_n_coffin { \phantom{空} } +\coffin_new:N \l__cchess_board_piece_z_coffin +\hcoffin_gset:Nn \l__cchess_board_piece_z_coffin { \phantom{a} } -% 红方棋盘坐标字母与竖线标位对应关系 +% 红方棋盘坐标字母与红棋竖线标位对应关系 \prop_const_from_keyval:Nn \c__cchess_board_red_x_idx_prop { a = 九, b = 八, c = 七 , d = 六, e = 五, f = 四, g = 三, h = 二, i = 一 } -% 黑方棋盘坐标字母与竖线标位对应关系 +% 黑方棋盘坐标字母与黑棋竖线标位对应关系 \prop_const_from_keyval:Nn \c__cchess_board_black_x_idx_prop { a = 1, b = 2, c = 3 , d = 4, e = 5, @@ -358,7 +403,7 @@ 5 = 五, 6 = 六, 7 = 七, 8 = 八, 9 = 九 } -% 棋谱文字说明列表(如车一进二等) +% 棋谱记录列表(如车一进二等) \clist_new:N \l__cchess_manual_clist % 棋子外框盒子容器 @@ -393,16 +438,21 @@ % 棋子缩放比例 \tl_new:N \l__cchess_piece_scale_tl % 待处理棋子字符 -\tl_new:N \l__cchess_pieces_tl +\tl_new:N \l__cchess_pieces_tl % 棋子字符格式 -\tl_new:N \l__cchess_piece_char_format_tl +\tl_new:N \l__cchess_piece_char_format_tl % 棋盘背景图片名称 -\tl_new:N \l__cchess_board_background_tl +\tl_new:N \l__cchess_board_background_tl % 棋子字符字形类型(实线、虚线等) -\int_new:N \l__cchess_charstroke_type_int +\int_new:N \l__cchess_charstroke_type_int + +% 打谱环境棋谱标签 +\tl_new:N \l__cchess_setman_label_tl +% 打谱结果每行棋谱步数 +\int_new:N \l__cchess_mans_per_line_int % 打谱环境用计数器 -% \int_new:N \c@cchessman +\newcounter{setman} % 增加两个临时int变量 \int_new:N \l_tmpc_int @@ -415,7 +465,8 @@ % 棋子盒子由l3draw实现, -% 棋子外围盒子及缩放设计思路来自zitie宏包(\url{https://www.ctan.org/pkg/zitie})。 +% 棋子外围盒子及缩放设计思路来自zitie宏包 +% (\url{https://www.ctan.org/pkg/zitie})。 % =============颜色处理函数============= % 填充色辅助函数 @@ -448,11 +499,11 @@ \coffin_ht:N #1 + \coffin_dp:N #1 } -% 计算基字符外框大小(外接正方形边长和外接圆半径) +% 计算外框大小(外接正方形边长和外接圆半径) \cs_new:Npn \__cchess_calc_piece_box_size: { - % 设置基字符格式的基字符盒子 - \hbox_set:Nn \l_tmpa_box { 将 } + % 设置计算基础盒子 + \hbox_set:Nn \l_tmpa_box { xx } % 盒子宽度 \dim_set:Nn \l_tmpa_dim @@ -491,31 +542,16 @@ % =============构造棋子函数============= % 字符盒子构造类型函数名称生成函数 -% 名称中6个参数分别表示: -% #1 左下角x坐标 -% #2 左下角y坐标 -% #3 右上角x坐标 -% #4 右上角y坐标 -% #5 x方向缩放比例(扩展保留参数) -% #6 y方向缩放比例(扩展保留参数) +% #1 缩放比例 \cs_new_nopar:Npn \__cchess_piece_box_type:n #1 { __cchess_piece_box_construct_type_ #1 :n } % 字符盒子构造类型函数名称命令生成函数 -% 名称命令中6个参数分别表示: -% #1 左下角x坐标 -% #2 左下角y坐标 -% #3 右上角x坐标 -% #4 右上角y坐标 -% #5 x方向缩放比例(扩展保留参数) -% #6 y方向缩放比例(扩展保留参数) +% #1 缩放比例 \cs_new_nopar:Npn \__cchess_piece_box_type_c:n #1 { - \use:c - { - __cchess_piece_box_construct_type_ #1 :n - } + \use:c { __cchess_piece_box_construct_type_ #1 :n } } % 字符盒子构造类型函数内部生成器函数 @@ -647,25 +683,21 @@ % =============构造棋盘函数============= % 棋盘部件构造函数函数名称生成函数 % 名称中2个参数分别表示: -% #1 x方向缩放比例(暂未使用保留参数) -% #2 y方向缩放比例(暂未使用保留参数) +% #1 x方向缩放比例(暂未使用, 保留参数) +% #2 y方向缩放比例(暂未使用, 保留参数) \cs_new_nopar:Npn \__cchess_board_type:n #1 { __cchess_board_construct_type_ #1 :nn } -% 字符盒子构造类型函数名称命令生成函数 % 名称命令中2个参数分别表示: -% #1 x方向缩放比例(暂未使用保留参数) -% #2 y方向缩放比例(暂未使用保留参数) +% #1 x方向缩放比例(暂未使用, 保留参数) +% #2 y方向缩放比例(暂未使用, 保留参数) \cs_new_nopar:Npn \__cchess_board_type_c:n #1 { - \use:c - { - __cchess_board_construct_type_ #1 :nn - } + \use:c { __cchess_board_construct_type_ #1 :nn } } -% 字符盒子构造类型函数生成器内部函数 +% 棋盘类型函数生成器内部函数 % #1 类型名称 \cs_new:Npn \__cchess_new_board_private_construct:nn #1 { @@ -675,7 +707,7 @@ \cs_generate_variant:Nn \__cchess_new_board_private_construct:nn { V } \cs_generate_variant:Nn \__cchess_new_board_private_construct:nn { x } -% 字符盒子构造类型函数生成器函数 +% 棋盘类型函数生成器函数 % #1 类型名称 \cs_new:Npn \__cchess_new_board_construct:nn #1 { @@ -687,10 +719,10 @@ \cs_generate_variant:Nn \__cchess_new_board_construct:nn { V } \cs_generate_variant:Nn \__cchess_new_board_construct:nn { x } -% 无棋盘 +% 空棋盘 \__cchess_new_board_construct:nn { none } { } -% 半部棋盘 +% 仅格子线半部棋盘 \__cchess_new_board_private_construct:nn { __semiboard } { \draw_scope_begin: @@ -787,7 +819,7 @@ \draw_scope_end: } -% 兵、炮标志 +% 兵、炮标志(半棋盘) \__cchess_new_board_private_construct:nn { __semipos } { \hcoffin_set:Nn \l_tmpa_coffin @@ -867,7 +899,7 @@ \draw_scope_end: } -% 象位线 +% 象位虚线 \__cchess_new_board_private_construct:nn { __elephantcross } { \draw_scope_begin: @@ -910,8 +942,8 @@ \color_select:n { cchessboardlinecolor } - \hcoffin_set:Nn \l_char_tmpa_coffin { 河 } - \hcoffin_set:Nn \l_char_tmpb_coffin { 楚 } + \hcoffin_set:Nn \l_char_tmpa_coffin { 楚 } + \hcoffin_set:Nn \l_char_tmpb_coffin { 河 } \hcoffin_set:Nn \l_char_tmpc_coffin { 漢 } \hcoffin_set:Nn \l_char_tmpd_coffin { 界 } @@ -924,7 +956,7 @@ \coffin_rotate:cn { l_char_tmp ##1 _coffin } { 90 } } - % 测量盒子容器总高度(用内切圆则不需要) + % 测量盒子容器总高度 \dim_set:Nn \l_tmpa_dim { \__cchess_coffin_ht_plus_dp:N \l_char_tmpa_coffin } @@ -933,7 +965,8 @@ \fp_to_dim:n { \fp_eval:n { \gridsize * 0.45 } } } - \clist_map_inline:Nn \l_tmpa_clist + % 缩放盒子容器 + \clist_map_inline:nn { a, b, c, d } { \coffin_scale:cnn { l_char_tmp ##1 _coffin } { @@ -945,17 +978,26 @@ % 排版文字 \draw_scope_begin: - \int_set:Nn \l_tmpa_int { 1 } - \clist_map_inline:Nn \l_tmpa_clist - { - \draw_path_scope_begin: - \draw_transform_shift:n - { \gridsize * \l_tmpa_int, \gridsize * 4.5 } - \draw_coffin_use:cnn { l_char_tmp ##1 _coffin } { hc } { vc } - \draw_path_scope_end: - \int_incr:N \l_tmpa_int - \int_incr:N \l_tmpa_int - } + \draw_path_scope_begin: + \draw_transform_shift:n { \gridsize * 2, \gridsize * 4.5 } + \draw_transform_shift:n { -\gridsize / 2, 0pt } + \draw_coffin_use:cnn { l_char_tmpb_coffin } { hc } { vc } + \draw_path_scope_end: + \draw_path_scope_begin: + \draw_transform_shift:n { \gridsize * 2, \gridsize * 4.5 } + \draw_transform_shift:n { \gridsize / 2, 0pt } + \draw_coffin_use:cnn { l_char_tmpa_coffin } { hc } { vc } + \draw_path_scope_end: + \draw_path_scope_begin: + \draw_transform_shift:n { \gridsize * 6, \gridsize * 4.5 } + \draw_transform_shift:n { -\gridsize / 2, 0pt } + \draw_coffin_use:cnn { l_char_tmpc_coffin } { hc } { vc } + \draw_path_scope_end: + \draw_path_scope_begin: + \draw_transform_shift:n { \gridsize * 6, \gridsize * 4.5 } + \draw_transform_shift:n { \gridsize / 2, 0pt } + \draw_coffin_use:cnn { l_char_tmpd_coffin } { hc } { vc } + \draw_path_scope_end: \draw_scope_end: } @@ -1255,13 +1297,18 @@ % =============棋子文字设置函数============= % 设置棋子的文字 % 红棋编码用大写字母,默认: -% K=帅,A=仕,E=相,R=车,C=砲,H=马,P=兵 +% K=帅,A=仕,E/B=相,R=车,C=砲,H/N=马,P=兵 % 黑棋编码用小字字母,默认: -% k=将,a=士,e=象,r=車,c=炮,h=馬,p=卒 +% k=将,a=士,e/b=象,r=車,c=炮,h/n=馬,p=卒 % #1 棋子编码 % #2 棋子字符 \cs_new_nopar:Npn \__cchess_piece_char_setup:nn #1#2 { + \clist_if_in:NnF \c__cchess_pieces_name_clist { #1 } + { + \msg_error:nnx { cchess } { piecename-exists } { #1 } + } + \prop_gput:Nnn \c__cchess_board_pieces_alph_name_prop { #1 } { #2 } } @@ -1310,21 +1357,10 @@ boardlinecolor .initial:n = black , boardlinecolor* .code:n = { \__cchess_color_select:nnn { cchessboardlinecolor } #1 } , - % 设置棋子字符 - piecechar .code:n = { \__cchess_piece_char_setup:nn #1 }, - piecechar .initial:n = {K}{\c__cchess_K_tl} , - - % 字符格式 - piecefont .code:n = { \tl_set:Nn \l__cchess_piece_char_format_tl {#1} - \__cchess_calc_piece_box_size: - }, + % 棋盘背景图片 + boardbg .tl_set:N = \l__cchess_board_background_tl , + boardbg .initial:n = {} , - % 边框类型 - piecetype .code:n = { \exp_args:NNx \clist_if_in:NnTF - \g__cchess_piece_box_list_clist {#1} - { \tl_set:Nx \l__cchess_piece_box_type_tl {#1} } - { \msg_error:nnx { cchess } { box-exists } {#1} } - }, % 缩放方式 resize .code:n = { \exp_args:NNx \clist_if_in:NnTF \g__cchess_resize_method_clist {#1} @@ -1340,6 +1376,22 @@ width .dim_set:N = \l__cchess_manual_width_dim , height .dim_set:N = \l__cchess_manual_height_dim , + % 设置棋子字符 + piecechar .code:n = { \__cchess_piece_char_setup:nn #1 }, + piecechar .initial:n = {K}{\c__cchess_K_tl} , + + % 字符格式 + piecefont .code:n = { \tl_set:Nn \l__cchess_piece_char_format_tl {#1} + \__cchess_calc_piece_box_size: + }, + + % 边框类型 + piecetype .code:n = { \exp_args:NNx \clist_if_in:NnTF + \g__cchess_piece_box_list_clist {#1} + { \tl_set:Nx \l__cchess_piece_box_type_tl {#1} } + { \msg_error:nnx { cchess } { box-exists } {#1} } + }, + % 字符边框线宽 boxlinewd .dim_set:N = \l__cchess_box_linewidth_dim , boxlinewd .initial:n = 0.4pt , @@ -1434,9 +1486,13 @@ { \int_set_eq:NN \l__cchess_charstroke_type_int \l_keys_choice_int }, charstroke .initial:n = bold, - % 棋盘背景图片 - boardbg .tl_set:N = \l__cchess_board_background_tl , - boardbg .initial:n = {} , + % 打谱环境交叉引用标签 + label .tl_gset:N = \l__cchess_setman_label_tl , + label .initial:n = {} , + + % 每行棋谱步数 + mansperline .tl_gset:N = \l__cchess_mans_per_line_int , + mansperline .initial:n = 2 , unknown .code:n = { \msg_error:nn { cchess } { unknown-option } } } @@ -1448,7 +1504,7 @@ piecefont = \kaishu, piecetype = ooo, boardtype = x+tn, - resize = none, + resize = none, } % 选项设置用户接口 @@ -1491,7 +1547,7 @@ % 缩放棋子盒子容器 \coffin_resize:Nnn \l__cchess_piece_coffin { \piecesize }{ \piecesize } - % 复制结果以备后续使用 + % 保存结果 \coffin_gset_eq:cN { l__cchess_piece_ ##1 _coffin } \l__cchess_piece_coffin } @@ -1531,17 +1587,17 @@ } % =============创建棋子占位coffins============= - % 缩放空白棋子(n---null) -\cs_new:Nn \__cchess_board_piece_n_resize: + % 缩放空白棋子 +\cs_new:Nn \__cchess_board_piece_z_resize: { - \coffin_resize:Nnn \l__cchess_piece_n_coffin { \piecesize } { \piecesize } + \coffin_resize:Nnn \l__cchess_piece_z_coffin { \piecesize } { \piecesize } } -% 执行缩放 -\__cchess_board_piece_n_resize: +% 缩放空白棋子 +\__cchess_board_piece_z_resize: % 将棋子盒子容器布置到棋盘指定位置(用于棋谱和棋盘排版) % #1 棋子参数 -% 棋子参数的形式为{0,0}{k},{0,1}{K},注意需要包含大括号, +% 棋子参数的形式为{{0,0}{k},{0,1}{K}},注意需要包含大括号, % 不同棋子之间用英文逗号分隔 \cs_new:Npn \__cchess_board_piece_pos_construct:n #1 { @@ -1550,7 +1606,7 @@ \draw_begin: % 在四个角布置空白棋子实现占位(用于撑满棋子画布) \clist_set:Nn \l_tmpa_clist - { {0, 0}{n}, {8, 0}{n}, {0, 9}{n}, {8, 9}{n}} + { {0, 0}{z}, {8, 0}{z}, {0, 9}{z}, {8, 9}{z}} \clist_map_inline:Nn \l_tmpa_clist { \__cchess_piece_set_handle:nn ##1 @@ -1575,7 +1631,7 @@ % 如果文件名不为空则载入图片,否则创建一个空盒子容器 \tl_if_empty:NTF \l__cchess_board_background_tl { - \phantom{将} + \phantom{a} }{ \includegraphics{\l__cchess_board_background_tl} } @@ -1670,6 +1726,43 @@ } } +% 在正文中排版棋子 +\cs_new:Npn \__cchess_getpiece_handle:nn #1#2 + { + % 构建红黑各7个棋子 + \__cchess_pieces_construct: + + % 设置指定格式的基字符盒子 + \hbox_set:Nn \l_tmpa_box { #1 将 } + + % 盒子高度 + \dim_set:Nn \l_tmpa_dim + { + \box_ht_plus_dp:N \l_tmpa_box + } + + % 棋子高度 + \dim_set:Nn \l_tmpb_dim + { + \__cchess_coffin_ht_plus_dp:N \l__cchess_piece_K_coffin + } + + % 缩放棋子 + \coffin_scale:cnn { l__cchess_piece_ #2 _coffin } + { + \dim_ratio:nn { \l_tmpa_dim } { \l_tmpb_dim } + }{ + \dim_ratio:nn { \l_tmpa_dim } { \l_tmpb_dim } + } + + % 盒子深度 + \dim_set:Nn \l_tmpb_dim { \box_dp:N \l_tmpa_box } + + % 输出盒子(下沉深度距离) + \coffin_typeset:cnnnn { l__cchess_piece_ #2 _coffin } + { l } { b } { 0pt } { -\l_tmpb_dim } + } + % =============排版棋谱============= % 棋谱排版 \cs_new:Npn \__cchess_manual_output:n #1 @@ -1820,12 +1913,14 @@ } \cs_generate_variant:Nn \__cchess_piece_set:nnn {VV} +% ====================================================== % ===采用棋子替换方式创建棋子画布coffin(用于打谱排版)=== -% 缩放棋子盒子容器 +% ====================================================== +% 缩放占棋子盒子容器 \cs_new:Nn \__cchess_board_pieces_resize: { % 空白棋子 - \coffin_resize:Nnn \l__cchess_board_piece_n_coffin + \coffin_resize:Nnn \l__cchess_board_piece_z_coffin { \piecesize } { \piecesize } % 其它棋子,按行(a-i)列(a-j)编号命名。 @@ -1912,8 +2007,8 @@ } % 棋子占位替换函数 -% #1 x方向数字型坐标值(a-i) -% #2 y方向数字型坐标值(a-j) +% #1 横向字符型坐标值(a-i) +% #2 纵向字符型坐标值(a-j) % #3 棋子名称(单英文字母) \cs_new:Npn \__cchess_piece_replace:nnn #1#2#3 { @@ -1958,14 +2053,14 @@ } % 棋子删除函数 -% #1 x方向数字型坐标值(a-i) -% #2 y方向数字型坐标值(a-j) +% #1 横向字符型坐标值(a-i) +% #2 纵方向字符型坐标值(a-j) % #3 棋子名称(单英文字母) \cs_new:Npn \__cchess_piece_remove:nn #1#2 { \coffin_gset_eq:cN { l__cchess_board_piece_ #1 _ #2 _coffin } - \l__cchess_board_piece_n_coffin + \l__cchess_board_piece_z_coffin } \cs_generate_variant:Nn \__cchess_piece_remove:nn {VV} @@ -2028,10 +2123,10 @@ } % 棋子移动函数 -% #1 原位置x方向数字型坐标值(a-i) -% #2 原位置y方向数字型坐标值(a-j) -% #3 新位置x方向数字型坐标值(a-i) -% #4 新位置y方向数字型坐标值(a-j) +% #1 原位置横向字符型坐标值(a-i) +% #2 原位置纵向字符型坐标值(a-j) +% #3 新位置横向字符型坐标值(a-i) +% #4 新位置纵向字符型坐标值(a-j) % #5 棋子名称(单英文字母) \cs_new:Npn \__cchess_piece_move:nnnnn #1#2#3#4#5 { @@ -2050,14 +2145,14 @@ % 生成打谱棋谱记录 % TODO:暂未实现纵向同类棋子前后判断 -% #1 原位置x方向数字型坐标值(a-i) -% #2 原位置y方向数字型坐标值(a-j) -% #3 新位置x方向数字型坐标值(a-i) -% #4 新位置y方向数字型坐标值(a-j) +% #1 原位置横向字符型坐标值(a-i) +% #2 原位置纵向字符型坐标值(a-j) +% #3 新位置横向字符型坐标值(a-i) +% #4 新位置纵向字符型坐标值(a-j) % #5 棋子名称(单英文字母) \cs_new:Npn \__cchess_piece_manual_str_construct:nnnnn #1#2#3#4#5 { - % 将字母坐标数据转换为整数坐标 + % 将字符坐标数据转换为整数坐标 \prop_get:NnN \c__cchess_board_pos_alph_num_prop { #1 } \l_tmpa_tl \prop_get:NnN \c__cchess_board_pos_alph_num_prop { #2 } \l_tmpb_tl \prop_get:NnN \c__cchess_board_pos_alph_num_prop { #3 } \l_tmpc_tl @@ -2226,6 +2321,11 @@ \tl_use:N \l_tmpa_tl } +% 定义\label命令的变体函数 +%\label { #1 } +\cs_set_eq:NN \__cchess_setman_label:n \label +\cs_generate_variant:Nn \__cchess_setman_label:n { x } + % 打谱环境后处理函数 \cs_new:Nn \__cchess_setcchessman_post_setup: { @@ -2257,36 +2357,27 @@ % 星号环境需要输出打谱记录 \bool_if:NT \l__cchess_with_setman_bool { - % 测量打谱记录盒子水平尺寸 - \hcoffin_set:Nn \l_tmpa_coffin { 车九平八\quad 车九平八} - \dim_set:Nn \l_tmpa_dim { \coffin_wd:N \l_tmpa_coffin } + % 递增计数器 + \refstepcounter{setman} + % 设置label标签 + \__cchess_setman_label:x { \l__cchess_setman_label_tl } - % 构建打谱记录垂直盒子容器 - \vcoffin_set:Nnn \l_tmpa_coffin { \l_tmpa_dim } + % 构造临时文件 + \iow_open:Nn \g_tmpa_iow { - % 遍历打谱记录列表,输出打谱记录 - \bool_until_do:nn { \clist_if_empty_p:N \l__cchess_manual_clist } - { - % 取消首行缩进 - \noindent - \clist_pop:NN \l__cchess_manual_clist \l_tmpa_tl + \c_sys_jobname_str\l__cchess_setman_label_tl\thesetman .man + } - \clist_if_empty:NTF \l__cchess_manual_clist - { - \l_tmpa_tl - }{ - \clist_pop:NN \l__cchess_manual_clist \l_tmpb_tl - \l_tmpa_tl - \quad - \l_tmpb_tl - \par - } - } + % 遍历打谱记录列表,输出打谱记录到临时文件 + \bool_until_do:nn { \clist_if_empty_p:N \l__cchess_manual_clist } + { + \clist_pop:NN \l__cchess_manual_clist \l_tmpa_tl + \tl_set:Nx \l_tmpb_tl {\l_tmpa_tl} + \iow_now:Nx \g_tmpa_iow { \l_tmpb_tl } } - % 拼装打谱记录盒子容器到结果容器 - \coffin_join:NnnNnnnn \l__cchess_manual_coffin - { l } { t } \l_tmpa_coffin { r } { t } { -10pt } { -\piecesize } + % 关闭文件 + \iow_close:N \g_tmpa_iow } % 输出结果盒子容器 @@ -2294,4 +2385,60 @@ { l }{ b } { 0pt } { 0pt } } +% 参考雾月的回复:https://ask.latexstudio.net/ask/question/7430.html +% LaTeX3 并未定义 \use_i:nnnnn +\cs_set:Npn \use_i:nnnnn #1#2#3#4#5 {#1} + +% 打谱棋谱排版描述处理 +\cs_new:Npn \__cchess_setman_print:n #1 + { + % 根据棋谱label构建文件名 + \cs_if_exist:cTF { r@#1 } + { + % 这一步是得到 ref,它保存在 \r@#1 中。 + % \r@#1 有两项,当使用 hyperref 时, + % \r@#1 有 5 项,这里使用 \empty 统一解决 + \tl_set:Nx \l_tmpa_tl + { + \c_sys_jobname_str + #1 \exp_args:NNc \exp_after:wN \use_i:nnnnn { r@ #1 } + \c_empty_tl \c_empty_tl \c_empty_tl .man + } + + % 打开文件读取数据并输出结果 + \ior_open:NnTF \g_tmpb_ior { \l_tmpa_tl } + { + % 循环计数 + \int_set:Nn \l_tmpa_int { 1 } + % 循环读取一行棋谱 + \ior_str_map_variable:NNn \g_tmpb_ior \l_tmpb_str + { + % 转换为token + \tl_set_rescan:Nno \l_tmpb_tl + { + \char_set_catcode_letter:N \_ + \char_set_catcode_letter:N : + }{ \l_tmpb_str } + + % 输出结果 + \tl_use:N \l_tmpb_tl + + % 根据每行步数确定输出\quad或是\par + \int_set:Nn \l_tmpb_int + { + \int_mod:nn { \l_tmpa_int } { \l__cchess_mans_per_line_int } + } + \int_compare:nNnTF { \l_tmpb_int } = { 0 } + { \par } { \quad } + + \int_incr:N \l_tmpa_int + } + } + { \msg_error:nnx { cchess } { file-not-found } { \l_tmpa_tl } } + + % 关闭文件 + \iow_close:N \g_tmpa_ior + }{ \G@refundefinedtrue }% 引用未定义 + } + \endinput diff --git a/macros/latex/contrib/chinesechess/chinesechess.tex b/macros/latex/contrib/chinesechess/chinesechess.tex index 9220174cc8..60404db623 100644 --- a/macros/latex/contrib/chinesechess/chinesechess.tex +++ b/macros/latex/contrib/chinesechess/chinesechess.tex @@ -123,7 +123,7 @@ { \__codedoc_cmd:no {#1} { #2 } } \ExplSyntaxOff -\def\vers{\texttt{v1.0.0} } +\def\vers{\texttt{v1.1.0} } \begin{document} \title{ @@ -150,15 +150,14 @@ \section{引言} -\pkg{chinesechess}是一个基于\pkg{l3draw}用\pkg{Expl3}开发的 -中国象棋排版宏包。它提供了\tn{cchessboard} 全棋盘、 -\tn{cchessbord*}空白棋盘和\tn{cchessman}棋谱排版命令。同时, +\pkg{chinesechess}是一个基于\pkg{l3draw}绘图宏包,用\pkg{Expl3}% +开发的中国象棋排版宏包。它提供了\tn{cchessboard}(全棋盘)、% +\tn{cchessbord*}(空棋盘)和\tn{cchessman}(棋谱)排版命令。同时, 该宏包还提供了用于打谱的排版环境\env{setcchessman},在该环境 -中,可以通过环境专用命令\tn{init}初始化棋谱状态,\tn{set}在 -指定位置布置棋子,\tn{del}删除指定位置的棋子,\tn{mov}实现 -棋子的移动,从而实现打谱操作,并在环境结束后以最终状态排版棋谱。 -另外,也可以通过星号环境\env{setcchessman*}实现棋谱的文本描述 -输出。 +中,可以通过环境专用命令\tn{init}(初始化棋谱状态),\tn{set}(在 +指定位置布置棋子),\tn{del}(删除指定位置的棋子),\tn{mov}(实现 +棋子的移动),从而实现打谱操作,并在环境结束后以最终状态排版棋谱。 +另外,也可以通过星号环境\env{setcchessman*}实现棋谱文本输出。 棋子、棋盘、背景等外观可以通过命令、环境选项或\tn{cchessset}% 命令进行设置。 @@ -226,8 +225,8 @@ 编码 & 红棋 & 编码 & 黑棋\\\hline K & 帥 & k & 將 \\ A & 仕 & a & 士 \\ - E & 相 & e & 象 \\ - H & 马 & h & 馬 \\ + B(E) & 相 & b(e) & 象 \\ + N(H) & 马 & n(h) & 馬 \\ R & 车 & r & 車 \\ C & 炮 & c & 炮 \\ P & 兵 & p & 卒 \\\hline @@ -274,7 +273,9 @@ 指定位置的棋子,\tn{mov}实现棋子的移动,从而实现打谱操作。 在环境结束后以最终打谱状态排版棋谱。 - 星号环境\env{setcchessman*}会同时排版棋谱的文本描述(如:车一进二等)。 + 星号环境\env{setcchessman*}用于记录排版棋谱的文本描述(如:车一进二等)。 + 可在在\env{setcchessman*}环境中用label选项进行标记,然后用\tn{printman}% + 输出该棋谱。 在\oarg{外观选项}中可以通过key-value的方式设置棋子、棋盘的颜色、 字体、字号、线宽等外观。 @@ -302,27 +303,6 @@ \end{setcchessman} \end{SideBySideExample} -\begin{SideBySideExample}[frame=single,numbers=left, - xrightmargin=.45\linewidth,gobble=2] - \centering - % 为便排版,进行缩放 - \cchessset{resize=real, - width=.30\linewidth} - \begin{setcchessman*} - % 残局初始化 - \init{ {{4,0}{K}}, {{2,2}{p}}, - {{1,7}{C}}, {{4,9}{k}} } - % 添加棋子 - \set{e,d}{P} \set{8,g}{h} - % 删除棋子 - \del{4,3} - % 移动棋子 - \mov{C}{b,h}{b,b} \mov{p}{2,2}{3,2} - \mov{K}{4,0}{4,1} \mov{h}{8,6}{6,7} - \mov{K}{4,1}{3,1} \mov{h}{6,7}{5,5} - \end{setcchessman*} -\end{SideBySideExample} - \subsection{打谱专用命令} \subsubsection{\tn{init}棋谱初始化命令} @@ -386,6 +366,52 @@ \textbf{\textsf{注意: }}该命令只能用于\env{setcchessman}环境中。 +\subsection{\tn{printman}输出打谱结果命令} + +\begin{function}{\printman} + \begin{syntax} + \cs{printman} \marg{\env{setcchessman*}环境的label标签} + \end{syntax} +\end{function} + + 输出由label标签指定的\env{setcchessman*}打谱环境生成的棋谱。 + +\subsection{\tn{getpiece}输出棋子命令} + +\begin{function}{\getpiece} + \begin{syntax} + \cs{getpiece} \oarg{棋子字号} \marg{棋子编码} + \end{syntax} +\end{function} + + 按\oarg{棋子字号}指定的字号将用\marg{棋子编码}指定的棋子在当前位置输出。 + + \marg{棋子编码}中的编码详见表表\ref{tab-piececode}。 + +\begin{SideBySideExample}[frame=single,numbers=left, + xrightmargin=.28\linewidth,gobble=2] + \centering + \getpiece{K}\getpiece{A}\getpiece{B}\getpiece{R}% + \getpiece{N}\getpiece{C}\getpiece{P} + + \getpiece{k}\getpiece{a}\getpiece{b}\getpiece{r}% + \getpiece{n}\getpiece{c}\getpiece{p} +\end{SideBySideExample} + +\subsection{\tn{piecechar}棋子字符设置命令} + +\begin{function}{\piecechar} + \begin{syntax} + \cs{piecechar} \marg{棋子编码} \marg{棋子字符} + \end{syntax} +\end{function} + + 用于将\marg{棋子编码}指定的棋子字符设置为指定的\marg{棋子字符}。 + + \marg{棋子编码}中的编码详见表表\ref{tab-piececode}。 + + \textbf{\textsf{说明: }}该功能也可以通过|piecechar|外观选项实现。 + \subsection{\tn{resetpiece}棋子字符复位命令} \begin{function}{\resetpiece} @@ -624,14 +650,14 @@ piecechar={E}{\faChessBishop}, piecechar={H}{\faChessKnight}, piecechar={R}{\faChessRook}, - piecechar={C}{\faBomb}, + piecechar={C}{\faMeteor}, piecechar={P}{\faChessPawn}, piecechar={k}{\faChessQueen}, piecechar={a}{\faShield*}, piecechar={e}{\faChessBishop}, piecechar={h}{\faChessKnight}, piecechar={r}{\faChessRook}, - piecechar={c}{\faBomb}, + piecechar={c}{\faMeteor}, piecechar={p}{\faChessPawn}, boardlinecolor=red] \end{SideBySideExample} @@ -862,6 +888,47 @@ redupper=red,blkupper=black] \end{SideBySideExample} +\bigskip + +\subsection{打谱} + +\subsubsection{label标签} + +\begin{option}{ opt = label, desc = {= \meta{棋谱标签}}, init=init-none } + 设置\env{setcchessman*}打谱环境交叉引用标签。 +\end{option} + +\subsubsection{每行棋谱步数} + +\begin{option}{ opt = mansperline, desc = {= \meta{每行棋谱步数}}, init=2 } + 设置\tn{printman}输出棋谱时,每行输出棋谱的步数。 +\end{option} + +\begin{SideBySideExample}[frame=single,numbers=left, + xrightmargin=.45\linewidth,gobble=2] + \centering + \printman{test} + + \bigskip + + % 为便排版,进行缩放 + \cchessset{resize=real, + width=0.90\linewidth} + \begin{setcchessman*}[label=test] + % 残局初始化 + \init{ {{4,0}{K}}, {{2,2}{p}}, + {{1,7}{C}}, {{4,9}{k}} } + % 添加棋子 + \set{e,d}{P} \set{8,g}{h} + % 删除棋子 + \del{4,3} + % 移动棋子 + \mov{C}{b,h}{b,b} \mov{p}{2,2}{3,2} + \mov{K}{4,0}{4,1} \mov{h}{8,6}{6,7} + \mov{K}{4,1}{3,1} \mov{h}{6,7}{5,5} + \end{setcchessman*} +\end{SideBySideExample} + % \bigskip % \title{ |