¿Existe una mejor manera de crear un juego de tres en raya en LaTeX? Actualmente tengo el siguiente código:
\documentclass{beamer}
\mode<presentation>
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amsthm}
\usepackage{array}
\usepackage{graphicx}
\begin{document}
\begin{frame}
\frametitle{A game of noughts and crosses}
Here is a game of noughts and crosses. On the left we have the game, and on the right the commentary.\\
\begin{columns}
\begin{column}{0.1\textwidth}
\vspace{1.75cm}
\begin{tabular}{c|c|c}
& & \\ \hline
& & \\ \hline
& &
\end{tabular}
\end{column} \pause
\begin{column}{0.70\textwidth}
\begin{itemize}
\item crosses goes first, makes optimal move. A good player will never lose from this start.
\end{itemize}
\end{column}
\end{columns}
\end{frame}
\end{document}
Esto divide la diapositiva en dos donde tengo el juego en un lado y el comentario en el otro. Quiero poder jugar agregando Os y X en la cuadrícula, diapositiva por diapositiva, y al mismo tiempo agregar comentarios. Claramente el primer paso es:
\begin{tabular}{c|c|c}
& & \\ \hline
& X & \\ \hline
& &
\end{tabular}
Me pregunto si hay una mejor manera de hacer esto. ¿Cómo puedo hacer para que el juego se llene diapositiva por diapositiva (es decir, X reproduce en la diapositiva 1, O reproduce en la diapositiva 2, agrega comentarios, X reproduce en la diapositiva 3, etc.)?
Respuesta1
Cuando va a haber mucho código repetido (para los diferentes juegos, en este caso), escribo una macro para simplificar mi archivo latex y para que sea más fácil cambiar cosas más adelante, si es necesario.
(I)El primer pensamiento que me vino a la mente fue escribir una macro que tomara como "entrada":
- una lista separada por comas de las posiciones de las X
- una lista separada por comas de las posiciones de las O
- el comentario
Las posiciones X y O las codificaría como 1,2,...,9 leyendo de izquierda a derecha y de arriba a abajo, en la cuadrícula. Por ejemplo, \NoughtsCrosses{5,6}{9}{Third move}
produciría
(II)Una segunda forma de hacer esto es asumir que los movimientos se alternan como X,O,X,... y simplemente dar una lista de movimientos separados por comas junto con el comentario. Por ejemplo, \NoughtsCrossesII{5,9,6,4}{Fourth move}
produciría
Como dice cfr en los comentarios a la pregunta, probablemente desee encerrar estos comandos dentro de algo así \only<5>{\NoughtsCrossesII{5,9,6,4}{Fourth move}}
para revelar un movimiento a la vez. Hago esto en el MWE a continuación.
(iii)Teniendo en cuenta el último comentario, y yendo un poco OTT, una macro más inteligente simplemente tomaría una lista de movimientos y comentarios y luego construiría todas las diapositivas del juego en el marco. Todas las macros hasta ahora usan tikz y el \foreach
comando tikz permite múltiples variables de bucle separadas por una barra, por lo que la forma más sencilla de implementar esto es usar la siguiente sintaxis:
\NoughtsCrossesGame{%
5/First move,
9/Second move,
6/Third move,
4/Fouth move
}
El resultado es el "igual" que el anterior excepto que el "juego" aparece en 4 diapositivas. La macro \NoughtsCrossesGame
toma un argumento opcional, que se comporta de manera similar al argumento opcional del \pause
comando. Es decir, actúa como un "desplazamiento" que controla cuándo los movimientos del juego comienzan a aparecer en las diapositivas del cuadro determinado.
Aquí hay un código que brinda las definiciones de las tres macros anteriores, completadas en un MWE para mostrar cómo usarlas:
\documentclass{beamer}
\usepackage{tikz}
% Helper macro for placing a node at "position" 1,2,...,9 into the grid
% \PlaceMarker[optional node styling]<position><X or O>
\usepackage{xparse}
\NewDocumentCommand\PlaceMarker{ O{}mm }{%
\ifnum#2>0
\def\markercol{#1}
\def\PlaceMakerNumber{#2}
\else
\def\markercol{red}
\def\PlaceMakerNumber{\numexpr-#2}
\fi
\ifcase\PlaceMakerNumber%
\or\node[\markercol] at (1,3) {#3}; % 1 = (3,1)
\or\node[\markercol] at (2,3) {#3}; % 2 = (3,2)
\or\node[\markercol] at (3,3) {#3}; % 3 = (3,3)
\or\node[\markercol] at (1,2) {#3}; % 4 = (2,1)
\or\node[\markercol] at (2,2) {#3}; % 5 = (2,2)
\or\node[\markercol] at (3,2) {#3}; % 6 = (2,3)
\or\node[\markercol] at (1,1) {#3}; % 7 = (1,1)
\or\node[\markercol] at (2,1) {#3}; % 8 = (1,2)
\or\node[\markercol] at (3,1) {#3}; % 9 = (1,3)
\fi
}
% Creates a noughts and cross game with commentary
%\NoughtsCrosses{x-positions}{y-positions}{Commentary}
\newcommand\NoughtsCrosses[3]{%
\begin{tikzpicture}
\foreach \x in {1.5,2.5} {
\draw[ultra thick](\x,0.5)--+(0,3);
\draw[ultra thick](0.5,\x)--+(3,0);
}
\foreach \x in {#1} {\PlaceMarker{\x}{X}}
\foreach \y in {#2} {\PlaceMarker{\y}{O}}
\node[text width=40mm,text ragged, anchor=west] at (5,3) {#3};
\end{tikzpicture}
}
% Creates a noughts and cross game with commentary
%\NoughtsCrossesII{move positions}{Commentary}
% Moves alternate as X,O,...
\newcommand\NoughtsCrossesII[2]{%
\begin{tikzpicture}
\foreach \x in {1.5,2.5} {
\draw[ultra thick](\x,0.5)--+(0,3);
\draw[ultra thick](0.5,\x)--+(3,0);
}
\foreach \move [count=\m] in {#1} {
\ifodd\m \PlaceMarker{\move}{X}
\else\PlaceMarker{\move}{O}
\fi
}
\node[text width=40mm,text ragged, anchor=west] at (5,3) {#2};% add comment
\end{tikzpicture}
}
% Creates a noughts and cross game with commentary
%\NoughtsCrossesII{move positions}{Commentary}
% Moves alternate as X,O,...
\makeatletter
\newcommand\NoughtsCrossesGame[2][0]{%
\begin{tikzpicture}
\foreach \x in {1.5,2.5} {
\draw[ultra thick](\x,0.5)--+(0,3);
\draw[ultra thick](0.5,\x)--+(3,0);
}
% count length of game
\foreach \move/\com [count=\lmove] in {#2} {}
\def\endgame{\the\numexpr\lmove+#1\relax}
\def\Endgame{\the\numexpr\endgame+1\relax}
\foreach \move/\com [count=\m,
evaluate=\m as \mm using int(\m+#1),
evaluate=\move as \mov using int(abs(-\move))] in {#2} {
\ifodd\m\def\Marker{X}
\else\def\Marker{O}
\fi
\def\mmm{\the\numexpr\mm+1\relax}
\only<\mm>{\PlaceMarker[blue]{\mov}{\Marker}}
\ifnum\move<0
\only<\mmm-\endgame>{\PlaceMarker{\mov}{\Marker}}
\only<\Endgame->{\PlaceMarker[blue]{\mov}{\Marker}}
\else
\only<\mmm->{\PlaceMarker{\mov}{\Marker}}
\fi
\only<\mm>{
\node[text width=40mm,text ragged, anchor=west] at (5,3){\com};
}
}
\end{tikzpicture}
}
\makeatother
\begin{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{frame}{A game of noughts and crosses}
Here is a game of noughts and crosses. On the left we have the
game, and on the right the commentary.
\medskip
\only<2>{\NoughtsCrosses{5}{}{First move}}
\only<3>{\NoughtsCrosses{5}{9}{Second move}}
\only<4>{\NoughtsCrosses{5,6}{9}{Third move}}
\only<5>{\NoughtsCrossesII{5,9,6,4}{Fourth move}}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{frame}{Another game of noughts and crosses}
Here is a game of noughts and crosses. On the left we have the
game, and on the right the commentary.
\pause Here is a clever game
\medskip
\NoughtsCrossesGame[1]{% offset start of game because of \pause above
-5/First move,
6/Middle square,
7/Forcing,
3/Forced block,
-9/Forced block leading to a pincer!,
8/Forced defence!,
-1/Wins!
}
\end{frame}
\end{document}
Algunos comentarios:
- Todas las macros usantikzdibujar los juegos ya que esto da un mejor control sobre la colocación de los marcadores X/O y al dibujar la cuadrícula
- La
\PlaceMarker
macro es una "función auxiliar" para colocar un marcador en la posición especificada. Esto se utiliza\ifcase
para traducir los índices de posición1,2,...,9
en(x,y)
coordenadas. - Las macros se utilizan
\foreach
para recorrer la lista de posiciones de marcadores separadas por comas. La segunda macro sirve, además,\ifodd
para determinar si se coloca una X o una O. - El "comentario" se coloca dentro de un nodo tikz como texto izquierdo irregular de 40 mm de ancho. Es posible que necesites ajustar la ubicación de las coordenadas (x,y) y el ancho del texto.
- Como se solicitó en los comentarios, he mejorado las macros para permitir resaltar fácilmente algunos de los movimientos. Dar un índice de "posición negativa" ahora colorea el correspondiente
X
oO
. Por ejemplo,\NoughtsCrosses{-5,-6}{9}{Third move}
hará que las dosX
s sean rojas. - Lo que es más divertido, la
\NoughtsCrossesGame
macro ahora colorea cada movimiento y luego coloca la última racha "ganadora" en azul al final del juego; la racha ganadora debe resaltarse nuevamente usando índices de posición negativos. En ambos casos la coloración se realiza mediante una mejora de\PlaceMarker
, aunque la coloración automática de for\NoughtsCrosses
es más complicada.
Para completar, aquí hay una versión animada de la última diapositiva producida por el \NoughtsCrossesGame
ejemplo:
Excepto por el marco creado por Beamer, esta colección de diapositivas es esencialmente el resultado del comando:
\NoughtsCrossesGame[1]{% offset start of game because of \pause above
-5/First move,
6/Middle square,
7/Forcing,
3/Forced block,
-9/Forced block leading to a pincer!,
8/Forced defence!,
-1/Wins!
}