4

As noted in Christian Hupfer's answer, the package sgame is incompatible with array. Is there a more tolerant alternative for typesetting payoff matrices in game theory?

MNWE:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[]{array}
\usepackage{sgame}

\begin{document}

\begin{game}{2}{2}[You][Your partner][Prisoner's Dilemma]
    & Talk      & Quiet \\
    Talk  & $-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ 
\end{game}

\end{document}

produces an error, as expected:

! Missing # inserted in alignment preamble.
<to be read again> 
                   \cr 
l.26 ...{2}[You][Your partner][Prisoner's Dilemma]

?

Note that I realise I can do this without a dedicated package in any number of ways. I'm asking if somebody has already invented a wheel of the kind I seek.

4
  • Can help you istgame package? ctan.org/pkg/istgame – Sebastiano Oct 20 '19 at 8:29
  • 1
    @Sebastiano That's for drawing trees, isn't it? – cfr Oct 20 '19 at 15:29
  • I've also seen it use for game theory here in some question or answer. – Sebastiano Oct 20 '19 at 15:38
  • 2
    @Sebastiano Yes, because they use trees in game theory. But they also use payoff matrices and that's what sgame draws. Unfortunately, it seems code for payoff matrices is thinner on the ground than code for trees. What I'm looking for is more like a table, but I just thought somebody might have coded it already :). – cfr Oct 20 '19 at 15:43
4

You mean something like this?

\documentclass{article}
\usepackage{xparse,hhline,array,multirow}
\usepackage[table]{xcolor} % necessary only for \cellcolor in the last example

\newcommand\doubleactivetilde{~~} % hhline wants ~ to mean 'column with no line'

\ExplSyntaxOn

\seq_new:N \l_cfr_game_body_seq
\seq_new:N \l_cfr_game_first_seq
\tl_new:N \l_cfr_game_first_tl
\cs_generate_variant:Nn \seq_set_split:Nnn { NnV }

\cs_new_protected:Nn \__cfr_game_first:n
 {
  & \multicolumn{1}{c}{#1}
 }

\NewDocumentEnvironment{game}{mmooob}
 {% #1 = number of rows, #2 = number of columns (besides the label column)
  % #3 = left label, #4 = top label, #5 = bottom label
  % #6 = body

  % split the body at \\
  \seq_set_split:Nnn \l_cfr_game_body_seq { \\ } { #6 }
  % in case there's a trailing \\
  \seq_pop_right:NN \l_cfr_game_body_seq \l_tmpa_tl
  \tl_if_empty:NF \l_tmpa_tl { \seq_put_right:NV \l_cfr_game_body_seq \l_tmpa_tl }
  %
  \seq_pop_left:NN \l_cfr_game_body_seq \l_cfr_game_first_tl
  \seq_set_split:NnV \l_cfr_game_first_seq { & } \l_cfr_game_first_tl
  % discard the first (empty) item
  \seq_pop_left:NN \l_cfr_game_first_seq \l_tmpa_tl
  \begin{tabular}{@{}c@{}r*{#2}{|c}|}
  % top label
  \IfValueT{#4}{\multicolumn{2}{@{}c}{} & \multicolumn{#2}{c}{#4} \\}
  % first row
  \multicolumn{2}{c}{} \seq_map_function:NN \l_cfr_game_first_seq \__cfr_game_first:n \\
  \exp_args:No \hhline{\doubleactivetilde*{#2}{|-}|}
  \IfValueTF{#3}{\multirow{#1}{*}{#3\quad}}{\multicolumn{1}{@{}c@{}}{}}
  & \seq_use:Nn \l_cfr_game_body_seq
   { \\ \exp_args:No \hhline{\doubleactivetilde*{#2}{|-}|} & } \\
  \exp_args:No \hhline{\doubleactivetilde*{#2}{|-}|}
  \IfValueT{#5}
   {
    \multicolumn{2}{c}{\rule{0pt}{1.25\normalbaselineskip}} &
    \multicolumn{#2}{c}{\makebox[0pt]{#5}} \\
   }
  \end{tabular}
}{}

\ExplSyntaxOff

\begin{document}

\begin{game}{2}{2}[You][Your partner][Prisoner's Dilemma]
    & Talk      & Quiet \\
    Talk  & $-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\bigskip
\hrule
\bigskip

\begin{game}{2}{2}[You][Your partner]
    & Talk      & Quiet \\
    Talk  & $-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\bigskip
\hrule
\bigskip

\begin{game}{2}{2}[You]
    & Talk      & Quiet \\
    Talk  & $-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\bigskip
\hrule
\bigskip

\begin{game}{2}{2}
    & Talk      & Quiet \\
    Talk  &\cellcolor{yellow}$-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\end{document}

enter image description here

A modified version that equalizes column widths.

\documentclass{article}
\usepackage{xparse,hhline,array,multirow}
\usepackage[table]{xcolor} % necessary only for \cellcolor in the last example

\newcommand\doubleactivetilde{~~} % hhline wants ~ to mean 'column with no line'

\ExplSyntaxOn

\seq_new:N \l_cfr_game_body_seq
\seq_new:N \l_cfr_game_first_seq
\tl_new:N \l_cfr_game_first_tl
\dim_new:N \l__cfr_game_dim
\cs_generate_variant:Nn \seq_set_split:Nnn { NnV }

\cs_new_protected:Nn \__cfr_game_first:n
 {
  & \multicolumn{1}{c}{#1}
 }

\NewDocumentEnvironment{game}{mmooob}
 {% #1 = number of rows, #2 = number of columns (besides the label column)
  % #3 = left label, #4 = top label, #5 = bottom label
  % #6 = body

  % split the body at \\
  \seq_set_split:Nnn \l_cfr_game_body_seq { \\ } { #6 }
  % in case there's a trailing \\
  \seq_pop_right:NN \l_cfr_game_body_seq \l_tmpa_tl
  \tl_if_empty:NF \l_tmpa_tl { \seq_put_right:NV \l_cfr_game_body_seq \l_tmpa_tl }
  %
  \seq_pop_left:NN \l_cfr_game_body_seq \l_cfr_game_first_tl
  \seq_set_split:NnV \l_cfr_game_first_seq { & } \l_cfr_game_first_tl
  % discard the first (empty) item
  \seq_pop_left:NN \l_cfr_game_first_seq \l_tmpa_tl
  \__cfr_game_equalize_columns:
  \begin{tabular}{@{}c@{}r|*{#2}{w{c}{\l__cfr_game_dim}|}}
  % top label
  \IfValueT{#4}{\multicolumn{2}{@{}c}{} & \multicolumn{#2}{c}{#4} \\}
  % first row
  \multicolumn{2}{c}{} \seq_map_function:NN \l_cfr_game_first_seq \__cfr_game_first:n \\
  \exp_args:No \hhline{\doubleactivetilde*{#2}{|-}|}
  \IfValueTF{#3}{\multirow{#1}{*}{#3\quad}}{\multicolumn{1}{@{}c@{}}{}}
  & \seq_use:Nn \l_cfr_game_body_seq
   { \\ \exp_args:No \hhline{\doubleactivetilde*{#2}{|-}|} & } \\
  \exp_args:No \hhline{\doubleactivetilde*{#2}{|-}|}
  \IfValueT{#5}
   {
    \multicolumn{2}{c}{\rule{0pt}{1.25\normalbaselineskip}} &
    \multicolumn{#2}{c}{\makebox[0pt]{#5}} \\
   }
  \end{tabular}
}{}

\cs_new_protected:Nn \__cfr_game_equalize_columns:
 {
  \dim_zero:N \l__cfr_game_dim
  % measure the header cells
  \seq_map_function:NN \l_cfr_game_first_seq \__cfr_game_measure_cell:n
  % measure the cells in the body
  \seq_map_inline:Nn \l_cfr_game_body_seq
   {
    \__cfr_game_measure_columns:n { ##1 }
   }
 }
\cs_new_protected:Nn \__cfr_game_measure_columns:n
 {
  \seq_set_split:Nnn \l_tmpa_seq { & } { #1 }
  \seq_indexed_map_inline:Nn \l_tmpa_seq
   {
    \int_compare:nT { ##1 > 1 }
     {
      \__cfr_game_measure_cell:n { ##2 }
     }
   }
 }
\cs_new_protected:Nn \__cfr_game_measure_cell:n
 {
  \hbox_set:Nn \l_tmpa_box { #1 }
  \dim_set:Nn \l__cfr_game_dim { \dim_max:nn { \l__cfr_game_dim } { \box_wd:N \l_tmpa_box } }
 }
\ExplSyntaxOff

\begin{document}

\begin{game}{2}{2}[You][Your partner][Prisoner's Dilemma]
    & Talk      & Quiet \\
    Talk  & $-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\bigskip
\hrule
\bigskip

\begin{game}{2}{2}[You][Your partner]
    & Talk      & Quiet \\
    Talk  & $-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\bigskip
\hrule
\bigskip

\begin{game}{2}{2}[You]
    & Talk      & Quiet \\
    Talk  & $-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\bigskip
\hrule
\bigskip

\begin{game}{2}{2}
    & Talk      & Quiet \\
    Talk  &\cellcolor{yellow}$-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\bigskip
\hrule
\bigskip

\begin{game}{2}{2}
    & Talk      & Quiet \\
    Talk  &\cellcolor{yellow}$-10,-10$ & $-1,-20$ aaaaaaaaaaaaa \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\bigskip
\hrule
\bigskip

\begin{game}{2}{2}
    & Talk      & Quiet, quiet, quiet, quiet \\
    Talk  &\cellcolor{yellow}$-10,-10$ & $-1,-20$ \\
    Quiet & $-20,-1$  & $-5,-5$ \\
\end{game}

\end{document}

enter image description here

5
  • 1
    This looks fantastic. (Haven't tried it yet.) I wasn't really trying to get anybody to code something, but thank you very much for doing so. (I hoped somebody would know of an existing solution. I can't be the only person who wants a payoff matrix in a document which uses array.) – cfr Oct 20 '19 at 15:45
  • @egreg One thing that sgame.sty does is make the width of the columns of the table (excluding the first column of labels) the same. Is there an easy modification of your code that achieves that? – Martin J. Osborne Jan 16 '20 at 17:13
  • @MartinJ.Osborne Edited version online. – egreg Jan 16 '20 at 21:14
  • @egreg Beautiful! Two points: (1) There is now a double vertical line rather than a single one between the columns. Changing the end of the line that starts begin{tabular} from |}} to `}|}' fixes that without, as far as I can see, any undesirable side-effects. (2) The columns widths aren't equalized if the reason for their disparity is a difference in the widths of the column headings. For example, if, in your first example, the second column heading is "Completely and totally silent" then that column is much wider than the first one. At the moment I can't see how to fix that. Any ideas? – Martin J. Osborne Jan 17 '20 at 4:31
  • @MartinJ.Osborne FIxed version online – egreg Jan 17 '20 at 7:55

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.