我正在尝试自动生成一系列 BINGO 卡。因此,我需要一个 5 x 5 的表格,其中有允许文本换行的方形单元格。我还想从 30 个不同单词的“库”中为每个单元格随机分配一个单词,当然,我需要将中心单元格标记为“FREE”。这意味着对于每张卡,库中的 6 个单词将不会被使用。我知道这可以通过 tikz 和一些宏来实现,但我不熟悉随机选择单词所需的宏,而且我在网上找不到足够的帮助。有人可以帮忙吗?
谢谢!
- 我基本上已经解决了我自己的问题;然而,我仍然有一个主要问题,正如 MWE 之后所述:
\documentclass[10pt]{article}
\usepackage{xstring}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand*{\random}[5]{%
\pgfmathparse{random(5)}%
\ifcase\pgfmathresult\relax
\or#1\or#2\or#3\or#4\or#5
\fi%
}
\newcommand*{\randomtwo}[6]{
\pgfmathparse{random(6)}
\ifcase\pgfmathresult\relax
\or#1\or#2\or#3\or#4\or#5\or#6
\fi%
}
\newcommand*{\randomthree}[6]{
\pgfmathparse{random(6)}
\ifcase\pgfmathresult\relax
\or#1\or#2\or#3\or#4\or#5\or#6
\fi%
}
\newcommand*{\randomfour}[6]{
\pgfmathparse{random(6)}
\ifcase\pgfmathresult\relax
\or#1\or#2\or#3\or#4\or#5\or#6
\fi%
}
\newcommand*{\randomfive}[6]{
\pgfmathparse{random(6)}
\ifcase\pgfmathresult\relax
\or#1\or#2\or#3\or#4\or#5\or#6
\fi%
}
\newcommand*{\randomsix}[6]{
\pgfmathparse{random(6)}
\ifcase\pgfmathresult\relax
\or#1\or#2\or#3\or#4\or#5\or#6
\fi%
}
\def\NumOfColumns{5}%
\def\Sequence{1, 2, 3, 4, 5}%
\newcommand{\Size}{3.25cm}
\tikzset{Square/.style={
inner sep=0pt,
text width=\Size,
minimum size=\Size,
draw=black,
align=center,
}
}
\begin{document}
\begin{tikzpicture}[draw=black, thick, x=\Size,y=\Size]
\foreach \row in \Sequence{%
\foreach \col in \Sequence {%
\pgfmathtruncatemacro{\value}{\col+\NumOfColumns*(\row-1)}
\def\NodeText{\random{\randomtwo{radioactivity}{$\alpha$ particle}{$\gamma$-ray}{in--situ leaching}{half--life, $t_{\frac{1}{2}}$}{GM counter}}{\randomthree{Manhattan Project}{$3-5$ \%}{$^{232}$Th}{breeder}{greenhouse gas}{ICP--MS}}{\randomfour{NRC}{conversion}{solid}{Rocky Flats}{smoke detector}{Trinity}}{\randomfive{START}{Yucca Mountain}{Chart of the Nuclides}{Chernobyl}{Savannah River Site}{Hanford Site}}{\randomsix{PUREX}{UO$_2$}{Y--12}{Bq}{LSC}{gaseous diffusion}}}
\pgfmathsetmacro{\ColRowProduce}{\col*\row}
\IfEq{\ColRowProduce}{9}{% If is center square
\node [] at ($(\col,-\row)-(0.5,0.5)$) {FREE};
}{
\node [Square] at ($(\col,-\row)-(0.5,0.5)$) {\large \NodeText};
}
}
}
\end{tikzpicture}
\end{document}
最大的问题是我的 BINGO 卡上出现了重复的单词。我可以设置一个循环来防止这种情况吗?此外,如果有人有办法清理此代码,我将不胜感激。
答案1
这是可行的方法。但我不确定它的效率。下面的代码从用户输入的项目列表中选择随机项目,并从这些项目构建一个随机的 24 个项目序列(25 个减去中心方块),没有重复项。\NodeText
调用时,会从随机列表中删除一个项目并放置在节点中。如果提供的项目太少(即少于 24 个),并且可以提供的项目数量没有上限,则会发出错误。对于您想要生成的每张新宾果卡,只需调用\setItems
并重新生成一张卡。欢迎对代码提出评论/建议改进!
\documentclass[10pt]{article}
\usepackage{xstring}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xparse}
\input{random.tex}
\newcount\randomnum
\ExplSyntaxOn
\seq_new:N \g_my_items_seq
\seq_new:N \l_my_tmp_items_seq
\seq_new:N \g_my_randomized_seq
\int_new:N \l_tmp_int
\msg_new:nnnn {bingo} {Too~few~items!} {Provide~at~least~24~items!}{}
\cs_generate_variant:Nn \seq_item:Nn {Nx}
\cs_generate_variant:Nn \seq_remove_all:Nn {Nx}
\NewDocumentCommand {\myItems} {m}
{
\seq_clear:N \g_my_items_seq % clear item list
\seq_gset_split:Nnn \g_my_items_seq {;} {#1} % put item list in seq
\int_compare:nNnT {\seq_count:N \g_my_items_seq} < {24} {\msg_error:nn {bingo} {Too~few~items!}} % check whether there are enough items
}
\NewDocumentCommand{\setItems}{}
{
\seq_set_eq:NN \l_my_tmp_items_seq \g_my_items_seq % put in temp seq so that multiple cards can be produced
\prg_replicate:nn {24} %generate random list of 24 items
{
\int_set:Nn \l_tmp_int {\seq_count:N \l_my_tmp_items_seq}% set current length of list
\setrannum{\randomnum}{1}{\int_use:N \l_tmp_int} % choose random num up to length of seq
\seq_put_right:Nx \g_my_randomized_seq {\seq_item:Nn \l_my_tmp_items_seq {\the\randomnum}}% grab corresponding item and put in tmp seq
\seq_remove_all:Nx \l_my_tmp_items_seq {\seq_item:Nn \l_my_tmp_items_seq {\the\randomnum}}%delete that item from temp seq
}
\seq_clear:N \l_my_tmp_items_seq %clear temp seq when done
}
\NewDocumentCommand {\NodeText}{}
{
\seq_gpop_right:NN \g_my_randomized_seq \l_tmpa_tl %pop item from randomized seq into token list
\tl_use:N \l_tmpa_tl %use that item.
}
\ExplSyntaxOff
\def\NumOfColumns{5}%
\def\Sequence{1, 2, 3, 4, 5}%
\newcommand{\Size}{3.25cm}
\tikzset{Square/.style={
inner sep=0pt,
text width=\Size,
minimum size=\Size,
draw=black,
align=center,
}
}
\begin{document}
%\myItems{this;will;produce;an;error;because;there;aren't;enough;items}
\myItems{radioactivity;$\alpha$ particle;$\gamma$-ray;in--situ leaching;half--life, $t_{\frac{1}{2}}$;GM counter;Manhattan Project;$3-5$ \%;$^{232}$Th;breeder;greenhouse gas;ICP--MS;conversion;solid;Rocky Flats;smoke detector;Trinity;START;Yucca Mountain;Chart of Nuclides;Chernobyl;Savannah River Site;Hanford Site;PUREX;UO$_2$;Y--12;Bq;LSC;gaseous diffusion}
\setItems
\begin{tikzpicture}[draw=black, thick, x=\Size,y=\Size]
\foreach \row in \Sequence{%
\foreach \col in \Sequence {%
\pgfmathtruncatemacro{\value}{\col+\NumOfColumns*(\row-1)}
\pgfmathsetmacro{\ColRowProduce}{\col*\row}
\IfEq{\ColRowProduce}{9}{% If is center square
\node [] at ($(\col,-\row)-(0.5,0.5)$) {FREE};
}{
\node [Square] at ($(\col,-\row)-(0.5,0.5)$) {\large \NodeText};
}
}
}
\end{tikzpicture}
\setItems
\begin{tikzpicture}[draw=black, thick, x=\Size,y=\Size]
\foreach \row in \Sequence{%
\foreach \col in \Sequence {%
\pgfmathtruncatemacro{\value}{\col+\NumOfColumns*(\row-1)}
\pgfmathsetmacro{\ColRowProduce}{\col*\row}
\IfEq{\ColRowProduce}{9}{% If is center square
\node [] at ($(\col,-\row)-(0.5,0.5)$) {FREE};
}{
\node [Square] at ($(\col,-\row)-(0.5,0.5)$) {\large \NodeText};
}
}
}
\end{tikzpicture}
\end{document}
答案2
这是我使用 的版本arrayjobx
。首先,指定一个包含 30 个单词的列表。在每次迭代中,从长度递减的列表中选择一个单词,然后用列表中的最后一个单词替换所选单词。
\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usepackage{arrayjobx}
\usepackage{xifthen}
\usepackage{trimspaces}
\makeatletter
\def\trimspace#1{\trim@spaces@in{#1}}
\makeatother
\newarray\randomwords
\readarray{randomwords}{%
Mouse & Philanthropy & Ember & Vermillion & Saber &
Tumor & Cook & Lick & Money & Superfluous &
Quiz & Thesis & Dent & Head & Drum &
Light & Key & Purple & Million & Retro &
Loud & Gear & Hijack & Trophy & Long &
Shotgun & Asphalt & Scripture & Pollution & Crack}
\newcommand{\bingofield}{}
\newcommand{\replacementword}{}
\begin{document}
\begin{tikzpicture}
\foreach \x in {1,...,5}
{ \foreach \y in {1,...,5}
\pgfmathtruncatemacro{\fieldnumber}{25-5*\y+\x}
\ifthenelse{\fieldnumber=13}{\xdef\bingofield{BINGO}}{}
\ifthenelse{\fieldnumber<13 \OR \fieldnumber>13}%
{ \pgfmathtruncatemacro{\maxvalue}{30+1-\fieldnumber}
\pgfmathtruncatemacro{\myrandom}{random(\maxvalue)}
\checkrandomwords(\myrandom)\trimspace\cachedata
\xdef\bingofield{\cachedata}
\checkrandomwords(\maxvalue)\trimspace\cachedata
\xdef\replacementword{\cachedata}
\randomwords(\myrandom)={\replacementword}
}{}
\node[above right,text width=1.7cm,minimum width=2cm,minimum height=2cm,draw,align=center] at (\x*2,\y*2) {\tiny \bingofield};
}
\end{tikzpicture}
\end{document}
@MichaelA:我会做得更好。由于之前的版本显然不起作用(所有单词都不同完全是偶然的,但不能保证),我完全重写了它。只需cellsize
根据自己的喜好更改即可。您还可以通过调整来创建更大的网格(例如 7x7)gridsize
。
代码
\documentclass[tikz,border=2mm]{standalone}
\usepackage{xifthen}
\usepackage{xstring}
\newcommand{\randomwords}{%
;Mouse;Philanthropy;Ember;Vermillion;Saber;Tumor;Cook%
;Lick;Money;Superfluous;Quiz;Thesis;Dent;Head;Drum;Light%
;Key;Purple;Million;Retro;Loud;Gear;Hijack;Trophy;Long%
;Shotgun;Asphalt;Scripture;Pollution;Crack;}
\pgfmathsetmacro{\cellsize}{3.3}
\pgfmathtruncatemacro{\gridsize}{5}
\pgfmathtruncatemacro{\fieldcount}{\gridsize*\gridsize-1}
\pgfmathtruncatemacro{\bingo}{\fieldcount/2}
\StrCount{\randomwords}{;}[\numwords]
\begin{document}
\begin{tikzpicture}
\foreach \f in {0,...,\fieldcount}
{ \pgfmathtruncatemacro{\x}{mod(\f,\gridsize)}
\pgfmathtruncatemacro{\y}{div(\f,\gridsize)}
\draw ({\x*\cellsize},{\y*\cellsize}) rectangle ({(\x+1)*\cellsize},{(\y+1)*\cellsize});
\ifthenelse{\f=\bingo}
{ \node at ({(\x+0.5)*\cellsize},{(\y+0.5)*\cellsize}) {BINGO!};
}
{ \pgfmathtruncatemacro{\maxvalue}{\numwords-1-\f)}
\pgfmathtruncatemacro{\myrandom}{random(\maxvalue)}
\pgfmathtruncatemacro{\mynextrandom}{\myrandom+1}
\StrBetween[\myrandom,\mynextrandom]{\randomwords}{;}{;}[\randomword]
\StrDel{\randomwords}{\randomword;}[\randomwords]
\xdef\randomwords{\randomwords}
%\node at ({(\x+0.5)*\cellsize},{(\y+0.5)*\cellsize}) {\myrandom-\maxvalue-\randomword};
\node at ({(\x+0.5)*\cellsize},{(\y+0.5)*\cellsize}) {\randomword};
}
}
\end{tikzpicture}
\end{document}
输出
只是为了好玩,我添加了一些行和列标题,现在你可以将它用作手动随机单词生成器或作为你的老式冒险游戏的“复制保护”。我还添加了一些颜色。
代码
\documentclass[tikz,border=2mm]{standalone}
\usepackage{xifthen}
\usepackage{xstring}
\newcommand{\randomwords}{%
;lavish;cheap;swift;fence;hospital;society;condemned;summer;teeny-tiny;scary;door;broad;wheel;second%
;merciful;return;prevent;enormous;loud;neighborly;crown;proud;open;fearless;trap;grape;run;overflow%
;clumsy;land;bare;beef;icky;turkey;strange;lace;listen;spade;size;sweltering;basket;rabbits;search%
;sleepy;guarantee;large;pot;mass;paint;admit;calendar;kind;hammer;bruise;ticket;cuddly;ocean%
;psychotic;connection;carpenter;sack;spurious;coil;imagine;laugh;riddle;muddled;juice;army;berserk%
;true;slimy;incandescent;hose;nippy;unhealthy;side;rice;lick;public;need;snatch;pear;aspiring;back%
;oil;filthy;stale;authority;round;succeed;cattle;snake;expert;sail;aback;whisper;powerful;charming%
;handsome;rifle;profit;longing;division;needless;saw;nonchalant;nauseating;cloth;fax;suggest;copy%
;chop;capable;cough;gullible;simple;test;children;race;business;}
\pgfmathsetmacro{\cellsize}{2}
\pgfmathtruncatemacro{\gridsize}{11}
\pgfmathtruncatemacro{\fieldcount}{\gridsize*\gridsize-1}
\pgfmathtruncatemacro{\bingo}{\fieldcount/2}
\StrCount{\randomwords}{;}[\numwords]
\newcounter{myletter}
\pgfmathtruncatemacro{\minusgrid}{\gridsize-1}
\begin{document}
\begin{tikzpicture}
\foreach \f in {0,...,\fieldcount}
{ \pgfmathtruncatemacro{\x}{mod(\f,\gridsize)}
\pgfmathtruncatemacro{\y}{div(\f,\gridsize)}
\pgfmathtruncatemacro{\mycolor}{mod(\f,2)*100}
\draw[fill=yellow!\mycolor!red!10] ({\x*\cellsize},{\y*\cellsize}) rectangle ({(\x+1)*\cellsize},{(\y+1)*\cellsize});
\ifthenelse{\f=\bingo}
{ \node[rotate=45] at ({(\x+0.5)*\cellsize},{(\y+0.5)*\cellsize}) {BINGO!};
}
{ \pgfmathtruncatemacro{\maxvalue}{\numwords-1-\f)}
\pgfmathtruncatemacro{\myrandom}{random(\maxvalue)}
\pgfmathtruncatemacro{\mynextrandom}{\myrandom+1}
\StrBetween[\myrandom,\mynextrandom]{\randomwords}{;}{;}[\randomword]
\StrDel{\randomwords}{\randomword;}[\randomwords]
\xdef\randomwords{\randomwords}
%\node at ({(\x+0.5)*\cellsize},{(\y+0.5)*\cellsize}) {\myrandom-\maxvalue-\randomword};
\node[rotate=45] at ({(\x+0.5)*\cellsize},{(\y+0.5)*\cellsize}) {\randomword};
}
\ifthenelse{\x=0}
{ \draw[fill=blue!10] ({\x*\cellsize},{\y*\cellsize}) rectangle ({(\x-0.5)*\cellsize},{(\y+1)*\cellsize});
\node at ({(\x-0.25)*\cellsize},{(\y+0.5)*\cellsize}) {\pgfmathparse{int(\gridsize-\y)}\pgfmathresult};
}{}
\ifthenelse{\y=\minusgrid}
{ \draw[fill=blue!10] ({\x*\cellsize},{(\y+1)*\cellsize}) rectangle ({(\x+1)*\cellsize},{(\y+1.5)*\cellsize});
\pgfmathparse{int(\x+1)}
\setcounter{myletter}{\pgfmathresult}
\node at ({(\x+0.5)*\cellsize},{(\y+1.25)*\cellsize}) {\Alph{myletter}};
}{}
}
\end{tikzpicture}
\end{document}