0

The context is a kids game where a sequence of questions appear on screen, one at a time, and the answers appear gradually and randomly one letter at a time by the press of some button.

For example, ``Question 1 : What is the capital of Italy ?'' The answer appears as a blank of unspecified number of characters, and by press of some button perhaps E shows up and then - - R - - E - -, and then one by one all the way to - -ROME- -. Or a similar arrangement.

What is the instrument for this? How do I make the letters show up randomly.

Maesumi
  • 9,059
  • 2
    As a slide show, each slide shows a slightly different image. OTOH, the letters always show up in the same order (pseudo-random or not). You might need to put each letter into a \makebox or tikz node to keep the spacing constant. – John Kormylo Apr 30 '20 at 14:01
  • 2
    I'd use OCGs and a bit of JavaScript for the random bit. But kerning and ligatures will get lost, because characters have to be treated one by one. Perhaps I would choose caps or small caps for the answers. – AlexG Apr 30 '20 at 18:09

1 Answers1

1

Here is something that does that. I am also writing this because apart from the memberQ macro, which is more or less taken from here, it defines pgf functions randompermutation(<n>), which yields a random permutation of integers {1,...,<n>}, and take, which returns a sublist. The macro defined based on these functions and the parser module is \ShowPartially. In order to use it on a word, you have to first "initialize" it, e.g.

 \ShowPartially{initial,n=2,word=Murmeltier}    

Then one permutation of the numbers {1,...,<# of characters>} is stored and you can show e.g. 4 random letters with

 \ShowPartially{n=4}

That way the results for larger n will always the letters that show for smaller n. If you want to create a new permutation list, just call \ShowPartially again with the initial key.

\documentclass{article}
\usepackage{pgf}
\usepgfmodule{parser}
\makeatletter
%membership test    
\pgfmathdeclarefunction{memberQ}{2}{%
  \begingroup%
    \edef\pgfutil@tmpb{0}%memberQ({\lstPast},\inow)
    \edef\pgfutil@tmpa{#2}%
    \expandafter\pgfmath@member@i#1\pgfmath@token@stop
    \edef\pgfmathresult{\pgfutil@tmpb}%
    \pgfmath@smuggleone\pgfmathresult%
  \endgroup}
\def\pgfmath@member@i#1{%
    \ifx\pgfmath@token@stop#1%
    \else
      \edef\pgfutil@tmpc{#1}%
      \ifx\pgfutil@tmpc\pgfutil@tmpa\relax%
      \gdef\pgfutil@tmpb{1}%
      \fi%
      \expandafter\pgfmath@member@i
    \fi}  
\pgfmathdeclarefunction{randompermutation}{1}{%
\begingroup%          
\c@pgf@counta=0%
\edef\pgfutil@tmpa{0}%
\loop
\advance\c@pgf@counta by1%
\edef\pgfutil@tmpa{\pgfutil@tmpa,\the\c@pgf@counta}%
\ifnum\c@pgf@counta<#1\relax
\repeat
\loop
\advance\c@pgf@counta by-1%
\pgfmathtruncatemacro{\pgfutil@tmpb}{1+rnd*\c@pgf@counta}%
\pgfmathtruncatemacro{\pgfutil@tmpc}{{\pgfutil@tmpa}[\pgfutil@tmpb]}%
\ifnum\c@pgf@counta=\numexpr#1-1\relax
\edef\pgfmathresult{\pgfutil@tmpc}%
\else
\edef\pgfmathresult{\pgfmathresult,\pgfutil@tmpc}%
\fi
\edef\pgfutil@tmpd{\pgfutil@tmpa}%
\edef\pgfutil@tmpa{0}%
\pgfutil@for\my@item:={\pgfutil@tmpd}\do{%
\unless\ifnum\pgfutil@tmpc=\my@item
\unless\ifnum\my@item=0\relax
\edef\pgfutil@tmpa{\pgfutil@tmpa,\my@item}%
\fi\fi}%
\ifnum\c@pgf@counta>0\relax
\repeat
\pgfmath@smuggleone\pgfmathresult%
\endgroup}
\pgfmathdeclarefunction{take}{2}{%
\begingroup%
\c@pgf@counta=0%
\pgfutil@for\my@item:={#1}\do{%
\advance\c@pgf@counta by1%
\ifnum\c@pgf@counta<#2\relax
\ifnum\c@pgf@counta=1\relax
\edef\pgfmathresult{\my@item}%
\else
\edef\pgfmathresult{\pgfmathresult,\my@item}%
\fi\fi}%
\pgfmath@smuggleone\pgfmathresult%
\endgroup}
\makeatother    
\newif\ifhideletterinitial
\hideletterinitialfalse
\pgfkeys{/hide letter/.cd,initial/.is if=hideletterinitial,n/.initial=1,
word/.initial=Rome}
\newcounter{letterpos}
\pgfparserdef{letterhide}{all};{\pgfparserswitch{final}}% 
\pgfparserdefunknown{letterhide}{all}%
{\stepcounter{letterpos}%
\unless\ifhideletterinitial
\pgfmathtruncatemacro{\itest}{memberQ({\mysublist},\number\value{letterpos})}%
\ifnum\itest=1\relax
\pgfparserletter
\else
\phantom{\pgfparserletter}%
\fi
\fi}% \pgfparserletter
\pgfparserset{letterhide/silent=true}%
\newcommand{\ShowPartially}[1]{%
\pgfkeys{/hide letter/.cd,#1}%
\ifhideletterinitial
\setcounter{letterpos}{0}%
\xdef\HideLetterWord{\pgfkeysvalueof{/hide letter/word}}%
\edef\temp{\noexpand\pgfparserparse{letterhide}\HideLetterWord;}%
\temp
\xdef\HideLetterNum{\number\value{letterpos}}%
\pgfmathsetmacro{\myperm}{randompermutation(\HideLetterNum)}%
\xdef\HideLetterPerm{\myperm}%
\hideletterinitialfalse
\fi
\pgfmathsetmacro{\mysublist}{take("\HideLetterPerm",\pgfkeysvalueof{/hide letter/n})}%
\setcounter{letterpos}{0}%
\edef\temp{\noexpand\pgfparserparse{letterhide}\HideLetterWord;}%
\temp
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
\pgfmathsetseed{123}
\ShowPartially{initial,n=2,word=Murmeltier} 

\ShowPartially{n=3}

\ShowPartially{n=4}

\ShowPartially{n=5}

\ShowPartially{n=8}

\pgfmathsetseed{42}
\ShowPartially{initial,n=5,word=Amsterdam}  
\end{document}

enter image description here

And this is an ocgx2 version thereof.

\documentclass{article}
\usepackage{ocgx2}
\usepackage{pgf}
\usepgfmodule{parser}
\renewcommand*\familydefault{\sfdefault}
\makeatletter
%membership test    
\pgfmathdeclarefunction{memberQ}{2}{%
  \begingroup%
    \edef\pgfutil@tmpb{0}%memberQ({\lstPast},\inow)
    \edef\pgfutil@tmpa{#2}%
    \expandafter\pgfmath@member@i#1\pgfmath@token@stop
    \edef\pgfmathresult{\pgfutil@tmpb}%
    \pgfmath@smuggleone\pgfmathresult%
  \endgroup}
\def\pgfmath@member@i#1{%
    \ifx\pgfmath@token@stop#1%
    \else
      \edef\pgfutil@tmpc{#1}%
      \ifx\pgfutil@tmpc\pgfutil@tmpa\relax%
      \gdef\pgfutil@tmpb{1}%
      \fi%
      \expandafter\pgfmath@member@i
    \fi}  
\pgfmathdeclarefunction{randompermutation}{1}{%
\begingroup%          
\c@pgf@counta=0%
\edef\pgfutil@tmpa{0}%
\loop
\advance\c@pgf@counta by1%
\edef\pgfutil@tmpa{\pgfutil@tmpa,\the\c@pgf@counta}%
\ifnum\c@pgf@counta<#1\relax
\repeat
\loop
\advance\c@pgf@counta by-1%
\pgfmathtruncatemacro{\pgfutil@tmpb}{1+rnd*\c@pgf@counta}%
\pgfmathtruncatemacro{\pgfutil@tmpc}{{\pgfutil@tmpa}[\pgfutil@tmpb]}%
\ifnum\c@pgf@counta=\numexpr#1-1\relax
\edef\pgfmathresult{\pgfutil@tmpc}%
\else
\edef\pgfmathresult{\pgfmathresult,\pgfutil@tmpc}%
\fi
\edef\pgfutil@tmpd{\pgfutil@tmpa}%
\edef\pgfutil@tmpa{0}%
\pgfutil@for\my@item:={\pgfutil@tmpd}\do{%
\unless\ifnum\pgfutil@tmpc=\my@item
\unless\ifnum\my@item=0\relax
\edef\pgfutil@tmpa{\pgfutil@tmpa,\my@item}%
\fi\fi}%
\ifnum\c@pgf@counta>0\relax
\repeat
\pgfmath@smuggleone\pgfmathresult%
\endgroup}
\pgfmathdeclarefunction{take}{2}{%
\begingroup%
\c@pgf@counta=0%
\pgfutil@for\my@item:={#1}\do{%
\advance\c@pgf@counta by1%
\ifnum\c@pgf@counta<#2\relax
\ifnum\c@pgf@counta=1\relax
\edef\pgfmathresult{\my@item}%
\else
\edef\pgfmathresult{\pgfmathresult,\my@item}%
\fi\fi}%
\pgfmath@smuggleone\pgfmathresult%
\endgroup}
\makeatother    
\newif\ifhideletterinitial
\hideletterinitialfalse
\pgfkeys{/hide letter/.cd,initial/.is if=hideletterinitial,n/.initial=1,
word/.initial=Rome}
\newcounter{letterpos}
\pgfparserdef{letterhide}{all};{\pgfparserswitch{final}}% 
\pgfparserdefunknown{letterhide}{all}%
{\stepcounter{letterpos}%
\unless\ifhideletterinitial
\pgfmathtruncatemacro{\itest}{memberQ({\mysublist},\number\value{letterpos})}%
\ifnum\itest=1\relax
\pgfparserletter
\else
\phantom{\pgfparserletter}%
\fi
\fi}% \pgfparserletter
\pgfparserset{letterhide/silent=true}%
\newcommand{\ShowPartially}[1]{%
\pgfkeys{/hide letter/.cd,#1}%
\ifhideletterinitial
\setcounter{letterpos}{0}%
\xdef\HideLetterWord{\pgfkeysvalueof{/hide letter/word}}%
\edef\temp{\noexpand\pgfparserparse{letterhide}\HideLetterWord;}%
\temp
\xdef\HideLetterNum{\number\value{letterpos}}%
\pgfmathsetmacro{\myperm}{randompermutation(\HideLetterNum)}%
\xdef\HideLetterPerm{\myperm}%
\hideletterinitialfalse
\fi
\pgfmathsetmacro{\mysublist}{take("\HideLetterPerm",\pgfkeysvalueof{/hide letter/n})}%
\setcounter{letterpos}{0}%
\edef\temp{\noexpand\pgfparserparse{letterhide}\HideLetterWord;}%
\temp
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
\pgfmathsetseed{123}

\edef\iloop{2}\hfill\loop
\actionsocg[onmouseall]{}{,,ocg\iloop,}{,,,ocg\iloop}{\iloop}\ 
\edef\iloop{\the\numexpr\iloop+1}%
\ifnum\iloop<11\relax
\repeat


\ShowPartially{initial,n=1,word=Murmeltier}\par 

\edef\iloop{2}\loop
\begin{ocg}{OCG 2}{ocg\iloop}{0}
\ShowPartially{n=\iloop}
\end{ocg}\par
\edef\iloop{\the\numexpr\iloop+1}%
\ifnum\iloop<11\relax
\repeat
\end{document}

When viewed with Acrobat reader, this shows numbers from 1 to 10, and if you click on one of these numbers, the corresponding subset of letters shows up. (I have no idea how one can upload an illustration here.)

  • Toto, we're not in Kansas, or I have a feeling this is not kids game anymore! – Maesumi May 01 '20 at 12:10
  • Thanks! By the way how do we handle spaces, for example if answer is "New York" it comes out as "NewYork". As is I can replace the spaces with -. – Maesumi May 02 '20 at 23:05
  • 1
    @Maesumi As usual in LaTeX, a space can be obtained width \ (backslash-space) as in \ShowPartially{initial,n=10,word=New\ York\ City}. –  May 02 '20 at 23:08