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?

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}
  • 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. – Carlos Higa Mar 29 '17 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.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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