1 ! Z-Chess: two-player chess for the Z-machine
\r
2 ! Copyright (C) 2002, 2003, 2004 Eric Schmidt
\r
4 ! This program is free software; you can redistribute it and/or modify
\r
5 ! it under the terms of the GNU General Public License as published by
\r
6 ! the Free Software Foundation; either version 3 of the License, or
\r
7 ! (at your option) any later version.
\r
9 ! This program is distributed in the hope that it will be useful,
\r
10 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 ! GNU General Public License for more details.
\r
13 ! You should have received a copy of the GNU General Public License
\r
14 ! along with this program. If not see http://www.gnu.org/licenses/
\r
16 ! The author may be contacted at <eschmidt@safeaccess.com>.
\r
21 ! ---------------------------------------
\r
22 ! Constants, Arrays, and Global Variables
\r
23 ! ---------------------------------------
\r
29 Global width; Global height;
\r
31 ! The board position
\r
33 Global bleft; Global btop;
\r
38 Constant normal = 1;
\r
46 Global unicode_support = false;
\r
48 ! Code points for chess symbols
\r
50 Constant uni_wKing = $2654;
\r
51 Constant uni_wQueen = $2655;
\r
52 Constant uni_wRook = $2656;
\r
53 Constant uni_wBishop = $2657;
\r
54 Constant uni_wKnight = $2658;
\r
55 Constant uni_wPawn = $2659;
\r
56 Constant uni_bKing = $265a;
\r
57 Constant uni_bQueen = $265b;
\r
58 Constant uni_bRook = $265c;
\r
59 Constant uni_bBishop = $265d;
\r
60 Constant uni_bKnight = $265e;
\r
61 Constant uni_bPawn = $265f;
\r
63 ! Reading from the keyboard
\r
65 Constant uKey = $81;
\r
66 Constant dKey = $82;
\r
67 Constant lKey = $83;
\r
68 Constant rKey = $84;
\r
69 Constant EnterKey = $0d;
\r
71 ! The board caption system
\r
75 Constant whitemove = 0;
\r
76 Constant blackmove = 1;
\r
77 Constant promote = 2;
\r
78 Constant illegal = 3;
\r
79 Constant cillegal = 4;
\r
81 Constant checkmate = 6;
\r
82 Constant stalemate = 7;
\r
83 Constant lowpieces = 8;
\r
84 Constant saveyes = 9;
\r
85 Constant loadyes = 10;
\r
86 Constant saveno = 11;
\r
87 Constant loadno = 12;
\r
89 ! Notice that all the messages the game displays are of even length.
\r
90 ! This is deliberate. The window is likely to be of even width
\r
91 ! and so only even-lengthed messages can be perfectly centered.
\r
95 "White's turn to move" 20
\r
96 "Black's turn to move" 20
\r
97 "Type letter of piece" 20
\r
99 "Illegal move - check" 20
\r
103 "Draw by too few pieces" 22
\r
104 "Save succeeded" 14
\r
105 "Load succeeded" 14
\r
106 "Unable to save" 14
\r
107 "Unable to load" 14;
\r
111 Global rank = 6; Global file = 0; ! This defaults to WQRP
\r
113 ! Currently selected piece;
\r
115 Global mover = NULL;
\r
119 Constant wPawn = 1;
\r
120 Constant wKnight = 2;
\r
121 Constant wBishop = 3;
\r
122 Constant wRook = 4;
\r
123 Constant wQueen = 5;
\r
124 Constant wKing = 6;
\r
126 Constant threshold = 7; ! If (a_piece < threshold), it is white.
\r
128 Constant bPawn = 7;
\r
129 Constant bKnight = 8;
\r
130 Constant bBishop = 9;
\r
131 Constant bRook = 10;
\r
132 Constant bQueen = 11;
\r
133 Constant bKing = 12;
\r
136 bRook bKnight bBishop bQueen bKing bBishop bKnight bRook
\r
137 bPawn bPawn bPawn bPawn bPawn bPawn bPawn bPawn
\r
138 nothing nothing nothing nothing nothing nothing nothing nothing
\r
139 nothing nothing nothing nothing nothing nothing nothing nothing
\r
140 nothing nothing nothing nothing nothing nothing nothing nothing
\r
141 nothing nothing nothing nothing nothing nothing nothing nothing
\r
142 wPawn wPawn wPawn wPawn wPawn wPawn wPawn wPawn
\r
143 wRook wKnight wBishop wQueen wKing wBishop wKnight wRook;
\r
145 Array working_position -> 64;
\r
147 Global WhiteToMove = true;
\r
152 ! For calculating check
\r
153 ! We define "old" variables for backups
\r
155 Global wKingPos = e1; Global owKingPos;
\r
156 Global bKingPos = e8; Global obKingPos;
\r
160 Global just_castled;
\r
162 Global wking_moved; Global owking_moved;
\r
163 Global bking_moved; Global obking_moved;
\r
164 Global a1rook_moved; Global oa1rook_moved;
\r
165 Global h1rook_moved; Global oh1rook_moved;
\r
166 Global a8rook_moved; Global oa8rook_moved;
\r
167 Global h8rook_moved; Global oh8rook_moved;
\r
169 ! The numbers of squares to do with castling
\r
170 ! (It would be nice if Inform had octal numbers.)
\r
189 Global epPawn = NULL; Global oepPawn = NULL;
\r
191 ! The current game status
\r
199 ! The main routine: set game up and receive input
\r
201 [ Main input square piece i j;
\r
203 ! Check for large enough screen
\r
207 if (width < 22) "Regretably, this interpreter has not provided a
\r
208 wide enough window for this program.";
\r
209 if (height < 10) "Regretably, this interpreter has not provided a
\r
210 tall enough window for this program.";
\r
212 ! Check for color. If the fixed-pitch font bit is set in the header, we got
\r
213 ! here from a restart and shouldn't warn about the color.
\r
215 if (0->1 & 1) colorflag = true;
\r
216 else if (0-->$8 & $$10) font on; ! Turn bit back off
\r
218 print "WARNING: This interpreter has not provided color.
\r
219 The game may not perform optimally.^";
\r
220 @read_char 1 -> input;
\r
225 bleft = (width - 16) / 2 + 1;
\r
226 btop = (height - 10) / 2 + 2;
\r
227 if (height % 2) btop++; ! Favor lower row
\r
237 ! Set cursor position
\r
240 j = file * 2 + bleft;
\r
245 @read_char 1 -> input;
\r
249 print "^^Release 1 - Initial release^^
\r
251 ^ * Added color support
\r
252 ^ * Fixed two castling bugs^^
\r
254 ^ * Unicode support
\r
255 ^ * Changed license to GPL^^
\r
257 ^ * Added ability to save and restore game";
\r
258 @read_char 1 -> input;
\r
263 print "Use the arrow keys to move the cursor around.
\r
264 Press space bar (or enter) to select a piece.
\r
265 Move the cursor to the square you want to move the
\r
266 piece, and press space bar (or enter) again to move.
\r
267 To castle, move the king to its destination, and the
\r
268 rook will automatically move to its. To deselect the
\r
269 piece you've selected, press space bar when the cursor
\r
271 White pieces are indicated by the letter W and black pieces by
\r
272 B. If supported by your system, the piece type will be shown as
\r
273 a chess figurine. If not, a letter is used. This is the first
\r
274 letter of the piece's name, except that a knight is represented
\r
276 When a pawn promotion occurs, you must specify which type of
\r
277 piece to promote it to. Do this by typing the letter of the
\r
278 piece you want to promote it to.^^
\r
279 At the main display, you can type D to view these directions,
\r
280 I to view legal information, C to view major changes between
\r
281 versions, Q to quit, N to start a new game, S to save a game,
\r
282 or L to load a game from disk.^^
\r
283 The author may be contacted at <eschmidt@@64safeaccess.com>.";
\r
284 @read_char 1 -> input;
\r
289 print "Z-Chess: Chess for the Z-Machine^
\r
290 Copyright (C) 2002, 2003, 2004 Eric Schmidt^^
\r
291 This program is free software. It may be distributed
\r
292 under the terms of the GNU General Public License
\r
293 version 3, or (at your option) any later version.^^
\r
294 This program is distributed in the hope that it will be
\r
295 useful, but WITHOUT ANY WARRANTY; without even the implied
\r
296 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\r
297 See the GNU General Public License for more details. You should
\r
298 have received a copy of the GNU General Public License along
\r
299 with this program. If not see http://www.gnu.org/licenses/";
\r
300 @read_char 1 -> input;
\r
307 Message(loadno); ! Load failed if we get here
\r
310 font off; ! Hack: We use the fixed-pitch font bit to
\r
311 @restart; ! signal that a restart is taking place
\r
314 @set_cursor height 1;
\r
322 Message(loadno); ! Cannot reach here if succeeded
\r
329 0: Message(saveno);
\r
330 1: Message(saveyes);
\r
331 2: Message(loadyes);
\r
334 uKey: if (rank > 0) { rank--; PrintCaption(); }
\r
335 dKey: if (rank < 7) { rank++; PrintCaption(); }
\r
336 lKey: if (file > 0) { file--; PrintCaption(); }
\r
337 rKey: if (file < 7) { file++; PrintCaption(); }
\r
339 if (GameOver) break;
\r
340 square = rank * 8 + file;
\r
341 piece = position->square;
\r
342 if (mover == NULL && piece
\r
343 && WhiteToMove == (piece < threshold)) mover = square;
\r
344 else if (mover == square) mover = NULL;
\r
345 else if (mover ~= NULL) {
\r
346 if (~~AttemptToMove(mover,square)) PrintCaption();
\r
355 ! Pre 1.0 terps won't allow @check_unicode
\r
356 if (~~(0->$32)) return;
\r
358 @split_window height;
\r
361 ! Would there be support for one chess glyph but not the
\r
362 ! others? Well, we might as well be on the safe side.
\r
363 @"EXT:12S" uni_wKing -> i; if (~~(i & 1)) return;
\r
364 @"EXT:12S" uni_wQueen -> i; if (~~(i & 1)) return;
\r
365 @"EXT:12S" uni_wRook -> i; if (~~(i & 1)) return;
\r
366 @"EXT:12S" uni_wBishop -> i; if (~~(i & 1)) return;
\r
367 @"EXT:12S" uni_wKnight -> i; if (~~(i & 1)) return;
\r
368 @"EXT:12S" uni_wPawn -> i; if (~~(i & 1)) return;
\r
369 @"EXT:12S" uni_bKing -> i; if (~~(i & 1)) return;
\r
370 @"EXT:12S" uni_bQueen -> i; if (~~(i & 1)) return;
\r
371 @"EXT:12S" uni_bRook -> i; if (~~(i & 1)) return;
\r
372 @"EXT:12S" uni_bBishop -> i; if (~~(i & 1)) return;
\r
373 @"EXT:12S" uni_bKnight -> i; if (~~(i & 1)) return;
\r
374 @"EXT:12S" uni_bPawn -> i; if (~~(i & 1)) return;
\r
376 ! The interpreter has passed the sieve.
\r
377 unicode_support = true;
\r
381 @split_window height;
\r
385 print "(D)irections"; spaces width - 18; print "(I)nfo";
\r
392 ! Routine to print the position
\r
395 @set_cursor btop bleft;
\r
397 for (: i < 64: i++) {
\r
399 ! Set printing colors, considering color support
\r
402 if (i / 8 % 2 == i % 2) @push cyan; else @push red;
\r
403 if (position->i < threshold) @push white; else @push black;
\r
407 if (i / 8 % 2 == i % 2) style roman; else style reverse;
\r
409 ! Print the piece symbol
\r
411 ! Could look weird if system does not support color or both reverse and
\r
413 if (i == mover) style bold;
\r
415 if (~~position->i) print (char) ' ';
\r
416 else if (position->i < threshold) print (char) 'W';
\r
417 else print (char) 'B';
\r
419 if (unicode_support) {
\r
420 switch (position->i) {
\r
421 nothing: print (char) ' ';
\r
422 wPawn: @"EXT:11" uni_wPawn;
\r
423 wKnight: @"EXT:11" uni_wKnight;
\r
424 wBishop: @"EXT:11" uni_wBishop;
\r
425 wRook: @"EXT:11" uni_wRook;
\r
426 wQueen: @"EXT:11" uni_wQueen;
\r
427 wKing: @"EXT:11" uni_wKing;
\r
428 bPawn: @"EXT:11" uni_bPawn;
\r
429 bKnight: @"EXT:11" uni_bKnight;
\r
430 bBishop: @"EXT:11" uni_bBishop;
\r
431 bRook: @"EXT:11" uni_bRook;
\r
432 bQueen: @"EXT:11" uni_bQueen;
\r
433 bKing: @"EXT:11" uni_bKing;
\r
436 switch (position->i) {
\r
437 nothing: print (char) ' ';
\r
438 wPawn, bPawn: print (char) 'P';
\r
439 wKnight, bKnight: print (char) 'N';
\r
440 wBishop, bBishop: print (char) 'B';
\r
441 wRook, bRook: print (char) 'R';
\r
442 wQueen, bQueen: print (char) 'Q';
\r
443 wKing, bKing: print (char) 'K';
\r
445 if (i == mover) style roman;
\r
448 ! If at the end of a row, move to the next line
\r
452 @set_colour normal normal;
\r
461 ! The board caption
\r
464 if (GameOver) Message(GameOver);
\r
466 if (WhiteToMove) Message(whitemove);
\r
467 else Message(blackmove);
\r
471 ! AttemptToMove evaluates the move and makes it if legal
\r
472 ! It returns true if it prints a message, false if not
\r
474 [ AttemptToMove start end;
\r
476 ! First, the basic test
\r
478 if (~~MovePrimitive(start, end, position)) {
\r
479 Message(illegal); return;
\r
484 TransferPos(position, working_position);
\r
485 DoMove(start, end, working_position);
\r
487 ! If the move is illegal due to check, restore the old game status
\r
489 if (InCheck(working_position)) {
\r
490 TransferVarsToNew();
\r
495 ! Do promotion if needed
\r
497 if ((end <= h8 || end >= a1) && working_position->end == wPawn or bPawn)
\r
502 TransferPos(working_position, position);
\r
503 TransferVarsToOld();
\r
504 WhiteToMove = ~~WhiteToMove;
\r
506 ! Finally, evaulate for a draw, win, or check
\r
508 if (HasntLegal()) rfalse;
\r
509 if (InCheck(position)) return Message(check);
\r
513 ! Moving data around
\r
515 [ TransferPos p_array1 p_array2 i;
\r
516 for (: i < 64: i++) p_array2->i = p_array1->i;
\r
519 [ TransferVarsToNew;
\r
520 wKingPos = owKingPos;
\r
521 bKingPos = obKingPos;
\r
522 wking_moved = owking_moved;
\r
523 bking_moved = obking_moved;
\r
524 a1rook_moved = oa1rook_moved;
\r
525 h1rook_moved = oh1rook_moved;
\r
526 a8rook_moved = oa8rook_moved;
\r
527 h8rook_moved = oh8rook_moved;
\r
531 [ TransferVarsToOld;
\r
532 owKingPos = wKingPos;
\r
533 obKingPos = bKingPos;
\r
534 owking_moved = wking_moved;
\r
535 obking_moved = bking_moved;
\r
536 oa1rook_moved = a1rook_moved;
\r
537 oh1rook_moved = h1rook_moved;
\r
538 oa8rook_moved = a8rook_moved;
\r
539 oh8rook_moved = h8rook_moved;
\r
543 ! MovePrimitive tests if a move is legal, but doesn't
\r
544 ! consider check. Returns true if the move seems legal,
\r
545 ! false if it seems illegal.
\r
547 [ MovePrimitive start end p_array side otherside
\r
548 srank sfile erank efile a b c d;
\r
550 ! Find the sides of the pieces on the starting
\r
551 ! and ending squares
\r
553 side = p_array->start < threshold;
\r
554 if (p_array->end == nothing) otherside = NULL;
\r
555 else otherside = (p_array->end < threshold);
\r
557 ! If they are the same, stop now
\r
559 if (side == otherside) rfalse;
\r
561 ! Locate the pieces on the board
\r
568 ! Now, the actual evaluation
\r
570 switch (p_array->start) {
\r
573 ! For pawns, the rules are different for each side
\r
574 ! so test and set key numbers appropriately.
\r
577 a = 1; b = 6; c = 4; d = 8;
\r
580 a = -1; b = 1; c = 3; d = -8;
\r
583 if (srank - erank == a) {
\r
587 if (sfile == efile && otherside == NULL) rtrue;
\r
591 if (sfile - efile == -1 or 1 &&
\r
592 (otherside ~= NULL || eppawn == end+d)) rtrue;
\r
597 if (srank == b && erank == c && sfile == efile && (~~p_array->(start-d))
\r
598 && otherside == NULL) rtrue;
\r
600 ! The knights, bishops, rooks, queens, and kings
\r
603 if ((srank - erank == 1 or -1 && sfile - efile == 2 or -2) ||
\r
604 (srank - erank == 2 or -2 && sfile - efile == 1 or -1)) rtrue;
\r
606 return DiagonalMove(srank, sfile, erank, efile, p_array);
\r
608 return StraightMove(srank, sfile, erank, efile, p_array);
\r
610 return DiagonalMove(srank, sfile, erank, efile, p_array)
\r
611 || StraightMove(srank, sfile, erank, efile, p_array);
\r
613 if (srank - erank < 2 && erank - srank < 2
\r
614 && sfile - efile < 2 && efile - sfile < 2) rtrue;
\r
619 if (p_array->start == wKing && ~~wking_moved) {
\r
620 if (end == g1 && ~~h1rook_moved)
\r
621 return StraightMove(7, 4, 7, 7, p_array);
\r
622 if (end == c1 && ~~a1rook_moved)
\r
623 return StraightMove(7, 4, 7, 0, p_array);
\r
625 if (p_array->start == bKing && ~~bking_moved) {
\r
626 if (end == g8 && ~~h8rook_moved)
\r
627 return StraightMove(0, 4, 0, 7, p_array);
\r
628 if (end == c8 && ~~a8rook_moved)
\r
629 return StraightMove(0, 4, 0, 0, p_array);
\r
634 ! DiagonalMove tests if a diagonal move is valid.
\r
635 ! That is, that the squares are diagonal from each other
\r
636 ! and nothing is in the way. Returns true if valid, false if not.
\r
638 [ DiagonalMove srank sfile erank efile p_array i j;
\r
640 ! Make sure squares are diagonal from each other
\r
642 if (srank - erank ~= sfile - efile or efile - sfile) rfalse;
\r
644 ! Before testing for obstacles, find the direction of the move
\r
646 if (srank < erank) i = 1; else i = -1;
\r
647 if (sfile < efile) j = 1; else j = -1;
\r
649 ! Now test for obstacles
\r
652 srank = srank + i; sfile = sfile + j;
\r
653 if (srank == erank) break;
\r
654 if (p_array->(srank * 8 + sfile)) rfalse;
\r
658 ! StraightMove is similar to DiagonalMove
\r
660 [ StraightMove srank sfile erank efile p_array i;
\r
661 if (srank ~= erank && sfile ~= efile) rfalse;
\r
662 if (srank == erank) {
\r
663 if (sfile < efile) i = 1; else i = -1;
\r
666 if (sfile == efile) break;
\r
667 if (p_array->(srank * 8 + sfile)) rfalse;
\r
671 if (srank < erank) i = 1; else i = -1;
\r
674 if (srank == erank) break;
\r
675 if (p_array->(srank * 8 + sfile)) rfalse;
\r
680 ! DoMove actually performs the move, taking special note of
\r
681 ! castling and en passant.
\r
683 [ DoMove start end p_array;
\r
685 ! If en passant, remove the pawn being taken
\r
687 if (p_array->end == nothing && (start - end) % 8 &&
\r
688 p_array->start == wPawn or bPawn)
\r
689 p_array->(epPawn) = nothing;
\r
691 ! If a pawn is being moved 2 squares, store it in epPawn
\r
692 ! If not, we clear it
\r
696 if (p_array->start == wPawn or bPawn && start - end == 16 or -16)
\r
699 ! Set movement variables if necessary
\r
701 if (start == a1) a1rook_moved = true;
\r
702 else if (start == h1) h1rook_moved = true;
\r
703 else if (start == a8) a8rook_moved = true;
\r
704 else if (start == h8) h8rook_moved = true;
\r
705 else if (start == e1) wKing_moved = true;
\r
706 else if (start == e8) bKing_moved = true;
\r
710 p_array->end = p_array->start;
\r
711 p_array->start = nothing;
\r
713 ! Set variable if a king moved
\r
715 if (p_array->end == wKing) wKingPos = end;
\r
716 else if (p_array->end == bKing) bKingPos = end;
\r
718 ! If castling, move the rooks also, and set just_castled
\r
720 just_castled = false;
\r
721 if (p_array->end == wKing && start == e1) {
\r
722 if (end == g1) {DoMove(h1, f1, p_array); just_castled = true;}
\r
723 else if (end == c1) {DoMove(a1, d1, p_array); just_castled = true;}
\r
725 else if (p_array->end == bKing && start == e8) {
\r
726 if (end == g8) {DoMove(h8, f8, p_array); just_castled = true;}
\r
727 else if (end == c8) {DoMove(a8, d8, p_array); just_castled = true;}
\r
731 ! Promotion finds from the player the piece to promote to and executes
\r
734 [ Promotion pawn input a i;
\r
735 if (working_position->pawn == bPawn) a = 6;
\r
737 i = (width - 20) / 2 + 21;
\r
738 @set_cursor mrow i;
\r
741 @read_char 1 -> input;
\r
743 'q', 'Q': working_position->pawn = wQueen + a; return;
\r
744 'n', 'N': working_position->pawn = wKnight + a; return;
\r
745 'b', 'B': working_position->pawn = wBishop + a; return;
\r
746 'r', 'R': working_position->pawn = wRook + a; return;
\r
751 ! InCheck tests if the current side to move is in check.
\r
752 ! Returns true if in check, false if not.
\r
754 [ InCheck p_array king kstart kmiddle i s_ep;
\r
756 ! First, find the king
\r
758 if (WhiteToMove) king = wKingPos; else king = bKingPos;
\r
760 ! If castling, check the starting and middle squares too.
\r
762 if (just_castled) {
\r
763 if (king == g1) { kstart = e1; kmiddle = f1; }
\r
764 else if (king == c1) { kstart = e1; kmiddle = d1; }
\r
765 else if (king == g8) { kstart = e8; kmiddle = f8; }
\r
766 else if (king == c8) { kstart = e8; kmiddle = d8; }
\r
770 s_ep = epPawn; ! DoMove wrecks epPawn. Save a backup.
\r
771 DoMove(king, kstart, p_array);
\r
772 if (InCheck(p_array)) i = true;
\r
773 DoMove(kstart, kmiddle, p_array);
\r
774 if (InCheck(p_array)) i = true;
\r
775 DoMove(kmiddle, king, p_array);
\r
776 if (WhiteToMove) p_array->kmiddle = wRook;
\r
777 else p_array->kmiddle = bRook;
\r
782 ! Now, find all enemy pieces, and use MovePrimitive
\r
783 ! to see if they can take the king
\r
786 for (: i < 64: i++) {
\r
787 if (p_array->i < threshold) continue;
\r
788 if (MovePrimitive(i, king, p_array)) rtrue;
\r
791 for (: i < 64: i++) {
\r
792 if (p_array->i == nothing) continue;
\r
793 if (p_array->i < threshold
\r
794 && MovePrimitive(i, king, p_array)) rtrue;
\r
799 ! HasntLegal tests if the game is over due to checkmate, stalemate,
\r
800 ! or insufficiant material to mate, and sets gameover accordingly.
\r
802 [ HasntLegal i j k knight lbishop dbishop;
\r
804 ! Try to find a legal move for side to move with MovePrimitive, DoMove, and InCheck.
\r
807 for (: i < 64: i++) {
\r
808 if (position->i == nothing ||
\r
809 position->i >= threshold) continue;
\r
810 for (j = 0: j < 64: j++) {
\r
811 if (MovePrimitive(i, j, position) && DoMove(i, j, position)
\r
812 && (~~InCheck(position))) k = true;
\r
813 TransferPos(working_position, position);
\r
814 TransferVarsToNew();
\r
819 for (: i < 64: i++) {
\r
820 if (position->i < threshold) continue;
\r
821 for (j = 0: j < 64: j++) {
\r
822 if (MovePrimitive(i, j, position) && DoMove(i, j, position)
\r
823 && (~~InCheck(position))) k = true;
\r
824 TransferPos(working_position, position);
\r
825 TransferVarsToNew();
\r
832 ! If i is 64, the entire loop found no legal move
\r
835 if (InCheck(position)) gameover = checkmate;
\r
836 else gameover = stalemate;
\r
840 ! The final task is to check for low pieces. Anything other than
\r
841 ! a minor piece or king means no draw. Two minor pieces
\r
842 ! mean no draw, unless they are two bishops found on the same
\r
843 ! color square. The same is true of any number of bishops
\r
844 ! of the same color square.
\r
846 for (i = 0: i < 64: i++)
\r
847 switch (position->i) {
\r
848 wPawn, bPawn, wRook, bRook, wQueen, bQueen: rfalse;
\r
850 if (knight || lbishop || dbishop) rfalse;
\r
853 if (i / 8 % 2 == i % 2) lbishop = true;
\r
854 else dbishop = true;
\r
855 if (knight || (lbishop && dbishop)) rfalse;
\r
857 gameover = lowpieces;
\r
860 ! A routine to center all the messages neatly under the board
\r
862 [ Message num start;
\r
864 start = (width - mArray-->(num+1)) / 2;
\r
865 @set_cursor mrow 1;
\r
867 print (string) mArray-->num;
\r