2 % modified to work with older babel versions
3 \NeedsTeXFormat{LaTeX2e}
4 \ProvidesPackage{lyxskak}
6 \DeclareOption{tiny}{\AtEndOfClass{\tinyboard}}
7 \DeclareOption{small}{\AtEndOfClass{\smallboard}}
8 \DeclareOption{normal}{\AtEndOfClass{\normalboard}}
9 \DeclareOption{large}{\AtEndOfClass{\largeboard}}
10 \DeclareOption{notation}{\AtEndOfClass{\notationOn}}
11 \DeclareOption{mover}{\AtEndOfClass{\showmoverOn}}
12 \DeclareOption{moveroff}{\AtEndOfClass{\showmoverOff}}
13 \DeclareOption{notationoff}{\AtEndOfClass{\notationOff}}
14 \DeclareOption{ps}{\def\ps@on{\True}}
15 \DeclareOption{psoff}{\def\ps@on{\False}}
16 \DeclareOption{english}{\AtEndOfClass{\skaklanguage[english]}}
17 \DeclareOption{styleA}{\AtEndOfClass{\styleA}}
18 \DeclareOption{styleB}{\AtEndOfClass{\styleB}}
19 \ExecuteOptions{notation,normal,psoff,english,moveroff,styleB}
21 %\AtBeginDocument{\skaklanguage{english}}
23 \RequirePackage{lambda,ifthen,calc}
24 % Now, we rename the ifthenelse here as skak@ifthenelse and then use that
25 % this is to co-exist with older babel.sty that redefine ifthenelse!
26 \let\skak@ifthenelse\ifthenelse
27 \ps@on{\RequirePackage{pstricks,pst-node}\SpecialCoor%
28 \newpsstyle{psskak}{arrowinset=0,nodesep=.25,armA=.75,arrowsize=.2 1,
29 linearc=.2,arrowlength=1.25,linewidth=0.04,
30 doubleline=true,doublesep=.06}}{}
34 % list related functions
35 \def\IsNil#1{#1{\False}{\True}}
37 \def\Member#1#2#3% ('a -> 'a -> bool) -> 'a -> 'a list -> bool
38 {#3{\MemberA{#1}{#2}}{\False}}
42 {\Member{#1}{#2}{#4}}}
44 % Explode: string -> char list
45 \def\Explode#1{\EqStr{Z}{#1}{\Nil}{\ExplodeA#1Z}}
46 \def\ExplodeA#1#2Z{\EqStr{Z}{#2}%
48 {\Cons{#1}{\ExplodeA#2Z}}}
50 \def\BoolToString#1{% bool -> string
53 % the basic manipulation of the board
54 \def\Set#1#2{% square -> piece -> unit
55 \expandafter\xdef\csname#1\endcsname{#2}}
56 \def\Get#1{% square -> piece
60 \expandafter\def\csname#1\endcsname{#2}}
65 \def\PieceNames{\Listize[K,Q,R,B,N]}
66 \def\FileNames{\Listize[a,b,c,d,e,f,g,h]}
67 \def\RankNames{\Listize[1,2,3,4,5,6,7,8]}
69 %% what pieces to show
70 %\def\ShowOnlyList{\Listize[K,Q,R,B,N,P,k,q,r,b,n,p]}
72 \def\showonly#1{\expandafter\def\csname ShowOnlyList\endcsname{\Listize[#1]}}
73 \def\showall{\showonly{K,Q,R,B,N,P,k,q,r,b,n,p}}
76 \def\showonlywhite{\showonly{K,Q,R,B,N,P}}
77 \def\showonlyblack{\showonly{k,q,r,b,n,p}}
78 \def\showonlypawns{\showonly{p,P}}
82 {#1\def\next{#2}\else\def\next{#3}\fi
84 \def\EqStr#1#2{% % has to be changed
86 \def\EqPiece#1#2{\TeXif{\if#1#2}}
89 \def\RankOf(#1){\Second{#1}}
90 \def\FileOf(#1){\First{#1}}
93 \skak@ifthenelse{\equal{#1}{#2}}{\True}{\False}}
95 %% is this really necessary????
96 \def\MySecond(#1#2){#2}
97 \def\MyFirst(#1#2){#1}
99 \def\MyEqual#1#2{% string -> string -> bool
100 \xdef\arga{#1}\xdef\argb{#2}%
101 \TeXif{\ifx\arga\argb }}
102 % \skak@ifthenelse{\equal{#1}{#2}}{\True}{\False}}
104 \def\MyEqualB#1#2#3#4{%
105 \skak@ifthenelse{\equal{#1}{#2}}{#3}{#4}}
107 \def\myrightfile#1#2{% filediscriminator -> square -> bool
108 \Member{\MyEqual}{#2}{\File{#1}}}
110 \def\RightRank(#1){%square -> bool
111 \EqStr{\RankDiscriminator}{Z}%
113 % {\EqStr{\RankDiscriminator}{\Second{#1}}}}
114 % {\expandafter\EqStr{\RankDiscriminator}{\MySecond(#1)}}}
115 {\Member{\MyEqual}{#1}{\Rank{\RankDiscriminator}}}}
116 \def\RightFile(#1){%square -> bool
117 \EqStr{\FileDiscriminator}{Z}%
119 {\Member{\MyEqual}{#1}{\File{\FileDiscriminator}}}}
121 % {\myrightfile{\FileDiscriminator}{#1}}}
123 % {\expandafter\EqStr{\FileDiscriminator}{\FileOf(#1)}}}
124 % {\edef\myhelper{\MyFirst(#1)}\Unlistize{\Explode{#1Z}}%
125 % (rf-test\myhelper)\EqStr{\FileDiscriminator}{\myhelper}}}
126 %% {(rf-test)\EqStr{\FileDiscriminator}{\MyFirst(#1)}}}
129 \def\Glue#1#2% 'a -> 'b -> 'ab , eg. a -> 1 -> a1
132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133 %%%%% adding ornaments to a board %%%%%%%%%%%%%%%%%%%
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135 % usefull when adding ps arrows:
136 % set@fileangle: from -> to -> angle -> unit
137 \def\set@fileangle#1#2#3{%
138 \expandafter\xdef\csname fileangle.#1.#2\endcsname{#3}}
139 \def\get@fileangle#1#2{\ifx\csname fileangle.#1.#2\endcsname\relax
140 \errmessage{Files #1 and #2 does not belong to a valid knight move}%
141 \else \csname fileangle.#1.#2\endcsname\fi}
142 \def\set@rankangle#1#2#3{%
143 \expandafter\xdef\csname rankangle.#1.#2\endcsname{#3}}
144 \def\get@rankangle#1#2{\ifx\csname rankangle.#1.#2\endcsname\relax%
145 \errmessage{Ranks #1 and #2 does not belong to a valid knight move}%
146 \else \csname rankangle.#1.#2\endcsname\fi}
148 \def\testfileangle{fileangles:\get@fileangle{a}{b},\get@fileangle{h}{f}}
149 \def\testrankangle{rankangles:\get@rankangle{1}{3},\get@rankangle{4}{5}}
152 \set@fileangle{a}{b}{0}\set@fileangle{a}{c}{0}
154 \set@fileangle{b}{a}{0}\set@fileangle{b}{c}{0}\set@fileangle{b}{d}{0}
156 \set@fileangle{c}{a}{180}\set@fileangle{c}{b}{0}
157 \set@fileangle{c}{d}{0}\set@fileangle{c}{e}{0}
159 \set@fileangle{d}{b}{180}\set@fileangle{d}{c}{0}
160 \set@fileangle{d}{e}{0}\set@fileangle{d}{f}{0}
162 \set@fileangle{e}{c}{180}\set@fileangle{e}{d}{0}
163 \set@fileangle{e}{f}{0}\set@fileangle{e}{g}{0}
165 \set@fileangle{f}{d}{180}\set@fileangle{f}{e}{0}
166 \set@fileangle{f}{g}{0}\set@fileangle{f}{h}{0}
168 \set@fileangle{g}{e}{180}\set@fileangle{g}{f}{0}\set@fileangle{g}{h}{0}
170 \set@fileangle{h}{f}{180}\set@fileangle{h}{g}{0}
173 \set@rankangle{1}{2}{0}\set@rankangle{1}{3}{90}
175 \set@rankangle{2}{1}{0}\set@rankangle{2}{3}{0}\set@rankangle{2}{4}{90}
177 \set@rankangle{3}{1}{270}\set@rankangle{3}{2}{0}
178 \set@rankangle{3}{4}{0}\set@rankangle{3}{5}{90}
180 \set@rankangle{4}{2}{270}\set@rankangle{4}{3}{0}
181 \set@rankangle{4}{5}{0}\set@rankangle{4}{6}{90}
183 \set@rankangle{5}{3}{270}\set@rankangle{5}{4}{0}
184 \set@rankangle{5}{6}{0}\set@rankangle{5}{7}{90}
186 \set@rankangle{6}{4}{270}\set@rankangle{6}{5}{0}
187 \set@rankangle{6}{7}{0}\set@rankangle{6}{8}{90}
189 \set@rankangle{7}{5}{270}\set@rankangle{7}{6}{0}\set@rankangle{7}{8}{0}
191 \set@rankangle{8}{6}{270}\set@rankangle{8}{7}{0}
193 % PSTricks addon that allows hollow arrowheads
195 \edef\pst@arrowtable{\pst@arrowtable,<|-|>}
196 \def\tx@ArrowTriangleA{ArrowTriangleA }
197 \def\tx@ArrowTriangleB{ArrowTriangleB }
199 /ArrowTriangleA { CLW dup 3.5 div SLW mul add dup 2 div /w ED mul dup
201 0 h a sub moveto w h L 0 0 L w neg h L 0 h a sub L
202 gsave 1 setgray fill grestore gsave
203 stroke grestore } def
204 \psk@arrowinset \psk@arrowlength \psk@arrowsize
207 /ArrowTriangle { CLW dup 2 div SLW mul add dup 2 div
208 /w ED mul dup /h ED mul /a ED
209 { 0 h T 1 -1 scale } if w neg h moveto 0 0 L w h L w neg a neg
210 rlineto w neg a rlineto w 0 rmoveto gsave stroke grestore } def
211 true \psk@arrowinset \psk@arrowlength \psk@arrowsize
213 % end of PSTricks addon
217 \newcounter{ps@knightangle} \newcounter{ps@inverse}
218 \def\printknightmove#1#2{%
219 \setcounter{ps@knightangle}{\get@fileangle{\First#1}{\First#2}+%
220 \get@rankangle{\Second#1}{\Second#2} + \value{ps@inverse}}%
221 \ncdiagg[style=psskak,angleA=\arabic{ps@knightangle}]{-|>}{#1}{#2}}
223 \def\printarrow#1#2{\ncline[style=psskak]{-|>}{#1}{#2}}
225 \def\ps@highlightsquare#1{%
226 \pscustom[linewidth=.06]{\translate(#1)\psframe(-.5,-.5)(.5,.5)}}
228 \def\highlight#1{% comma separated list eg, \highlight{a1,b4,d4}
229 \Apply{\ps@highlightsquare}{\Listize[#1]}}
230 %%%%% end of adding ornaments to a board %%%%%%%%%%%%%%%%%%%%%%%%
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235 %%%%% support for other languages %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 % \uc@king queen rook bishop knight pawn holds the letters
238 % representinng the pieces in the current language
239 % \skak@currentPieceNames : char list, holds the current piece names
240 % \def\skak@pieceToEnglish#1{% string -> string, (pgn(curr. lang) -> pgn(eng))
241 % \skak@piece@toEnglish(#1Z)}
242 \def\skak@piece@toEnglish#1{%
243 \EqPiece{#1}{\uc@king}%
245 {\EqPiece{#1}{\uc@queen}%
247 {\EqPiece{#1}{\uc@rook}%
249 {\EqPiece{#1}{\uc@bishop}%
251 {\EqPiece{#1}{\uc@knight}%
253 {\errmessage{not a valid piece name in the current language:#1}}}}}}}
256 % {\skak@pgn@toEnglish(#2)}}
258 \def\skak@englishToEnglish#1{#1}
260 \def\skak@definepieces#1#2#3#4#5#6{%
268 \def\newskaklanguage#1#2{%
269 \expandafter\xdef\csname skaklanguage.#1\endcsname{#2}}
271 \newcommand{\skaklanguage}[1][english]{%
272 %\def\skaklanguage#1{%
273 \def\currentlanguage{#1}%
274 \skak@ifthenelse{\equal{#1}{english}}%
275 {\let\skak@pieceToEnglish=\skak@englishToEnglish%
276 \def\PieceNames{\Listize[K,Q,R,B,N]}}
277 {\edef\temp@lang{\csname skaklanguage.#1\endcsname}
278 \expandafter\skak@definepieces\temp@lang%
279 \let\skak@pieceToEnglish=\skak@piece@toEnglish%
281 \Listize[\uc@king,\uc@queen,\uc@rook,\uc@bishop,\uc@knight]}}}
284 \def\showskaklanguage{%
285 (\uc@king)(\uc@queen)(\uc@rook)(\uc@bishop)(\uc@knight)(\uc@pawn)}
287 %%%%% end of language support %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291 %%%%% parsing macros %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
293 \def\IsPieceName#1{\Member{\EqPiece}{#1}\PieceNames}
294 \def\IsFile#1% char -> bool
295 {\Member{\EqStr}{#1}\FileNames}
296 \def\IsRank#1% char -> bool
297 {\Member{\EqStr}{#1}\RankNames}
298 \def\IsCapture#1% char -> bool
300 \def\IsPromotion#1% char -> bool
302 \def\IsDash#1% char -> bool
304 \def\IsO#1% char -> bool
307 \def\File#1% file -> square list, eg. a -> [a1,a2,...,a8]
308 {\Map{\Glue{#1}}{\RankNames}}
309 \def\Rank#1% rank -> square list, eg. 1 -> [a1,b1,...,h1]
310 {\Map{\Twiddle\Glue{#1}}{\FileNames}}
313 % Compose: ('b -> 'c) -> ('a -> 'b) -> ('a -> c')
314 % Second: 'a -> 'b -> 'b
316 % Compose Second f: 'a -> ('a -> 'b -> unit)
317 % \def\Apply#1#2% ('a -> unit) -> ('a list -> unit)
318 % {\Force{\Map{#1}{#2}}}
319 % \def\Force#1{#1\ForceA{}}
320 % \def\ForceA#1{#1\Foldr\DoIt{}}
321 % \def\DoIt#1#2{#1#2}
323 \def\Sideeffect#1#2#3{% ('a -> unit) -> ('a -> 'b -> unit)
326 \def\Apply#1#2{% ('a -> unit) -> 'a list -> unit
327 \Foldr{\Sideeffect{#1}}{\relax}{#2}}
331 {\Apply{\Twiddle\Set{E}}{\Rank{1}}
332 \Apply{\Twiddle\Set{E}}{\Rank{2}}
333 \Apply{\Twiddle\Set{E}}{\Rank{3}}
334 \Apply{\Twiddle\Set{E}}{\Rank{4}}
335 \Apply{\Twiddle\Set{E}}{\Rank{5}}
336 \Apply{\Twiddle\Set{E}}{\Rank{6}}
337 \Apply{\Twiddle\Set{E}}{\Rank{7}}
338 \Apply{\Twiddle\Set{E}}{\Rank{8}}}
361 \def\ParseFenRank#1{\ParseFenRankA(#1Z)}
362 \def\ParseFenRankA(#1#2){%
365 {\FenConvert{#1}\ParseFenRankA(#2)}}
367 \def\SetCheckKing#1#2{% square -> piece -> unit
369 {\edef\WhiteKingSquare{#1}}%
371 {\edef\BlackKingSquare{#1}}%
375 \def\InitRank#1#2#3#4#5#6#7#8#9{%
376 \SetCheckKing{a#9}{#1}%
377 \SetCheckKing{b#9}{#2}%
378 \SetCheckKing{c#9}{#3}%
379 \SetCheckKing{d#9}{#4}%
380 \SetCheckKing{e#9}{#5}%
381 \SetCheckKing{f#9}{#6}%
382 \SetCheckKing{g#9}{#7}%
383 \SetCheckKing{h#9}{#8}}
385 \def\SetRank#1#2{% rank -> fenrank -> unit
386 \edef\pap{\ParseFenRank{#2}}%
387 \expandafter\InitRank\pap#1}
390 \def\InitBoard(#1/#2/#3/#4/#5/#6/#7/#8){%
401 \def\WhiteCastling{-}
402 \def\BlackCastling{-}
404 \def\ExtractWhiteCastling#1{\def\tempCastling{-}%
405 \ExtractWhiteCastlingA(#1Z)%
406 \edef\WhiteCastling{\tempCastling}}
407 \def\ExtractWhiteCastlingA(#1#2){%
410 {\Or{\EqPiece{K}{#1}}{\EqPiece{Q}{#1}}%
411 {\EqStr{-}{\tempCastling}%
412 {\edef\tempCastling{#1}\ExtractWhiteCastlingA(#2)}%
413 {\edef\tempCastling{\tempCastling#1}}}%
414 {\ExtractWhiteCastlingA(#2)}}}
416 \def\ExtractBlackCastling#1{\def\tmpCastling{-}%
417 \ExtractBlackCastlingA(#1Z)%
418 \edef\BlackCastling{\tmpCastling}}
419 \def\ExtractBlackCastlingA(#1#2){%
422 {\Or{\EqPiece{k}{#1}}{\EqPiece{q}{#1}}%
423 {\EqStr{-}{\tmpCastling}%
424 {\edef\tmpCastling{#1}\ExtractBlackCastlingA(#2)}%
425 {\edef\tmpCastling{\tmpCastling#1}}}%
426 {\ExtractBlackCastlingA(#2)}}}
428 \newcounter{halfmove}
430 \def\fenboard#1{\FenBoard#1)}
431 \def\FenBoard#1 #2 #3 #4 #5 #6){%
433 \def\WhiteToMove{\EqStr{w}{#2}}%
434 \ExtractWhiteCastling{#3}%}
435 \ExtractBlackCastling{#3}%}
436 \def\EnPassantSquare{#4}%
437 \setcounter{halfmove}{#5}%
438 \setcounter{move}{#6}}
441 \newcounter{helpgobble}
446 \def\Fen@RawRank#1{\PieceToFen{\Get{a#1}}\PieceToFen{\Get{b#1}}%
447 \PieceToFen{\Get{c#1}}\PieceToFen{\Get{d#1}}%
448 \PieceToFen{\Get{e#1}}\PieceToFen{\Get{f#1}}%
449 \PieceToFen{\Get{g#1}}\PieceToFen{\Get{h#1}}}
452 \EqStr{-}{\WhiteCastling}%
455 \EqStr{-}{\BlackCastling}%
460 \def\Fen@handlenumbers#1#2#3#4#5#6#7#8{\setcounter{helpgobble}{0}%
461 \Fen@handleA(#1#2#3#4#5#6#7#8Z)}
462 \def\Fen@handleA(#1#2){%
464 {\ifnum0=\thehelpgobble%
465 \else\edef\temp@rank{\temp@rank\arabic{helpgobble}}\fi}%
467 {\stepcounter{helpgobble}\Fen@handleA(#2)}%
468 {\ifnum0=\thehelpgobble\edef\temp@rank{\temp@rank#1}\Fen@handleA(#2)%
469 \else\edef\temp@rank{\temp@rank\arabic{helpgobble}#1}%
470 \setcounter{helpgobble}{0}\Fen@handleA(#2)\fi}}}
473 \def\Fen@Rank#1{\edef\temp@rank{}\edef\temp@rankA{\Fen@RawRank{#1}}%
474 \expandafter\Fen@handlenumbers\temp@rankA}
477 \Fen@Rank{8}\edef\temp@board{\temp@rank/}%
478 \Fen@Rank{7}\edef\temp@board{\temp@board\temp@rank/}%
479 \Fen@Rank{6}\edef\temp@board{\temp@board\temp@rank/}%
480 \Fen@Rank{5}\edef\temp@board{\temp@board\temp@rank/}%
481 \Fen@Rank{4}\edef\temp@board{\temp@board\temp@rank/}%
482 \Fen@Rank{3}\edef\temp@board{\temp@board\temp@rank/}%
483 \Fen@Rank{2}\edef\temp@board{\temp@board\temp@rank/}%
484 \Fen@Rank{1}\edef\temp@board{\temp@board\temp@rank}%
485 \edef\temp@board{\temp@board\space\WhiteToMove{w}{b}}%
486 \edef\temp@board{\temp@board\space\PrintCastling\space\EnPassantSquare}%
487 \edef\temp@board{\temp@board\space\arabic{halfmove}\space\arabic{move}}}
490 \def\boardasfen{\Fen@calculate\temp@board} % if someone wants fen in
494 %%%%% manipulation of the board state
495 % the special out-of-bounds square
496 \Set{Offboard}{X} % note: no piece is named X
498 \def\EnPassantSquare{-}% updated by ExecuteMove
501 \def\WhiteToMove{\True}
503 \def\WhiteKingSquare% unit -> square
505 \def\BlackKingSquare% unit -> square
507 \def\KingSquare#1{% bool -> square
508 #1\WhiteKingSquare\BlackKingSquare}
509 \def\SetKingSquare#1#2{% bool -> square -> unit
510 #1{\xdef\WhiteKingSquare{#2}}{\xdef\BlackKingSquare{#2}}}
513 % neighbours of a square
514 \def\SetNeighbour#1#2#3% direction -> square -> square -> unit, #2's
515 % neighbour in direction #1 is #3
516 {\expandafter\xdef\csname#1.#2\endcsname{#3}}
517 \def\GetNeighbour#1#2% direction -> square -> square
518 {\csname#1.#2\endcsname}
520 % first we deal with the board boarder ;-)
521 \def\FF#1#2{\SetNeighbour{#1}{#2}{Offboard}}
523 \def\ForwardDirection#1% bool -> direction; up for white, down for black
525 \def\BackwardDirection#1% bool -> direction
527 \def\LeftDirection#1% bool -> direction
529 \def\RightDirection#1% bool -> direction
533 \Apply{\FF{left}}{\File{a}}
534 \Apply{\FF{upleft}}{\File{a}}
535 \Apply{\FF{downleft}}{\File{a}}
536 \Apply{\FF{right}}{\File{h}}
537 \Apply{\FF{upright}}{\File{h}}
538 \Apply{\FF{downright}}{\File{h}}
539 \Apply{\FF{up}}{\Rank{8}}
540 \Apply{\FF{upleft}}{\Rank{8}}
541 \Apply{\FF{upright}}{\Rank{8}}
542 \Apply{\FF{down}}{\Rank{1}}
543 \Apply{\FF{downleft}}{\Rank{1}}
544 \Apply{\FF{downright}}{\Rank{1}}
547 \def\SetUpNeighbour#1#2#3% direction -> rank -> rank -> unit
548 {\SetNeighbour{#1}{a#2}{a#3}%
549 \SetNeighbour{#1}{b#2}{b#3}%
550 \SetNeighbour{#1}{c#2}{c#3}%
551 \SetNeighbour{#1}{d#2}{d#3}%
552 \SetNeighbour{#1}{e#2}{e#3}%
553 \SetNeighbour{#1}{f#2}{f#3}%
554 \SetNeighbour{#1}{g#2}{g#3}%
555 \SetNeighbour{#1}{h#2}{h#3}}
556 \let\SetDownNeighbour=\SetUpNeighbour%
557 \SetUpNeighbour{up}{1}{2}
558 \SetUpNeighbour{up}{2}{3}
559 \SetUpNeighbour{up}{3}{4}
560 \SetUpNeighbour{up}{4}{5}
561 \SetUpNeighbour{up}{5}{6}
562 \SetUpNeighbour{up}{6}{7}
563 \SetUpNeighbour{up}{7}{8}
564 \SetDownNeighbour{down}{2}{1}
565 \SetDownNeighbour{down}{3}{2}
566 \SetDownNeighbour{down}{4}{3}
567 \SetDownNeighbour{down}{5}{4}
568 \SetDownNeighbour{down}{6}{5}
569 \SetDownNeighbour{down}{7}{6}
570 \SetDownNeighbour{down}{8}{7}
574 \def\SetUpRightNeighbour#1#2#3% direction -> rank -> rank -> unit
575 {\SetNeighbour{#1}{a#2}{b#3}%
576 \SetNeighbour{#1}{b#2}{c#3}%
577 \SetNeighbour{#1}{c#2}{d#3}%
578 \SetNeighbour{#1}{d#2}{e#3}%
579 \SetNeighbour{#1}{e#2}{f#3}%
580 \SetNeighbour{#1}{f#2}{g#3}%
581 \SetNeighbour{#1}{g#2}{h#3}%
582 \SetNeighbour{#1}{h#2}{Offboard}}
583 \let\SetDownRightNeighbour=\SetUpRightNeighbour
584 \SetUpRightNeighbour{upright}{1}{2}
585 \SetUpRightNeighbour{upright}{2}{3}
586 \SetUpRightNeighbour{upright}{3}{4}
587 \SetUpRightNeighbour{upright}{4}{5}
588 \SetUpRightNeighbour{upright}{5}{6}
589 \SetUpRightNeighbour{upright}{6}{7}
590 \SetUpRightNeighbour{upright}{7}{8}
591 \SetDownRightNeighbour{downright}{2}{1}
592 \SetDownRightNeighbour{downright}{3}{2}
593 \SetDownRightNeighbour{downright}{4}{3}
594 \SetDownRightNeighbour{downright}{5}{4}
595 \SetDownRightNeighbour{downright}{6}{5}
596 \SetDownRightNeighbour{downright}{7}{6}
597 \SetDownRightNeighbour{downright}{8}{7}
601 \def\SetUpLeftNeighbour#1#2#3% direction -> rank -> rank -> unit
602 {\SetNeighbour{#1}{a#2}{Offboard}%
603 \SetNeighbour{#1}{b#2}{a#3}%
604 \SetNeighbour{#1}{c#2}{b#3}%
605 \SetNeighbour{#1}{d#2}{c#3}%
606 \SetNeighbour{#1}{e#2}{d#3}%
607 \SetNeighbour{#1}{f#2}{e#3}%
608 \SetNeighbour{#1}{g#2}{f#3}%
609 \SetNeighbour{#1}{h#2}{g#3}}
610 \let\SetDownLeftNeighbour=\SetUpLeftNeighbour
611 \SetUpLeftNeighbour{upleft}{1}{2}
612 \SetUpLeftNeighbour{upleft}{2}{3}
613 \SetUpLeftNeighbour{upleft}{3}{4}
614 \SetUpLeftNeighbour{upleft}{4}{5}
615 \SetUpLeftNeighbour{upleft}{5}{6}
616 \SetUpLeftNeighbour{upleft}{6}{7}
617 \SetUpLeftNeighbour{upleft}{7}{8}
618 \SetDownLeftNeighbour{downleft}{2}{1}
619 \SetDownLeftNeighbour{downleft}{3}{2}
620 \SetDownLeftNeighbour{downleft}{4}{3}
621 \SetDownLeftNeighbour{downleft}{5}{4}
622 \SetDownLeftNeighbour{downleft}{6}{5}
623 \SetDownLeftNeighbour{downleft}{7}{6}
624 \SetDownLeftNeighbour{downleft}{8}{7}
627 \def\SetLeftNeighbour#1#2#3% direction -> file -> file -> unit
628 {\SetNeighbour{#1}{#21}{#31}%
629 \SetNeighbour{#1}{#22}{#32}%
630 \SetNeighbour{#1}{#23}{#33}%
631 \SetNeighbour{#1}{#24}{#34}%
632 \SetNeighbour{#1}{#25}{#35}%
633 \SetNeighbour{#1}{#26}{#36}%
634 \SetNeighbour{#1}{#27}{#37}%
635 \SetNeighbour{#1}{#28}{#38}}
636 \let\SetRightNeighbour=\SetLeftNeighbour
637 \SetLeftNeighbour{left}{b}{a}
638 \SetLeftNeighbour{left}{c}{b}
639 \SetLeftNeighbour{left}{d}{c}
640 \SetLeftNeighbour{left}{e}{d}
641 \SetLeftNeighbour{left}{f}{e}
642 \SetLeftNeighbour{left}{g}{f}
643 \SetLeftNeighbour{left}{h}{g}
644 \SetRightNeighbour{right}{a}{b}
645 \SetRightNeighbour{right}{b}{c}
646 \SetRightNeighbour{right}{c}{d}
647 \SetRightNeighbour{right}{d}{e}
648 \SetRightNeighbour{right}{e}{f}
649 \SetRightNeighbour{right}{f}{g}
650 \SetRightNeighbour{right}{g}{h}
654 % the knight needs special attention
655 \def\KnightSquares#1% square -> square list
656 {\csname#1.knight\endcsname}
658 \def\SetKnightSquares#1#2% square -> square list -> unit
659 {\expandafter\def\csname#1.knight\endcsname{#2}}
662 \SetKnightSquares{a1}{\Listize[b3,c2]}
663 \SetKnightSquares{a2}{\Listize[b4,c3,c1]}
664 \SetKnightSquares{a3}{\Listize[b5,c4,c2,b1]}
665 \SetKnightSquares{a4}{\Listize[b6,c5,c3,b2]}
666 \SetKnightSquares{a5}{\Listize[b7,c6,c4,b3]}
667 \SetKnightSquares{a6}{\Listize[b8,c7,c5,b4]}
668 \SetKnightSquares{a7}{\Listize[c8,c6,b5]}
669 \SetKnightSquares{a8}{\Listize[c7,b6]}
671 \SetKnightSquares{b1}{\Listize[a3,c3,d2]}
672 \SetKnightSquares{b2}{\Listize[a4,c4,d3,d1]}
673 \SetKnightSquares{b3}{\Listize[a5,c5,d4,d2,a1,c1]}
674 \SetKnightSquares{b4}{\Listize[a6,c6,d5,d3,a2,c2]}
675 \SetKnightSquares{b5}{\Listize[a7,c7,d6,d4,a3,c3]}
676 \SetKnightSquares{b6}{\Listize[a8,c8,d7,d5,a5,c5]}
677 \SetKnightSquares{b7}{\Listize[d8,d6,a5,c5]}
678 \SetKnightSquares{b8}{\Listize[d7,a6,c6]}
680 \SetKnightSquares{c1}{\Listize[a2,b3,d3,e2]}
681 \SetKnightSquares{c2}{\Listize[a1,a3,b4,d4,e3,e1]}
682 \SetKnightSquares{c3}{\Listize[a2,a4,b1,b5,d1,d5,e2,e4]}
683 \SetKnightSquares{c4}{\Listize[a3,a5,b2,b6,d2,d6,e3,e5]}
684 \SetKnightSquares{c5}{\Listize[a4,a6,b3,b7,d3,d7,e4,e6]}
685 \SetKnightSquares{c6}{\Listize[a5,a7,b4,b8,d4,d8,e5,e7]}
686 \SetKnightSquares{c7}{\Listize[a6,a8,b5,d5,e6,e8]}
687 \SetKnightSquares{c8}{\Listize[a7,b6,d6,e7]}
689 \SetKnightSquares{d1}{\Listize[b2,c3,e3,f2]}
690 \SetKnightSquares{d2}{\Listize[b1,b3,c4,e4,f3,f1]}
691 \SetKnightSquares{d3}{\Listize[b2,b4,c1,c5,e1,e5,f2,f4]}
692 \SetKnightSquares{d4}{\Listize[b3,b5,c2,c6,e2,e6,f3,f5]}
693 \SetKnightSquares{d5}{\Listize[b4,b6,c3,c7,e3,e7,f4,f6]}
694 \SetKnightSquares{d6}{\Listize[b5,b7,c4,c8,e4,e8,f5,f7]}
695 \SetKnightSquares{d7}{\Listize[b6,b8,c5,e5,f6,f8]}
696 \SetKnightSquares{d8}{\Listize[b7,c6,e6,f7]}
698 \SetKnightSquares{e1}{\Listize[c2,d3,f3,g2]}
699 \SetKnightSquares{e2}{\Listize[c1,c3,d4,f4,g3,g1]}
700 \SetKnightSquares{e3}{\Listize[c2,c4,d1,d5,f1,f5,g2,g4]}
701 \SetKnightSquares{e4}{\Listize[c3,c5,d2,d6,f2,f6,g3,g5]}
702 \SetKnightSquares{e5}{\Listize[c4,c6,d3,d7,f3,f7,g4,g6]}
703 \SetKnightSquares{e6}{\Listize[c5,c7,d4,d8,f4,f8,g5,g7]}
704 \SetKnightSquares{e7}{\Listize[c6,c8,d5,f5,g6,g8]}
705 \SetKnightSquares{e8}{\Listize[c7,d6,f6,g7]}
707 \SetKnightSquares{f1}{\Listize[d2,e3,g3,h2]}
708 \SetKnightSquares{f2}{\Listize[d1,d3,e4,g4,h3,h1]}
709 \SetKnightSquares{f3}{\Listize[d2,d4,e1,e5,g1,g5,h2,h4]}
710 \SetKnightSquares{f4}{\Listize[d3,d5,e2,e6,g2,g6,h3,h5]}
711 \SetKnightSquares{f5}{\Listize[d4,d6,e3,e7,g3,g7,h4,h6]}
712 \SetKnightSquares{f6}{\Listize[d5,d7,e4,e8,g4,g8,h5,h7]}
713 \SetKnightSquares{f7}{\Listize[d6,d8,e5,g5,h6,h8]}
714 \SetKnightSquares{f8}{\Listize[d7,e6,g6,h7]}
716 \SetKnightSquares{g1}{\Listize[h3,f3,e2]}
717 \SetKnightSquares{g2}{\Listize[h4,f4,e3,e1]}
718 \SetKnightSquares{g3}{\Listize[h5,f5,e4,e2,h1,f1]}
719 \SetKnightSquares{g4}{\Listize[h6,f6,e5,e3,h2,f2]}
720 \SetKnightSquares{g5}{\Listize[h7,f7,e6,e4,h3,f3]}
721 \SetKnightSquares{g6}{\Listize[h8,f8,e7,e5,h4,f4]}
722 \SetKnightSquares{g7}{\Listize[e8,e6,h5,f5]}
723 \SetKnightSquares{g8}{\Listize[h6,f6,e7]}
725 \SetKnightSquares{h1}{\Listize[g3,f2]}
726 \SetKnightSquares{h2}{\Listize[g4,f3,f1]}
727 \SetKnightSquares{h3}{\Listize[g5,f4,f2,g1]}
728 \SetKnightSquares{h4}{\Listize[g6,f5,f3,g2]}
729 \SetKnightSquares{h5}{\Listize[g7,f6,f4,g3]}
730 \SetKnightSquares{h6}{\Listize[g8,f7,f5,g4]}
731 \SetKnightSquares{h7}{\Listize[f8,f6,g5]}
732 \SetKnightSquares{h8}{\Listize[f7,g6]}
735 % % finding the neighbours of a square, used when the king moves...
736 % \def\Neighbours#1% square -> square list
737 % {\Map{\Twiddle\GetNeighbour{#1}}%
738 % {\Listize[left,upleft,up,upright,right,downright,down,downleft]}}
740 % StringToTokens: string -> string list, cut at spaces
741 \def\StringToTokens#1%
742 {\skak@ifthenelse{\equal{#1}{}}{\Nil}{\StrToTokens(#1 )}}
743 \def\StrToTokens (#1 #2){%
746 \Cons{#1}{\EqStr{#2}{} {\Nil} {\StrToTokens(#2)}}}
748 \def\BlackPiece#1% char -> piece
761 \def\PieceNameToPiece#1#2% piecename -> bool -> piece
762 {#2{#1}{\BlackPiece{#1}}}
764 % setting up variables for ParseMove
766 \gdef\MoveToRank{Z}\gdef\MoveToFile{Z}%
767 \gdef\RankDiscriminator{Z}\gdef\FileDiscriminator{Z}%
768 \gdef\PieceNameToMove{Z}%
769 \gdef\Capture{\False}%
770 \gdef\Promotion{\False}\gdef\PromotionPieceName{Z}%
771 \gdef\Castling{\False}\gdef\LongCastling{\False}}
773 \def\ParseMove#1{% string -> unit
776 \def\ParseMoveA(#1#2){% char -> string -> unit
778 {\gdef\PieceNameToMove{\skak@pieceToEnglish{#1}}%
779 \gdef\PieceToMove{\PieceNameToPiece{\PieceNameToMove}{\WhiteToMove}}%
780 \ParseCoordinates(#2Z)%
781 \gdef\MoveTo{\MoveToFile\MoveToRank}}%
783 {\def\Castling{\True}%
784 \ParseCastling(#2Z)}%
785 {\ParseCoordinates(#1#2Z)%
786 \gdef\MoveTo{\MoveToFile\MoveToRank}}}}
788 \def\FirstChar(#1#2){#1}
790 \def\ParseCoordinates(#1#2){% char -> string -> unit
794 {\EqStr{\MoveToFile}{Z}%
795 {}% first File name in move so nothing to do
796 {\xdef\FileDiscriminator{\MoveToFile}}%
797 \gdef\MoveToFile{#1}%
798 \ParseCoordinates(#2)}%
800 {\EqStr{\MoveToRank}{Z}%
802 {\gdef\RankDiscriminator{\MoveToRank}}%
803 \gdef\MoveToRank{#1}%
804 \ParseCoordinates(#2)}%
806 {\gdef\Capture{\True}%
807 \ParseCoordinates(#2)}%
809 {\def\Promotion{\True}%
810 \gdef\PromotionPieceName{\skak@pieceToEnlish{\FirstChar(#2)}}}}%
811 {}% no more information is of interest
814 % help for \ParseCastling
815 \def\ParseCastlingA(#1#2#3){%
817 {\gdef\LongCastling{\True}}%
820 \def\ParseCastling(-O#1){% strip the first -O, at least Z is left
821 \ParseCastlingA(#1VW)}
823 % \def\ParseCastling(-O#1#2){%
826 % {\def\LongCastling{\True}}}
829 % for testing purposes
832 MoveToRank: \MoveToRank, MoveToFile: \MoveToFile, \\
833 RankDiscriminator: \RankDiscriminator, FileDiscriminator:
834 \FileDiscriminator, \\ Promotion: \BoolToString{\Promotion},
835 PromotionPieceName: \PromotionPieceName
836 Capture: \BoolToString{\Capture}, \\
837 PieceNameToMove: \PieceNameToMove, \\
838 Castling: \BoolToString{\Castling},
839 LongCastling: \BoolToString{\LongCastling}}
841 % castling, with preparation for eg, FisheRandom
842 %\def\WhiteShortRook{h1}
843 %\def\WhiteLongRook{a1}
844 %\def\BlackShortRook{h8}
846 \def\FirstRank#1{% bool -> rank
848 \def\CastleKingFile#1{% bool -> file, LongCastling is used as argument
850 \def\CastleRookToFile#1{%
852 \def\CastleRookFromFile#1{%
855 \def\CastleDone#1{% bool -> unit
856 #1{\gdef\WhiteCastling{-}}{\gdef\BlackCastling{-}}}
858 \def\ExecuteCastling{% relies on \ParseMove
859 \stepcounter{halfmove}%
860 \gdef\MoveTo{\CastleKingFile{\LongCastling}\FirstRank{\WhiteToMove}}%
862 \gdef\MoveTo{\CastleRookToFile{\LongCastling}\FirstRank{\WhiteToMove}}%
863 \DoTheMove{\CastleRookFromFile{\LongCastling}\FirstRank{\WhiteToMove}}%
864 \CastleDone{\WhiteToMove}}
867 %%% after ParseMove has gathered info we find the piece to move
868 % LookFor looks in one direction, stopping if a non-empty square is
870 \def\LookFor#1#2#3{% (piece -> bool) -> square -> direction -> square list
871 \LookForA{#1}{\GetNeighbour{#3}{#2}}{#3}} % we have to skip the
873 \def\LookForA#1#2#3{% (piece -> bool) -> square -> direction -> square list
876 {\EqPiece{E}{\Get{#2}}% empty square => continue in the given direction
877 {\LookForA{#1}{\GetNeighbour{#3}{#2}}{#3}}%
881 % IsRightPiece is true if a piece matching #1 is on square#2
882 \def\IsRightPiece#1#2{% piece -> square -> bool
883 \EqPiece{#1}{\Get{#2}}}
885 \def\IsRookQueen#1#2{% bool -> piece -> bool
886 \Or{\EqPiece{#2}{\PieceNameToPiece{R}{#1}}}%
887 {\EqPiece{#2}{\PieceNameToPiece{Q}{#1}}}%
889 \def\IsBishopQueen#1#2{% bool -> piece -> bool
890 \Or{\EqPiece{#2}{\PieceNameToPiece{B}{#1}}}%
891 {\EqPiece{#2}{\PieceNameToPiece{Q}{#1}}}%
894 % (piece-> bool) -> square -> direction list -> square list
895 \def\ScanDirections#1#2#3{\Foldr{\Compose\Cat{\LookFor{#1}{#2}}}\Nil{#3}}
898 % relies on the info gathered by ParseMove
899 \def\FindPieceSquares#1#2{% bool -> square -> square list
900 \EqPiece{\PieceNameToMove}{R}%
902 {\EqPiece{\PieceToMove}}{#2}{\Listize[up,down,left,right]}}%
903 {\EqPiece{\PieceNameToMove}{B}%
905 {\EqPiece{\PieceToMove}}{#2}%
906 {\Listize[upright,downright,downleft,upleft]}}%
907 {\EqPiece{\PieceNameToMove}{Q}%
909 {\EqPiece{\PieceToMove}}{#2}%
910 {\Listize[up,down,left,right,upleft,upright,downleft,downright]}}%
911 {\Filter{\IsRightPiece{\PieceToMove}}{\KnightSquares{#2}}}}}}
913 \def\UniqueMove% bool, if the descriminators <> Z
915 {\Not{\EqStr{\RankDiscriminator}{Z}}}%
916 {\Not{\EqStr{\FileDiscriminator}}{Z}}}
918 \def\DoTheMove#1{% move the piece from #1 to \MoveToFile\MoveToRank
919 \edef\oldpiece{\Get{\MoveToFile\MoveToRank}}%
920 \Set{\MoveTo}{\Get{#1}}\Set{#1}{E}%
923 \def\DoTheMoveList#1{\DoTheMove{\Head{#1}}}
925 % undoes the move to #1
926 \def\UndoMove#1{% square -> unit, relies on \oldpiece and \MoveToFile/Rank
927 \Set{#1}{\Get{\MoveToFile\MoveToRank}}\Set{\MoveToFile\MoveToRank}{\oldpiece}%
928 \Or{\EqPiece{\PieceToMove}{K}}{\EqPiece{\PieceToMove}{k}}%
929 {\SetKingSquare{\WhiteToMove}{#1}}%
932 \def\NoEnemiesFound{% bool
933 \IsNil{\Cat{\ScanDirections{\IsRookQueen{\Not\WhiteToMove}}%
934 {\KingSquare{\WhiteToMove}}{\Listize[up,down,left,right]}}%
935 {\ScanDirections{\IsBishopQueen{\Not\WhiteToMove}}%
936 {\KingSquare{\WhiteToMove}}%
937 {\Listize[upleft,downright,downleft,upright]}}}}
939 \newboolean{helplegal}
941 \def\LegalMove#1{% square -> bool, is the move possible to do?
944 {\UndoMove{#1}\True}%
945 {\UndoMove{#1}\False}}%
946 % \skak@ifthenelse{\boolean{helplegal}}{\True}{\False}}
947 % \def\LegalMove#1{% square -> bool, is the move possible to do?
948 % % \edef\oldpiece{\Get{\MoveToFile\MoveToRank}}%
950 % % \setboolean{helplegal}{\NoEnemiesFound{true}{false}}%
951 % \gdef\HelpLegal{\NoEnemiesFound}
954 % % \skak@ifthenelse{\boolean{helplegal}}{\True}{\False}}
956 % relies on \ParseMove
957 \def\TrimMoveList#1{% square -> bool
959 \And{\RightRank(\trimhelp)}{\And{\RightFile(\trimhelp)}{\LegalMove{\trimhelp}}}}
960 %\And{\RightRank(#1)}{\And{\RightFile(#1)}{\LegalMove{#1}}}}
962 \def\ExecuteKingMove{% relies on ParseMove, WhiteToMove
963 \DoTheMove{\KingSquare{\WhiteToMove}}%
964 \SetKingSquare{\WhiteToMove}{\MoveTo}%
966 {\edef\WhiteCastling{-}}%
967 {\edef\BlackCastling{-}}}
969 % % used by UpdateCastling
970 % \def\RemoveLongCastling{% relies on \WhiteToMove
972 % {\EqStr{KQ}{\WhiteCastling}%
973 % {\edef\WhiteCastling{K}}%
974 % {\EqStr{Q}{\WhiteCastling}%
975 % {\edef\WhiteCastling{-}}
977 % {\EqStr{kq}{\BlackCastling}%
978 % {\edef\BlackCastling{k}}%
979 % {\EqStr{q}{\BlackCastling}%
980 % {\edef\BlackCastling{-}}%
983 % used by UpdateCastling
984 \def\RemoveLongCastling{% relies on \WhiteToMove
986 {\skak@ifthenelse{\equal{KQ}{\WhiteCastling}}%
987 {\gdef\WhiteCastling{K}}%
988 {\skak@ifthenelse{\equal{Q}{\WhiteCastling}}%
989 {\gdef\WhiteCastling{-}}%
991 {\skak@ifthenelse{\equal{kq}{\BlackCastling}}%
992 {\gdef\BlackCastling{k}}%
993 {\skak@ifthenelse{\equal{q}{\BlackCastling}}%
994 {\edef\BlackCastling{-}}%
997 % % used by UpdateCastling
998 % \def\RemoveShortCastling{% relies on \WhiteToMove
1000 % {\skak@ifthenelse{\equal{KQ}{\WhiteCastling}}%
1001 % %\EqStr{KQ}{\WhiteCastling}%
1002 % {\edef\WhiteCastling{Q}}%
1003 % {\EqStr{K}{\WhiteCastling}%
1004 % {\edef\WhiteCastling{-}}%
1006 % {\skak@ifthenelse{\equal{kq}{\BlackCastling}}%
1007 % %\EqStr{kq}{\BlackCastling}%
1008 % {\edef\BlackCastling{q}}%
1009 % {\EqStr{k}{\BlackCastling}%
1010 % {\edef\BlackCastling{-}}%
1013 % used by UpdateCastling
1014 \def\RemoveShortCastling{% relies on \WhiteToMove
1016 {\skak@ifthenelse{\equal{KQ}{\WhiteCastling}}%
1017 %\EqStr{KQ}{\WhiteCastling}%
1018 {\gdef\WhiteCastling{Q}}%
1019 {\skak@ifthenelse{\equal{K}{\WhiteCastling}}
1020 {\gdef\WhiteCastling{-}}%
1022 {\skak@ifthenelse{\equal{kq}{\BlackCastling}}%
1023 %\EqStr{kq}{\BlackCastling}%
1024 {\gdef\BlackCastling{q}}%
1025 {\EqStr{k}{\BlackCastling}%
1026 {\gdef\BlackCastling{-}}%
1029 \def\UpdateCastling{% relies on \ParseMove
1030 \EqPiece{R}{\PieceNameToMove}%
1031 { \EqSquare{\MoveFrom}{\CastleRookFromFile{\True}\FirstRank{\WhiteToMove}}%
1032 {\RemoveLongCastling}%
1033 {\EqSquare{\MoveFrom}{\CastleRookFromFile{\False}\FirstRank{\WhiteToMove}}%
1034 {\RemoveShortCastling}%
1036 {}}% non rook moves will not change the castling possibilities
1038 \def\ExecutePieceMove{% relies on the info gathered by ParseMove
1039 \Capture{\setcounter{halfmove}{0}}{\stepcounter{halfmove}}%
1041 {\DoTheMove{\FileDiscriminator\RankDiscriminator}}%
1042 {\EqPiece{K}{\PieceNameToMove}%
1045 % (\Unlistize{\FindPieceSquares{\WhiteToMove}{\MoveTo}},%
1046 % \Unlistize{\Filter{\TrimMoveList}%
1047 % {\FindPieceSquares{\WhiteToMove}{\MoveTo}}})%
1048 \Apply{\DoTheMove}{\Filter{\TrimMoveList}%
1049 {\FindPieceSquares{\WhiteToMove}{\MoveTo}}}}%
1053 % % for pawn captures and moves
1054 % \newcounter{rankhelp}
1055 % % \def\FromRank{\setcounter{rankhelp}{\MoveToRank}%
1056 % % \addtocounter{rankhelp}{\WhiteToMove{-1}{1}}
1057 % % \arabic{rankhelp}}
1059 \EqStr{1}{\MoveToRank}%
1060 {\WhiteToMove{0}{2}}%
1061 {\EqStr{2}{\MoveToRank}%
1062 {\WhiteToMove{1}{3}}%
1063 {\EqStr{3}{\MoveToRank}%
1064 {\WhiteToMove{2}{4}}%
1065 {\EqStr{4}{\MoveToRank}%
1066 {\WhiteToMove{3}{5}}%
1067 {\EqStr{5}{\MoveToRank}%
1068 {\WhiteToMove{4}{6}}%
1069 {\EqStr{6}{\MoveToRank}%
1070 {\WhiteToMove{5}{7}}%
1071 {\EqStr{7}{\MoveToRank}%
1072 {\WhiteToMove{6}{8}}%
1073 {\EqStr{8}{\MoveToRank}%
1074 {\WhiteToMove{7}{9}}%
1076 \def\InitialRank{\WhiteToMove{2}{7}}
1078 \def\ExecutePawnMove{% relies on the info obtained by ParseMove
1079 \setcounter{halfmove}{0}%
1081 {\EqPiece{E}{\Get{\MoveTo}}%
1082 {\Set{\MoveToFile\FromRank}{E}}%
1084 \DoTheMove{\FileDiscriminator\FromRank}%
1085 \def\EnPassantSquare{-}}%
1086 {\EqPiece{E}{\Get{\MoveToFile\FromRank}}%
1087 {\edef\EnPassantSquare{\MoveToFile\FromRank}% two square move
1088 \DoTheMove{\MoveToFile\InitialRank}}%
1089 {\DoTheMove{\MoveToFile\FromRank}% one square move
1090 \def\EnPassantSquare{-}}}%
1092 {\Set{\MoveTo}{\PieceNameToPiece{\PromotionPieceName}{\WhiteToMove}}}%
1096 \def\MakeMove#1{% string -> unit
1097 % (In MakeMove: WhiteToMove \BoolToString\WhiteToMove)
1100 \EqPiece{Z}{\PieceNameToMove}%
1102 {\gdef\EnPassantSquare{-}\ExecuteCastling}%
1103 {\ExecutePawnMove}}%
1104 {\gdef\EnPassantSquare{-}%
1107 {\gdef\WhiteToMove{\False}}%
1108 {\gdef\WhiteToMove{\True}\addtocounter{move}{1}}%
1109 %(End MakeMove: WhiteToMove \BoolToString\WhiteToMove)
1113 %\def\MakeMove#1{#1}
1115 \def\mainline{\begingroup\catcode`\#=12 \@mainline}
1116 \def\@mainline#1{\endgroup\gdef\NumberNext{\True}%
1117 \Mainline(#1 Z ){\mainlinestyle\typeset@A{#1}}}
1120 \def\hidemoves{\begingroup\catcode`\#=12 \@hidemoves}
1121 \def\@hidemoves#1{\endgroup\def\NumberNext{\True}%
1125 \newcounter{helpnumber}
1126 \newcounter{helpnumberMove}
1127 % \def\EatNumber#1{\setcounter{helpnumber}{0}\EatNumberA(#1Z)%
1128 % \skak@ifthenelse{\value{move}=\value{helpnumber}}%
1129 % {\def\NumberOK{\True}}%
1130 % {\def\NumberOK{\False}}}%
1132 \setcounter{helpnumberMove}{\arabic{move}}%
1133 \setcounter{helpnumber}{0}\EatNumberA(#1WXYZ)%
1134 \skak@ifthenelse{\value{helpnumberMove}=\value{helpnumber}}%
1135 {\gdef\NumberOK{\True}}%
1136 {\gdef\NumberOK{\False}}}%
1137 \def\EatNumberA(#1.#2){%
1138 \setcounter{helpnumber}{#1}%
1139 \LookForMove(.#2)% sets \ExpectedColur and \CurrentMove
1142 \def\LookForMove(#1#2#3#4){%
1143 \EqStr{.}{#2}% ... after the move number
1144 {\gdef\ExpectedColour{\False}%
1146 {\gdef\ExpectedColour{\True}%
1147 \HandleMove(#2#3#4)}}%
1149 \def\HandleMove(#1XYZ){% executes a move if one is found
1153 \def\StripMove(#1W){% the execution of a move like 1.e4
1154 \MakeMoveMainline{#1}}
1156 \def\MakeMoveMainline#1{%
1160 \gdef\ExpectedColour{\False}}%
1161 {\errmessage{mainline: black, not white, to move}}}%
1163 {\errmessage{mainline: white, not black, to move}}%
1164 {\MakeMove{#1}\gdef\NumberNext{\True}}}}}
1167 \def\Mainline(#1 #2){%
1171 {\EatNumber{#1}% sets \NumberOK, \ExpectedColour
1172 % executes a move not separated from the
1173 % number with a space, eg, 1.e4
1175 {\gdef\NumberNext{\False}%
1177 {\errmessage{mainline: not the correct move number}}}%
1178 {\MakeMoveMainline{#1}%
1183 %%% figurine notation
1184 %\input{fig1\@ptsize.clo}
1185 \newcommand{\skakfamily}{\usefont{U}{skak}{m}{n}}
1186 \DeclareTextFontCommand{\textskak}{\skakfamily}
1188 \def\liftfig#1{\textskak{#1}}
1191 \def\styleA@opentypesetting{}
1192 \def\styleA@closetypesetting{}
1193 \def\styleA@whiteopen{.}
1194 \def\styleA@blackopen{. -}
1195 \def\styleA@beforenumber{}
1196 \def\styleA@beforewhite{ }
1197 \def\styleA@afterwhite{}
1198 \def\styleA@beforeblack{, }
1199 \def\styleA@afterblack{ }
1202 \let\opentypesetting=\styleA@opentypesetting
1203 \let\closetypesetting=\styleA@closetypesetting
1204 \let\whiteopen=\styleA@whiteopen
1205 \let\blackopen=\styleA@blackopen
1206 \let\beforenumber=\styleA@beforenumber
1207 \let\beforewhite=\styleA@beforewhite
1208 \let\afterwhite=\styleA@afterwhite
1209 \let\beforeblack=\styleA@beforeblack
1210 \let\afterblack=\styleA@afterblack
1212 %%%% the default style
1215 \def\styleB@opentypesetting{}
1216 \def\styleB@closetypesetting{}
1217 \def\styleB@whiteopen{ }
1218 \def\styleB@blackopen{\ldots}
1219 \def\styleB@beforenumber{}
1220 \def\styleB@beforewhite{}
1221 \def\styleB@afterwhite{ }
1222 \def\styleB@beforeblack{}
1223 \def\styleB@afterblack{ }
1226 \let\opentypesetting=\styleB@opentypesetting
1227 \let\closetypesetting=\styleB@closetypesetting
1228 \let\whiteopen=\styleB@whiteopen
1229 \let\blackopen=\styleB@blackopen
1230 \let\beforenumber=\styleB@beforenumber
1231 \let\beforewhite=\styleB@beforewhite
1232 \let\afterwhite=\styleB@afterwhite
1233 \let\beforeblack=\styleB@beforeblack
1234 \let\afterblack=\styleB@afterblack
1237 \def\styleC@opentypesetting{%
1239 \hspace{.2\linewidth}\=\hspace{.2\linewidth}\=%
1240 \hspace{.2\linewidth}\= \kill}
1241 \def\styleC@closetypesetting{\end{tabbing}}
1242 \def\styleC@whiteopen{}
1243 \def\styleC@blackopen{\>\ldots}
1244 \def\styleC@beforenumber{\>}
1245 \def\styleC@beforewhite{\>}
1246 \def\styleC@afterwhite{}
1247 \def\styleC@beforeblack{\>}
1248 \def\styleC@afterblack{\\}
1251 \let\opentypesetting=\styleC@opentypesetting
1252 \let\closetypesetting=\styleC@closetypesetting
1253 \let\whiteopen=\styleC@whiteopen
1254 \let\blackopen=\styleC@blackopen
1255 \let\beforenumber=\styleC@beforenumber
1256 \let\beforewhite=\styleC@beforewhite
1257 \let\afterwhite=\styleC@afterwhite
1258 \let\beforeblack=\styleC@beforeblack
1259 \let\afterblack=\styleC@afterblack
1264 \def\mainlinestyle{\bfseries}%\let\Fig=\Figb}% could also contain
1265 % definitions of the
1266 % various style options
1267 \def\variationstyle{}%\let\Fig=\Fign} % as with mainlinestyle
1270 \def\typeset@number#1{\TypeSetAfterBlack{\afterblack}{}%
1271 \gdef\TypeSetAfterBlack{\True}%
1272 \beforenumber\typeset@numberA(#1WXYZ)}% 22: -> 22\?open
1273 \def\typeset@numberA(#1.#2){%
1274 #1\typeset@numberHandlePeriods(.#2)}
1275 \def\typeset@numberHandlePeriods(#1#2#3#4){%
1276 \EqStr{.}{#2}% ... after the number
1277 {\blackopen\gdef\TypeSetColour{\False}\gdef\TypeSetAfterWhite{\False}%
1278 \typeset@numberHandleMove(#4)}%
1279 {\whiteopen\gdef\TypeSetColour{\True}\gdef\TypeSetAfterWhite{\True}%
1280 \typeset@numberHandleMove(#2#3#4)}}
1281 \def\typeset@numberHandleMove(#1XYZ){%
1284 {\typeset@numberStripMove(#1)}}
1285 \def\typeset@numberStripMove(#1W){%
1286 \typeset@A@move{#1}}
1288 \def\typeset@A@move#1{%
1290 {\beforewhite\mbox{\typeset@A@moveA(#1Z)}\gdef\TypeSetColour{\False}}%
1291 {\TypeSetAfterWhite{\afterwhite}{}%
1292 \beforeblack\mbox{\typeset@A@moveA(#1Z)}%
1293 \gdef\TypeSetColour{\True}\gdef\TypeSetNumberNext{\True}}}
1294 \def\typeset@A@moveA(#1#2){%
1298 {\xdef\temp@piece{\skak@pieceToEnglish{#1}}%
1299 \expandafter\liftfig\temp@piece}%
1303 {\ensuremath{\!\!\:\times\!\!\;}}%
1305 {\ensuremath{\dagger}}%
1307 \typeset@A@moveA(#2)}}
1310 \def\typeset@A#1{\gdef\TypeSetNumberNext{\True}%
1311 \gdef\TypeSetAfterBlack{\False}\opentypesetting\typeset@AA(#1 Z )%
1313 \def\typeset@AA(#1 #2){%
1316 {\TypeSetNumberNext%
1317 {\typeset@number{#1}% sets \TypeSetColour
1318 \gdef\TypeSetNumberNext{\False}%
1320 {\typeset@A@move{#1}%
1324 \def\variation{\begingroup\catcode`\#=12 \@variation}
1325 \def\@variation#1{\endgroup{\variationstyle\typeset@A{#1}}}
1327 % typesetting moves with out move number
1328 \def\wmove{\begingroup\catcode`\#=12 \@wmove}
1329 \def\@wmove#1{\endgroup{\variationstyle\typeset@A@moveA(#1Z)}}
1330 \def\bmove{\begingroup\catcode`\#=12 \@bmove}
1331 \def\@bmove#1{\endgroup{\variationstyle\ldots\typeset@A@moveA(#1Z)}}
1334 % printing of the board
1335 \newlength{\squarelength}
1336 \newlength{\showlength}
1337 \newlength{\ranklift}
1339 \def\setup@showboard#1{\font\Skak=skak#1%
1340 \setlength{\squarelength}{#1pt}%
1342 \ps@on{\psset{unit=\the\squarelength}
1343 \edef\ps@squarecenter{(-.5,.5)}}
1345 \notationfont\setlength{\ranklift}{.5\squarelength-.8ex}\normalsize}
1349 \def\tinyboard{\font\notationfont=cmss6\setup@showboard{10}}
1350 \def\smallboard{\font\notationfont=cmss8\setup@showboard{15}}
1351 \def\normalboard{\font\notationfont=cmss10\setup@showboard{20}}
1352 \def\largeboard{\font\notationfont=cmss12\setup@showboard{30}}
1357 \def\ToggleWhiteSquare{%
1358 \WhiteSquare{\def\WhiteSquare{\False}}{\def\WhiteSquare{\True}}}
1360 \def\WhiteSquarePiece#1{%
1361 \EqPiece{E}{#1}{0}{#1}}
1363 \def\BlackSquarePiece#1{%
1365 {\EqPiece{P}{#1}{O}%
1366 {\EqPiece{p}{#1}{o}%
1367 {\EqPiece{R}{#1}{S}%
1368 {\EqPiece{r}{#1}{s}%
1369 {\EqPiece{N}{#1}{M}%
1370 {\EqPiece{n}{#1}{m}%
1371 {\EqPiece{B}{#1}{A}%
1372 {\EqPiece{b}{#1}{a}%
1373 {\EqPiece{Q}{#1}{L}%
1374 {\EqPiece{q}{#1}{l}%
1375 {\EqPiece{K}{#1}{J}{j}}}}}}}}}}}}}
1377 \def\FilterShowOnly#1{% piece -> piece, shows only the pieces in
1379 \Member{\EqStr}{#1}{\ShowOnlyList}%
1383 \def\Showchar#1{% square -> drawn square
1385 {\WhiteSquarePiece{\Compose\FilterShowOnly\Get{#1}}}%
1386 {\BlackSquarePiece{\Compose\FilterShowOnly\Get{#1}}}%
1389 \ps@on{\expandafter\pnode\ps@squarecenter{#1}}{}}
1391 \def\Showrank#1{% rank -> drawn rank
1392 \Skak\Apply{\Showchar}{\Rank{#1}}}
1394 \def\ShowrankInverse#1{% rank -> drawn rank
1395 \Skak\Apply{\Showchar}{\Reverse{\Rank{#1}}}}
1396 % \Skak\Apply{\Showchar}{\Rank{#1}}}
1398 \def\ShowMoverWhiteNormal{\pscustom{\translate(h1)
1399 \psline{->}(1,0.25)(1,0.8)%
1400 \psframe(0.84,-0.16)(1.16,0.16)}}
1402 \def\ShowMoverBlackNormal{%
1403 \pscustom[fillstyle=solid,fillcolor=gray]{\translate(h8)%
1404 \psline{->}(1,-0.25)(1,-0.8)%
1405 \psframe(0.84,-0.16)(1.16,0.16)}}
1407 \def\ShowMoverWhiteInverse{\pscustom{\translate(a1)
1408 \psline{->}(1,-0.25)(1,-0.8)%
1409 \psframe(0.84,-0.16)(1.16,0.16)}}
1411 \def\ShowMoverBlackInverse{%
1412 \pscustom[fillstyle=solid,fillcolor=gray]{\translate(a8)%
1413 \psline{->}(1,0.25)(1,0.8)%
1414 \psframe(0.84,-0.16)(1.16,0.16)}}
1419 \def\WhiteSquare{\True}
1420 \vbox{\offinterlineskip
1422 \hbox{\vrule width1pt
1423 \vbox{\hbox{\Showrank{8}}\ToggleWhiteSquare
1424 \hbox{\Showrank{7}}\ToggleWhiteSquare
1425 \hbox{\Showrank{6}}\ToggleWhiteSquare
1426 \hbox{\Showrank{5}}\ToggleWhiteSquare
1427 \hbox{\Showrank{4}}\ToggleWhiteSquare
1428 \hbox{\Showrank{3}}\ToggleWhiteSquare
1429 \hbox{\Showrank{2}}\ToggleWhiteSquare
1430 \hbox{\Showrank{1}}}%
1433 \setcounter{ps@inverse}{0}
1436 {\ShowMoverWhiteNormal}
1437 {\ShowMoverBlackNormal}}
1441 \def\show@board@inverse{%
1442 \def\WhiteSquare{\True}
1443 \vbox{\offinterlineskip
1445 \hbox{\vrule width1pt
1446 \vbox{\hbox{\ShowrankInverse{1}}\ToggleWhiteSquare
1447 \hbox{\ShowrankInverse{2}}\ToggleWhiteSquare
1448 \hbox{\ShowrankInverse{3}}\ToggleWhiteSquare
1449 \hbox{\ShowrankInverse{4}}\ToggleWhiteSquare
1450 \hbox{\ShowrankInverse{5}}\ToggleWhiteSquare
1451 \hbox{\ShowrankInverse{6}}\ToggleWhiteSquare
1452 \hbox{\ShowrankInverse{7}}\ToggleWhiteSquare
1453 \hbox{\ShowrankInverse{8}}}%
1456 \setcounter{ps@inverse}{180}
1459 {\ShowMoverWhiteInverse}
1460 {\ShowMoverBlackInverse}}
1464 \def\ShowrankNumber#1{%
1466 \raisebox{\ranklift}[0cm][0cm]{%
1467 \makebox[\squarelength][r]{\notationfont#1\hspace*{.1\squarelength}}}}}
1469 \def\ShowrankWithNumber#1{\ShowrankNumber{#1}%
1470 \vrule width1pt \Showrank{#1}\vrule width1pt}
1472 \def\ShowrankInverseWithNumber#1{\ShowrankNumber{#1}%
1473 \vrule width1pt\ShowrankInverse{#1}\vrule width1pt}
1476 \def\Showfile#1{\hbox to \squarelength{\hfil\notationfont#1\hfil}}
1477 \def\Showfiles{\hfil\Showfile{a}\Showfile{b}\Showfile{c}\Showfile{d}%
1478 \Showfile{e}\Showfile{f}\Showfile{g}\Showfile{h}\hfil}
1479 \def\Showfiles@inverse{\hfil\Showfile{h}\Showfile{g}\Showfile{f}\Showfile{e}%
1480 \Showfile{d}\Showfile{c}\Showfile{b}\Showfile{a}\hfil}
1482 \def\show@board@notation{%
1483 \def\WhiteSquare{\True}%
1484 \vbox{\offinterlineskip%
1486 \hbox{\ShowrankWithNumber{8}}\ToggleWhiteSquare
1487 \hbox{\ShowrankWithNumber{7}}\ToggleWhiteSquare
1488 \hbox{\ShowrankWithNumber{6}}\ToggleWhiteSquare
1489 \hbox{\ShowrankWithNumber{5}}\ToggleWhiteSquare
1490 \hbox{\ShowrankWithNumber{4}}\ToggleWhiteSquare
1491 \hbox{\ShowrankWithNumber{3}}\ToggleWhiteSquare
1492 \hbox{\ShowrankWithNumber{2}}\ToggleWhiteSquare
1493 \hbox{\ShowrankWithNumber{1}}\ToggleWhiteSquare
1495 \vspace*{.1\squarelength}
1497 \setcounter{ps@inverse}{0}
1500 {\ShowMoverWhiteNormal}
1501 {\ShowMoverBlackNormal}}
1505 \def\show@board@notation@inverse{%
1506 \def\WhiteSquare{\True}%
1507 \vbox{\offinterlineskip%
1509 \hbox{\ShowrankInverseWithNumber{1}}\ToggleWhiteSquare
1510 \hbox{\ShowrankInverseWithNumber{2}}\ToggleWhiteSquare
1511 \hbox{\ShowrankInverseWithNumber{3}}\ToggleWhiteSquare
1512 \hbox{\ShowrankInverseWithNumber{4}}\ToggleWhiteSquare
1513 \hbox{\ShowrankInverseWithNumber{5}}\ToggleWhiteSquare
1514 \hbox{\ShowrankInverseWithNumber{6}}\ToggleWhiteSquare
1515 \hbox{\ShowrankInverseWithNumber{7}}\ToggleWhiteSquare
1516 \hbox{\ShowrankInverseWithNumber{8}}\ToggleWhiteSquare
1518 \vspace*{.1\squarelength}
1519 \hbox{\Showfiles@inverse}}
1520 \setcounter{ps@inverse}{180}
1523 {\ShowMoverWhiteInverse}
1524 {\ShowMoverBlackInverse}}
1528 % on the fly configuration
1529 \def\notationOn{\let\showboard=\show@board@notation%
1530 \let\showinverseboard=\show@board@notation@inverse}
1531 \def\notationOff{\let\showboard=\show@board%
1532 \let\showinverseboard=\show@board@inverse}
1534 \def\showmoverOn{\def\ShowMover{\True}}
1535 \def\showmoverOff{\def\ShowMover{\False}}
1539 \fenboard{rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1}}
1542 %%%% storing and loading of games
1544 \def\savegame#1{% writes the board as fen to #1.fen
1545 \newwrite\skakstore%
1546 \immediate\openout\skakstore=#1.fen%
1548 \immediate\write\skakstore{\temp@board}%
1549 \immediate\closeout\skakstore}
1551 % loading a board from a fen file is also possible
1552 % the file #1.fen should contain nothing but a fen of
1557 \openin\load@in=#1.fen\relax%
1558 \read\load@in to \load@read%
1560 \expandafter\FenBoard\load@read)}
1562 %%% temporary storing of a game position, without resorting to files
1563 % \def\storegame#1{\Fen@calculate%
1564 % \def#1{\temp@board}}
1565 % \def\restoregame#1{\expandafter\FenBoard#1)}
1566 \def\storegame#1{\Fen@calculate%
1567 \expandafter\xdef\csname chessgame.#1\endcsname{\temp@board}}
1568 \def\restoregame#1{%
1569 \edef\restore@temp{\csname chessgame.#1\endcsname}
1570 \expandafter\FenBoard\restore@temp)}