有沒有更好的方法在 LaTeX 中構建圈和十字遊戲?我目前有以下程式碼:
\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}
這將幻燈片一分為二,一側是遊戲,另一側是評論。我希望能夠透過在網格中逐張添加 Os 和 X 來玩遊戲,同時添加評論。顯然第一步是:
\begin{tabular}{c|c|c}
& & \\ \hline
& X & \\ \hline
& &
\end{tabular}
我只是想知道是否有更好的方法來做到這一點?如何讓遊戲逐張填滿幻燈片(即 X 在幻燈片 1 上播放,O 在幻燈片 2 上播放,添加評論,X 在幻燈片 3 上播放,等等)。
答案1
當存在大量重複程式碼時(在本例中,針對不同的遊戲),我會編寫一個巨集來簡化我的乳膠檔案 - 並在需要時更輕鬆地進行更改。
(我)我想到的第一個想法是寫一個作為「輸入」的巨集:
- 以逗號分隔的 X 位置列表
- 以逗號分隔的 O 位置列表
- 評論
我將 X 和 O 位置編碼為 1,2,...,9 在網格中從左到右、從上到下讀取。例如,\NoughtsCrosses{5,6}{9}{Third move}
會產生
(二)第二種方法是假設棋步交替為 X,O,X,...,並給出以逗號分隔的棋步清單以及註釋。例如,\NoughtsCrossesII{5,9,6,4}{Fourth move}
會產生
正如 cfr 在該問題的評論中所說,您可能希望將這些命令包含在類似的內容中,\only<5>{\NoughtsCrossesII{5,9,6,4}{Fourth move}}
以便一次顯示一個動作。我在下面的 MWE 中執行此操作。
(三)考慮到最後一句話,並進行一點OTT,更聰明的巨集將簡單地獲取動作和評論的列表,然後在框架中建立遊戲的所有幻燈片。到目前為止,所有巨集都使用 tikz 和 tikz\foreach
命令允許使用斜線分隔多個循環變量,因此實現此目的的最簡單方法是使用以下語法:
\NoughtsCrossesGame{%
5/First move,
9/Second move,
6/Third move,
4/Fouth move
}
輸出與上面“相同”,只是“遊戲”出現在 4 張幻燈片上。宏觀\NoughtsCrossesGame
採用可選參數,其行為類似指令的可選參數\pause
。也就是說,它充當“偏移”,控制遊戲中的動作何時開始出現在給定幀的幻燈片中。
下面的程式碼給出了上述三個巨集的定義,並完成了 MWE 以展示如何使用它們:
\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}
一些評論:
- 所有巨集都使用蒂克茲繪製遊戲,因為這樣可以更好地控制 X/O 標記的位置和繪製網格
- 該
\PlaceMarker
巨集是一個“輔助函數”,用於將標記放置在指定位置。這用於\ifcase
將位置索引轉換1,2,...,9
為(x,y)
座標。 - 這些巨集用於
\foreach
循環遍歷以逗號分隔的標記位置清單。此外,第二個巨集也用於\ifodd
確定是放置 X 還是 O。 - 「評論」被放置在 tikz 節點內,作為寬度為 40 毫米的參差不齊的左側文字。您可能需要微調 (x,y) 座標的位置和文字的寬度。
- 根據評論中的要求,我改進了宏,以便輕鬆突出顯示某些動作。現在,給予「負位置」索引會為對應的
X
或著色O
。例如,\NoughtsCrosses{-5,-6}{9}{Third move}
將使兩個X
s 變為紅色。 - 更有趣的是,
\NoughtsCrossesGame
巨集現在為每個動作著色,然後在遊戲結束時將最終的「獲勝」連勝標記為藍色 - 必須再次使用負位置索引來突出顯示連勝。在這兩種情況下,著色都是透過 的增強來完成的\PlaceMarker
,儘管 的自動著色\NoughtsCrosses
更複雜。
為了完整起見,以下是此範例產生的最後一張投影片的動畫版本\NoughtsCrossesGame
:
除了beamer製作的框架之外,這組幻燈片本質上是命令的輸出:
\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!
}