我正在尝试生成 BINGO 卡,但卡上的所有数字都必须不同。以下是我目前得到的结果:
\documentclass[a4paper]{article}
\usepackage{xstring}
\usepackage{tikz}
\usetikzlibrary{calc}
\def\NumOfColumns{5}%
\def\Sequence{1/A/1/15, 2/B/16/30, 3/C/31/45, 4/D/46/60, 5/E/61/71}%
\newcommand{\Size}{1.5cm}
\tikzset{Square/.style={
inner sep=0pt,
text width=\Size,
minimum size=\Size,
draw=black,
fill=white,
align=center,
}
}
\begin{document}
\begin{tikzpicture}[draw=black, ultra thick, x=\Size,y=\Size]
\node [Square] at ($(0.5,-0.5)-(0,0)$) {\Huge B};
\node [Square] at ($(0.5,-0.5)-(-1.0,0)$) {\Huge I};
\node [Square] at ($(0.5,-0.5)-(-2.0,0)$) {\Huge N};
\node [Square] at ($(0.5,-0.5)-(-3.0,0)$) {\Huge G};
\node [Square] at ($(0.5,-0.5)-(-4.0,0)$) {\Huge O};
\foreach \row/\rowLetter/\MinNumber/\MaxNumber in \Sequence{%
\foreach \col/\colLetter/\MinNumber/\MaxNumber in \Sequence {%
\pgfmathtruncatemacro{\value}{\col+\NumOfColumns*(\row-1)}
\def\NodeText{\pgfmathparse{random(\MinNumber,\MaxNumber)}\pgfmathresult}
\pgfmathsetmacro{\ColRowProduce}{\col*\row}
\IfEq{\ColRowProduce}{9}{% If is center square
\node [Square] at ($(\col,-\row)-(0.5,0.5)$) {\Huge X};
}{
\node [Square] at ($(\col,-\row)-(0.5,0.5)$) {\Huge \NodeText};
}
}
}
\end{tikzpicture}
\end{document}
在此代码中,一列可以有重复的数字。我该如何避免这种情况?
答案1
我曾经定义过\pgfmathrandomitemnorepeat
与数学'\pgfmathdeclarerandomlist
沙\pgfmathrandomitem
。
语法完全相同:首先使用
\pgfmathdeclarerandomlist{⟨list name⟩}{{⟨item-1⟩}{⟨item 2⟩}...}
进而
\pgfmathrandomitemnorepeat{⟨macro⟩}{⟨list name⟩}
\documentclass[a4paper]{article}
\usepackage{xstring}
\usepackage{tikz}
\usetikzlibrary{calc}
\makeatletter
\def\glet{\global\let}
\def\pgfmathrandomitemnorepeat#1#2{%
\pgfmath@ifundefined{pgfmath@randomlist@#2}{\pgfmath@error{Unknown random list `#2'}}{%
\xdef\pgfmath@randomlistlength{\csname pgfmath@randomlist@#2\endcsname}%
\pgfmathrandominteger{\pgfmath@randomtemp}{1}{\pgfmath@randomlistlength}%
\expandafter\glet\expandafter#1\csname pgfmath@randomlist@#2@\pgfmath@randomtemp\endcsname%
\expandafter\glet\expandafter\pgfmathrandomlist@lastitem\csname pgfmath@randomlist@#2@\pgfmath@randomlistlength\endcsname%
\expandafter\glet\csname pgfmath@randomlist@#2@\pgfmath@randomtemp\endcsname\pgfmathrandomlist@lastitem%
\expandafter\pgfmathtruncatemacro\csname pgfmath@randomlist@#2\endcsname{\pgfmath@randomlistlength-1}%
\expandafter\xdef\csname pgfmath@randomlist@#2\endcsname{\csname pgfmath@randomlist@#2\endcsname}%
}}
\pgfmathdeclarerandomlist{1-100}{
{00}{01}{02}{03}{04}{05}{06}{07}{08}{09}
{10}{11}{12}{13}{14}{15}{16}{17}{18}{19}
{20}{21}{22}{23}{24}{25}{26}{27}{28}{29}
{30}{31}{32}{33}{34}{35}{36}{37}{38}{39}
{40}{41}{42}{43}{44}{45}{46}{47}{48}{49}
{50}{51}{52}{53}{54}{55}{56}{57}{58}{59}
{60}{61}{62}{63}{64}{65}{66}{67}{68}{69}
{70}{71}{72}{73}{74}{75}{76}{77}{78}{79}
{80}{81}{82}{83}{84}{85}{86}{87}{88}{89}
{90}{91}{92}{93}{94}{95}{96}{97}{98}{99}
}
\def\NumOfColumns{5}%
\def\Sequence{1/A/1/15, 2/B/16/30, 3/C/31/45, 4/D/46/60, 5/E/61/71}%
\newcommand{\Size}{1.5cm}
\tikzset{Square/.style={
inner sep=0pt,
text width=\Size,
minimum size=\Size,
draw=black,
fill=white,
align=center,
}
}
\begin{document}
\begin{tikzpicture}[draw=black, ultra thick, x=\Size,y=\Size]
\node [Square] at ($(0.5,-0.5)-(0,0)$) {\Huge B};
\node [Square] at ($(0.5,-0.5)-(-1.0,0)$) {\Huge I};
\node [Square] at ($(0.5,-0.5)-(-2.0,0)$) {\Huge N};
\node [Square] at ($(0.5,-0.5)-(-3.0,0)$) {\Huge G};
\node [Square] at ($(0.5,-0.5)-(-4.0,0)$) {\Huge O};
\foreach \row/\rowLetter/\MinNumber/\MaxNumber in \Sequence{%
\foreach \col/\colLetter/\MinNumber/\MaxNumber in \Sequence {%
\pgfmathtruncatemacro{\value}{\col+\NumOfColumns*(\row-1)}
\pgfmathrandomitemnorepeat\NodeText{1-100}
\pgfmathsetmacro{\ColRowProduce}{\col*\row}
\IfEq{\ColRowProduce}{9}{% If is center square
\node [Square] at ($(\col,-\row)-(0.5,0.5)$) {\Huge X};
}{
\node [Square] at ($(\col,-\row)-(0.5,0.5)$) {\Huge \NodeText};
}
}
}
\end{tikzpicture}
\end{document}
答案2
您还可以将已经使用的值存储在列表中,将新值与其进行比较,并获取另一个值(如果它在列表中)。
\documentclass[a4paper]{article}
\usepackage{xstring}
\usepackage{tikz}
\usetikzlibrary{calc}
\def\NumOfColumns{5}%
\def\Sequence{1/A/1/15, 2/B/16/30, 3/C/31/45, 4/D/46/60, 5/E/61/71}%
\newcommand{\Size}{1.5cm}
\tikzset{Square/.style={
inner sep=0pt,
text width=\Size,
minimum size=\Size,
draw=black,
fill=white,
align=center,
}
}
\newif\ifNumberNotUnique
\begin{document}
\begin{tikzpicture}[draw=black, ultra thick, x=\Size,y=\Size]
\node [Square] at ($(0.5,-0.5)-(0,0)$) {\Huge B};
\node [Square] at ($(0.5,-0.5)-(-1.0,0)$) {\Huge I};
\node [Square] at ($(0.5,-0.5)-(-2.0,0)$) {\Huge N};
\node [Square] at ($(0.5,-0.5)-(-3.0,0)$) {\Huge G};
\node [Square] at ($(0.5,-0.5)-(-4.0,0)$) {\Huge O};
% initialize list of used numbers, needs to be global
\xdef\NumbersUsed{0}
\foreach \row/\rowLetter/\MinNumber/\MaxNumber in \Sequence{%
\foreach \col/\colLetter/\MinNumber/\MaxNumber in \Sequence {%
\pgfmathtruncatemacro{\value}{\col+\NumOfColumns*(\row-1)}
% primitive \loop, because a repeat-until is needed
\loop
\pgfmathtruncatemacro{\NodeText}{random(\MinNumber,\MaxNumber)}
% also the \ifNumberNotUnique need to be global
\global\NumberNotUniquefalse
% test all used numbers against new number
\foreach \NewNumber in \NumbersUsed{%
\IfEq{\NewNumber}{\NodeText}{%
\global\NumberNotUniquetrue
}{}%
}
\ifNumberNotUnique
\repeat
% add new number to list
\xdef\NumbersUsed{\NumbersUsed,\NodeText}
\pgfmathsetmacro{\ColRowProduce}{\col*\row}
\IfEq{\ColRowProduce}{9}{% If is center square
\node [Square] at ($(\col,-\row)-(0.5,0.5)$) {\Huge X};
}{
\node [Square] at ($(\col,-\row)-(0.5,0.5)$) {\Huge \NodeText};
}
}
}
\end{tikzpicture}
% for debugging
\NumbersUsed\quad\ifNumberNotUnique Shit\else Ok\fi
\end{document}
\Sequence
(如果对此有任何顾虑的话,此解决方案的另一个优点是,列中的数字保持在给定的范围内。)