Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I am trying to automatically generate a series of BINGO cards. So, I need a 5 x 5 table with square cells that allow text wrapping. I also want to randomly assign a word to each cell from a "bank" of 30 different words, and I need the center cell to, of course, be labeled "FREE". This means that for each card, 6 words from the bank will not be used. I know that this can be accomplished with tikz and some macros, but I am not familiar with the macros needed to randomly select the words, and I am having trouble finding adequate help on the web. Can someone please help?

Thanks!

-- I mostly figured out my own question; however, I still have one major problem as stated after the 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}

The biggest problem is that I get repeat words on my BINGO card. Can I set up a loop to prevent this? Also, if anyone has a way of cleaning up this code, I would be grateful.

share|improve this question
2  
Related Question: A table with square cells. You should use this to get started and get as far as you can; Then post a compilable MWE so that those trying to help have something to start from. –  Peter Grill Jul 15 '12 at 6:32
    
It looks like you only need \random and \randomtwo, randoms 3-6 are the same as \randomtwo. Is there a reason that you've grouped your entries as sets of 6? –  Scott H. Jul 15 '12 at 21:37
    
Yes, as stated in the original question, I need a bank of thirty words to choose from, and \newcommand only takes 9 arguments. I could accomplish the same with fewer \random commands, but it means that there will not be an equal probability of each of the words being selected. In all reality, I need a command that allows random selection between thirty different words, but I don't know of one. –  Shanna Jul 16 '12 at 0:55

2 Answers 2

up vote 9 down vote accepted

Here's something that works. I'm not sure about its efficiency however. The code below selects random items from a user entered list of items and from these builds a randomized sequence of 24 items (25 less the center square) without duplicates. When \NodeText is called, an item is removed from the randomized list and placed in the node. An error is issued when too few items are provided (i.e. less than 24) and there isn't an upper limit on the number of items that can be supplied. For each new bingo card that you want to generate, you just call \setItems and regenerate a card. Comments/suggested improvements on the code are welcomed!

enter image description here

\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}
share|improve this answer
    
Scott -- Thanks so much for your help ... this solution is really really close. I'm not familiar with the code you used in the preamble, so I don't really know where to begin to correct the issues with \setrannum. However, I will work on it. Thanks! –  Shanna Jul 16 '12 at 16:24
    
Hi Shanna, it works now :) –  Scott H. Jul 16 '12 at 16:51
    
This is awesome! -- It works perfectly, thanks so much for your help! –  Shanna Jul 16 '12 at 17:22
    
So I've been looking for something like this for ages! ...the only problem is I can't quite get it to work. I'm under the impression that I'm supposed to replace the "N" with \setrannum with the number of items I want from the sequence, (so I've been changing it to 24), but is there more I'm supposed to adjust before this will finally compile for me? The closest I've gotten is 101 errors. –  aklingensmith Oct 4 '13 at 1:46
    
Hmmm. I've been able to get some success by using an online compiler (writeLaTeX) instead of my normal compiler (TeXnicCenter), but now when it compiles a few of the bingo squares are blank. –  aklingensmith Oct 4 '13 at 2:11

Here's my version using arrayjobx. First you specify a list of thirty words. In each iteration, a word from a list of decreasing length is chosen, then the chosen word is replaced by last word of the list.

\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}

enter image description here

share|improve this answer
    
Hi Tom, I don't know enough about the packages you have used to tell where they're coming from, but there are a couple of duplicates in your table: Dent and Scripture. –  Scott H. Sep 7 '12 at 0:57

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.