From: Jason Self Date: Wed, 21 Aug 2019 02:47:54 +0000 (-0700) Subject: Import zchess by Eric Schmidt X-Git-Url: https://jxself.org/git/?a=commitdiff_plain;h=c73daca34d9751fc03049d102d32a6c236bebefa;p=zchess.git Import zchess by Eric Schmidt Release 4; Serial number 040124 From http://www.ifarchive.org/if-archive/games/source/inform/zchess.zip --- c73daca34d9751fc03049d102d32a6c236bebefa diff --git a/README b/README new file mode 100644 index 0000000..d277dfe --- /dev/null +++ b/README @@ -0,0 +1,31 @@ +This repository contains a copy of zchess by Eric Schmidt. + +http://www.ifarchive.org/if-archive/games/source/inform/zchess.zip + +To compile this game you will also need version 6 of the Inform +compiler from https://jxself.org/git/?p=inform.git + +Once the compiler has been compiled and is ready for use return to +this directory and run: + + inform zchess.inf + +You will then get the story file for this game that can be run using +any appropriate Z-Machine interpreter, such as Frotz. Your GNU/Linux +distro probably has that packaged already for easy installation. + +-- +Copyright (C) 2019 Jason Self + +You may copy, redistribute and/or modify this under the terms of the +GNU General Public License as published by the Free Software +Foundation, either version 2 of the License, or (at your option) any +later version. + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file. If not, see https://gnu.org/licenses/ \ No newline at end of file diff --git a/gpl.txt b/gpl.txt new file mode 100644 index 0000000..45645b4 --- /dev/null +++ b/gpl.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/zchess.inf b/zchess.inf new file mode 100644 index 0000000..0e7be5f --- /dev/null +++ b/zchess.inf @@ -0,0 +1,872 @@ +! Z-Chess: two-player chess for the Z-machine +! Copyright (C) 2002, 2003, 2004 Eric Schmidt + +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. + +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +! The author may be contacted at . + +Release 4; +Serial "040124"; + +! --------------------------------------- +! Constants, Arrays, and Global Variables +! --------------------------------------- + +Constant NULL = -1; + +! The screen size + +Global width; Global height; + +! The board position + +Global bleft; Global btop; + +! The board colors + +Global colorflag; +Constant normal = 1; +Constant black = 2; +Constant red = 3; +Constant cyan = 8; +Constant white = 9; + +! Unicode + +Global unicode_support = false; + +! Code points for chess symbols + +Constant uni_wKing = $2654; +Constant uni_wQueen = $2655; +Constant uni_wRook = $2656; +Constant uni_wBishop = $2657; +Constant uni_wKnight = $2658; +Constant uni_wPawn = $2659; +Constant uni_bKing = $265a; +Constant uni_bQueen = $265b; +Constant uni_bRook = $265c; +Constant uni_bBishop = $265d; +Constant uni_bKnight = $265e; +Constant uni_bPawn = $265f; + +! Reading from the keyboard + +Constant uKey = $81; +Constant dKey = $82; +Constant lKey = $83; +Constant rKey = $84; +Constant EnterKey = $0d; + +! The board caption system + +Global mrow; + +Constant whitemove = 0; +Constant blackmove = 1; +Constant promote = 2; +Constant illegal = 3; +Constant cillegal = 4; +Constant check = 5; +Constant checkmate = 6; +Constant stalemate = 7; +Constant lowpieces = 8; +Constant saveyes = 9; +Constant loadyes = 10; +Constant saveno = 11; +Constant loadno = 12; + +! Notice that all the messages the game displays are of even length. +! This is deliberate. The window is likely to be of even width +! and so only even-lengthed messages can be perfectly centered. + +Array mArray --> +! message length + "White's turn to move" 20 + "Black's turn to move" 20 + "Type letter of piece" 20 + "Illegal move" 12 + "Illegal move - check" 20 + "Check!" 6 + "Checkmate!" 10 + "Stalemate!" 10 + "Draw by too few pieces" 22 + "Save succeeded" 14 + "Load succeeded" 14 + "Unable to save" 14 + "Unable to load" 14; + +! Cursor location + +Global rank = 6; Global file = 0; ! This defaults to WQRP + +! Currently selected piece; + +Global mover = NULL; + +! The position + +Constant wPawn = 1; +Constant wKnight = 2; +Constant wBishop = 3; +Constant wRook = 4; +Constant wQueen = 5; +Constant wKing = 6; + +Constant threshold = 7; ! If (a_piece < threshold), it is white. + +Constant bPawn = 7; +Constant bKnight = 8; +Constant bBishop = 9; +Constant bRook = 10; +Constant bQueen = 11; +Constant bKing = 12; + +Array position -> + bRook bKnight bBishop bQueen bKing bBishop bKnight bRook + bPawn bPawn bPawn bPawn bPawn bPawn bPawn bPawn + nothing nothing nothing nothing nothing nothing nothing nothing + nothing nothing nothing nothing nothing nothing nothing nothing + nothing nothing nothing nothing nothing nothing nothing nothing + nothing nothing nothing nothing nothing nothing nothing nothing + wPawn wPawn wPawn wPawn wPawn wPawn wPawn wPawn + wRook wKnight wBishop wQueen wKing wBishop wKnight wRook; + +Array working_position -> 64; + +Global WhiteToMove = true; + +Constant e1 = 60; +Constant e8 = 4; + +! For calculating check +! We define "old" variables for backups + +Global wKingPos = e1; Global owKingPos; +Global bKingPos = e8; Global obKingPos; + +! Castling + +Global just_castled; + +Global wking_moved; Global owking_moved; +Global bking_moved; Global obking_moved; +Global a1rook_moved; Global oa1rook_moved; +Global h1rook_moved; Global oh1rook_moved; +Global a8rook_moved; Global oa8rook_moved; +Global h8rook_moved; Global oh8rook_moved; + +! The numbers of squares to do with castling +! (It would be nice if Inform had octal numbers.) + +Constant a8 = 0; +Constant a1 = 56; +Constant h1 = 63; +Constant h8 = 7; + +Constant f1 = 61; +Constant g1 = 62; +Constant d1 = 59; +Constant c1 = 58; + +Constant f8 = 5; +Constant g8 = 6; +Constant d8 = 3; +Constant c8 = 2; + +! En passant + +Global epPawn = NULL; Global oepPawn = NULL; + +! The current game status + +Global GameOver; + +! ------------ +! The Routines +! ------------ + +! The main routine: set game up and receive input + +[ Main input square piece i j; + + ! Check for large enough screen + + height = 0->$20; + width = 0->$21; + if (width < 22) "Regretably, this interpreter has not provided a + wide enough window for this program."; + if (height < 10) "Regretably, this interpreter has not provided a + tall enough window for this program."; + + ! Check for color. If the fixed-pitch font bit is set in the header, we got + ! here from a restart and shouldn't warn about the color. + + if (0->1 & 1) colorflag = true; + else if (0-->$8 & $$10) font on; ! Turn bit back off + else { + print "WARNING: This interpreter has not provided color. + The game may not perform optimally.^"; + @read_char 1 -> input; + } + + ! Locate board + + bleft = (width - 16) / 2 + 1; + btop = (height - 10) / 2 + 2; + if (height % 2) btop++; ! Favor lower row + mrow = btop + 8; + + CheckUnicode(); + + CompleteRedraw(); + + ! Main gain loop + + while (1) { + ! Set cursor position + + i = btop + rank; + j = file * 2 + bleft; + @set_cursor i j; + + ! Receive input + + @read_char 1 -> input; + switch (input) { + 'c', 'C': + @erase_window -1; + print "^^Release 1 - Initial release^^ + Release 2 + ^ * Added color support + ^ * Fixed two castling bugs^^ + Release 3 + ^ * Unicode support + ^ * Changed license to GPL^^ + Release 4 + ^ * Added ability to save and restore game"; + @read_char 1 -> input; + CompleteRedraw(); + + 'd', 'D': + @erase_window -1; + print "Use the arrow keys to move the cursor around. + Press space bar (or enter) to select a piece. + Move the cursor to the square you want to move the + piece, and press space bar (or enter) again to move. + To castle, move the king to its destination, and the + rook will automatically move to its. To deselect the + piece you've selected, press space bar when the cursor + is on the piece.^^ + White pieces are indicated by the letter W and black pieces by + B. If supported by your system, the piece type will be shown as + a chess figurine. If not, a letter is used. This is the first + letter of the piece's name, except that a knight is represented + by N.^^ + When a pawn promotion occurs, you must specify which type of + piece to promote it to. Do this by typing the letter of the + piece you want to promote it to.^^ + At the main display, you can type D to view these directions, + I to view legal information, C to view major changes between + versions, Q to quit, N to start a new game, S to save a game, + or L to load a game from disk.^^ + The author may be contacted at ."; + @read_char 1 -> input; + CompleteRedraw(); + + 'i', 'I': + @erase_window -1; + print "Z-Chess: Chess for the Z-Machine^ + Copyright (C) 2002, 2003, 2004 Eric Schmidt^^ + This program is free software. It may be distributed + under the terms of the GNU General Public License + version 2, or (at your option) any later version.^^ + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should + have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA"; + @read_char 1 -> input; + CompleteRedraw(); + + 'l', 'L': + @erase_window -1; + @restore -> i; + CompleteRedraw(); + Message(loadno); ! Load failed if we get here + + 'n', 'N': + font off; ! Hack: We use the fixed-pitch font bit to + @restart; ! signal that a restart is taking place + + 'q', 'Q': + @set_cursor height 1; + @erase_line 1; + quit; + + 'r', 'R': + @erase_window -1; + @restore -> i; + CompleteRedraw(); + Message(loadno); ! Cannot reach here if succeeded + + 's', 'S': + @erase_window -1; + @save -> i; + CompleteRedraw(); + switch (i) { + 0: Message(saveno); + 1: Message(saveyes); + 2: Message(loadyes); + } + + uKey: if (rank > 0) { rank--; PrintCaption(); } + dKey: if (rank < 7) { rank++; PrintCaption(); } + lKey: if (file > 0) { file--; PrintCaption(); } + rKey: if (file < 7) { file++; PrintCaption(); } + EnterKey, ' ': + if (GameOver) break; + square = rank * 8 + file; + piece = position->square; + if (mover == NULL && piece + && WhiteToMove == (piece < threshold)) mover = square; + else if (mover == square) mover = NULL; + else if (mover ~= NULL) { + if (~~AttemptToMove(mover,square)) PrintCaption(); + mover = NULL; + } + PrintPos(); + } + } +]; + +[ CheckUnicode i; + ! Pre 1.0 terps won't allow @check_unicode + if (~~(0->$32)) return; + + @split_window height; + @set_window 1; + + ! Would there be support for one chess glyph but not the + ! others? Well, we might as well be on the safe side. + @"EXT:12S" uni_wKing -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_wQueen -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_wRook -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_wBishop -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_wKnight -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_wPawn -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_bKing -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_bQueen -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_bRook -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_bBishop -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_bKnight -> i; if (~~(i & 1)) return; + @"EXT:12S" uni_bPawn -> i; if (~~(i & 1)) return; + + ! The interpreter has passed the sieve. + unicode_support = true; +]; + +[ CompleteRedraw; + @split_window height; + @set_window 1; + @erase_window -2; + style reverse; + print "(D)irections"; spaces width - 18; print "(I)nfo"; + style roman; + + PrintPos(); + PrintCaption(); +]; + +! Routine to print the position + +[ PrintPos i; + @set_cursor btop bleft; + + for (: i < 64: i++) { + + ! Set printing colors, considering color support + + if (colorflag) { + if (i / 8 % 2 == i % 2) @push cyan; else @push red; + if (position->i < threshold) @push white; else @push black; + @set_colour sp sp; + } + else + if (i / 8 % 2 == i % 2) style roman; else style reverse; + + ! Print the piece symbol + + ! Could look weird if system does not support color or both reverse and + ! bold type + if (i == mover) style bold; + + if (~~position->i) print (char) ' '; + else if (position->i < threshold) print (char) 'W'; + else print (char) 'B'; + + if (unicode_support) { + switch (position->i) { + nothing: print (char) ' '; + wPawn: @"EXT:11" uni_wPawn; + wKnight: @"EXT:11" uni_wKnight; + wBishop: @"EXT:11" uni_wBishop; + wRook: @"EXT:11" uni_wRook; + wQueen: @"EXT:11" uni_wQueen; + wKing: @"EXT:11" uni_wKing; + bPawn: @"EXT:11" uni_bPawn; + bKnight: @"EXT:11" uni_bKnight; + bBishop: @"EXT:11" uni_bBishop; + bRook: @"EXT:11" uni_bRook; + bQueen: @"EXT:11" uni_bQueen; + bKing: @"EXT:11" uni_bKing; + } + } else { + switch (position->i) { + nothing: print (char) ' '; + wPawn, bPawn: print (char) 'P'; + wKnight, bKnight: print (char) 'N'; + wBishop, bBishop: print (char) 'B'; + wRook, bRook: print (char) 'R'; + wQueen, bQueen: print (char) 'Q'; + wKing, bKing: print (char) 'K'; + } + if (i == mover) style roman; + } + + ! If at the end of a row, move to the next line + + if (i % 8 == 7) { + style roman; + @set_colour normal normal; + if (i < 63) { + new_line; + spaces bleft - 1; + } + } + } +]; + +! The board caption + +[ PrintCaption; + if (GameOver) Message(GameOver); + else { + if (WhiteToMove) Message(whitemove); + else Message(blackmove); + } +]; + +! AttemptToMove evaluates the move and makes it if legal +! It returns true if it prints a message, false if not + +[ AttemptToMove start end; + + ! First, the basic test + + if (~~MovePrimitive(start, end, position)) { + Message(illegal); return; + } + + ! Make the move + + TransferPos(position, working_position); + DoMove(start, end, working_position); + + ! If the move is illegal due to check, restore the old game status + + if (InCheck(working_position)) { + TransferVarsToNew(); + Message(cillegal); + return; + } + + ! Do promotion if needed + + if ((end <= h8 || end >= a1) && working_position->end == wPawn or bPawn) + Promotion(end); + + ! Update the board + + TransferPos(working_position, position); + TransferVarsToOld(); + WhiteToMove = ~~WhiteToMove; + + ! Finally, evaulate for a draw, win, or check + + if (HasntLegal()) rfalse; + if (InCheck(position)) return Message(check); + rfalse; +]; + +! Moving data around + +[ TransferPos p_array1 p_array2 i; + for (: i < 64: i++) p_array2->i = p_array1->i; +]; + +[ TransferVarsToNew; + wKingPos = owKingPos; + bKingPos = obKingPos; + wking_moved = owking_moved; + bking_moved = obking_moved; + a1rook_moved = oa1rook_moved; + h1rook_moved = oh1rook_moved; + a8rook_moved = oa8rook_moved; + h8rook_moved = oh8rook_moved; + epPawn = oepPawn; +]; + +[ TransferVarsToOld; + owKingPos = wKingPos; + obKingPos = bKingPos; + owking_moved = wking_moved; + obking_moved = bking_moved; + oa1rook_moved = a1rook_moved; + oh1rook_moved = h1rook_moved; + oa8rook_moved = a8rook_moved; + oh8rook_moved = h8rook_moved; + oepPawn = epPawn; +]; + +! MovePrimitive tests if a move is legal, but doesn't +! consider check. Returns true if the move seems legal, +! false if it seems illegal. + +[ MovePrimitive start end p_array side otherside + srank sfile erank efile a b c d; + + ! Find the sides of the pieces on the starting + ! and ending squares + + side = p_array->start < threshold; + if (p_array->end == nothing) otherside = NULL; + else otherside = (p_array->end < threshold); + + ! If they are the same, stop now + + if (side == otherside) rfalse; + + ! Locate the pieces on the board + + srank = start / 8; + sfile = start % 8; + erank = end / 8; + efile = end % 8; + + ! Now, the actual evaluation + + switch (p_array->start) { + wPawn, bPawn: + + ! For pawns, the rules are different for each side + ! so test and set key numbers appropriately. + + if (side) { + a = 1; b = 6; c = 4; d = 8; + } + else { + a = -1; b = 1; c = 3; d = -8; + } + + if (srank - erank == a) { + + ! Standard move? + + if (sfile == efile && otherside == NULL) rtrue; + + ! Capture? + + if (sfile - efile == -1 or 1 && + (otherside ~= NULL || eppawn == end+d)) rtrue; + } + + ! Two square move? + + if (srank == b && erank == c && sfile == efile && (~~p_array->(start-d)) + && otherside == NULL) rtrue; + + ! The knights, bishops, rooks, queens, and kings + + wKnight, bKnight: + if ((srank - erank == 1 or -1 && sfile - efile == 2 or -2) || + (srank - erank == 2 or -2 && sfile - efile == 1 or -1)) rtrue; + wBishop, bBishop: + return DiagonalMove(srank, sfile, erank, efile, p_array); + wRook, bRook: + return StraightMove(srank, sfile, erank, efile, p_array); + wQueen, bQueen: + return DiagonalMove(srank, sfile, erank, efile, p_array) + || StraightMove(srank, sfile, erank, efile, p_array); + wKing, bKing: + if (srank - erank < 2 && erank - srank < 2 + && sfile - efile < 2 && efile - sfile < 2) rtrue; + } + + ! Castling? + + if (p_array->start == wKing && ~~wking_moved) { + if (end == g1 && ~~h1rook_moved) + return StraightMove(7, 4, 7, 7, p_array); + if (end == c1 && ~~a1rook_moved) + return StraightMove(7, 4, 7, 0, p_array); + } + if (p_array->start == bKing && ~~bking_moved) { + if (end == g8 && ~~h8rook_moved) + return StraightMove(0, 4, 0, 7, p_array); + if (end == c8 && ~~a8rook_moved) + return StraightMove(0, 4, 0, 0, p_array); + } + rfalse; +]; + +! DiagonalMove tests if a diagonal move is valid. +! That is, that the squares are diagonal from each other +! and nothing is in the way. Returns true if valid, false if not. + +[ DiagonalMove srank sfile erank efile p_array i j; + + ! Make sure squares are diagonal from each other + + if (srank - erank ~= sfile - efile or efile - sfile) rfalse; + + ! Before testing for obstacles, find the direction of the move + + if (srank < erank) i = 1; else i = -1; + if (sfile < efile) j = 1; else j = -1; + + ! Now test for obstacles + + for (::) { + srank = srank + i; sfile = sfile + j; + if (srank == erank) break; + if (p_array->(srank * 8 + sfile)) rfalse; + } +]; + +! StraightMove is similar to DiagonalMove + +[ StraightMove srank sfile erank efile p_array i; + if (srank ~= erank && sfile ~= efile) rfalse; + if (srank == erank) { + if (sfile < efile) i = 1; else i = -1; + for (::) { + sfile = sfile + i; + if (sfile == efile) break; + if (p_array->(srank * 8 + sfile)) rfalse; + } + } + else { + if (srank < erank) i = 1; else i = -1; + for (::) { + srank = srank + i; + if (srank == erank) break; + if (p_array->(srank * 8 + sfile)) rfalse; + } + } +]; + +! DoMove actually performs the move, taking special note of +! castling and en passant. + +[ DoMove start end p_array; + + ! If en passant, remove the pawn being taken + + if (p_array->end == nothing && (start - end) % 8 && + p_array->start == wPawn or bPawn) + p_array->(epPawn) = nothing; + + ! If a pawn is being moved 2 squares, store it in epPawn + ! If not, we clear it + + epPawn = NULL; + + if (p_array->start == wPawn or bPawn && start - end == 16 or -16) + epPawn = end; + + ! Set movement variables if necessary + + if (start == a1) a1rook_moved = true; + else if (start == h1) h1rook_moved = true; + else if (start == a8) a8rook_moved = true; + else if (start == h8) h8rook_moved = true; + else if (start == e1) wKing_moved = true; + else if (start == e8) bKing_moved = true; + + ! The move + + p_array->end = p_array->start; + p_array->start = nothing; + + ! Set variable if a king moved + + if (p_array->end == wKing) wKingPos = end; + else if (p_array->end == bKing) bKingPos = end; + + ! If castling, move the rooks also, and set just_castled + + just_castled = false; + if (p_array->end == wKing && start == e1) { + if (end == g1) {DoMove(h1, f1, p_array); just_castled = true;} + else if (end == c1) {DoMove(a1, d1, p_array); just_castled = true;} + } + else if (p_array->end == bKing && start == e8) { + if (end == g8) {DoMove(h8, f8, p_array); just_castled = true;} + else if (end == c8) {DoMove(a8, d8, p_array); just_castled = true;} + } +]; + +! Promotion finds from the player the piece to promote to and executes +! the promotion. + +[ Promotion pawn input a i; + if (working_position->pawn == bPawn) a = 6; + message(promote); + i = (width - 20) / 2 + 21; + @set_cursor mrow i; + + while (1) { + @read_char 1 -> input; + switch (input) { + 'q', 'Q': working_position->pawn = wQueen + a; return; + 'n', 'N': working_position->pawn = wKnight + a; return; + 'b', 'B': working_position->pawn = wBishop + a; return; + 'r', 'R': working_position->pawn = wRook + a; return; + } + } +]; + +! InCheck tests if the current side to move is in check. +! Returns true if in check, false if not. + +[ InCheck p_array king kstart kmiddle i s_ep; + + ! First, find the king + + if (WhiteToMove) king = wKingPos; else king = bKingPos; + + ! If castling, check the starting and middle squares too. + + if (just_castled) { + if (king == g1) { kstart = e1; kmiddle = f1; } + else if (king == c1) { kstart = e1; kmiddle = d1; } + else if (king == g8) { kstart = e8; kmiddle = f8; } + else if (king == c8) { kstart = e8; kmiddle = d8; } + } + + if (kstart) { + s_ep = epPawn; ! DoMove wrecks epPawn. Save a backup. + DoMove(king, kstart, p_array); + if (InCheck(p_array)) i = true; + DoMove(kstart, kmiddle, p_array); + if (InCheck(p_array)) i = true; + DoMove(kmiddle, king, p_array); + if (WhiteToMove) p_array->kmiddle = wRook; + else p_array->kmiddle = bRook; + epPawn = s_ep; + if (i) rtrue; + } + + ! Now, find all enemy pieces, and use MovePrimitive + ! to see if they can take the king + + if (WhiteToMove) + for (: i < 64: i++) { + if (p_array->i < threshold) continue; + if (MovePrimitive(i, king, p_array)) rtrue; + } + else + for (: i < 64: i++) { + if (p_array->i == nothing) continue; + if (p_array->i < threshold + && MovePrimitive(i, king, p_array)) rtrue; + } + rfalse; +]; + +! HasntLegal tests if the game is over due to checkmate, stalemate, +! or insufficiant material to mate, and sets gameover accordingly. + +[ HasntLegal i j k knight lbishop dbishop; + + ! Try to find a legal move for side to move with MovePrimitive, DoMove, and InCheck. + + if (WhiteToMove) + for (: i < 64: i++) { + if (position->i == nothing || + position->i >= threshold) continue; + for (j = 0: j < 64: j++) { + if (MovePrimitive(i, j, position) && DoMove(i, j, position) + && (~~InCheck(position))) k = true; + TransferPos(working_position, position); + TransferVarsToNew(); + if (k) jump out; + } + } + else + for (: i < 64: i++) { + if (position->i < threshold) continue; + for (j = 0: j < 64: j++) { + if (MovePrimitive(i, j, position) && DoMove(i, j, position) + && (~~InCheck(position))) k = true; + TransferPos(working_position, position); + TransferVarsToNew(); + if (k) jump out; + } + } + + .out; + + ! If i is 64, the entire loop found no legal move + + if (i == 64) { + if (InCheck(position)) gameover = checkmate; + else gameover = stalemate; + rtrue; + } + + ! The final task is to check for low pieces. Anything other than + ! a minor piece or king means no draw. Two minor pieces + ! mean no draw, unless they are two bishops found on the same + ! color square. The same is true of any number of bishops + ! of the same color square. + + for (i = 0: i < 64: i++) + switch (position->i) { + wPawn, bPawn, wRook, bRook, wQueen, bQueen: rfalse; + wKnight, bKnight: + if (knight || lbishop || dbishop) rfalse; + knight = true; + wBishop, bBishop: + if (i / 8 % 2 == i % 2) lbishop = true; + else dbishop = true; + if (knight || (lbishop && dbishop)) rfalse; + } + gameover = lowpieces; +]; + +! A routine to center all the messages neatly under the board + +[ Message num start; + num = num * 2; + start = (width - mArray-->(num+1)) / 2; + @set_cursor mrow 1; + spaces start; + print (string) mArray-->num; + spaces start; +];