diff options
author | Norbert Preining <norbert@preining.info> | 2022-06-29 03:00:54 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2022-06-29 03:00:54 +0000 |
commit | 1803d67dcb084b1d6b825dd2f1a39df83c11db02 (patch) | |
tree | 083814d64daa39afbd3ceea4804d903a2585077a /macros/plain/contrib | |
parent | 2ef43af0215fc52966c9bbd8d5df6db6d6af224b (diff) |
CTAN sync 202206290300
Diffstat (limited to 'macros/plain/contrib')
-rw-r--r-- | macros/plain/contrib/reverxii/README.md | 21 | ||||
-rw-r--r-- | macros/plain/contrib/reverxii/reverxii.dtx | 379 | ||||
-rw-r--r-- | macros/plain/contrib/reverxii/reverxii.pdf | bin | 234070 -> 0 bytes | |||
-rw-r--r-- | macros/plain/contrib/reverxii/reverxii.tex | 18 |
4 files changed, 0 insertions, 418 deletions
diff --git a/macros/plain/contrib/reverxii/README.md b/macros/plain/contrib/reverxii/README.md deleted file mode 100644 index 77fba86111..0000000000 --- a/macros/plain/contrib/reverxii/README.md +++ /dev/null @@ -1,21 +0,0 @@ -Playing Reversi, in the spirit of xii.tex -================================= -* E-mail: blflatex@gmail.com -* Released under the LaTeX Project Public License v1.3c or later - See http://www.latex-project.org/lppl.txt - -The file `reverxii.tex` is a 983 character long (La)TeX program which -lets you play Reversi against your favorite typesetting engine. -Play by running the following command (or the same with `pdftex`, or -`latex`, or `pdflatex` etc.) - - tex reverxii.tex - -in the command line. This will also produce a record of your -game as `reverxii.dvi`. On the other hand, typeset the documentation -by running - - pdflatex reverxii.dtx - -All suggestions/comments/bug reports are welcome! -See https://github.com/blefloch/latex-reverxii diff --git a/macros/plain/contrib/reverxii/reverxii.dtx b/macros/plain/contrib/reverxii/reverxii.dtx deleted file mode 100644 index 084afdc544..0000000000 --- a/macros/plain/contrib/reverxii/reverxii.dtx +++ /dev/null @@ -1,379 +0,0 @@ -{\def\x{plain}\expandafter}\ifx\fmtname\x - \errmessage{Use LaTeX for the documentation reverxii.dtx. Play with reverxii.tex} -\fi -\documentclass{article} -\usepackage{shortvrb,verbatim} -\MakeShortVerb| -\title{\texttt{reverxii}\\ - Playing Reversi in \TeX{}} -\author{Bruno Le Floch} -\date{November 6, 2021} -\newcommand{\cs}[1]{\texttt{\char`\\ #1}} -\newcommand{\meta}[1]{$\langle \mathit{#1}\rangle$} -\newcommand{\enquote}[1]{``#1''} -\begin{document} -\maketitle - -\begin{abstract} - \texttt{reverxii.tex} is a $983$ character long \TeX{} program which - lets you play Reversi against your favorite typestting engine. To - play, run plain \TeX{} or \LaTeX{} (either the dvi or the pdf - engines), on the command line, on the file \texttt{reverxii.tex}. In - most distributions, this can mean running \texttt{tex reverxii.tex} in - a terminal. To typeset the documentation, run \LaTeX{} on - \texttt{reverxii.dtx}, with any engine (\emph{e.g.}, \texttt{pdflatex - reverxii.dtx}). -\end{abstract} - -\section{The code} - -Line breaks can be removed, and the stripped down code takes $983$ -characters. -{\small \verbatiminput{reverxii.tex}} -In fact, the first line and |\ifx\>\:1\fi| are only used to support -\LaTeX{} and can be removed for plain \TeX{}. This reduces the code down to $938$ characters. - -To play a two-player game, change |1=P| to |0=P| near the end: -this changes the computer player from $0$ to $1$, hence disabling it. - -\section{Explanation} - -\subsection{Some comments} - -The name \texttt{reverxii.tex} is of course a reference to the infamous -\texttt{xii.tex}, also on CTAN, which typesets the lyrics of the -\textit{Twelve days of Christmas} using code that very few can understand. -In my case, I aimed for the shortest possible code, rather than the -most obfuscated. In particular, I did not assign weird catcodes -other than making most characters active. - -Since I was aiming for short code, the text presented to the player -is concise, but hopefully enough to leave the game understandable -and usable. Despite aiming for short code, I thought it would be -neat to typeset a record of the game as it goes: after all, \TeX{} -is a typesetting program. This used up around $38$ characters, putting -me above the $900$ character line. - -One technique used to make the code shorter is to rename any primitive -used more than once into a single active character. Also, counters -holding the information about the board are accessed directly by number. - -A careful reader would notice that changing one of the remaining -one-character control sequences to active characters (|$| is still %$ -unused) would gain one character. I didn't do it, because it messes -up the code-highlighting of my editor |:)|. Of course, I chose the -control sequences which are not active characters to be those appearing -the least, only twice each. - -\subsubsection{On with the code!} - -In \LaTeXe{}, detected by comparing the spaces |\>| and~|\:| (only one -of them is defined in plain \TeX{}), load a document class. -\begin{verbatim} -\ifx\>\:\documentclass{report}\fi -\end{verbatim} -We do not need \cs{begin}|{document}| because the text is eventually -typeset inside an \cs{halign} table, which means \cs{everypar} (and its -usual error) is never called. - -First set up the page dimensions. This would not be enough for pdf output. -\begin{verbatim} -\vsize5cm -\hsize3cm -\end{verbatim} - -Since plain \TeX{} does not provide the \cs{typeout} command, we are -using \cs{message}, hence need to setup a new line character. It is -arbitrarily chosen to be |*|, which will be made active and \cs{let} -to \cs{cr}. -\begin{verbatim} -\newlinechar`* -\end{verbatim} - -Then a first loop to make many characters active. The loop ends when -reaching the trailing brace group: there we make spaces active, then -redefine |~| for the next loop. We still have an annoying |13~| in the -input stream. Introduce a short-hand for count registers whose number -starts with |1| (or in fact |11| in \LaTeX{} given the test -|\ifx\>\:1\fi|, see later for why we do this). Then remove |13| by -setting |\count11| to |213| (this counter is used for allocation later -on). The next loop is triggered by the |~| which we left. -\begin{verbatim} -\def~#1{\catcode`#113~} -~IJKLMNOPQRSTUVWXYZjqz@.[|](/+^'";:?,_)!* -{ 13\def~#1#2{\let#1#2~}\def+{\count\ifx\>\:1\fi1}+1=2} -\end{verbatim} - -At this stage, |~| is defined to take two arguments, \cs{let} the -first to the second, and repeat. As announced |*| becomes \cs{cr}, -so that it will be a new line both in messages and in alignments. -We try to keep a relatively consistent naming scheme: opening -conditionals are left delimiters, \cs{or} and \cs{else} are -middle delimiters, and \cs{fi} is a right bracket. Other primitives -which are used a lot are also given short names. The loop ends by -redefining |~| to \cs{def}. -\begin{verbatim} -*\cr -[\ifnum -(\ifcase -|\or -/\else -]\fi -N\number -@\advance -X\expandafter -!\global -?\message -~\def -\end{verbatim} - -It is time to allocate counters. Unfortunately, \cs{newcount} is -\cs{outer} in plain \TeX{}, so it is unpractical to use. We have -defined |+| to be |\count1| in plain and |\count11| in \LaTeX{}. This -will eventually let us access a table of $8\times 8$ counters |+11| to -|+88|, which are thus |\count111| to |\count188| in plain, and -|\count1111| to |\count1188| in \LaTeX{}. This is needed because plain -\TeX{} without e\TeX{} extensions only has $256$ counters, while -\LaTeX{} \emph{uses} some of these counters already so we must use the -higher counters provided by the e\TeX{} extensions, always available in -\LaTeX{}. The following text explains the plain \TeX{} case; in the -other case just replace |\count1| by |\count11|. - -We have set |+1|, -\emph{aka.} |\count11| to $213$, and will allocate counters -starting from that number upwards. Repeatedly advance |+1| -by $1$ and define the next character to be the counter number |+1|, -then repeat. As always, the loop is interrupted by making it -redefine the looping macro |.| to be a counter. We use the trailing -dot to assign it the value $-1$, then assign a couple of counters: -starting player, other player, and the initial position: -the squares in rows and columns $4$ and $5$ are initially -filled in a cross pattern. -\begin{verbatim} -.#1{@+1 1\countdef#1+1.}.IJKLPQRSTUVWYZ.-1P1T2+44P+55P+45T+54T -\end{verbatim} -Let us summarize which counters are used where: -\begin{itemize} -\item [P] is the current player ($1$ for |-| or $2$ for |0|); -\item [T] is the other player; -\item [Q] is the row number; -\item [J] is the column number; -\item [S] is the step size in the row direction; -\item [K] is the step size in the column direction; -\item [R] is the score difference, positive when $0$ is winning; -\item [V] is used when computing the value of placing a piece at - the position (|Q|,|J|); -\item [W] is the value of the best possible move according to the AI, - also used to end the game if neither player can move; -\item [U] is the row number of the best move; -\item [L] is the column number of the best move; -\item [Y] is a boolean, true ($0$) most of the time, - it has to do with when we flip or not, but I don't - understand it now, help welcome; -\item [Z] is a temporary counter, used locally to compute - how much a given cell matters (\emph{i.e.} corners are important), - and used globally as a boolean to indicate whether to flip pieces - or not. -\end{itemize} - -The board is stored in counters |1|\meta{row}\meta{column}. -An empty square is has the value $0$, a square for player |-| -has value $1$, and player |0| corresponds to the value $2$. -The macro |j| retrieves that value, assuming that the row and -column numbers are stored as |Q| and |J|, and returns |.|, -that is, $-1$, if outside the board. Recall that |[| is \cs{ifnum}, -|/| is \cs{else}, and |]| is \cs{fi}. When |Q| and |J| are -within bounds, the value is retrieved by |^| as -|\count1|\meta{row}\meta{column}. Note that |j| and |^| are -only safe to use on the left-hand side of an \cs{ifnum} test -(because of expansion issues), and that |^| can be used -on the left-hand side of an assignment. -\begin{verbatim} -~j{[0<Q[9>Q[0<J[9>J^/.]/.]/.]/.]} -~^{+NQNJ} -\end{verbatim} - -We often need to loop over numbers from $1$ to $8$; here is a macro. -\begin{verbatim} -~:#1{#11#12#13#14#15#16#17#18} -\end{verbatim} - -The macros to print the board, both to the dvi and to the console. -|M| spews its argument as a \cs{message} (|?|), and directly typeset. -This is used rather directly to print the first and last lines (|'|), -which are simply alignment cells containing each number from $1$ to $8$, -with some care given to spaces and new lines. -The |_| macro receives a digit and the corresponding capital letter -as arguments, and outputs that row of the board. First place the -letter on the left of the board, then loop from $1$ to $8$, -typesetting and \cs{message}ing a space, |-| or |0|, depending on -the value of the relevant count register. Note the two spaces -in the definition: the first ends the counter's number, the second -is typeset (in plain \TeX{}, active spaces expand to a normal space). -\begin{verbatim} -~M#1{?{#1}#1} -~'{M :{&M}&M{*}} -~_#1#2{M#2:{\B#1}&M#2&M{*}} -~\B#1#2{&M{(+#1#2 |-|0]}} -\end{verbatim} - -The input is done by |q|, which queries the user until they give -a correct input, so that |Q| and |J| are in the range $[1,8]$. -Prompt the user with a small \cs{message}, giving an example -of what move he could do (only true at the start, but the hope -is that the player will understand what the input format is). -The code that follows is similar to \LaTeXe{}'s \cs{@onelevel@sanitize}. -We extract the two first characters from the the \cs{meaning} -of the user's input (remember, |X| is \cs{expandafter}), -as |#2| and |#3| of \cs{D}. Grab the character code of each, -relative to the characters |@| (row) or |0| (column). -The closing parenthesis is where most of the work is done. -It sets |V| to the value of placing a piece in the cell -$(|Q|,|J|)$, zero if the move does not flip any of the opponent's -pieces, or if the cell is outside the board. After performing -that calculation, if |V| is zero, the move was not valid, -and we query the user again. -\begin{verbatim} -~q{?{Row and column? e.g. E6*}\read.to\EX\D\meaning\E ;} -~\D#1->#2#3#4;{Q`#2@Q-`@J`#3@J-`0)(V?{Invalid move #2#3.}q]} -\end{verbatim} - -So\ldots{} how do we compute the \enquote{value} of a move? -It is automatically invalid if |j| does not return $0$: -either the cell is occupied, or it is outside the board. -Then for each of the $8$ directions around the cell, -we count the number of pieces that are flipped in that -direction. The direction is stored as two counters, -|S| and |K|, each $\pm 1$ or $0$. We call |,| a first -time to test whether flipping should happen in that direction, -and, if it is (as indicated by the global value of |Z|), -call it again to actually flip. The call to |,| must happen -within a group, because it directly changes the row and column -numbers |Q| and |J|, following which cell is being queried. -\begin{verbatim} -~){V0 (jS1z1z0z.S0z1z.S.z1z0z.]} -~z#1{{K#1Z1{Y1,}(Z,]}} -\end{verbatim} - -The macro |,| is recursive. At each step, move $(|Q|,|J|)$ -in the direction $(|S|,|K|)$. Then, if that cell (|j|) -contains a piece belonging to the other player (|T|), -do some stuff |(Y!^P!;2]O| and repeat. What is it that -we do? Well, if the condition |Y| is met (I don't remember -how that works), we set the current cell to belong to the -player, globally, and change the score difference by $2$ -(see |;|), also globally. Then, we compute with |O| the value -corresponding to the cell that we might be flipping (see |O|). - -Otherwise (|/|), if the cell (|j|) contains a piece from the -current player (|P|), it means we have reached the end of a -run of the form \meta{initial cell} \meta{opponent's pieces} -\meta{own piece}, hence the \meta{opponent's pieces} should -count as flipped if we place our piece in the \meta{initial - cell}. Until there, all changes to |V| were local, returning -to the old value at the end of the group that |,| is contained -in. Since the run in that direction was successful, we escape -the value of |V| from the group with |\global V=V|. Under -some conditions, we set the boolean |Z| to true, globally (|!Z0|), -which triggers a second call to |,| with different setting, -and actually flips the opponent's pieces. -\begin{verbatim} -~,{@QS@JK[j=T(Y!^P!;2]O,/[j=P!VV(I(Y/!Z0]]]]} -\end{verbatim} - -I moved those |O| and |"| guys a little bit in this explanation, -but not in the original implemenation, because it is hard -to sync. We assign weights to each of the $64$ cells: -\begin{center} - \halign{&\hfil#\hfil\cr - 9 & 1 & 6 & 6 & 6 & 6 & 1 & 9 \cr - 1 & 1 & 2 & 2 & 2 & 2 & 1 & 1 \cr - 6 & 2 & 4 & 4 & 4 & 4 & 2 & 6 \cr - 6 & 2 & 4 & 4 & 4 & 4 & 2 & 6 \cr - 6 & 2 & 4 & 4 & 4 & 4 & 2 & 6 \cr - 6 & 2 & 4 & 4 & 4 & 4 & 2 & 6 \cr - 1 & 1 & 2 & 2 & 2 & 2 & 1 & 1 \cr - 9 & 1 & 6 & 6 & 6 & 6 & 1 & 9 \cr} -\end{center} -All weights are positive, so that every move which flips a piece -ends up with a positive overall value. The AI would be better if -the places next to corners had a negative weight, but I would have -too much code to rewrite for that to work. We really have three -types of rows and three types of columns. Converting from |Q| -or |J| is done by |"|, then we assemble the two as a number -in the range $[0,8]$, and use another \cs{ifcase} construction -to produce the weights. -\begin{verbatim} -~O{Z"Q\multiplyZ3@Z"J@V(Z9|1|6|1|1|2|6|2|4] } -~"#1{(#1|0|1|2|2|2|2|1|0]} -\end{verbatim} - -The counter |R| keeps track of the score difference, -and is updated with |;2| (when flipping a piece) or |;1| (when -adding a piece). The counter |R| should be \cs{advance}d (|@|) -by a positive amount when the current player |P| is player |0|, -and a negative amount for player |-|. -\begin{verbatim} -~;{@R(P|-]} -\end{verbatim} - -After printing the board, we go through every cell and find the -one with the highest value. The macro \cs{A}, does one row, hence -|\:\A| does all the rows. Store the argument as the row number |Q|, -then loop over columns. After setting the column number |J| to -its argument, \cs{C} calls |)|, which as explained above computes -the value of placing a piece there, throws away that case if it flips -nothing, otherwise also counts the weight of the current cell. Then -update the best value |W| and the best row |U| and column |L| if -the new |V| is larger than |W|. -\begin{verbatim} -~\A#1{Q#1:\C} -~\C#1{J#1)[0<VO[V>WWVUQLJ]]} -\end{verbatim} - -We won't need |~| as \cs{def} anymore, so we reuse it as the main command. -\begin{itemize} -\item First exchange the players: set |P| equal to |T|, but first expand - the value of |P| after |T| to set that as well. -\item Secondly, open an alignment, with a repeating preamble adding a space - at its end. Then message a new-line (we should be using |?| rather than - |M| here, I think) to keep a clean output. Afterwards, print the top line - with |'|, the eight lines of the bulk with |_|, and the bottom line, - which happens to end with |?{*}*|, \emph{i.e.}, ends with \cs{cr}: - we can thus close the alignment, and cause \TeX{} to output the page. -\item After printing, it is time to check whether there is a move or not. - We don't want to flip pieces at this stage, hence set the boolean |I| - to false ($1$). And we reset the best value to $0$, unless it was - already $0$ (which means that the previous player had no available - move), in which case we set it to $-1$. Then loop over rows, finding - the best value (see \cs{A}). Reset the boolean |I| to be true. -\item If a move was found in the previous step ($|W|>0$), either - use it if the player is the AI, or query the user. The various - booleans are set up in such a way as to do the flipping, so - calling |)| does it. Then also put a player's piece in the current - cell |^|, and increase the score difference by $1$. -\item Finally, if neither player could move, declare the game ended, - give the score, and \cs{dump} the run (not \cs{end} because we want to - support both plain \TeX{} and \LaTeX{}). Otherwise, repeat. -\end{itemize} -Of course, after defining |~|, we call it. Let's play! -\begin{verbatim} -~~{ - PXTXTNP - \halign{&## *M{*}'_1A_2B_3C_4D_5E_6F_7G_8H'}\vfil\break - I1 W(W./0] :\AI0 - [0<W - [1=PQUJL/q] - ) - ^P;1 - ] - [.=W - ?{(RTie/ Player [0>R-/0] wins by N[0>R-]R].} - X\dump - ] - ~ -} -~ -\end{verbatim} - -\end{document}
\ No newline at end of file diff --git a/macros/plain/contrib/reverxii/reverxii.pdf b/macros/plain/contrib/reverxii/reverxii.pdf Binary files differdeleted file mode 100644 index 3117f4b371..0000000000 --- a/macros/plain/contrib/reverxii/reverxii.pdf +++ /dev/null diff --git a/macros/plain/contrib/reverxii/reverxii.tex b/macros/plain/contrib/reverxii/reverxii.tex deleted file mode 100644 index 85e5c4ea83..0000000000 --- a/macros/plain/contrib/reverxii/reverxii.tex +++ /dev/null @@ -1,18 +0,0 @@ -\ifx\>\:\documentclass{report}\fi -\vsize5cm\hsize3cm\newlinechar`*\def~#1{\catcode`#113~} -~IJKLMNOPQRSTUVWXYZjqz@.[|](/+^'";:?,_)!*{ 13\def~#1#2{\let#1#2~} -\def+{\count\ifx\>\:1\fi1}+1=2}*\cr[\ifnum(\ifcase|\or/\else]\fiN\number -@\advanceX\expandafter!\global?\message~\def.#1{@+1 1\countdef#1+1.} -.IJKLPQRSTUVWYZ.-1P1T2+44P+55P+45T+54T -~j{[0<Q[9>Q[0<J[9>J^/.]/.]/.]/.]} -~^{+NQNJ}~:#1{#11#12#13#14#15#16#17#18}~M#1{?{#1}#1} -~_#1#2{M#2:{\B#1}&M#2&M{*}}~\B#1#2{&M{(+#1#2 |-|0]}} -~q{?{Row and column? e.g. E6*}\read.to\EX\D\meaning\E ;} -~\D#1->#2#3#4;{Q`#2@Q-`@J`#3@J-`0)(V?{Invalid move #2#3.}q]} -~){V0 (jS1z1z0z.S0z1z.S.z1z0z.]}~;{@R(P|-]}~z#1{{K#1Z1{Y1,}(Z,]}} -~,{@QS@JK[j=T(Y!^P!;2]O,/[j=P!VV(I(Y/!Z0]]]]}~\A#1{Q#1:\C} -~\C#1{J#1)[0<VO[V>WWVUQLJ]]}~"#1{(#1|0|1|2|2|2|2|1|0]} -~O{Z"Q\multiplyZ3@Z"J@V(Z9|1|6|1|1|2|6|2|4] }~'{M :{&M}&M{*}} -~~{PXTXTNP\halign{&## *M{*}'_1A_2B_3C_4D_5E_6F_7G_8H'}\vfil\break -I1W(W./0] :\AI0 [0<W[1=PQUJL/q])^P;1][.=W?{(RTie/ Player [0>R-/0] -wins by N[0>R-]R].}X\dump]~}~
\ No newline at end of file |