我正在尝试为棋盘游戏 (Amazons) 制作打印命令。我指定尺寸和棋盘状态,因此 \AmazonsBoard{3}{3}{WXX---BXX} 将绘制一个小型 3x3 棋盘。有 4 种不同的方块类型,“W、B、-、X”,我想为它们各自绘制一些单独的东西。我有的(精简版)代码是,
\documentclass{article}
\usepackage{tikz}
\usepackage{xstring}
\usepackage{xifthen}
\newcommand{\AmazonsBoard}[3]{
\begin{tikzpicture}
\newcounter{index}
\foreach \x in {1,...,#1}
\foreach \y in {1,...,#2}
{
\setcounter{index}{(\x)+(#2 - \y) * #1};
\draw[draw = black] (\x, \y) rectangle ++(1, 1);
\IfStrEq{W}{\StrChar{#3}{\value{index}}}
{
\draw[color= black](\x + 0.5,\y + 0.5) node{\StrChar{#3}{\value{index}}};
}{}
}
\end{tikzpicture}%
}
\begin{document}
\AmazonsBoard{3}{3}{WXX---BXX}
\end{document}
但这不起作用,因为\IfStrEq{W}{\StrChar{#3}{\value{index}}}
。它没有做我认为它应该做的事情,也就是类似的事情if (#3[index] == "W"){}
。为什么不是这样,我该如何解决这个问题?
答案1
您不能pgfmath
在中使用表达式\setcounter
,但这不是唯一的问题。
由于两个原因,它也\StrChar{#3}{\value{index}
不能使用\IfStrEq
:它不可扩展并且\value{index}
不是字符串,而是一个抽象数字。
这有效:
\documentclass{article}
\usepackage{tikz}
\usepackage{xstring}
\newcommand{\AmazonsBoard}[3]{%
\begin{tikzpicture}
\foreach \x in {1,...,#1}{
\foreach \y in {1,...,#2}{
\pgfmathsetmacro{\tempA}{int((\x)+(#2 - \y) * #1)}
\draw[draw = black] (\x, \y) rectangle ++(1, 1);
\StrChar{#3}{\tempA}[\tempB]
\IfStrEq{W}{\tempB}{%
\draw[color= black](\x + 0.5,\y + 0.5) node{\tempB};%
}{}%
}
}
\end{tikzpicture}%
}
\begin{document}
\AmazonsBoard{3}{3}{WXX-W-BXX}
\end{document}
答案2
您不需要使用一堆条件来检查一个字母W
,X
或者B
您-
可以只定义一些名称中包含该字母的样式,比如说
amazonsBoard/W/.style={fill=red},
amazonsBoard/X/.style={fill=blue!50},
amazonsBoard/B/.style={fill=green},
amazonsBoard/-/.style={fill=gray},
你现在要做的就是
\path[amazonsBoard/\macroThatHasThatLetterStored] …;
% or to be on the safe side
\path[amazonsBoard/\macroThatHasThatLetterStored/.try] …;
(这处理程序.try
意味着 PGFKeys 将尝试该密钥,但如果找不到则不会发出任何抱怨。)
如果你现在接受以下形式的输入
{{W,X,X},{-,-,-},{B,X,X}}
即行列表,其中每行都是自己的列表,您的宏可以定义为
\newcommand{\AmazonsBoard}[2][]{%
\begin{tikzpicture}[#1]
\foreach[count=\rowY] \row in {#2} {
\foreach[count=\colX] \column in \row {
\draw[black, amazonsBoard/\column/.try]
(\colX,\rowY) rectangle node{\column} ++(1, 1);
}
}
\end{tikzpicture}}
与
\AmazonsBoard[
amazonsBoard/W/.style={fill=red},
amazonsBoard/X/.style={fill=blue!50},
amazonsBoard/B/.style={fill=green},
amazonsBoard/-/.style={fill=gray},
]{{W,X,X},{-,-,-},{B,X,X}}
你已经得到了
无需操作字符串。
但你想省去右边的,
部分?
在这里,我定义了一个no separator
键,它自定义了\foreach
列表解析器,以便它只抓取一个标记(即一个字母)并将其用作其元素。(...
当然,语法不再起作用。)
现在你只需要给出列数和一些evaluate
离子
你的\AmazonsBoard
命令可以自行解决其余问题。
代码
\documentclass[tikz]{standalone}
\makeatletter
\pgfkeys{
/pgf/foreach/no separator/.code={% token for token
\def\pgffor@scan@custom##1{\def\pgffor@value{##1}\pgffor@scanned}%
\def\pgffor@scan@custom@comma,{\pgfutil@ifnextchar\pgffor@stop
\pgffor@scanone{\pgffor@scan@custom,}}%
\def\pgffor@scan{\pgfutil@ifnextchar,\pgffor@scan@custom@comma{%
\pgfutil@ifnextchar\pgffor@stop
\pgffor@scanone\pgffor@scan@custom}}}}
\makeatother
\newcommand{\AmazonsBoard}[3][]{%
\begin{tikzpicture}[#1]
\foreach[
count=\i from 0, no separator, % ← !
evaluate=\i as \colX using {mod(\i,#2)},
evaluate=\i as \rowY using {int(\i/#2)}
] \elem in {#3} {
\draw[black, amazonsBoard/\elem/.try]
(\colX,\rowY) rectangle node{\elem} ++(1, 1);}
\end{tikzpicture}}
\begin{document}
\AmazonsBoard[
amazonsBoard/W/.style={fill=red},
amazonsBoard/X/.style={fill=blue!50},
amazonsBoard/B/.style={fill=green},
amazonsBoard/-/.style={fill=gray},
]{3}{WXX---BXX}
\end{document}