% sgamex.sty
% Martin J. Osborne
% https://www.economics.utoronto.ca/osborne
% Version 1.01
% 2020.02.17
%
% Alternative implementation of sgame.sty that avoids incompatibilities with the array style and other styles.
%
% Main code written by Enrico Gregorio; used with his permission
% See his answer at https://tex.stackexchange.com/questions/512905/is-there-an-alternative-to-sgame-compatible-with-array
% Method for saving and restoring \arrayrule color due to David Carlisle
% See his answer at https://tex.stackexchange.com/questions/527455/get-current-value-of-arrayrulecolor-for-a-colortbl
%
% Note
% Implications of ssualfalse different from that in sgame.sty: text is not raised, but stretch *is* applied
%
% This material is subject to the LATEX Project Public License 1.3c.

\RequirePackage{xparse,hhline,array,multirow}
\RequirePackage[table]{xcolor} 

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

\let\gamestretch=\arraystretch
\let\origarraystretch=\arraystretch

\newdimen\sgcolsep
\newdimen\origtabcolsep
\sgcolsep\tabcolsep
\newdimen\origarrayrulewidth
\origarrayrulewidth\arrayrulewidth
\newdimen\sgrulewidth
\sgrulewidth\arrayrulewidth

\def\sglinecolor{black}
\def\sgtextcolor{black}

\newdimen\sgraiseamt

\newif\ifgamemath\gamemathfalse
\newif\ifssual\ssualtrue
\newif\ifirpawcgl
\newif\ifirplwcgl

\newcount\sg@leftcols
\newcount\sg@rightcols

\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}{>{\ifssual\raise\sgraiseamt\hbox\bgroup\fi}c<{\ifssual\egroup\fi}}{#1}
}

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

	% save current value of arrayrulecolor
	\global\let\saved@CT@arc@\CT@arc@
	% save current value of tabcolsep
	\origtabcolsep\tabcolsep
	\tabcolsep\sgcolsep

	\color{\sgtextcolor}	
	\arrayrulecolor{\sglinecolor}
	\arrayrulewidth\sgrulewidth
	\renewcommand{\arraystretch}{\gamestretch}
	
	\setbox0=\hbox{I}
	\sgraiseamt\gamestretch\baselineskip
	\divide\sgraiseamt by 5
	\multiply\sgraiseamt by 2
	\advance\sgraiseamt by -\ht0
	\divide\sgraiseamt by 2

	\sg@leftcols 2
	\sg@rightcols #2

	\IfValueTF{#5}{
		\def\sg@rowplayerlabel{#3}
		\def\sg@colplayerlabel{#4}
		\def\sg@gamelabel{#5}
	}{
		\IfValueTF{#4}{
			\def\sg@rowplayerlabel{#3}
			\def\sg@colplayerlabel{#4}
			\def\sg@gamelabel{}
		}{
			\IfValueTF{#3}{
				\def\sg@rowplayerlabel{}
				\def\sg@colplayerlabel{}
				\def\sg@gamelabel{#3}
			}{
				\def\sg@rowplayerlabel{}
				\def\sg@colplayerlabel{}
				\def\sg@gamelabel{}
			}
		}
	}

	\ifx\sg@gamelabel\empty\else
		\ifirpawcgl
			\sg@leftcols 1
			\advance\sg@rightcols by 1
		\fi
		\ifirplwcgl
			\sg@leftcols 0
			\advance\sg@rightcols by 2
		\fi
	\fi
	
	% 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@{}>{\raise\sgraiseamt\hbox\bgroup}r<{\egroup}|*{#2}{>{\raise\sgraiseamt\hbox\bgroup\ifgamemath\(\fi}w{c}{\l__cfr_game_dim}<{\ifgamemath\)\fi\egroup}|}}
		% top label
		\ifx\sg@colplayerlabel\empty\else\multicolumn{2}{@{}c}{} & \multicolumn{#2}{c}{\sg@colplayerlabel} \\\fi
		% first row
		\multicolumn{2}{c}{} \seq_map_function:NN \l_cfr_game_first_seq \__cfr_game_first:n \\
		\exp_args:No \hhline{\doubleactivetilde*{#2}{|-}|}
		\ifx\sg@rowplayerlabel\empty
			\multicolumn{1}{@{}c@{}}{}
		\else
			\multirow{#1}{*}{\sg@rowplayerlabel\quad}
		\fi
		& \seq_use:Nn \l_cfr_game_body_seq
		{ \\ \exp_args:No \hhline{\doubleactivetilde*{#2}{|-}|} & } \\
		\exp_args:No \hhline{\doubleactivetilde*{#2}{|-}|}
		\ifx\sg@gamelabel\empty\else
			\ifnum\sg@leftcols>0
				\multicolumn{\sg@leftcols}{c}{\rule{0pt}{1.25\normalbaselineskip}} &
			\fi
			\multicolumn{\sg@rightcols}{c}{\makebox[0pt]{\sg@gamelabel}} \\
		\fi
	\end{tabular}

	% restore original values
	\global\let\CT@arc@\saved@CT@arc@
	\origtabcolsep\tabcolsep
	\arrayrulewidth\origarrayrulewidth
	\renewcommand{\arraystretch}{\origarraystretch}
}{}

\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
