6

I am trying to make some math fact equation sheets that are based on random number generation. I have quite a bit of learning to do... but this is where I think should start: Use random numbers to make LaTeX generate a string of equations for me.

Right now, the basic idea is that: I first have \pgfmathsetmacro{\A}{random(1,4)} set \A as 1,2, 3 or 4.

  1. If \A=1, then I want 1+2=3 to appear.
  2. If \A=2, then I want 2+1=3 to appear.
  3. If \A=3, then I want 3=2+1 to appear.
  4. If \A=4, then I want 3=1+2 to appear.

This is what I've got so far, but the nested \ifthen structure seems very inelegant and will basically not scale to when I have, say, 100 different equations to choose from instead of just 4.

What's a better way?

\documentclass{article}

\usepackage{pgf}
\usepackage{pgffor}
\usepackage{ifthen}

\pagestyle{empty}
\setlength{\parindent}{0pt}

% THE FOUR EQUATIONS
% 1.   1+2=3
% 2.   2+1=3
% 3.   3=2+1 
% 4.   3=1+2

\pgfmathsetseed{\number\pdfrandomseed}

\newcommand{\InitVariables}
{\pgfmathsetmacro{\A}{random(1,4)}} 

\newcommand*{\onefact}
{
 \InitVariables
 \ifthenelse
  {\equal{\A}{1}}{1+2=3}
   {
    \ifthenelse{\equal{\A}{2}}{3=2+1}
     {
      \ifthenelse{\equal{\A}{3}}{3=2+1}{3=1+2}
     }
   }
}

\newcommand{\myequations}[1]
{
 \foreach \x in {1,...,#1}
  {\onefact\\}
}

\begin{document}

\myequations{10} 

\end{document}

5 Answers5

8

An ideal usecase for luatex:

\documentclass[margin=1mm, varwidth=true]{standalone}
\usepackage{luacode}

\begin{luacode}
  userdata = userdata or {}

  local questions = {
      "1 + 2 = 3" ,
      "2 + 1 = 3" ,
      "3 = 2 + 1" ,
      "3 = 1 + 2" ,
    }

  function userdata.fact()
    local A = math.random(#questions)
    tex.print(questions[A])
  end
\end{luacode}

\newcommand\Fact{\luadirect{userdata.fact()}}

\begin{document}

\begin{itemize}
  \item $\Fact$ 
  \item $\Fact$ 
  \item $\Fact$ 
  \item $\Fact$ 
  \item $\Fact$
\end{itemize}

\end{document}

which gives

enter image description here

Aditya
  • 62,301
7

If you have 100 different cases, then your code logic is wrong at some point. But for not too many cases you can do \ifcase

\documentclass{article}
\usepackage{pgfmath}

\pgfmathsetseed{\number\pdfrandomseed}
\pgfmathtruncatemacro{\A}{random(1,4)}

\begin{document}

\ifcase\A\relax%
  \or 1+2=3% Because \A starts from 1
  \or 2+1=3%
  \or 3=2+1%
  \or 3=1+2%
\fi

\end{document}
percusse
  • 157,807
  • How does 100 cases imply something is wrong with the code logic? And what does \ifcase\A\relax mean? I can't make sense of it. – WeCanLearnAnything Sep 19 '16 at 22:26
  • @WeCanLearnAnything It means that you are doing a lookup so it shouldn't be a if or switch it should get the index and pick it up from some array/table/database whatever. It shouldn't list all the possibilities inline. – percusse Sep 19 '16 at 22:32
  • \ifcase works with integers. \A\relax means roughly after finishing \A stop looking for more numbers from this point and carry on with the code. – percusse Sep 19 '16 at 22:32
  • Hmm. How would I enter that array/table/database into LaTeX? Does that have to be a separate document or separate file?? – WeCanLearnAnything Sep 19 '16 at 22:37
  • search for datatools or pgfplotstable on this site – percusse Sep 19 '16 at 22:44
  • Ok, I'll look those up. – WeCanLearnAnything Sep 19 '16 at 23:03
  • Where should I go to learn about making and using an "array/table/database"? There are a lot of math facts my kids need to learn and so I need to organize and categorize them properly so that random numbers can draw from them to make worksheets. – WeCanLearnAnything Nov 21 '16 at 20:30
6

I think it's easy to define essentially an array of options so you can define or redefine them as needed without having to define them all together in a nested structure.

\documentclass{article}

\usepackage{pgffor}

\usepackage{ifthen}

\pagestyle{empty}
\setlength{\parindent}{0pt}

% THE FOUR EQUATIONS
% 1.   1+2=3
% 2.   2+1=3
% 3.   3=2+1 
% 4.   3=1+2

\def\defchoice#1#2{\expandafter\def\csname X-#1\endcsname{#2}}
\defchoice{1}{$1+2=3$}
\defchoice{2}{$2+1=3$}
\defchoice{3}{$3=2+1$}
\defchoice{4}{$3=1+2$}

\pgfmathsetseed{\number\pdfrandomseed}

\newcommand{\InitVariables}
{\pgfmathsetmacro{\A}{random(1,4)}} 

\newcommand*{\onefact}
{%%%%%%%%%% dont forget % at end of line
 \InitVariables
  \csname X-\A\endcsname}


\newcommand{\myequations}[1]
{%
 \foreach \x in {1,...,#1}
  {\onefact\par}% don't end a paragraph with \\
}

\begin{document}

\myequations{10} 

\end{document}
David Carlisle
  • 757,742
  • This seems to look good. What does \def\defchoice#1#2{\expandafter\def\csname X-#1\endcsname{#2}} mean? I can't make sense of this... – WeCanLearnAnything Sep 19 '16 at 22:28
  • @WeCanLearnAnything: \def\defchoice#1#2{...} creates a macro called \defchoices{#1}{#2} where you have to supply it with [2] arguments (both are mandatory). It creates a macro called \X-#1 that contains the definition #2. However, creating a macro with numbers in its name is not easy. You have to do this using a \csname ... \endcsname construction, so we use \expandafter\def\csname ... \endcsname to first create the control sequence, then \define it. – Werner Sep 19 '16 at 22:41
  • Ok, I understand the \def\defchoice#1#2{...} part. But then there's another macro created within that? And why would it have the name \X- #1? – WeCanLearnAnything Sep 19 '16 at 23:56
  • @WeCanLearnAnything you need a macro name to store each choice, the prefix is arbitrary, I just chose \X-1, \X-2, \X-3 ... – David Carlisle Sep 20 '16 at 00:02
  • @WeCanLearnAnything http://tex.stackexchange.com/questions/39380/what-exactly-do-csname-and-endcsname-do – David Carlisle Sep 20 '16 at 00:04
5

LaTeX3 provides a fairly intuitive switch or case-like structure that allows you to define a case and its corresponding resolution. For your implementation, you can use:

\usepackage{xparse}    
\ExplSyntaxOn
\NewDocumentCommand{\onefact}{m}{
  \int_case:nnF {#1}
    {
      { 1 }{ 1 + 2 = 3 }
      { 2 }{ 2 + 1 = 3 }
      { 3 }{ 3 = 2 + 1 }
      { 4 }{ 3 = 1 + 2 }
    }
    { ? }
}
\ExplSyntaxOff

This will perform an integer comparison where the "else clause" (no match is found) results in ?. The use will be something like \onecase{2}, or \onecase{\A} where \A is defined as your random value between 1 and 4 (inclusive).

Werner
  • 603,163
2

Scalable means “good interface”. We define a set of possible outcomes with

\defineset{<name>}{<a>,<b>,...}

and then \printfromset{<name>} will choose one of the outcomes at random; the random number will be computed from the number of possible outcomes associated with the particular set.

\documentclass{article}
\usepackage{xparse}

\input{random} % for random numbers
\randomi=\pdfrandomseed % initialize the seed

\ExplSyntaxOn

\cs_new_eq:NN \wcla_get_random:Nnn \setrannum
\int_new:N \l_wcla_random_int

\NewDocumentCommand{\defineset}{mm}
 {
  \tl_new:c { g_wcla_set_#1_tl }
  \int_zero:N \l_tmpa_int
  \clist_map_inline:nn { #2 }
   {
    \int_incr:N \l_tmpa_int
    \tl_gput_right:cx { g_wcla_set_#1_tl }
     {
      { \int_to_arabic:n { \l_tmpa_int } }
      { \exp_not:n { ##1 } }
     }
   }
 }

\NewDocumentCommand{\printfromset}{m}
 {
  \wcla_get_random:Nnn \l_wcla_random_int 
   { 1 }
   { \int_eval:n { \tl_count:c { g_wcla_set_#1_tl } /2 } }
  \int_case:nv { \l_wcla_random_int } { g_wcla_set_#1_tl }
 }
\cs_generate_variant:Nn \int_case:nn { nv }
\ExplSyntaxOff


\defineset{equations}{
  $1+2=3$,
  $2+1=3$,
  $3=2+1$,
  $3=1+2$
}
\defineset{letters}{A,B,C,D,E,F,G,H,I}

\begin{document}

\printfromset{equations}

\printfromset{equations}

\printfromset{letters}
\printfromset{letters}
\printfromset{letters}
\printfromset{letters}
\printfromset{letters}
\printfromset{letters}
\printfromset{letters}
\printfromset{letters}
\printfromset{letters}
\printfromset{letters}

\end{document}

The \defineset macro allocates a token list variable that's then filled in the format

{1}{<a>}{2}{<b>}...

which is good for \int_case:nn, provided we use the \int_case:nv variant. Note that the number of items is twice the number of outcomes.

The macro \printfromset generates a random number between 1 and half the length of the token list variable (we divide it by 2).

Here's a possible output

enter image description here

Note about random.tex, a set of macros by Donald Arsenau. The syntax is \setrannum<counter>{<low>}{<high>} which stores in the <counter> a random number between the integers <low> and <high> (extremes included). The seed is stored in the counter \randomi.

egreg
  • 1,121,712