3

I am trying to generate BINGO cards where but all the number in the card must be distinct. Here is what I got so far:

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

In this code a column can have repeated numbers. How can I avoid it?

1

2 Answers 2

3

I used to define a \pgfmathrandomitemnorepeat which is compatible with 's \pgfmathdeclarerandomlist and \pgfmathrandomitem.

The syntax is exactly the same: first use

\pgfmathdeclarerandomlist{⟨list name⟩}{{⟨item-1⟩}{⟨item 2⟩}...}

and then

\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}
1
  • I think that this solve the problem of repeated numbers but I'll have to modify it to keep the values of a given column in a predefined range. Thank you for your answer. Mar 29, 2017 at 18:29
1

You can also store the already used values i a list, compare the new value with it and get another one, if it was in the list.

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

(This solution has also the advantage that the numbers in the columns stay within the range given in \Sequence, if this is of any concern.)

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .