xgammon/COPYING100644 764 144 43076 6776466624 12331 0ustar delleusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, 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 Appendix: 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) 19yy 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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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. xgammon/TODO100644 764 144 3704 7020335144 11707 0ustar delleusersHomepage Mail von lambert Hochladen CVS autoconf xgammon: status checken load funktioniert nicht Und zwar: Schwarz darf seine Zuege nicht ziehen :-) Es wird nicht gespeichert, ob die Wuerfel bereits zu sehen waren (Lösung: Parameter (seen)/(not seen) nach einem Restart wird das Brett nicht neu gezeichnet nach dem Speichern einer Position: Manchmal? kein Spiel mehr moeglich? nach demDoppeln muesste zuerst das Brett neu gezeichnet werden standardresourcen beim start laden etwas hektisches redraw gelgentlich -Wall fuer alles :-) database? Wie erweitern? ausgabe noch nicht wirklich schoen Help-Button/About-Button Nach einem Undo vom Out Field wird kein Redraw gemacht (echter Bug!) (Nach File-Save passiert rihtiges Redraw!) Das Doubling-Fenster ist zu schmal fuer das Wort "doubling" Wenn zweite Partie startet, wird der Wuerfel nich neu gezeichnet, wenn zwischendurch das Feld verdeckt wird Nach einem Doulble zog der Compi bevor das Dialog-Fanster verschwunden war Zum Debugging: Alle Positionen speichern (Zugnummer im Protokollfenster) !!Copyright notiz vereinheitlichen Spielen: Wenn er rauswuerfelt, aber noch ein pin besetzt ist, sollte das rausnehmen hohe Prioritaet haben! Hat auf das Rausschlagen verzichtet, obwohl danach das Spiel sicher verloren ist. (Schwarz am rauswuerfel, Weiss weit zurueck) haette schlagen koennen, baute aber lieber Barrikade, die nie mehr benutzt werden konnte. In verlorenem Running Game wenigstens versuchen, nicht doppelt/dreifach zu verlieren. In folgender Position: turn: black dice values: 1 5 doubler value: 2 last doubler: black on bar: black: 0, white: 0 pin 1: 4 white men pin 2: 3 white men pin 20: 1 black men pin 21: 1 black men pin 23: 4 black men pin 24: 1 black men kann man die 5 von pin 21 rausziehen. danach ist aber nur der einzige Zug moeglich der eine Zugumstellung einer legalen Zugfolge ist. (Bug oder nicht Bug? Ich denke Bug.) vim:nowrap xgammon/doc/Copyright100644 764 144 1131 7013622271 13651 0ustar delleusers /* xgammon version 0.95a, a backgammon program Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de 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. 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 COPYING for more details. */ xgammon/doc/README100644 764 144 11670 7013622271 12667 0ustar delleusers xgammon.0.98.tar.gz, a prerelease backgammon program for Linux. 1. Intro, description and changes 2. How to make xgammon 2.1 Requirements 2.2 Troubles compiling xgammon ? 2.2 Troubles running xgammon ? 3. Portations 4. Bugs 5. General Happiness 1. Intro, description and changes: It is again still a prerelease. And it still has the same features: xgammon contains an X11/Xaw interface, a simple file selector and saving dialog, You can edit positions and perform rollouts. Position dump to a mail file in the format used in backgammon newsgroups. They will probably really work now. And there are new features: Easier movement of stones, by simple button clicks. You can play against an opponent on a remote X-Terminal. (experimental). See man page for detail. Additionally: The endgame database shrunk from 6.5Mb to only 3.2Mb now. An Imakefile is provided now. Thanks to thomas@ghpc8.ihf.rwth-aachen.de and Bart Skinner (bart@skinner.cs.uoregon.edu) There were a LOT of bugfixes! But, it's playing abilities didn't increase ... (Sorry.) 2. How to make xgammon First of all unpack the xgammon-0.98.tar.gz gunzip xgammon-0.98.tar.gz tar xf xgammon-0.98.tar will do. xmkmf or imake generates the Makefile. make creates xgammon, lib/db lib/xgammon.db Before you make install edit the last line of xgammon.ad file where you put the database. (Only if not in /usr/X386/lib/X11/xgammon) Then make install. There are precompiled binaries for linux in this packages, so you probably only need to install these. The default install section of the Makefile looks like this: install -c -s xgammon /usr/X386/bin install -c -m 0444 XGammon.ad /usr/X386/lib/X11/app-defaults/XGammon install -c -m 0444 lib/xgammon.db /usr/X386/lib/X11/xgammon For "private" use change them to your liking. and either: cat xgammon.ad >> ~/.Xdefaults or xrdb -load xgammon.ad or fill in a line in your ~/.Xdefaults like "include "xgammon.ad" If you have trouble compiling xgammon, there is a simple makefile.1. cp makefile.1 makefile make make database will probably do the job in most cases. 2.1 Requirements To make xgammon requires a lexer. Using flex version 2.3 or above will surely do. But any other will be also all right. You also need an Xaw library. 2.2 Troubles compiling xgammon ? 1. xgammon uses the usleep() function, which is not available on all systems. Either install gcc and libc on your system (a little afford, I know) or you may #define usleep(a) sleep (a) or some like that in xgammon.c, and set the .delaytime resource in xgammon.ad according to this definition. 2. the Xaw library is missing on some systems. You have to archie and ftp for it, no way. 3. Some verions of imake on linux don't set $(LEXLIB). Append the entry -lf to your LOCAL_LIBRARIES, or whatever library your lexer needs. 2.3 Troubles running xgammon ? 1. Sometimes xgammon comes up and at once crashes with an error message about a Bad Cursor parameter, or somthing alike. Most the times you only need to install the xgammon.ad file. (see above.) 2. Sometimes starting xgammon on two displays will not work. Make sure the other display has set xhost + and the application defaults are set properly. 3. With buttonmove true and playing on two displays, there seems to be no room for doubling, caused by some additional events. Play with buttonmove set false. 3. Portations xgammon is ported to some systems: BSD thomas@ghpc8.ihf.rwth-aachen.de AIX 3.1 It was us. SunOS 4.1 4.2 bart@skinner.cs.uoregon.edu, was the first and many others. IRIX 5.5 jay@midas.syrres.com, Paul.Emsley@chem.gla.ac.uk Thanks for your help. 4. Bugs 1. There are bugs, please report them all. If you found one, email to the authors with the closest discription possible. 2. Playing on 2 diplays will sometimes cause colors get lost. We couldn't work around this yet. Worse you may have a wrong cursor color on the other display. 3. Events on the menus aren't checked with 2 displays open. 5. General Happiness If you have any comments, suggestions or other information, please email: klasen@asterix.uni-muenster.de (Lambert Klasen) steuer@amadeus.statistik.uni-dortmund.de (Detlef Steuer) We would to very happy. We are still interested in further reports, porting this programs to other systems. Thanks in advance. Lambert Klasen Detlef Steuer klasen@asterix.uni-muenster.de (Lambert Klasen) steuer@amadeus.statistik.uni-dortmund.de (Detlef Steuer) xgammon/doc/xgammon.6100644 764 144 26275 7013622271 13553 0ustar delleusers.\" Copyright (c) 1995 Lambert Klasen Detlef Steuer .\" See section COPYING for conditions for redistribution .TH xgammon 6 "01Aug1995" "Game" "Game" .de BP .sp .ti -.2i \(** .. .SH NAME xgammon -- an X11 backgammon for linux .SH SYNOPSIS .hy 0 .na .B xgammon [\-otherdisplay ] .br [\-boardgeometry ] .br [\-boardcolor ] [\-bc ] .br [\-darkcolor ] [\-dc ] .br [\-lightcolor ] [\-lc ] .br [\-barcolor ] [\-b ] .br [\-whitecolor ] [\-blackcolor ] .br [\-doublerfont ] [\-smallFont ] .br [\-doubling +doubling] .br [\-watchmove +wachmove] .br [\-stonesteps ] .br [\-delaytime ] .br [\-buttonmove +buttonmove] .br [\-bm +bm] .br [\-autoplay +autoplay] .br [\-rollout +rollout] .br [\-nr ] .br [\-f ] .br [\-h (black|white)] .br [\-gamekind \-g (hvc|cvc|hvh)] .br [\-winat ] .br [\-? \-help] .ad b .hy 1 .SH DESCRIPTION `\|\fBxgammon\fP\|', a backgammon program for linux .SH OPTIONS \fBxgammon\fP recognizes the following options: .TP .B \fB\-otherdisplay\fP Play a game with a player on some remote X-Terminal. A second `xgammon' will be displayed there. (example: xgammon -otherdisplay somehost:0.0) .TP .B \fB\-boardgeometry\fP Defines the size of the board widget. `Geometry_string' must be an XtGeometry-string (example: 450x350). By default the relation of width/height of the board is 12/15. is rounded to this relation. .TP .B \fB\-boardcolor, \-bc\fP Sets the background color of the board. .TP .B \fB\-darkcolor, \-dc\fP Sets the color of dark points. .TP .B \fB\-lightcolor, \-lc\fP Sets the color of light points. .TP .B \fB\-barcolor, \-b\fP Sets the color of the bar and the left and right edge of the board. .TP .B \fB\-whitecolor, \-blackcolor\fP Sets the color of the stones. .TP .B \fB\-humancolor, -h\fP (black|white) Sets the color of the human player's stones. Implies a game between `xgammon' and a human being. (The default). .TP .B \fB\-doublerfont\fP , \fB\-smallFont\fP These are the fonts used for the doubler dice. Only one large and one small font can be selected now, not a font family yet. .TP .B \fB\-gamekind, \-g\fP (cvc|hvc|hvh) Sets the game. .br cvc means computer versus computer, .br hvc means human versus computer, .br hvh means human versus human, .TP .B \fB\-winat\fP Play a tournament up to points. .TP .B \fB\-watchmove, +watchmove\fP `xgammon' will "move" it's stones. .TP .B \fB\-stonesteps\fP You can speed up the stones by giving this resource a greater value. Implies watchmove is set `true'. .TP .B \fB\-delaytime\fP (tseconds) Sets a delaytime in tenth of a second, which gives you a closer look on the computer moves. Implies watchmove is set `false'. .TP .B \fB\-buttonmove \-mb, +buttonmove +bm\fP If buttonmove is true, you can set the stones simply by pressing the button. The left button sets the lower dice value, the right one the other. In case of equation both buttons can be used. .TP .B \fB\-autoplay, +autoplay\fP `Xgammon' will set your stones, if there is \fIonly\fP one possible move. .TP .B \fB\-doubling, +doubling\fP Sets the use of the doubler dice. Since the doubling of `xgammon' is still poor, you might wish to turn it off. .TP .B \fB\-rollout, +rollout\fP `Xgammon' will rollout a position. This rank is read from a file. (See -f option below.) This file is automatically generated from the current game, if not specified otherwise. .TP .B \fB\-nr\fP Sets the number of rollouts. .TP .B \fB\-f\fP Specifies the positionfile you want to use. The default is `xgammon.save'. .TP .B \fB\-database\fP Specifies the endgame database file to use. .SH HOW TO PLAY When you start the game, `\|\fBxgammon\fP\|' will immediately roll and start a game. When it's your turn: .br Move pointer to a stone. .br Press left button. .br Carry stone to the chosen point. .br Release button. .br That's it. .br To speed this a little up, try the +buttonmove option or .buttonmove resource. (See RESOURCES or OPTIONS.) .SH DOUBLING When you're allowed to double, `xgammon' draws empty dice. You can double by a single click on the doubler dice or press the `d' key. .br Some simple popups manage the rest. .br This is only possible, when the `doubling' resource is `true'. (See RESOURCES or OPTIONS.) .SH GAME OPTIONS There are three different kind of games. Human versus human, computer versus human, and computer versus computer. The last one isn't very meaningful yet, and more or less for reasons of development. .SH MENU OPTIONS .TP .B [\fBedit position\fP] If you click on this menu entry, `xgammon' will first break the current game or tournament and draw an empty board. Then you can enter a position to your liking. The right button gives you a black stone, the left button a white stone. The middle button removes a stone. If there are 15 stones of each color on the board `xgammon' will automatically ask you for the dice and doubler etc. in a popup. In case of stones already beared off, you can break the setting of stones by hitting any key. Choose `ok' button and the game continues. You can as well rollout or maildump this position. (For this purpose set the right gamekind first.) .TP .B [\fBcomputer finish\fP] If the game is almost done and you are bored with rolling it down, you can click this option and the computer will finish the game. At the end of the game the human player gets control again. .br In this mode the computer will not double. .TP .B [\fBrollout\fP] To rollout a position use this option. The number of games rolled out are set with the `numrollouts' resource or the -nr command line option. (see RESOURCES or OPTIONS.) Invoked from the game `xgammon' will fork itself and start a second, third ... process, so you can continue playing. There will be a popup to inform you about the current state and the result. This popup will vanish with any button or key event inside. The result of the rollout is additionally saved in a `xgammon.rollout..save' file. It is more appropriate to use this feature via commandline options. (See ROLLOUT below.) .TP .B [\fBmail dump\fP] Saves the current or an edited position in the format used by FIBS or in `rec.games.backgammon' newsgroup in a file named `xgammon.maildump'. .SH KEYS The board reacts on the following keys: .br `q', `c' or `d' quit the game. .br `u' undoes the current move move. .br `r' restarts the game (tournament). .br `s', `S', `l' and `L' save or load a position or game. .br You may set these keys in your .Xdefaults file. .SH TEXT WINDOWS There are two text windows in the `XGammon-Buttons' window, where the current tournament, moves, doubler actions etc. are printed. You can also add comments there. The text in the lower window will be saved if you invoke any save command. .SH EDIT A POSITION You may edit a position, and play out from there, by pressing the `edit position' menu entry in the `game' menu. Black stones are set with left mouse button, white stones with the right one. If you misplace a stone you can remove it with the middle button. There will be a popup asking for additional information, if you have entered 15 black and 15 white stones, or pressed any key to stop placing stones. .SH MAIL DUMP A POSITION Clicking the menu entry `mail dump' `xgammon' will save the current position in a file named `xgammon.maildump'. The occuring format is that used most often in `rec.games.backgammon' news group. So it should be very easy to edit a position, add some comments and then mail or post it. .SH ROLLOUTS Even if there is the menu option `rollout', this is more or less a command line option. An example would be .br `xgammon -rollout -nr 1000 -doubling -f rollout.save', .br which would rollout a 1000 times the position saved in `rollout.save'. It should be rather easy to modify the save file slightly, and make several rollouts of these positions. All results will be appended to these files. If you use the menu entry `rollout', it is most important to set an appropriate `numrollouts' resource in your `.Xdefault' file, because `xgammon' will not ask you for this value, when starting rollouts. .SH X RESOURCES .TP .B .otherdisplay: Play a game with a player on some remote X-Terminal. A second `xgammon' will be displayed there. (example: xgammon -otherdisplay somehost:0.0) .TP .B .boardColor: Specifies the background color of the board. .TP .B .lightColor: Specifies the background color of the lighter points. .TP .B .darkColor: Specifies the background color of the darker points. .TP .B .barColor: Specifies the color of the bar and the board borders. .TP .B .whiteColor: Specifies the color of the "white" stones. .TP .B .blackColor: Specifies the color of the "black" stones. .TP .B .doublerFont: , .smallFont: Defines the fonts used for doubler dice. The doubler dice size depends on the board size. If the board size is too small, the smallFont will be used. .TP .B *board.cursor: Sets the cursor to be used for the board widget(s). .TP .B .humanStones: If you want to play the white stones set this resource to "white". ("Black" is Default.) .TP .B .watchmove: If watchmove is true, you can see the stones "fly", when the computer moves. .TP .B .delaytime: Sets a delaytime in tenth of a second, which gives you a closer look on the computer moves. Implies watchmove is set `false'. .TP .B .stonesteps: You can speed up the stones by giving this resource a greater value. Implies watchmove is `true'. .TP .B .doubling: Sets the use of doubler dice. Since the doubling of the computer is still poor, you might wish to turn it off. .TP .B .buttonMove: If buttonmove is true, you can play by simply pressing a button. The left button sets the lower dice value, the right one the other. On equation both buttons can be used. .TP .B .numrollouts: Specifies the number of rollouts from a given position, before adding the result to a position file. Any unsigned integer value should be all right. .TP .B .positionfile: The file, where `xgammon' shall save and load all informations to-and-fro. .SH DIAGNOSTICS `Xgammon' uses the function usleep() for delaytime. Usleep is not defined on some systems. .br #define usleep(a) sleep(a) .br is set then. As a result, you can only delay seconds, not tseconds. .SH BUGS The program is still in state of development, so there are certainly bugs. `Xgammon' will save the current position in a `xgammon.sig_save' file on some signals. Please email this file to the authors. It may help find the bugs. If you can generate a core dump, gzip, uuencode and mail it, which would also be very helpful. .PP Otherdisplay: .br Some popup resources and actions on ".otherdisplay" sometimes get lost. .br Black can set white stones and vv. (funny feature ?) .SH AUTHORS Lambert Klasen and Detlef Steuer .br email: .br klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de xgammon/lib/db.c100644 764 144 13227 7020322354 12536 0ustar delleusers/* db.c Copyright (C) 1994,1995,1996,1997 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@gigamain.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #include #include double E_Werte[54264]; double Distribution[54264][30]; unsigned short database[54264][30]; long int NaufM[16][7]; long int Binomial[7][7]; long int Nummeroffset[7][8][16]; int pin[7] = {15, 0, 0, 0, 0, 0, 0}; long int fak(int n) { if (n < 2) return (1); else return (n * fak(n - 1)); } long int binomial(int n, int m) { return (fak(n) / fak(m) / fak(n-m)); } long int naufm(int n, int m) { if (n < m) return (0); if (m == 1) return (1); return (naufm(n - 1, m) + naufm(n - 1, m - 1)); } void set_naufm() { int i, j; for (i=1; i<16; i++) { for (j=1; j<7; j++) { NaufM[i][j] = naufm(i, j); } } } void set_binom() { int i, j; for (i = 1; i < 7; i++) { for (j = 1; j < 7; j++) { Binomial[i][j] = binomial(i, j); } } } void set_offset() { int start, next, summe, steine; int start2, summanden2; for (start = 0; start < 6; start++) { for (next = 1; start + next < 7; next++) { for (summe = 1; summe < 16; summe++) { Nummeroffset[start][next][summe] = 0; for (start2 = start; start2 < start + next; start2++) { for (steine = 1; steine < summe; steine++) { for (summanden2 = 1; summanden2 < 6 - start2 + 1; summanden2++) { Nummeroffset[start][next][summe] += Binomial[6 - start2][summanden2] * NaufM[steine][summanden2]; } } } } } } } long int rel_Stellungsnummer(int startpin) { int summe = 0; int i, nextpin; long int nummer = 0L; for (i = startpin + 1; i < 7; i++) { summe += pin[i]; } if (summe == 0) return (0); i = startpin + 1; while (pin[i] == 0 && i < 7) { i++; } nextpin = i - startpin; nummer += nextpin; nummer += Nummeroffset[startpin][nextpin][summe]; nummer += rel_Stellungsnummer(startpin + nextpin); return (nummer); } long calc(int anz, int w1, int w2, int w3, int w4) { int wurf[5] = {0, w1, w2, w3, w4}, rest[5]; double minewert = 100.0, tmpwert; int wurfend, maxpin = 0, i, feld, j, k; int start, end ; long tmpnummer, minnummer = 0L; if (pin[1] + pin[2] + pin[3] + pin[4] + pin[5] + pin[6] == 0) return (minnummer); if (anz == 0) return ((long) rel_Stellungsnummer(0)); for (i = 1; i < 7; i++) { if (pin[i] > 0) maxpin = i; } wurfend = anz; if (anz > 2) wurfend = 1; if (anz == 2) { if (wurf[1] == wurf[2]) wurfend = 1; else wurfend = 2; } for (j = 1; j < wurfend + 1; j++) { if (wurf[j] < maxpin) { start = wurf[j]; end = maxpin; } else { start = end = maxpin; } for (feld = end; feld > start - 1; feld--) { if (pin[feld] > 0) { pin[feld]--; if (feld > wurf[j]) pin[feld - wurf[j]]++; for (k = 1; k < 5; k++) { if (k < j) rest[k] = wurf[k]; if (k > j) rest[k - 1] = wurf[k]; } rest[4] = 0; tmpnummer = calc(anz - 1, rest[1], rest[2], rest[3], rest[4]); tmpwert = E_Werte[tmpnummer]; if (tmpwert < minewert) { minewert = tmpwert; minnummer = tmpnummer; } pin[feld]++; if (feld > wurf[j]) pin[feld - wurf[j]]--; } } } return (minnummer); } int set_V_Werte() { long int zugnummer = 0L, minstell, written_items; double erwartung; double aktv[30]; FILE *fid; int z1, z2, i,j, tmp, maxpin = 0; do { if (maxpin < 6) { pin[maxpin++]--; pin[maxpin]++; } else { i = 6; while (pin[i - 1] == 0) i--; tmp = pin[6]; pin[6] = 0; pin[i] = 1 + tmp; pin[i - 1]--; maxpin = i; } zugnummer++; printf(" %ld of 54263 completed\r",zugnummer); erwartung = 0.0; for (i = 0; i < 30; i++) { aktv[i] = 0.0; } for (z1 = 1; z1 < 7; z1++) { for (z2 = z1; z2 < 7; z2++) { if (z1 == z2) { minstell = calc(4, z1, z1, z1, z1); if (minstell == 0) aktv[0] += 1.0; else { for (i = 0; i < 29; i++) aktv[i + 1] += Distribution[minstell][i]; } } else { minstell = calc(2, z1, z2, 0, 0); if (minstell == 0) aktv[0] += 2.0; else { for (i = 0; i < 29; i++) { aktv[i + 1] += 2.0 * Distribution[minstell][i]; } } } } } for (i = 0; i < 29; i++) { Distribution[zugnummer][i] = aktv[i]/36.0; erwartung += Distribution[zugnummer][i] * (double) (i + 1); /*printf("%f\n", erwartung);*/ } E_Werte[zugnummer] = erwartung ; /*printf(" %.13f\n",erwartung);*/ } while (pin[6] != 15); for (i=0; i< 54263; i++) { for (j=0; j<18; j++) *(&database[1][0] + i*18 +j) = (unsigned short) (*(&Distribution[1][0]+i*30 + j) * 65535.0) ; } fid = fopen("xgammon.db", "w+b"); if (fid == NULL) {return 1;} written_items = fwrite(&database[1][0], sizeof(unsigned short), 18 * 54263, fid); if (written_items < 18*54263) {return 1;} if ( fclose(fid) == 0) {return 0;} return 1; } int main() { int success; set_binom(); set_naufm(); set_offset(); success = set_V_Werte(); if (success != 0) { printf("Creation of Bear-Off database failed!"); return 1; } return 0; } xgammon/src/Imakefile100644 764 144 2417 7020334272 13620 0ustar delleusersLOCAL_LIBRARIES = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB) $(LEXLIB) -lm XCOMM CFLAGS = -O2 -pipe OBJS = allow.o drawing.o load.o rollout.o \ decision.o edit.o misc.o save.o \ diawin.o filemenu.o popup.o xgammon.o SRCS = allow.c drawing.c load.c rollout.c \ decision.c edit.c misc.c save.c \ diawin.c filemenu.c popup.c xgammon.c ComplexProgramTarget(xgammon) InstallAppDefaults(XGammon) MakeDirectories(install, $(LIBDIR)/xgammon) InstallNonExec(lib/xgammon.db, $(LIBDIR)/xgammon) MANSUFFIX = 6 xgammon.o: xgammon.c $(CC) $(CFLAGS) -DDATABASE=\"$(LIBDIR)/xgammon/xgammon.db\" -c xgammon.c load.c: load.l $(LEX) load.l $(MV) lex.yy.c load.c ../lib/xgammon.db: @echo "compile database creating program" $(CC) lib/db.c -o lib/db @echo "done.." @echo "starting it" @echo "creating the database needed about 3 - 5 hours" @echo "on the old 386sx it had its first start :-)" @echo "I will tell you when the database is complete" cd ../lib; db; cd ../src @echo "database now complete " XGammon.ad: xgammon.ad $(LN) xgammon.ad XGammon.ad xgammon.man: xgammon.6 $(LN) xgammon.6 xgammon.man all:: lib/xgammon.db install:: lib/xgammon.db clean:: $(RM) lib/db.o lib/db xgammon/src/xgammon.ad100644 764 144 4122 7020334350 13753 0ustar delleusersxgammon*Form.background: DarkGoldenrod1 xgammon*Label.background: DarkGoldenrod1 xgammon*Label.resize: false xgammon*Command.background: DarkGoldenrod1 !xgammon*Command.background: DarkGoldenrod1 xgammon*Command.resize: false xgammon*MenuButton.background: DarkGoldenrod1 xgammon*text_display.background: AntiqueWhite xgammon*tournament_display.background: Ivory1 xgammon*tournament_display*font: 7x14 xgammon*text_display*font: 7x14 xgammon*Label.bottom: ChainTop xgammon*Label.top: ChainTop xgammon*Label.left: ChainLeft xgammon*Label.right: ChainLeft xgammon*Command.bottom: ChainTop xgammon*Command.top: ChainTop xgammon*Command.left: ChainLeft xgammon*Command.right: ChainLeft xgammon*MenuButton.bottom: ChainTop xgammon*MenuButton.top: ChainTop xgammon*MenuButton.left: ChainLeft xgammon*MenuButton.right: ChainLeft xgammon*tournament_display.top: ChainTop xgammon*tournament_display.left:ChainLeft xgammon*textdisplay.left: ChainLeft xgammon*tournament_display.width: 370 xgammon*tournament_display.height: 100 xgammon*text_display.width: 370 xgammon*text_display.height: 172 xgammon.x: 150 xgammon.y: 200 xgammon.boardGeometry: 390x312 xgammon.boardColor: tan1 xgammon.darkColor: tan3 xgammon.lightColor: tan xgammon.barColor: saddlebrown xgammon.whiteColor: white xgammon.blackColor: black xgammon*board.cursor: dot xgammon*board.Translations: #augment \n\ u: UndoMove() \n\ Ctrlc: Quit() \n\ Ctrld: Quit() \n\ Ctrlz: Quit() \n\ q: Quit() \n\ p: PipCount() \n\ Ctrlf: CompiFinish() \n\ Shiftr: Redraw() \n\ ShiftS: save(game) \n\ s: save(position) \n\ ShiftL: load(game) \n\ l: load(position) \n\ R: restart() xgammon.doublerfont: -*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-* xgammon.littlefont: -*-helvetica-medium-r-normal-*-24-*-*-*-*-*-*-* xgammon.rollout: false xgammon.numrollouts: 10 xgammon.watchmove: false xgammon.autoplay: true xgammon.buttonmove: false xgammon.stonesteps: 5 xgammon.delaytime: 5 xgammon.database: ../lib/xgammon.db xgammon/src/allow.c100644 764 144 30473 7013622221 13310 0ustar delleusers/* allow.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #include #include #include /* for the BOARD */ #include "gammon.h" /* check if a move is allowed */ int max_depth, /* max of current_depth */ current_depth = 0, /* current depth of move */ written_incomplete; /* flag if there are valid moves before there is a move with all dice used */ int done_yet; /* stones set yet */ extern int done_hit; /* stones hit (for UndoMove() only) */ MOVE current_move[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; /* global only for un_do() */ int test_move (void); int create_possible_moves (int dice_to_set, int *w, int actual_pin); int move_is_allowed (int from_pin, int to_pin); int current_in_rest (MOVE current_move[], MOVE rest_move[]); void print_possible_moves (void); extern void AppendMoveString (); extern int have_to_hit (); #define OFF_BOARD ((turn==BLACK) ? i+w[j] >= end_pin : i+w[j] <= end_pin) #define aim i+w[j] int create_possible_moves (int dice_to_set, int *w, int actual_pin) { int stop_pin, /* last pin with stones of color */ rest_dice = dice_to_set, /* are there dice to set */ rest[4], /* of dice to set */ endgame = 0, /* the game is in the endgame */ hit, /* hit some stones ? */ diffdice, /* difference of dice values */ maxpin; /* first pin with stones of color */ int i, j, k; static MOVE latest[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; /* latest move examined */ if (actual_pin == end_pin) return dice_to_set; /* all done */ maxpin = start_pin; /* lookup first stone of color */ #ifdef DEBUG_POSSIBLE_MOVES printf("max- startpin: %d\n", maxpin); #endif while (!(Pin[maxpin].count && Pin[maxpin].color == turn)) maxpin += direction; #ifdef DEBUG_POSSIBLE_MOVES printf("maxpin: %d ", maxpin); #endif if (turn == BLACK && maxpin > 18) endgame = 1; else if (turn == WHITE && maxpin < 7) endgame = 1; if (Pin[BAR].count) /* where to stop */ stop_pin = BAR + direction; else stop_pin = end_pin; /* stop_pin letzter besetzter von machen */ if (actual_pin == stop_pin) return dice_to_set; /* at the end */ current_depth ++; while (!(Pin[actual_pin].count && Pin[actual_pin].color == turn)) { actual_pin += direction; if (actual_pin == end_pin) { current_depth --; /* don't forget */ return dice_to_set; } } #ifdef DEBUG_POSSIBLE_MOVES printf("stop pin: %d\n", stop_pin); #endif diffdice = dice_to_set; if (dice_to_set > 2) diffdice = 1; if (dice_to_set == 2) { if (w[0] == w[1]) diffdice = 1; else { if ( ((turn==BLACK) ? maxpin+w[0] >= end_pin : maxpin+w[0] <= end_pin) && ((turn==BLACK) ? maxpin+w[1] >= end_pin : maxpin+w[1] <= end_pin) ) diffdice = 1; else diffdice = 2; } } for (i=actual_pin; i!=stop_pin; i+=direction) { int break_flag = 0; while (Pin[i].color != turn) { i += direction; if (i == stop_pin) { break_flag = 1; break; } } if (break_flag) break; for (j=0; j 1)) || /* no other there ? */ (OFF_BOARD && ((endgame && i == maxpin) || (endgame && aim == end_pin)))) { /* case not on board a finish? */ /* have a move */ if (!OFF_BOARD) { /* no endgame */ if (Pin[aim].color == other) { /* hit other */ hit = 1; Pin[aim].color = turn; Pin[i].count --; if (Pin[i].count == 0) Pin[i].color = 0; } else { /* no hit */ Pin[aim].count ++; Pin[aim].color = turn; Pin[i].count --; if (Pin[i].count == 0) Pin[i].color = 0; } } else { /* endgame move */ Pin[i].count--; if (Pin[i].count == 0) Pin[i].color = 0; } for (k=0; k<4; k++) { /* delete dice */ if (kj) rest[k-1] = w[k]; } rest[3] = 0; latest[to_move-dice_to_set].from = i; /* possible entry in possible_moves */ if (!OFF_BOARD) latest[to_move-dice_to_set].to = aim; else latest[to_move-dice_to_set].to = end_pin; if (dice_to_set == 1) { /* last dice set i.e. move is complete */ if (written_incomplete) { list = possible_moves; written_incomplete = 0; } for (k = 0; k < to_move; k++) { /* enter in list */ list->from = latest[k].from; list->to = latest[k].to; list++; } for (k = to_move; k < 4; k++) { /* we decided that a move has alaways 4 parts so case no pash append zeros */ list->from = 0; list->to = 0; list++; } rest_dice = 0; max_depth = to_move; } else { /* move still incomplete */ if (j==0) rest_dice = create_possible_moves (dice_to_set-1, rest, i); else { rest_dice = create_possible_moves (dice_to_set-1, rest, i+direction); } if ((current_depth-1) >= max_depth) { written_incomplete = current_depth; /* flag to delete this moves if dice can be set comlete later (try figure out why!) */ max_depth = current_depth-1; /* max number of dice set yet */ for (k=0; kfrom = latest[k].from; list->to = latest[k].to; list ++; } for (k=current_depth; k<4; k++) { list->from = 0; list->to = 0; list ++; } } } /* end incomplete move */ Pin[i].count++; /* restore the board */ if (Pin[i].count == 1) Pin[i].color = turn; if (!OFF_BOARD) { if (hit) { Pin[aim].color = other; } else { Pin[aim].count--; if (Pin[aim].count == 0) Pin[aim].color = 0; } } } /* have found a movable stone */ } /* for all dice */ } /* for the board */ current_depth--; return rest_dice; } int test_move (void) { int move_depth; int possible_move_count; int k; max_depth = 0; current_depth = 0; written_incomplete = 0; list = possible_moves; move_depth = create_possible_moves (to_move, roll, start_pin); #ifdef WHATS_MAX_NUMBER { static int maxnumber=0; FILE *fid; if ((list-possible_moves)/4 > maxnumber) { maxnumber = (list-possible_moves)/4; fid = fopen("maxpos.xgammon", "a"); fprintf(fid," %d \n",maxnumber); fclose(fid); } } #endif #ifdef DEBUG_POSSIBLE_MOVES printf("maxdepth: %d\n", max_depth); printf("movedepth: %d\n", move_depth); print_possible_moves (); #endif /* check how many dice can be used this value should be returned by create_possible_moves() but doesn't */ for (k=0; k<4; k ++) { if (!(possible_moves+k)->from && !(possible_moves+k)->to ) break; } if (k < to_move) { to_move = k; if (k == 0) roll[0] = 0; /* global move done */ } #ifdef DEBUG_TM fprintf (stderr, "to_move %d\n", to_move); #endif /* check for use of greater dice value */ if (to_move == 1 && !pash) { int bigger_value = (abs(roll[0]) > abs(roll[1])) ? roll[0] : roll[1]; int have_bigger = 0; MOVE *m, *e = possible_moves; for (m=possible_moves; m!=list; m+=4) { if (m->to - m->from == bigger_value) { have_bigger = 1; break; } } if (have_bigger) { for (m=possible_moves; m!=list; m+=4) { if (m->to - m->from == bigger_value) { e->from = m->from; e->to = m->to; e += 4; } } list = e; } } possible_move_count = (list - possible_moves) / 4; return possible_move_count; } void print_possible_moves(void) { int k; MOVE *d; for (d = possible_moves; d!=list; d ++) { for (k = 0; k < 4; k++) printf ("%2d -> %2d ", d->from, d->to); printf ("\n"); } printf ("count = %d\n", (list - possible_moves) / 4); } int current_in_rest (MOVE current_move[], MOVE rest_move[]) { int i, j, possible = 1; for (i=0; ifrom == from_pin && (m+k)->to == to_pin) { for (j=0;jfrom; current_move[done_yet].to = (m+k)->to; done_yet++; } break; } } m += 4; } if (!allow) { m = possible_moves; while (!allow && m!= list) { /* test compound move */ from = from_pin; for (k=0; kfrom == from) { rest_move[k].from = rest_move[k].to = 0; if ((m+k)->to == to_pin) { allow = 1; } else from = (m+k)->to; } else { rest_move[k].from = (m+k)->from; rest_move[k].to = (m+k)->to; } } /* at this point it is clear, that the move is allowed and there is anything left over to move */ if (allow) { allow = current_in_rest(current_move,rest_move); } /* if current_in_rest() returns true, there is a possibible_move containing the already moved stones and the current move, so we can break the while loop */ if (!allow) m+=4; } /* while !allow && list */ if (allow ) { if (have_to_hit (from_pin, to_pin)) return 0; /* have a compound move and on between to hit a stone */ from = from_pin; for (k=0;kfrom == from) { current_move[done_yet].from = (m+k)->from; current_move[done_yet].to = (m+k)->to; done_yet++; if ((m+k)->to == to_pin) { break; } else from = (m+k)->to; } } } } /* test compound move */ if (allow) { if (done_yet == to_move) { AppendMoveString (current_move); for (i = 0; i < 4; i++) { current_move[i].from = 0; current_move[i].to = 0; } done_yet = 0; done_hit = 0; roll[0] = 0; /* reckon global */ return 1; } } else { /* !allow */ done_yet = old_done_yet; } return allow; } xgammon/src/decision.c100644 764 144 41015 7013622221 13761 0ustar delleusers/* $Id: decision.c,v 1.2 1999/10/08 20:09:59 delle Exp delle $ */ /* decision.c Copyright (C) 1994, 1999 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de Detlef.Steuer@gmx.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #include #include #include /* for the BOARD */ #include "gammon.h" extern MOVE *find_best_move (); extern long int PositionNumber (int STARTPIN, int color); int is_run (); float calculate_winning_percentage (int kind); float calculate_expected_time (); float evaluate (); void simple_pipcount (float *pc); void adjust_pipcount (float *pc); void sub_lossage_when_hit (float *pc); void Analyse_Doublet (int pin, int *set); void Analyse_No_Doublet (int pin, int *set); int Bar[3] = { 0, 0, 25 }; int Direction[3] = { 0, 1, -1 }; int Startpin[3] = { 0, 1, 24 }; int number_of_homepins[3] = { 0, 0, 0 }; int Endpin[3] = { 0, 24, 1 }; float Probtable[25]; float point_values[25] = { /* Wertetabelle fuer die 24 pins*/ 0.0, /* 0 is dummy */ 0.0, 1.0, 3.0, 8.0, 10.0, 10.0, 7.0, 6.0, 5.0, 4.0, 4.0, 6.0, /* 1 - 12 */ 6.0, 4.0, 4.0, 5.0, 6.0, 7.0, 10.0, 10.0, 8.0, 3.0, 1.0, 0.0 /* 13 - 25 */ }; /* Diese Tabelle enthaelt die exakten erwarteten Wartezeiten -1 bis ein Stein wieder eingewuerfelt ist */ float expected_waitingtime[7] = { 0.0, 1.0 / 35.0, 1.0 / 8.0, 1.0 / 3.0, 4.0 / 5.0, 25.0 / 11.0, 0.0 }; float prime_length_factor[8] = { 0.0, 1.0, 1.0, 1.2, 1.4, 1.7, 2.0, 2.0 }; void adjust_pipcount (float *pc) { int i; /* bestimmung der bestzten felder im Homefeld */ number_of_homepins[BLACK] = number_of_homepins[WHITE] = 0; for (i = 1; i < 7; i++) { if (Pin[ i].color == WHITE && Pin[ i].count>1) number_of_homepins[WHITE]++; if (Pin[25-i].color == BLACK && Pin[25-i].count>1) number_of_homepins[BLACK]++; } /* Verfeinerter pip_count (Steine auf bar als 25+x) Es wird die vereinfachung gemacht, das es n-mal solange dauert n Steine wieder hineinzuwuerfeln wie einen Stein hineinzuwuerfeln */ if (Pin[0].count) { if (number_of_homepins[WHITE] < 6) pc[BLACK] -= Pin[0].count * 8.1667 * expected_waitingtime[number_of_homepins[WHITE]]; else { for (i=6; i<26; i++) { if (Pin[i].color == WHITE) pc[WHITE] += Pin[i].count * (i - 5); } pc[BLACK] -= Pin[0].count * 8.1667 * expected_waitingtime[5]; } } if (Pin[25].count) { if (number_of_homepins[BLACK] < 6) pc[WHITE] -= Pin[25].count * 8.1667 * expected_waitingtime[number_of_homepins[BLACK]]; else { for (i=0; i<20; i++) { if (Pin[i].color == BLACK) pc[BLACK] += Pin[i].count * (20 - i); } pc[WHITE] -= Pin[25].count * 8.1667 * expected_waitingtime[5]; } } #ifdef DEBUG_EVALUATE printf("Verfeinerter Pipcount %f %f \n", pc[BLACK], pc[WHITE]); #endif } void add_prime_values(float *pc) { int i; for (i = 1; i < 25; i++) { if (Pin[i].color == BLACK && Pin[i].count > 1) { float zwischensumme = point_values[i]; int prime_length = 1; while (((i + 1) < 25 && Pin[i + 1].color == BLACK && Pin[i + 1].count > 1)) { i++; prime_length++; zwischensumme += point_values[i]; } zwischensumme *= prime_length_factor[prime_length]; pc[BLACK] += zwischensumme; } } for (i = 1; i < 25; i++) { if (Pin[i].color == WHITE && Pin[i].count > 1) { float zwischensumme = point_values[i]; int prime_length = 1; while (((i + 1) < 25 && Pin[i + 1].color == WHITE && Pin[i + 1].count > 1)) { i++; prime_length++; zwischensumme += point_values[i]; } zwischensumme *= prime_length_factor[prime_length]; pc[WHITE] += zwischensumme; } } } /* Diese Funktion soll eine Abschaetzung der Gewinnwahrscheinlichkeit fuer turn liefern. Im Endspiel wird diese exakt berechnet, sofern die Datenbank vorhanden ist */ float evaluate(int turn) { float pipcount[3] = {0.0, 0.0, 0.0}; int Runninggame = 1; float value = 0.0; Runninggame = is_run(); if(!endgame_database) Runninggame=0; /* Falls database nicht existiert*/ if (!Runninggame) { /* zunaechst ein grober pipcount*/ simple_pipcount(pipcount); #ifdef DEBUG_EVALUATE printf("Einfacher Pipcount %f %f \n", pipcount[BLACK], pipcount[WHITE]); #endif pipcount[other] += 8.1666 /* Anpassung an turn */; adjust_pipcount (pipcount) /* anpassen an BAR Besetzung*/; add_prime_values (pipcount) /* addieren der point_values */; /*sub_lossage_when_hit (pipcount); */ /* eventuelles geschlagenwerden */ #ifdef DEBUG_EVALUATE printf("Pipcount mit point_values %f %f \n", pipcount[BLACK], pipcount[WHITE]); #endif } else { /* Runninggame */ value = calculate_winning_percentage(ANSWER); /* die naechsten Zeilen garantieren, dass nur ins runninggame gewechselt wird wenn echt siegchance bestehen */ if (value >= 0.99) { value = calculate_expected_time(); return (1000.0 - value); } if (value >= 0.4 && value < 0.99) return ( 980.0 + value); if (value > 0.01) return (-899.0 + value); value = calculate_expected_time(); /* im Falle _sehr_ geringer Chancen wird als zweitbewertung der Erwartungswert herangezogen (hauptsaechlich Optik) */ return (-900.0 - value); } #ifdef DEBUG_EVALUATE printf("Wert der Position: %f \n", pipcount[turn] - pipcount[other]); #endif return (pipcount[turn] - pipcount[other]); } void sub_lossage_when_hit(float *pc) { int diceset[4]; int w1, w2, i, j; float lossage; for (i=0; i<25; i++) Probtable[i] = 0.0; for (i=0; i< 4; i++) diceset[i] = 0; /* first the non-doublets */ for (w1= 1; w1<6; w1++) { for (w2=w1+1; w2<7; w2++) { diceset[0] = w1; diceset[1] = w2; diceset[2] = w1; diceset[3] = 0; if (Pin[Bar[other]].count) { /* The enemies bar ist occupied */ if (Pin[Bar[other]].count > 1) diceset[2] = 0; Analyse_No_Doublet (Bar[other], diceset); if (Pin[Bar[other]].count> 1) diceset[0] = 0; else { int tp1, tp2, ways = 0, wp = 0; tp1 = Bar[other] + diceset[0] * Direction[other]; tp2 = Bar[other] + diceset[1] * Direction[other]; if (Pin[tp1].count < 2 || Pin[tp1].color == other) { ways++; wp = tp2; } if (Pin[tp2].count < 2 || Pin[tp2].color == other) { ways++; wp = tp1; } if (ways == 0) diceset[0] = 0; if (ways == 1) diceset[0] = wp; diceset[1] = 0; if (ways == 2) diceset[2] = 0; } } /* Bar analyse zuende */ for (i=Startpin[other]; i!=Endpin[other]; i+=Direction[other]) { if (Pin[i].color == other) Analyse_No_Doublet(i, diceset); } } } /* the doublets */ for (w1 = 1; w1 < 7; w1++) { diceset[0] = w1; diceset[1] = w1; diceset[2] = w1; diceset[3] = w1; if (Pin[Bar[other]].count) { /* The enemies bar ist occupied */ int tp; if (Pin[Bar[other]].count > 1) diceset[3] = 0; if (Pin[Bar[other]].count > 2) diceset[2] = 0; if (Pin[Bar[other]].count > 3) diceset[1] = 0; Analyse_Doublet(Bar[other], diceset); tp = Bar[other] + diceset[0] * Direction[other]; if (Pin[tp].color == turn && Pin[tp].count > 1) diceset[0] = 0; else { if (Pin[Bar[other]].count > 1) diceset[2] = 0; if (Pin[Bar[other]].count > 2) diceset[1] = 0; if (Pin[Bar[other]].count > 3) diceset[0] = 0; } } /* Bar analyse zuende */ for (i = Startpin[other]; i != Endpin[other]; i += Direction[other]) { if (Pin[i].color == other) Analyse_Doublet(i, diceset); } } /* Probability table is completly setup */ for (i = Startpin[turn]; i != Bar[other]; i += Direction[turn]) { if (Pin[i].count == 1 && Pin[i].color == turn && Probtable[i]) { lossage = 0.0; lossage += (i - Bar[turn]) * Direction[turn]; if (number_of_homepins[other] < 6) lossage += 8.16667 * expected_waitingtime[number_of_homepins[other]]; else { if (Pin[Bar[turn]].count) lossage += 8.16667 * expected_waitingtime[5]; else { for (j = Bar[other]; j != Bar[other] + 20 * Direction[other]; j += Direction[other]) { if (Pin[j].color == other) { lossage += Pin[j].count * (Bar[other] + 20 * Direction[other] - j) * Direction[other]; } } lossage += 8.1667 * expected_waitingtime[5]; } } #ifdef DEBUG_PROB printf("Blot auf %d, Wkeit = %f, Wert = %f \n", i, Probtable[i], lossage); #endif pc[turn] -= lossage * Probtable[i]; } } } void Analyse_Doublet(int pin, int *set) { int j; j = pin + set[0] * Direction[other]; if (j > 0 && j < 25) { Probtable[j] += 1.0 / 36.0; if (set[1] && (Pin[j].count < 2 || Pin[j].color == other)) { j += set[1] * Direction[other]; if (j > 0 && j < 25) { Probtable[j] += 1.0 / 36.0; if (set[2] && (Pin[j].count < 2 || Pin[j].color == other)) { j += set[2] * Direction[other]; if (j > 0 && j < 25) { Probtable[j] += 1.0 / 36.0; if (set[3] && (Pin[j].count < 2 || Pin[j].color == other)) { j += set[3] * Direction[other]; if (j > 0 && j < 25) Probtable[j] += 1.0 / 36.0; } } } } } } } void Analyse_No_Doublet(int pin, int *set) { int j, alset = 0; j = pin + set[0] * Direction[other]; if (j > 0 && j < 25) { Probtable[j] += 1.0 / 18.0; if (set[2] && (Pin[j].count < 2 || Pin[j].color == other)) { j = j + set[1] * Direction[other]; if (j > 0 && j < 25) { Probtable[j] += 1.0 / 18.0; alset = 1; } } j = pin + set[1] * Direction[other]; if (j > 0 && j < 25) { Probtable[j] += 1.0 / 18.0; if (set[2] && (Pin[j].count < 2 || Pin[j].color == other) && !alset) { j = j + set[0] * Direction[other]; if (j > 0 && j < 25) Probtable[j] += 1.0 / 18.0; } } } } int is_run() { int i, smallest_white = 0, smallest_black = 26; for (i = 0; i < 26; i++) { if (Pin[i].color == BLACK) { smallest_black = i; break; } } for (i = 25; i > -1; i--) { if (Pin[i].color == WHITE) { smallest_white = i; break; } } if (smallest_black < smallest_white) return (0); else return (1); } /* simple_pipcount: returns the simple pipcount for color not concerning turn, no special treatment of bar pc must be array[3] */ void simple_pipcount(float *pc) { int i, count[3] = { 0, 0, 0 }; for (i = 0; i < 26; i++) { if (Pin[i].color == BLACK) count[BLACK] -= Pin[i].count * (25 - i); if (Pin[i].color == WHITE) count[WHITE] -= Pin[i].count * i; } pc[BLACK] = (float) count[BLACK]; pc[WHITE] = (float) count[WHITE]; } int do_double (int kind) { float pipcount[3] = { 0.0, 0.0, 0.0 }; int Runninggame = 1; float chance; Runninggame = is_run(); if (!endgame_database) Runninggame = 0; /* Falls keine Datenbank existiert spielt er zumindest */ if (!Runninggame) { /* zunaechst ein grober pipcount*/ simple_pipcount(pipcount); /* Anpassung nach BAR*/ adjust_pipcount(pipcount); /* Anpassung entsprechend turn */ if (kind == ANSWER) pipcount[turn] += 8.1666; else pipcount[other] += 8.1666; if (pipcount[BLACK] > 0.0) pipcount[BLACK] = -0.5; if (pipcount[WHITE] > 0.0) pipcount[WHITE] = -0.5; if (kind == ANSWER) { chance = pipcount[turn] / pipcount[other]; #ifdef DEBUG_EVALUATE printf("Doubler: chance = %f kind = %d turn =%d \n", chance, kind, turn); #endif if (chance > 0.75) return 1; else return 0; } else { chance = pipcount[other] / pipcount[turn]; #ifdef DEBUG_EVALUATE printf("Doubler: chance = %f kind = %d turn =%d \n", chance, kind, turn); #endif if (chance >= 1.16) return 1; else return 0; } } else { chance = calculate_winning_percentage(kind); #ifdef DEBUG_EVALUATE printf("Doubler: chance = %f kind = %d turn =%d \n", chance, kind, turn); #endif if (kind == ANSWER) { if (chance >= 0.25) return 1; else return 0; } else { if (chance >= 0.65) return 1; else return 0; } } } float calc_endgame_offset(int color) { int i; float offset = 0.0; if (color == BLACK) { for (i = 1; i < 19; i++) if (Pin[i].color == BLACK) { offset += (19 - i) * Pin[i].count; /* Dies ist der reine Offset */ if (i < 7) offset += 4.0833333 * Pin[i].count; /* Extra punkte fuer crossovers */ if (i < 13) offset += 4.0833333 * Pin[i].count; offset += 4.0833333 * Pin[i].count; } } else { for (i = 24; i > 6; i--) if (Pin[i].color == WHITE) { offset += (i - 6) * Pin[i].count; if (i > 18) offset += 4.0833333 * Pin[i].count; if (i > 12) offset += 4.0833333 * Pin[i].count; offset += 4.0833333 * Pin[i].count; } } if (color == turn) offset += (19 + 16.3333333) * Pin[BAR].count; else offset += (19 + 16.3333333) * Pin[OTHER_BAR].count; #ifdef DEBUG_EVALUATE printf(" Offset = %f fuer Farbe %d \n", offset, color); #endif return (offset); } float calculate_expected_time() { float distribution[31]; unsigned short readarray[31]; float offset, e_value = 0.0; int nummer, i; nummer = PositionNumber(0, turn); if (nummer == 0L) return (0.0); fseek(endgame_database, (nummer - 1) * 60, 0); fread( readarray, 2, 30, endgame_database); for (i=0;i<30;i++) distribution[i]= ((float) readarray[i])/65535.0; offset = calc_endgame_offset(turn) / 8.16667; for (i = 0; i < 30; i++) e_value += ((float) i + 1.0 + offset) * distribution[i]; #ifdef DEBUG_EVALUATE printf(" EWert = %f \n", e_value); #endif return (e_value); } float calculate_winning_percentage(int kind) { float t_array[19], other_array[19], temp[19],sum; float turn_offset, other_offset, chance = 0, rest_prob; unsigned short readarray[19]; int t_off, o_off; int nummer, i, j; /* zunaechst fuer den turn einlesen */ nummer = PositionNumber (0, turn); if (nummer == 0L) return (1.0); fseek (endgame_database, (nummer - 1) * 36, 0); fread (readarray, 2, 18, endgame_database); sum=0.0; for (i=0; i<18; i++) { t_array[i] = ((float) readarray[i])/65535.0; sum+=t_array[i]; } for (i=0; i<=18;i++) t_array[i]/=sum; /* dann fuer den gegner */ nummer = PositionNumber(0, other); fseek (endgame_database, (nummer - 1) * 36, 0); fread (readarray, 2, 18, endgame_database); sum=0.0; for (i=0; i<18; i++) { other_array[i] = ((float) readarray[i])/65535.0; sum+=other_array[i]; } for (i=0; i<=18;i++) other_array[i]/=sum; t_array[18] = 0.0; other_array[18] = 0.0; /* Abstand zum Endgame mit einbeziehen */ turn_offset = calc_endgame_offset (turn) / 8.16667; other_offset = calc_endgame_offset (other) / 8.16667; /* Danach werden die Verteilungsfunktionen entsprechend dem offset transformiert */ if (turn_offset) { for (i = 0; i < 19; i++) temp[i] = 0; for (i = 0; i < 18; i++) { temp[i ] += (ceil(turn_offset) - turn_offset) * t_array[i]; temp[i+1] += (turn_offset - floor(turn_offset)) * t_array[i]; } for (i = 0; i < 19; i++) t_array[i] = temp[i]; } if (other_offset) { for (i = 0; i < 19; i++) temp[i] = 0; for (i = 0; i < 18; i++) { temp[i ] += (ceil(other_offset) - other_offset) * other_array[i]; temp[i+1] += (other_offset - floor(other_offset)) * other_array[i]; } for (i = 0; i < 19; i++) other_array[i] = temp[i]; } t_off = (int) floor(turn_offset); o_off = (int) floor(other_offset); if (kind == ANSWER) { /* diese frage soll herausfinden ob der andere am zug ist oder nicht Tut sie das? */ if ((turn == Player[0].color && Player[0].type == HUMAN) || (turn == Player[1].color && Player[1].type == HUMAN)) { for (i = 0; i < 19; i++) { rest_prob = 0.0; j = 0; while (j+o_off < i+t_off && j<31) j++; while (j < 19) { rest_prob += other_array[j]; j++; } chance += t_array[i] * rest_prob; } chance = 1 - chance; } else { for (i = 0; i < 19; i++) { rest_prob = 0.0; j = 0; while (j + t_off < i + o_off && j < 19) j++; while (j < 19) { rest_prob += t_array[j]; j++; } chance += rest_prob * other_array[i]; } chance = 1 - chance; } } else { for (i = 0; i < 19; i++) { rest_prob = 0.0; j = 0; while (j + o_off < i + t_off && j < 19) j++; while (j < 19) { rest_prob += other_array[j]; j++; } chance += t_array[i] * rest_prob; } } #ifdef DEBUG_EVALUATE printf(" Gewinnwahrscheinlichkeit fuer den Compi %f \n", chance); #endif return (chance); } xgammon/src/diawin.c100644 764 144 16024 7013622221 13441 0ustar delleusers/* diawin.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. The idea of this textwidget and the functions CreateDialogWindow(), AppendDialogText() and TextGetLastPos() are lifted from xxgdb and adopted for xgammon. * xdbx - X Window System interface to the dbx debugger * * Copyright 1989 The University of Texas at Austin * Copyright 1990 Microelectronics and Computer Technology Corporation * Copyright 1990 Thomson Consumer Electronics, Inc. */ #include #include #include #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" extern Widget form; extern FILE* protokol_file; void CreateDialogWindow (); void CreateRolloutText (); void AppendDialogText (); void Dispatch (); static XawTextPosition TextGetLastPos (); static XawTextPosition InputPos, lt; /* starting position of input text */ void print_dialog_text (); #define LINESIZ 512 /* input line length */ #define DIALOGSIZE 30000 /* max size of dialogue window buffer */ char add_text[LINESIZ]; /* global text buffer for strings from somewhere to add */ char DialogText[DIALOGSIZE]; /* text buffer for widget */ char TournamentText[DIALOGSIZE]; /* text buffer for widget */ Widget text_display, tournament_display; void CreateDialogWindow (X11SET *X11Set) { Arg args[7]; Cardinal n; n = 0; XtSetArg (args[n], XtNuseStringInPlace, True); n++; XtSetArg (args[n], XtNstring, (XtArgVal) DialogText); n++; XtSetArg (args[n], XtNlength, (XtArgVal) DIALOGSIZE); n++; XtSetArg (args[n], XtNeditType, (XtArgVal) XawtextAppend); n++; XtSetArg (args[n], XtNwrap, XawtextWrapWord); n++; XtSetArg (args[n], XtNfromVert, X11Set->tournament_display); n++; X11Set->text_display = XtCreateManagedWidget ("text_display", asciiTextWidgetClass, X11Set->form, args, n); } void CreateTournamentWindow (X11SET *X11Set) { Arg args[6]; Cardinal n; static XtActionsRec dialog_actions[] = { { "Dispatch", (XtActionProc) Dispatch}, { NULL, NULL} }; static String translations = "#override\n\ Return: newline() Dispatch()\n\ "; n = 0; XtSetArg (args[n], XtNuseStringInPlace, True); n++; XtSetArg (args[n], XtNstring, (XtArgVal) TournamentText); n++; XtSetArg (args[n], XtNlength, (XtArgVal) DIALOGSIZE); n++; XtSetArg (args[n], XtNeditType, (XtArgVal) XawtextAppend); n++; XtSetArg (args[n], XtNwrap, XawtextWrapWord); n++; XtSetArg (args[n], XtNfromVert, X11Set->quit); n++; X11Set->tournament_display = XtCreateManagedWidget ("tournament_display", asciiTextWidgetClass, X11Set->form, args, n ); XtOverrideTranslations (X11Set->tournament_display, XtParseTranslationTable (translations)); XtAppAddActions (app_con, dialog_actions, XtNumber(dialog_actions)); } void CreateRolloutText (Widget parent) { Arg args[6]; Cardinal n; n = 0; XtSetArg (args[n], XtNuseStringInPlace, True); n++; XtSetArg (args[n], XtNstring, (XtArgVal) DialogText); n++; XtSetArg (args[n], XtNlength, (XtArgVal) DIALOGSIZE); n++; XtSetArg (args[n], XtNeditType, (XtArgVal) XawtextAppend); n++; XtSetArg (args[n], XtNwrap, XawtextWrapWord); n++; Player[0].X11Set.text_display = XtCreateManagedWidget ("text_display", asciiTextWidgetClass, parent, args, n); } void AppendDialogText (int where, char *s) { XawTextPosition i, lastPos; XawTextBlock textblock, nullblock; TextWidget ctx; Widget w; if (where == UPPER) { ctx = (TextWidget) Player[0].X11Set.tournament_display; w = Player[0].X11Set.tournament_display; } else if (where == LOWER) { ctx = (TextWidget) Player[0].X11Set.text_display; w = Player[0].X11Set.text_display; } else { fprintf (stderr, "unkown widget for AppendDialogText ()\n"); return; } if (!s || !strcmp(s, "")) return; textblock.firstPos = 0; textblock.length = strlen(s); textblock.ptr = s; lastPos = TextGetLastPos (ctx); if (textblock.length > DIALOGSIZE) { fprintf (stderr, "xgammon error: cannot display string in dialogue window\n\ string has %d bytes; dialogue window size limit is %d bytes\n", textblock.length, DIALOGSIZE); return; } if (lastPos + textblock.length > DIALOGSIZE) { nullblock.firstPos = 0; nullblock.length = 0; nullblock.ptr = ""; i = textblock.length - (DIALOGSIZE - lastPos); if (i < 0.9*DIALOGSIZE) i += 0.1*DIALOGSIZE; while (DialogText[i] != '\n') i++; XawTextReplace (w, 0, i+1, &nullblock); lastPos = TextGetLastPos (ctx); } XawTextReplace (w, lastPos, lastPos, &textblock); InputPos = TextGetLastPos (ctx); if (where == UPPER) lt = InputPos; XawTextSetInsertionPoint (w, InputPos); if (gammon_resource.protokol) fprintf(protokol_file, "%s", s); if (gammon_resource.other_display) { if (where == UPPER) { ctx = (TextWidget) Player[1].X11Set.tournament_display; w = Player[1].X11Set.tournament_display; } else if (where == LOWER) { ctx = (TextWidget) Player[1].X11Set.text_display; w = Player[1].X11Set.text_display; } else { fprintf (stderr, "unkown widget for AppendDialogText ()\n"); return; } if (!s || !strcmp(s, "")) return; textblock.firstPos = 0; textblock.length = strlen(s); textblock.ptr = s; lastPos = TextGetLastPos (ctx); if (textblock.length > DIALOGSIZE) { fprintf (stderr, "xgammon error: cannot display string in dialogue window\n\ string has %d bytes; dialogue window size limit is %d bytes\n", textblock.length, DIALOGSIZE); return; } if (lastPos + textblock.length > DIALOGSIZE) { nullblock.firstPos = 0; nullblock.length = 0; nullblock.ptr = ""; i = textblock.length - (DIALOGSIZE - lastPos); if (i < 0.9*DIALOGSIZE) i += 0.1*DIALOGSIZE; while (DialogText[i] != '\n') i++; XawTextReplace (w, 0, i+1, &nullblock); lastPos = TextGetLastPos (ctx); } XawTextReplace (w, lastPos, lastPos, &textblock); InputPos = TextGetLastPos (ctx); if (where == UPPER) lt = InputPos; XawTextSetInsertionPoint (w, InputPos); } } XawTextPosition TextGetLastPos (Widget w) { TextWidget ctx = (TextWidget) w; return (ctx->text.lastPos); } void Dispatch (Widget w, XEvent *event, String *params, Cardinal *num_params) { char s[LINESIZ]; strcpy (s, TournamentText + lt); lt = TextGetLastPos (w); InputPos = TextGetLastPos (w); } void print_dialog_text (FILE *f) { fprintf (f, "%s\n", DialogText); } xgammon/src/drawing.c100644 764 144 126646 7013622221 13655 0ustar delleusers/* drawing.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" XPoint PinToPosition (int pin); void DrawEmptyBoard (); void DrawBoard (); void DrawDice (); void DeleteDice (); void DrawEmptyDice (); void DrawDiceValues (); void DrawDoubler (); void PutStone (unsigned int color, unsigned int pin); void DrawStone (); void RemoveStone (); void RedrawAllStones (); void FreePixmaps (); void CreatePixmaps (); static void draw_one (); static void draw_two (); static void draw_three (); static void draw_four (); static void draw_five (); static void draw_six (); int rect_width, rect_height; static int dice_x = 0, dice_y = 0; void DrawBoard (void) { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; Window window = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.board.gc; XCopyArea (dpy, pixmap, window, gc, 0, 0, width, height, 0, 0); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; window = Player[1].X11Set.board.window; gc = Player[1].X11Set.board.gc; XCopyArea (dpy, pixmap, window, gc, 0, 0, width, height, 0, 0); } } void DrawEmptyBoard (void) { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; GC board_gc = Player[0].X11Set.board.gc; GC gc = Player[0].X11Set.gc; XPoint c[3]; int i; int s = 0; static int here = 0; rect_width = stone_width; rect_height = stone_width * 5; XSetForeground (dpy, board_gc, gammon_resource.board_Pixel); XFillRectangle (dpy, pixmap, board_gc, 0, 0, width, height); XSetForeground (dpy, board_gc, gammon_resource.bar_Pixel); XFillRectangle (dpy, pixmap, board_gc, 0, 0, rect_width, height); XFillRectangle (dpy, pixmap, board_gc, rect_width * 7, 0, rect_width, height); XFillRectangle (dpy, pixmap, board_gc, width - rect_width, 0, rect_width, height); for (i=1; i<13; i++) { /* first draw a filled triangle */ c[0].x = i * rect_width; if (i>6) c[0].x += rect_width; c[0].y = 0; c[1].x = c[0].x + rect_width; c[1].y = 0; c[2].x = c[0].x + rect_width/2; c[2].y = rect_height; if (s) XSetForeground (dpy, board_gc, gammon_resource.light_Pixel); else XSetForeground (dpy, board_gc, gammon_resource.dark_Pixel); XFillPolygon (dpy, pixmap, board_gc, c, 3, Convex, CoordModeOrigin); /* then a little black border around it */ /* base */ XDrawLine (dpy, pixmap, gc, c[0].x, c[0].y, c[0].x, c[1].y); /* left side */ c[1].y = rect_height; c[1].x -= rect_width/2; XDrawLine (dpy, pixmap, gc, c[0].x, c[0].y, c[1].x, c[1].y); /* right side */ XDrawLine (dpy, pixmap, gc, c[0].x + rect_width, c[0].y, c[1].x, c[1].y); if (s==0) s=1; else s=0; } for(i=1; i<13; i++) { /* draw a triangle */ c[0].x = i * rect_width; if (i > 6) c[0].x += rect_width; c[0].y = height - 1; c[1].x = c[0].x + rect_width; c[1].y = height - 1; c[2].x = c[0].x + rect_width/2; c[2].y = height - rect_height; /* make the opposing colors different, so !s */ if (!s) XSetForeground (dpy, board_gc, gammon_resource.light_Pixel); else XSetForeground (dpy, board_gc, gammon_resource.dark_Pixel); XFillPolygon (dpy, pixmap, board_gc, c, 3, Convex, CoordModeOrigin); /* and around it a little black border */ c[0].x = i * rect_width; if (i > 6) c[0].x += rect_width; c[1].x = c[0].x + rect_width; c[0].y = c[1].y = height - 1; XDrawLine (dpy, pixmap, gc, c[0].x, c[0].y, c[0].x, c[1].y); c[1].y = height - rect_height; c[1].x -= rect_width/2; XDrawLine (dpy, pixmap, gc, c[0].x, c[0].y, c[1].x, c[1].y); XDrawLine (dpy, pixmap, gc, c[0].x + rect_width, c[0].y, c[1].x, c[1].y); if (s==0) s=1; else s=0; } if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; board_gc = Player[1].X11Set.board.gc; gc = Player[1].X11Set.gc; s = 0; rect_width = stone_width; rect_height = stone_width * 5; XSetForeground (dpy, board_gc, gammon_resource.board_Pixel); XFillRectangle (dpy, pixmap, board_gc, 0, 0, width, height); XSetForeground (dpy, board_gc, gammon_resource.bar_Pixel); XFillRectangle (dpy, pixmap, board_gc, 0, 0, rect_width, height); XFillRectangle (dpy, pixmap, board_gc, rect_width * 7, 0, rect_width, height); XFillRectangle (dpy, pixmap, board_gc, width - rect_width, 0, rect_width, height); for (i=1; i<13; i++) { /* first draw a filled triangle */ c[0].x = i * rect_width; if (i>6) c[0].x += rect_width; c[0].y = 0; c[1].x = c[0].x + rect_width; c[1].y = 0; c[2].x = c[0].x + rect_width/2; c[2].y = rect_height; if (s) XSetForeground (dpy, board_gc, gammon_resource.light_Pixel); else XSetForeground (dpy, board_gc, gammon_resource.dark_Pixel); XFillPolygon (dpy, pixmap, board_gc, c, 3, Convex, CoordModeOrigin); /* then a little black border around it */ /* base */ XDrawLine (dpy, pixmap, gc, c[0].x, c[0].y, c[0].x, c[1].y); /* left side */ c[1].y = rect_height; c[1].x -= rect_width/2; XDrawLine (dpy, pixmap, gc, c[0].x, c[0].y, c[1].x, c[1].y); /* right side */ XDrawLine (dpy, pixmap, gc, c[0].x + rect_width, c[0].y, c[1].x, c[1].y); if (s==0) s=1; else s=0; } for(i=1; i<13; i++) { /* draw a triangle */ c[0].x = i * rect_width; if (i > 6) c[0].x += rect_width; c[0].y = height - 1; c[1].x = c[0].x + rect_width; c[1].y = height - 1; c[2].x = c[0].x + rect_width/2; c[2].y = height - rect_height; /* make the opposing colors different, so !s */ if (!s) XSetForeground (dpy, board_gc, gammon_resource.light_Pixel); else XSetForeground (dpy, board_gc, gammon_resource.dark_Pixel); XFillPolygon (dpy, pixmap, board_gc, c, 3, Convex, CoordModeOrigin); /* and around it a little black border */ c[0].x = i * rect_width; if (i > 6) c[0].x += rect_width; c[1].x = c[0].x + rect_width; c[0].y = c[1].y = height - 1; XDrawLine (dpy, pixmap, gc, c[0].x, c[0].y, c[0].x, c[1].y); c[1].y = height - rect_height; c[1].x -= rect_width/2; XDrawLine (dpy, pixmap, gc, c[0].x, c[0].y, c[1].x, c[1].y); XDrawLine (dpy, pixmap, gc, c[0].x + rect_width, c[0].y, c[1].x, c[1].y); if (s==0) s=1; else s=0; } } /* other_display */ /*DrawBoard ();*/ here = 1; } void DrawDice (int color) { DeleteDice (); DrawEmptyDice (color); DrawDiceValues (); } void DeleteDice () { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; Window window = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.board.gc; int x; if (!dice_y) return; if (turn == BLACK) x = 3 * stone_width + stone_width/2 - 3; /* remove white dice */ else x = 9 * stone_width + stone_width/2 - 3; XSetForeground (dpy, gc, gammon_resource.board_Pixel); XFillRectangle (dpy, window, gc, x, dice_y - 3, stone_width * 2 + stone_width/2 + 6, dice_width + 6); XFillRectangle (dpy, window, gc, x, dice_y - 3, stone_width * 2 + stone_width/2 + 6, dice_width + 6); XFillRectangle (dpy, pixmap, gc, x, dice_y - 3, stone_width * 2 + stone_width/2 + 6, dice_width + 6); XFillRectangle (dpy, pixmap, gc, x, dice_y - 3, stone_width * 2 + stone_width/2 + 6, dice_width + 6); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; window = Player[1].X11Set.board.window; gc = Player[1].X11Set.board.gc; XSetForeground (dpy, gc, gammon_resource.board_Pixel); XFillRectangle (dpy, window, gc, x, dice_y - 3, stone_width * 2 + stone_width/2 + 6, dice_width + 6); XFillRectangle (dpy, window, gc, x, dice_y - 3, stone_width * 2 + stone_width/2 + 6, dice_width + 6); XFillRectangle (dpy, pixmap, gc, x, dice_y - 3, stone_width * 2 + stone_width/2 + 6, dice_width + 6); XFillRectangle (dpy, pixmap, gc, x, dice_y - 3, stone_width * 2 + stone_width/2 + 6, dice_width + 6); } } void DrawEmptyDice (int color) { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; Window window = Player[0].X11Set.board.window; GC diceGC = Player[0].X11Set.diceGC; static int backup_width = 0; unsigned long b, w; /* black and white pixel */ if (!backup_width) backup_width = width; dice_y = 6 * stone_width - dice_width/2; if (color == BLACK) { b = gammon_resource.white_Pixel; w = gammon_resource.black_Pixel; dice_x = 9 * stone_width + stone_width/2; } else { w = gammon_resource.white_Pixel; b = gammon_resource.black_Pixel; dice_x = 3 * stone_width + stone_width/2; } if (width != backup_width) { int line_width; backup_width = width; line_width = width/100; XSetLineAttributes (dpy, diceGC, line_width, LineSolid, CapRound, JoinMiter); } XSetForeground (dpy, diceGC, w); XFillRectangle (dpy, window, diceGC, dice_x, dice_y, dice_width, dice_width); XFillRectangle (dpy, window, diceGC, dice_x + dice_width + dice_width/2, dice_y, dice_width, dice_width); XFillRectangle (dpy, pixmap, diceGC, dice_x, dice_y, dice_width, dice_width); XFillRectangle (dpy, pixmap, diceGC, dice_x + dice_width + dice_width/2, dice_y, dice_width, dice_width); XSetForeground (dpy, diceGC, b); XDrawRectangle (dpy, window, diceGC, dice_x, dice_y, dice_width, dice_width); XDrawRectangle (dpy, window, diceGC, dice_x + dice_width + dice_width/2, dice_y, dice_width, dice_width); XDrawRectangle (dpy, pixmap, diceGC, dice_x, dice_y, dice_width, dice_width); XDrawRectangle (dpy, pixmap, diceGC, dice_x + dice_width + dice_width/2, dice_y, dice_width, dice_width); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; window = Player[1].X11Set.board.window; diceGC = Player[1].X11Set.diceGC; XSetForeground (dpy, diceGC, w); XFillRectangle (dpy, window, diceGC, dice_x, dice_y, dice_width, dice_width); XFillRectangle (dpy, window, diceGC, dice_x + dice_width + dice_width/2, dice_y, dice_width, dice_width); XFillRectangle (dpy, pixmap, diceGC, dice_x, dice_y, dice_width, dice_width); XFillRectangle (dpy, pixmap, diceGC, dice_x + dice_width + dice_width/2, dice_y, dice_width, dice_width); XSetForeground (dpy, diceGC, b); XDrawRectangle (dpy, window, diceGC, dice_x, dice_y, dice_width, dice_width); XDrawRectangle (dpy, window, diceGC, dice_x + dice_width + dice_width/2, dice_y, dice_width, dice_width); XDrawRectangle (dpy, pixmap, diceGC, dice_x, dice_y, dice_width, dice_width); XDrawRectangle (dpy, pixmap, diceGC, dice_x + dice_width + dice_width/2, dice_y, dice_width, dice_width); } } void DrawDiceValues (void) { switch (abs(roll[0])) { case 1: draw_one (dice_x, dice_y, dice_width); break; case 2: draw_two (dice_x, dice_y, dice_width); break; case 3: draw_three (dice_x, dice_y, dice_width); break; case 4: draw_four (dice_x, dice_y, dice_width); break; case 5: draw_five (dice_x, dice_y, dice_width); break; case 6: draw_six (dice_x, dice_y, dice_width); break; } switch (abs(roll[1])) { case 1: draw_one (dice_x + dice_width + dice_width/2, dice_y, dice_width); break; case 2: draw_two (dice_x + dice_width + dice_width/2, dice_y, dice_width); break; case 3: draw_three (dice_x + dice_width + dice_width/2, dice_y, dice_width); break; case 4: draw_four (dice_x + dice_width + dice_width/2, dice_y, dice_width); break; case 5: draw_five (dice_x + dice_width + dice_width/2, dice_y, dice_width); break; case 6: draw_six (dice_x + dice_width + dice_width/2, dice_y, dice_width); break; } } void DrawDoubler (int how_double, int who_doubled) /* doubler is as wide as a stone */ { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; Window window = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.board.gc; GC diceGC = Player[0].X11Set.diceGC; Display *o_dpy = Player[1].X11Set.dpy; Pixmap o_pixmap = Player[1].X11Set.board.pixmap; Window o_window = Player[1].X11Set.board.window; GC o_gc = Player[1].X11Set.board.gc; GC o_diceGC = Player[1].X11Set.diceGC; int x = 0; static int y = 0; /* yes */ int font_height, font_width; char t[3]; /* all the x+1, y-3, x-1 ... or some like that are more or lesss neccessary cause of XDrawLine () Function */ /* remove old doubler */ XSetForeground (dpy, gc, gammon_resource.bar_Pixel); XFillRectangle (dpy, window, gc, x, y - 3, stone_width, 2*stone_width); XFillRectangle (dpy, pixmap, gc, x, y - 3, stone_width, 2*stone_width); if (gammon_resource.other_display) { XSetForeground (o_dpy, o_gc, gammon_resource.bar_Pixel); XFillRectangle (o_dpy, o_window, o_gc, x, y - 3, stone_width, 2*stone_width); XFillRectangle (o_dpy, o_pixmap, o_gc, x, y - 3, stone_width, 2*stone_width); } /* set new position */ switch (who_doubled) { case BLACK: y = 2*stone_width; break; case WHITE: y = 9*stone_width; break; default: y = 5*stone_width + stone_width/2; break; } /* draw new one */ XSetForeground (dpy, diceGC, gammon_resource.white_Pixel); XFillRectangle (dpy, window, diceGC, x+1, y, stone_width-3, stone_width); XFillRectangle (dpy, pixmap, diceGC, x+1, y, stone_width-3, stone_width); XSetForeground (dpy, diceGC, gammon_resource.black_Pixel); XDrawRectangle (dpy, window, diceGC, x+1, y, stone_width-3, stone_width); XDrawRectangle (dpy, pixmap, diceGC, x+1, y, stone_width-3, stone_width); if (gammon_resource.other_display) { XSetForeground (o_dpy, o_diceGC, gammon_resource.white_Pixel); XFillRectangle (o_dpy, o_window, o_diceGC, x+1, y, stone_width-3, stone_width); XFillRectangle (o_dpy, o_pixmap, o_diceGC, x+1, y, stone_width-3, stone_width); XSetForeground (o_dpy, o_diceGC, gammon_resource.black_Pixel); XDrawRectangle (o_dpy, o_window, o_diceGC, x+1, y, stone_width-3, stone_width); XDrawRectangle (o_dpy, o_pixmap, o_diceGC, x+1, y, stone_width-3, stone_width); } sprintf (t, "%d", how_double); /* see 6 lines below */ /* decide witch font to use */ if ((Player[0].X11Set.doubler_font->ascent + Player[0].X11Set.doubler_font->descent + 6) > stone_width) { XSetFont (dpy, diceGC, Player[0].X11Set.small_font->fid); font_height = Player[0].X11Set.small_font->ascent + Player[0].X11Set.small_font->descent; font_width = Player[0].X11Set.small_font->per_char[t[0] - Player[0].X11Set.small_font->min_char_or_byte2].width; } else { XSetFont (dpy, diceGC, Player[0].X11Set.doubler_font->fid); font_height = Player[0].X11Set.doubler_font->ascent + Player[0].X11Set.doubler_font->descent; font_width = Player[0].X11Set.doubler_font->per_char[t[0] - Player[0].X11Set.doubler_font->min_char_or_byte2].width; } if (gammon_resource.other_display) { if ((Player[1].X11Set.doubler_font->ascent + Player[1].X11Set.doubler_font->descent + 6) > stone_width) { XSetFont (o_dpy, o_diceGC, Player[1].X11Set.small_font->fid); font_height = Player[1].X11Set.small_font->ascent + Player[1].X11Set.small_font->descent; font_width = Player[1].X11Set.small_font->per_char[t[0] - Player[1].X11Set.small_font->min_char_or_byte2].width; } else { XSetFont (o_dpy, o_diceGC, Player[1].X11Set.doubler_font->fid); font_height = Player[1].X11Set.doubler_font->ascent + Player[1].X11Set.doubler_font->descent; font_width = Player[1].X11Set.doubler_font->per_char[t[0] - Player[1].X11Set.doubler_font->min_char_or_byte2].width; } } font_width *= strlen (t); /* see 7 lines above */ /* draw the text */ x += stone_width/2 - font_width/2; y += stone_width - (stone_width - font_height)/2 - 3; XDrawImageString (dpy, window, diceGC, x , y, t, strlen (t)); XDrawImageString (dpy, pixmap, diceGC, x , y, t, strlen (t)); if (gammon_resource.other_display) { XDrawImageString (o_dpy, o_window, o_diceGC, x , y, t, strlen (t)); XDrawImageString (o_dpy, o_pixmap, o_diceGC, x , y, t, strlen (t)); } /* reset y for remove */ y -= stone_width - (stone_width - font_height)/2 - 3; } void draw_one (int dice_x, int dice_y, int dice_width) { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; Window window = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.diceGC; int x, y, r; r = dice_width/4; x = dice_x + dice_width/2 - r/2; y = dice_y + dice_width/2 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; window = Player[1].X11Set.board.window; gc = Player[1].X11Set.diceGC; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); } } void draw_two (int dice_x, int dice_y, int dice_width) { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; Window window = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.diceGC; int x, y, r; r = dice_width/4; x = dice_x + dice_width/4 - r/4; y = dice_y + dice_width/4 - r/4; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); x = dice_x + dice_width - (dice_width - 6)/4 - r; y = dice_y + dice_width - (dice_width - 6)/4 - r; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; window = Player[1].X11Set.board.window; gc = Player[1].X11Set.diceGC; x = dice_x + dice_width/4 - r/4; y = dice_y + dice_width/4 - r/4; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); x = dice_x + dice_width - (dice_width - 6)/4 - r; y = dice_y + dice_width - (dice_width - 6)/4 - r; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); } } void draw_three (int dice_x, int dice_y, int dice_width) { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; Window window = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.diceGC; int x, y, r; /* center */ r = dice_width/4; x = dice_x + dice_width/2 - r/2; y = dice_y + dice_width/2 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); /* upper left */ x = dice_x + dice_width/4 - r/2; y = dice_y + dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); /* lower right */ x = dice_x + dice_width - dice_width/4 - r/2; y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; window = Player[1].X11Set.board.window; gc = Player[1].X11Set.diceGC; /* center */ x = dice_x + dice_width/2 - r/2; y = dice_y + dice_width/2 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); /* upper left */ x = dice_x + dice_width/4 - r/2; y = dice_y + dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); /* lower right */ x = dice_x + dice_width - dice_width/4 - r/2; y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); } } void draw_four (int dice_x, int dice_y, int dice_width) { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; Window window = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.diceGC; int x, y, r; r = dice_width/4; x = dice_x + dice_width/4 - r/4; y = dice_y + dice_width/4 - r/4; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); x = dice_x + dice_width/4 - r/4; y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); x = dice_x + dice_width - dice_width/4 - r/2; y = dice_y + dice_width/4 - r/4; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); x = dice_x + dice_width - dice_width/4 - r/2; y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; window = Player[1].X11Set.board.window; gc = Player[1].X11Set.diceGC; x = dice_x + dice_width/4 - r/4; y = dice_y + dice_width/4 - r/4; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); x = dice_x + dice_width/4 - r/4; y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); x = dice_x + dice_width - dice_width/4 - r/2; y = dice_y + dice_width/4 - r/4; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); x = dice_x + dice_width - dice_width/4 - r/2; y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); } } void draw_five (int dice_x, int dice_y, int dice_width) { draw_one (dice_x+2, dice_y+2, dice_width); draw_four (dice_x, dice_y, dice_width); } void draw_six (int dice_x, int dice_y, int dice_width) { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; Window window = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.diceGC; int r, x, y; r = dice_width/4; /* left three */ x = dice_x + dice_width/3 - r/2 - 2; y = dice_y + dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); y = dice_y + dice_width/2 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); /* right three */ x = dice_x + dice_width - dice_width/3 - r/2 + 2; y = dice_y + dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); y = dice_y + dice_width/2 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; window = Player[1].X11Set.board.window; gc = Player[1].X11Set.diceGC; r = dice_width/4; /* left three */ x = dice_x + dice_width/3 - r/2 - 2; y = dice_y + dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); y = dice_y + dice_width/2 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); /* right three */ x = dice_x + dice_width - dice_width/3 - r/2 + 2; y = dice_y + dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); y = dice_y + dice_width/2 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); y = dice_y + dice_width - dice_width/4 - r/2; XFillArc (dpy, window, gc, x, y, r, r, 0*64, 360*64); XFillArc (dpy, pixmap, gc, x, y, r, r, 0*64, 360*64); } } void PutStone (unsigned int color, unsigned int pin) { Display *dpy = Player[0].X11Set.dpy; Pixmap pixmap = Player[0].X11Set.board.pixmap; XPoint p; p = PinToPosition (pin); /* before adding the stone to the Pin */ Pin[pin].count++; Pin[pin].color = color; DrawStone (p.x, p.y, color); /* this is not in DrawStone, DrawStone is for moved stones */ if (color == BLACK) { XFillArc (dpy, pixmap, Player[0].X11Set.stoneGC[0], p.x, p.y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pixmap, Player[0].X11Set.stoneGC[1], p.x, p.y, stone_width-1, stone_width-1, 0, 360*64); /* DrawArc is somtimes a pixel wider than FillArc, donno why */ } else { XFillArc (dpy, pixmap, Player[0].X11Set.stoneGC[1], p.x, p.y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pixmap, Player[0].X11Set.stoneGC[0], p.x, p.y, stone_width-1, stone_width-1, 0, 360*64); } if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; pixmap = Player[1].X11Set.board.pixmap; /* this is not in DrawStone, DrawStone is for moved stones */ if (color == BLACK) { XFillArc (dpy, pixmap, Player[1].X11Set.stoneGC[0], p.x, p.y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pixmap, Player[1].X11Set.stoneGC[1], p.x, p.y, stone_width-1, stone_width-1, 0, 360*64); /* DrawArc is somtimes a pixel wider than FillArc, donno why */ } else { XFillArc (dpy, pixmap, Player[1].X11Set.stoneGC[1], p.x, p.y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pixmap, Player[1].X11Set.stoneGC[0], p.x, p.y, stone_width-1, stone_width-1, 0, 360*64); } } } void DrawStone (int x, int y, int color) { Display *dpy = Player[0].X11Set.dpy; Window window = Player[0].X11Set.board.window; if (color == BLACK) { XFillArc (dpy, window, Player[0].X11Set.stoneGC[0], x, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, window, Player[0].X11Set.stoneGC[1], x, y, stone_width-1, stone_width-1, 0, 360*64); /* DrawArc is somtimes a pixel wider than FillArc, donno why */ } else { XFillArc (dpy, window, Player[0].X11Set.stoneGC[1], x, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, window, Player[0].X11Set.stoneGC[0], x, y, stone_width-1, stone_width-1, 0, 360*64); } if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; window = Player[1].X11Set.board.window; if (color == BLACK) { XFillArc (dpy, window, Player[1].X11Set.stoneGC[0], x, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, window, Player[1].X11Set.stoneGC[1], x, y, stone_width-1, stone_width-1, 0, 360*64); /* DrawArc is somtimes a pixel wider than FillArc, donno why */ } else { XFillArc (dpy, window, Player[1].X11Set.stoneGC[1], x, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, window, Player[1].X11Set.stoneGC[0], x, y, stone_width-1, stone_width-1, 0, 360*64); } } } void RemoveStone (int pin) { Display *dpy = Player[0].X11Set.dpy; Window window = Player[0].X11Set.board.window; Pixmap pixmap = Player[0].X11Set.board.pixmap; GC gc = Player[0].X11Set.board.gc; Pixmap pin_pixmap = Player[0].X11Set.board.pin_pixmap[0]; XPoint p; int i, c, copy_start, copy_start_in_pixmap (int pin); int pixmap_to_redraw (int pin); Pin[pin].count--; if (Pin[pin].count == 0) Pin[pin].color = 0; if (pin == FINISHED) { /* for UndoMove() */ p.x = width - stone_width; p.y = (turn == BLACK) ? height/2 + stone_width : 0; XCopyArea (dpy, pin_pixmap, window, gc, 0, 0, stone_width, stone_width*5, p.x, p.y); XCopyArea (dpy, pin_pixmap, pixmap, gc, 0, 0, stone_width, stone_width*5, p.x, p.y); for (i = Pin[pin].count, Pin[pin].count = 0; i; i--) PutStone (turn, pin); return; } p = PinToPosition (pin); c = pixmap_to_redraw (pin); copy_start = copy_start_in_pixmap (pin); pin_pixmap = Player[0].X11Set.board.pin_pixmap[c]; XCopyArea (dpy, pin_pixmap, window, gc, 0, copy_start, stone_width, stone_width, p.x, p.y); XCopyArea (dpy, pin_pixmap, pixmap, gc, 0, copy_start, stone_width, stone_width, p.x, p.y); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; window = Player[1].X11Set.board.window; pixmap = Player[1].X11Set.board.pixmap; gc = Player[1].X11Set.board.gc; pin_pixmap = Player[1].X11Set.board.pin_pixmap[0]; if (pin == FINISHED) { /* for UndoMove() */ p.x = width - stone_width; p.y = (turn == BLACK) ? height/2 + stone_width : 0; XCopyArea (dpy, pin_pixmap, window, gc, 0, 0, stone_width, stone_width*5, p.x, p.y); XCopyArea (dpy, pin_pixmap, pixmap, gc, 0, 0, stone_width, stone_width*5, p.x, p.y); for (i = Pin[pin].count, Pin[pin].count = 0; i; i--) PutStone (turn, pin); return; } p = PinToPosition (pin); copy_start = copy_start_in_pixmap (pin); pin_pixmap = Player[1].X11Set.board.pin_pixmap[c]; XCopyArea (dpy, pin_pixmap, window, gc, 0, copy_start, stone_width, stone_width, p.x, p.y); XCopyArea (dpy, pin_pixmap, pixmap, gc, 0, copy_start, stone_width, stone_width, p.x, p.y); } } int pixmap_to_redraw (int pin) { int layer, turn_color, direct, pin_color; if (pin == BAR || pin == OTHER_BAR) { if (Pin[pin].count<5) return 32 + 0; else if (Pin[pin].count<9) layer = 1; else if (Pin[pin].count<13) layer = 3; else layer = 5; turn_color = (turn == BLACK) ? 0 : 1; if (Pin[pin].count>8) direct = (turn == BLACK) ? 0 : 1; else direct = 0; return 32 + layer + turn_color + direct; } if (Pin[pin].count<5) layer = 0; else if (Pin[pin].count<9) layer = 1; else if (Pin[pin].count<13) layer = 2; else layer = 3; turn_color = (turn == BLACK) ? 0 : 2; pin_color = pin%2; direct = (pin <13) ? 0 : 16; return direct + pin_color + turn_color + (4 * layer); } int copy_start_in_pixmap (int pin) { if (pin<13) { if (Pin[pin].count < 5) return ( Pin[pin].count * stone_width); else if(Pin[pin].count < 9) return ((Pin[pin].count - 5) * stone_width + stone_width/2); else if(Pin[pin].count < 13) return ((Pin[pin].count - 9) * stone_width + stone_width/4); else return ((Pin[pin].count - 13) * stone_width + stone_width*3/4); } else { /* GRRRHHUUUMMPPFFFNNAAARRGGHHH */ if (Pin[pin].count < 5) return ((4 - Pin[pin].count) * stone_width); else if(Pin[pin].count < 9) return ((8 - Pin[pin].count) * stone_width + stone_width/2); else if(Pin[pin].count < 13) return ((13 - Pin[pin].count) * stone_width - stone_width/4); else return ((16 - Pin[pin].count) * stone_width - stone_width*3/4); } } void RedrawAllStones (void) { int i, c, backup_turn; if (turn == BLACK) { for (c = Pin[ 0].count, Pin[ 0].count = 0; c; c--) PutStone (BLACK, BAR); for (c = Pin[25].count, Pin[25].count = 0; c; c--) PutStone (WHITE, OTHER_BAR); } else { for (c = Pin[ 0].count, Pin[ 0].count = 0; c; c--) PutStone (BLACK, OTHER_BAR); for (c = Pin[25].count, Pin[25].count = 0; c; c--) PutStone (WHITE, BAR); } for (i=1; i<25; i++) { for (c = Pin[i].count, Pin[i].count = 0; c; c--) PutStone (Pin[i].color, i); } backup_turn = turn; /* for loading from a file */ turn = BLACK; /* for PutStone */ for (c = Pin[25+BLACK].count, Pin[25+BLACK].count = 0; c; c--) PutStone (BLACK, 25+BLACK); turn = WHITE; for (c = Pin[25+WHITE].count, Pin[25+WHITE].count = 0; c; c--) PutStone (WHITE, 25+WHITE); turn = backup_turn; } void FreePixmaps() { Display *dpy = Player[0].X11Set.dpy; Pixmap *p = Player[0].X11Set.board.pin_pixmap; int i; XFreePixmap (dpy, Player[0].X11Set.board.pixmap); for (i=0; i<41; i++) XFreePixmap (dpy, Player[0].X11Set.board.pin_pixmap[i]); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; p = Player[1].X11Set.board.pin_pixmap; XFreePixmap (dpy, Player[1].X11Set.board.pixmap); for (i=0; i<41; i++) XFreePixmap (dpy, p[i]); } } /* there is a comment in the sources of `xmgt' program: "... pixmap hell ..." so, here we go */ void CreatePixmaps (int player_index) { Display *dpy = Player[player_index].X11Set.dpy; Window window = Player[player_index].X11Set.board.window; Pixmap board_pixmap; Pixmap *pin_pixmap; GC board_gc = Player[player_index].X11Set.board.gc; XPoint down_p[3], up_p[3]; int i, j, y; unsigned int rect_width, rect_height; int screen_depth = DefaultDepth (dpy, DefaultScreen (dpy)); Player[player_index].X11Set.board.pixmap = XCreatePixmap (dpy, window, width, height, screen_depth); board_pixmap = Player[player_index].X11Set.board.pixmap; rect_width = stone_width; rect_height = stone_width * 5; down_p[0].x = 1; /* looks a little more slim */ down_p[1].x = rect_width - 1; down_p[2].x = rect_width/2; down_p[0].y = 0; down_p[1].y = 0; down_p[2].y = rect_height; up_p[0].x = rect_width/2; up_p[1].x = 1; up_p[2].x = rect_width - 1; up_p[0].y = 0; up_p[1].y = rect_height; up_p[2].y = rect_height; /* for the bar stuff: there are layer [0-3] with empty = bar_pixmap[0] first and second layer are epual for up and down so: p[1],p[2] black,white first layer p[3],p[4] black,white second layer for the third layer up and down are different so: p[5],p[6] black,white up layer p[7],p[8] black,white down layer for the pins: there are UP|DOWN DARK|LIGHT BLACK|WHITE EMPTY|ONE|TWO|THREE layers = 2 * 2 * 2 * 4 = 32 pixmaps two of them (empty ones) are equal and so left unused there are 15 stones: 5 in the first layer, 4 in the second and third and two in the fourth and last layer, (witch needs no redraw and so no pixmap) I think this lotta pixmaps are a little a one way street, and I should possibly think a little more (but don't) */ for (i=0; i<41; i++) Player[player_index].X11Set.board.pin_pixmap[i] = XCreatePixmap (dpy, window, rect_width, rect_height, screen_depth); pin_pixmap = Player[player_index].X11Set.board.pin_pixmap; /* now draw the boardcolor inside */ XSetForeground (dpy, board_gc, gammon_resource.board_Pixel); for (i=0; i<32; i++) XFillRectangle (dpy, pin_pixmap[i], board_gc, 0, 0, rect_width, rect_height); XSetForeground (dpy, board_gc, gammon_resource.dark_Pixel); for (i=0; i<16; i+=2) { /* UP && DARK */ XFillPolygon (dpy, pin_pixmap[i], board_gc, down_p, 3, Convex, CoordModeOrigin); XDrawLine (dpy, pin_pixmap[i], Player[player_index].X11Set.gc, down_p[0].x, down_p[0].y, down_p[2].x, down_p[2].y); XDrawLine (dpy, pin_pixmap[i], Player[player_index].X11Set.gc, down_p[1].x, down_p[1].y, down_p[2].x, down_p[2].y); } for (i=16; i<32; i+=2) { /* DOWN && DARK */ XFillPolygon (dpy, pin_pixmap[i], board_gc, up_p, 3, Convex, CoordModeOrigin); XDrawLine (dpy, pin_pixmap[i], Player[player_index].X11Set.gc, up_p[0].x, up_p[0].y, up_p[1].x, up_p[1].y); XDrawLine (dpy, pin_pixmap[i], Player[player_index].X11Set.gc, up_p[0].x, up_p[0].y, up_p[2].x, up_p[2].y); } XSetForeground (dpy, board_gc, gammon_resource.light_Pixel); for (i=1; i<16; i+=2) { /* UP && LIGHT */ XFillPolygon (dpy, pin_pixmap[i], board_gc, down_p, 3, Convex, CoordModeOrigin); XDrawLine (dpy, pin_pixmap[i], Player[player_index].X11Set.gc, down_p[0].x, down_p[0].y, down_p[2].x, down_p[2].y); XDrawLine (dpy, pin_pixmap[i], Player[player_index].X11Set.gc, down_p[1].x, down_p[1].y, down_p[2].x, down_p[2].y); } for (i=17; i<32; i+=2) { /* DOWN && LIGHT */ XFillPolygon (dpy, pin_pixmap[i], board_gc, up_p, 3, Convex, CoordModeOrigin); XDrawLine (dpy, pin_pixmap[i], Player[player_index].X11Set.gc, up_p[0].x, up_p[0].y, up_p[1].x, up_p[1].y); XDrawLine (dpy, pin_pixmap[i], Player[player_index].X11Set.gc, up_p[0].x, up_p[0].y, up_p[2].x, up_p[2].y); } /* now draw the first layer of stones into the pin_pixmaps where necessary */ for (i=4; i<32; i+=4) { if (i == 16) i = 20; /* skip empty ones */ for (j=0; j<5; j++) { y = stone_width * j; /* black stone on dark pin */ XFillArc (dpy, pin_pixmap[i], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[i], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); /* black stone on light pin */ XFillArc (dpy, pin_pixmap[i+1], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[i+1], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); /* white stone on dark pin */ XFillArc (dpy, pin_pixmap[i+2], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[i+2], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); /* white stone on light pin */ XFillArc (dpy, pin_pixmap[i+3], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[i+3], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); } } /* second layer */ for (i=8; i<32; i+=4) { if (i == 16) i = 24; /* skip empty ones */ for (j=0; j<4; j++) { y = stone_width * j + stone_width/2; XFillArc (dpy, pin_pixmap[i], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[i], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[i+1], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[i+1], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[i+2], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[i+2], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[i+3], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[i+3], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); } } /* third and last layer */ for (j=0; j<4; j++) { y = stone_width * j + stone_width/4; /* upper half of board */ XFillArc (dpy, pin_pixmap[12], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[12], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[13], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[13], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[14], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[14], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[15], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[15], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); y = stone_width * j + stone_width*3/4; /* lower half of board */ XFillArc (dpy, pin_pixmap[28], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[28], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[29], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[29], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[30], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[30], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[31], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[31], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); } /* now the drawing in the bar pin_pixmaps */ /* the bar background */ XSetForeground (dpy, board_gc, gammon_resource.bar_Pixel); for (i=0; i<9; i++) XFillRectangle(dpy, pin_pixmap[32+i], board_gc, 0, 0, rect_width, rect_height); for (i=1; i<9; i+=2) { /* first layer */ for (j=0; j<5; j++) { y = stone_width * j; XFillArc (dpy, pin_pixmap[32+i ], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[32+i ], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[32+i+1], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[32+i+1], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); }} for (i=3; i<9; i+=2) { /* second layer */ for (j=0; j<4; j++) { y = stone_width * j + stone_width/2; XFillArc (dpy, pin_pixmap[32+i ], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[32+i ], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[32+i+1], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[32+i+1], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); }} for (j=0; j<4; j++) { /* third layer */ y = stone_width * j + stone_width/4; XFillArc (dpy, pin_pixmap[32+5], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[32+5], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[32+6], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[32+7], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); y = stone_width * j + stone_width*3/4; XFillArc (dpy, pin_pixmap[32+7], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[32+8], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width-1, stone_width-1, 0, 360*64); XFillArc (dpy, pin_pixmap[32+8], Player[player_index].X11Set.stoneGC[1], 0, y, stone_width, stone_width, 0, 360*64); XDrawArc (dpy, pin_pixmap[32+8], Player[player_index].X11Set.stoneGC[0], 0, y, stone_width-1, stone_width-1, 0, 360*64); } } xgammon/src/edit.c100644 764 144 17521 7013622221 13116 0ustar delleusers/* edit.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #include #include #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" static void GetGameValuesPopup (); extern void DrawEmptyBoard (); extern void DrawBoard (); extern int EventToPin (); void EditPosition (void) { XEvent event; int black_count = 0, white_count = 0, p; for (p = 0; p<28; p++) { Pin[p].color = 0; Pin[p].count = 0; } DrawEmptyBoard (); DrawBoard (); AppendDialogText (LOWER, "\n\nedit a position:\npress left button to place a black stone,\nright button tp place a white stone,\nthe middle button to remove a stone,\nany key to break.\n"); while (1) { XtAppNextEvent (app_con, &event); if (event.xbutton.window == Player[0].X11Set.board.window) { if (event.type == ButtonRelease) { p = EventToPin (event.xbutton.x, event.xbutton.y); if (event.xbutton.button == 1) { if (Pin[p].color != WHITE && black_count<15) { black_count ++; PutStone (BLACK, p); } } else if (event.xbutton.button == 3) { if (p == BAR && white_count<15) { white_count ++; PutStone (WHITE, OTHER_BAR); } else if (Pin[p].color != BLACK && white_count<15) { white_count ++; PutStone (WHITE, p); } } else if (event.xbutton.button == 2) { if (Pin[p].color) { if (Pin[p].color == BLACK) black_count --; else if (Pin[p].color == WHITE) white_count --; RemoveStone (p); } } if (black_count + white_count == 30) break; } else if (event.type == KeyPress) break; } else XtDispatchEvent (&event); } GetGameValuesPopup (); if (black_count<15) { int i, t = turn; /* PutStone is too dump */ turn = BLACK; for (i=black_count; i<15; i++) PutStone (BLACK, FINISHED); turn = t; } if (white_count<15) { int i, t = turn; turn = WHITE; for (i=white_count; i<15; i++) PutStone (WHITE, FINISHED); turn = t; } initialize = EDITED_POSITION; /* set some global flags */ break_loop = EDITED_POSITION; end_of_game = 1; } static void GetGameValuesPopup (void) { Widget toplevel = Player[0].X11Set.toplevel; Widget popup_shell, form; Widget turn_label, doubler_label, owner_label, roll_label; Widget turn_switch, doubler_switch, owner_switch, roll_switch[2]; Widget ok; Arg args[4]; char value[15]; Dimension w, h; Position x, y; int ignore_dice = 0; XtSetArg (args[0], XtNx, &x); XtSetArg (args[1], XtNy, &y); XtGetValues (toplevel, args, 2); XtSetArg (args[0], XtNx, x+50); XtSetArg (args[1], XtNy, y+50); popup_shell = XtCreatePopupShell ("Edit Position", transientShellWidgetClass, toplevel, args, 2); form = XtCreateManagedWidget ("form", formWidgetClass, popup_shell, NULL, 0); turn_label = XtCreateManagedWidget ("turn: ", labelWidgetClass, form, NULL, 0); XtSetArg (args[0], XtNfromVert, turn_label); doubler_label = XtCreateManagedWidget ("doubler value:", labelWidgetClass, form, args, 1); XtSetArg (args[0], XtNfromVert, doubler_label); owner_label = XtCreateManagedWidget ("last doubler: ", labelWidgetClass, form, args, 1); XtSetArg (args[0], XtNfromVert, owner_label); roll_label = XtCreateManagedWidget ("dice: ", commandWidgetClass, form, args, 1); XtSetArg (args[0], XtNfromVert, roll_label); ok = XtCreateManagedWidget ("ok", commandWidgetClass, form, args, 1); XtSetArg (args[0], XtNfromHoriz, turn_label); if (turn == BLACK) strcpy (value,"black"); else strcpy (value,"white"); turn_switch = XtCreateManagedWidget (value, commandWidgetClass, form, args, 1); XtSetArg (args[0], XtNwidth, &w); XtSetArg (args[1], XtNheight, &h); XtGetValues (turn_switch, args, 2); XtSetArg (args[2], XtNwidth, w); XtSetArg (args[3], XtNheight, h); XtSetArg (args[0], XtNfromHoriz, doubler_label); XtSetArg (args[1], XtNfromVert, turn_label); sprintf (value, "%d", doubler.value); doubler_switch = XtCreateManagedWidget (value, commandWidgetClass, form, args, 4); XtSetArg (args[0], XtNfromHoriz, owner_label); XtSetArg (args[1], XtNfromVert, doubler_label); if (!doubler.owner) strcpy (value,"none"); else if (doubler.owner == BLACK) strcpy (value,"black"); else strcpy (value,"white"); owner_switch = XtCreateManagedWidget (value, commandWidgetClass, form, args, 4); { unsigned short d; XtSetArg (args[0], XtNhorizDistance, &d); XtGetValues (form, args, 1); XtSetArg (args[0], XtNfromHoriz, roll_label); XtSetArg (args[1], XtNfromVert, owner_label); XtSetArg (args[2], XtNwidth, w/2 - d/2); } roll[0] = abs (roll[0]); roll[1] = abs (roll[1]); sprintf (value, "%d", roll[0]); roll_switch[0] = XtCreateManagedWidget (value, commandWidgetClass, form, args, 4); XtSetArg (args[0], XtNfromHoriz, roll_switch[0]); XtSetArg (args[1], XtNfromVert, owner_label); sprintf (value, "%d", roll[1]); roll_switch[1] = XtCreateManagedWidget (value, commandWidgetClass, form, args, 4); XtPopup (popup_shell, XtGrabExclusive); while (1) { XEvent event; XtAppNextEvent (app_con, &event); if (event.type == ButtonRelease) { if (event.xbutton.window == XtWindow (turn_switch)) { if (turn == BLACK) { turn = WHITE; XtSetArg (args[0], XtNlabel, "white"); } else { turn = BLACK; XtSetArg (args[0], XtNlabel, "black"); } XtSetValues (turn_switch, args, 1); } else if (event.xbutton.window == XtWindow (doubler_switch)) { doubler.value *= 2; if (doubler.value > 64) doubler.value = 1; sprintf (value, "%d", doubler.value); XtSetArg (args[0], XtNlabel, value); XtSetValues (doubler_switch, args, 1); } else if (event.xbutton.window == XtWindow (owner_switch)) { if (!doubler.owner) { strcpy (value, "black"); doubler.owner = BLACK; } else if (doubler.owner == BLACK) { strcpy (value, "white"); doubler.owner = WHITE; } else { strcpy (value, "none"); doubler.owner = 0; } XtSetArg (args[0], XtNlabel, value); XtSetValues (owner_switch, args, 1); } else if (event.xbutton.window == XtWindow (roll_label)) { if (!ignore_dice) { ignore_dice = 1; strcpy (value, "ignore roll "); } else { ignore_dice = 0; strcpy (value, "dice: "); } XtSetArg (args[0], XtNlabel, value); XtSetValues (roll_label, args, 1); } else if (event.xbutton.window == XtWindow (roll_switch[0])) { roll[0] ++; if (roll[0] == 7) roll[0] = 1; sprintf (value, "%d", roll[0]); XtSetArg (args[0], XtNlabel, value); XtSetValues (roll_switch[0], args, 1); } else if (event.xbutton.window == XtWindow (roll_switch[1])) { roll[1] ++; if (roll[1] == 7) roll[1] = 1; sprintf (value, "%d", roll[1]); XtSetArg (args[0], XtNlabel, value); XtSetValues (roll_switch[1], args, 1); } else if (event.xbutton.window == XtWindow (ok)) break; } XtDispatchEvent (&event); } XtPopdown (popup_shell); switch_turn (); switch_turn (); /* set rest of vars */ if (turn == WHITE) { roll[0] *= -1; roll[1] *= -1; } if (ignore_dice) { roll[0] = (rand ()%6 + 1) * direction; roll[1] = (rand ()%6 + 1) * direction; } if (roll[0] == roll[1]) { roll[3] = roll[2] = roll[0]; pash = 1; to_move = 4; } else { roll[3] = roll[2] = 0; pash = 0; to_move = 2; } } xgammon/src/filemenu.c100644 764 144 21737 7013622221 14001 0ustar delleusers/* filemenu.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. The idea of this popup is lifted from xxgdb and adopted for xgammon. Especially the functions ScanDir (), Inlist () and changeDir () are almost literally copied. And the copied idea is visible in the functions File () CreateFilePopup () DisplayMenuFile (). * xdbx - X Window System interface to the dbx debugger * * Copyright 1989 The University of Texas at Austin * Copyright 1990 Microelectronics and Computer Technology Corporation * Copyright 1990 Thomson Consumer Electronics, Inc. */ #include #include /*#include */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" char cwd[MAXPATHLEN]; /* current working directory */ static char file_listDir[MAXPATHLEN]; /* current directory of file list */ static char **filelist; static int file_count = 0; static Widget popupshell, popup_pane, file_list, path_label; static Widget popup_form, dialog; extern Widget button_shell; extern void load (); extern void save (); void File (); void CreateSaveDialog (void); static void CreateFilePopup (char *dir); static void save_file (); static void changeDir (); static int InList (); static void ScanDir (); static void DisplayMenuFile (); static void CreateFilePopup (); static void PopdownPopup (); /* Change working directory to 'dir'. modify static global variable, cwd, to keep track of current working directory */ static void changeDir (char *dir) { char str[512]; int i,j; if (!strcmp (dir, "./")) return; if (!strcmp (dir, "../")) { for(i=0, j=0; cwd[i]; i++) if (cwd[i] == '/') j++; if( j == 1 ) strcpy (str, "/"); else { char *c; c = rindex (cwd, '/'); *c = '\0'; strcpy (str, cwd); } } else { if (!strcmp (cwd, "/")) cwd[0] = '\0'; sprintf (str, "%s/%s", cwd, dir); str[strlen (str) - 1]='\0'; } strcpy(cwd, str); } /* Determines if a directory entry should appear in the file list. The files included in the menu are: .. and directories files not having a .c .h .o .dvi suffix */ static int InList (const struct dirent *directory_entry) { char pathname[512]; struct stat statbuf; struct dirent *entry = (struct dirent *) directory_entry; if (entry->d_name[0] == '.' && entry->d_name[1] != '.') return False; /* ignore hidden files */ if (strcmp (cwd, "")) /* give full path name */ sprintf (pathname, "%s/%s", cwd, entry->d_name); else strcpy (pathname, entry->d_name); if (stat (pathname, &statbuf) == -1) return False; if (statbuf.st_mode & S_IFDIR) { /* is directory */ strcat(entry->d_name, "/"); ++(entry->d_reclen); return True; } if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".dvi") + 1, ".dvi") == 0) return False; else if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".c") + 1, ".c") == 0) return False; else if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".o") + 1, ".o") == 0) return False; else if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".h") + 1, ".h") == 0) return False; else if (*(entry)->d_name == '.') return False; /* hidden file */ else { ++(entry->d_reclen); return True; } return False; } /* Scans the working directory for files selected by InList (), sorted alphabetically, and stored in an array of pointers to directory entries called namelist. The names of the selected files are stored in filelist. */ static void ScanDir (char *dir) { extern int alphasort(); struct dirent **name; int i,j; file_count = scandir (dir, &name, InList, alphasort); if (file_count == -1) { fprintf (stderr,"scandir: cannot open %s", dir); return; } if (filelist) { for (i=0; filelist[i]; i++) XtFree((char *)filelist[i]); XtFree((char *)filelist); } filelist = (char **) XtMalloc((file_count+1) * sizeof(char *)); for (j=0; jd_name); XtFree((char *)name[j]); } filelist[j] = NULL; XtFree((char *)name); return; } /* Callback for the list widget: select a directory, display contents select a readable file, try load it */ static void DisplayMenuFile (Widget w, Widget popupshell, XawListReturnStruct *call_data) { char *filename, path_and_filename[MAXPATHLEN]; XtPopdown (popupshell); filename = call_data->string; if (filename == NULL) return; if (filename[ strlen (filename) - 1] == '/') { changeDir (filename); XtDestroyWidget (popupshell); CreateFilePopup (cwd); /* create new list */ File (); /* pop it up */ } else { char *v[2], *flag = "m"; sprintf(path_and_filename,"%s/%s", cwd, filename); v[0] = flag; v[1] = path_and_filename; load (0L, 0L, v, 0); } } static void PopdownPopup(Widget w, XtPointer calldata, XtPointer clientdata) { XtPopdown (popupshell); } /* Creates a popup shell with its child being a vpane widget containing * a file menu label, a file menu containing file names returned from * ScanDir(), and a cancel command button. * When an item in the list is selected, DisplayMenuFile is called. */ static void CreateFilePopup(char *dir) { Widget toplevel = Player[0].X11Set.toplevel; Widget cancel; Arg args[1]; popupshell = XtCreatePopupShell ("Select File", transientShellWidgetClass, toplevel, NULL, 0); popup_pane = XtCreateManagedWidget ("popup_pane", panedWidgetClass, popupshell, NULL, 0); ScanDir (dir); strcpy (file_listDir, dir); path_label = XtCreateManagedWidget (dir, labelWidgetClass, popup_pane, NULL, 0); XtSetArg (args[0], XtNlist, filelist); file_list = XtCreateManagedWidget ("file_list", listWidgetClass, popup_pane, args, 1); XtAddCallback(file_list, XtNcallback, (XtCallbackProc) DisplayMenuFile, popupshell); XtSetArg (args[0], XtNresize, False); cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, popup_pane, args, 1); XtAddCallback(cancel, XtNcallback, PopdownPopup, popupshell); } /* called by MenuSelect (xgammon.c) */ void File(void) { Widget text_display = Player[0].X11Set.text_display; Arg args[2]; Position x, y, offset; Dimension width, path_width, border_width, text_display_width; static int have_cwd = 0; if (!have_cwd) { getcwd ((char *) cwd, MAXPATHLEN); have_cwd = 1; } CreateFilePopup (cwd); XtSetArg (args[0], XtNwidth, &width); XtSetArg (args[1], XtNborderWidth, &border_width); XtGetValues (file_list, args, 2); XtSetArg (args[0], XtNwidth, &path_width); XtGetValues (path_label, args, 1); XtSetArg (args[0], XtNwidth, &text_display_width); XtGetValues (text_display, args, 1); if (path_width > width) width = path_width; offset = (Position) (text_display_width - width - border_width); XtTranslateCoords (text_display, offset, 0, &x, &y); x = (0 > x) ? 0 : x; y = (0 > y) ? 0 : y; XtSetArg (args[0], XtNx, x); XtSetArg (args[1], XtNy, y); XtSetValues (popupshell, args, 2); XtPopup (popupshell, XtGrabNonexclusive); } void CreateSaveDialog(void) { Widget toplevel = Player[0].X11Set.toplevel; Arg args[3]; Position x, y; XtSetArg (args[0], XtNx, &x); XtSetArg (args[1], XtNy, &y); XtGetValues (Player[turn-1].X11Set.button_shell, args, 2); XtSetArg (args[0], XtNx, x+50); /* pure arbitrary */ XtSetArg (args[1], XtNy, y+40); popupshell = XtCreatePopupShell ("XGammon-Save", transientShellWidgetClass, toplevel, args, 2); popup_form = XtCreateManagedWidget ("popup_form", formWidgetClass, popupshell, NULL, 0); XtSetArg (args[0], XtNlabel, "save as:"); XtSetArg (args[1], XtNvalue, ""); dialog = XtCreateManagedWidget ("dialog", dialogWidgetClass, popup_form, args, 2); XawDialogAddButton(dialog, "save", save_file, (XtPointer) dialog); XawDialogAddButton(dialog, "don't", PopdownPopup, NULL); XtPopup (popupshell, XtGrabExclusive); } void save_file (Widget w, XtPointer calldata, XtPointer clientdata) { char *v[2], *flag = "m"; v[0] = flag; v[1] = XawDialogGetValueString(dialog); XtPopdown (popupshell); if (!strlen (v[1])) return; else save (0L, 0L, v, 0); } xgammon/src/gammon.h100644 764 144 7146 7013622221 13436 0ustar delleusers/* gammon.h Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #define BLACK 1 #define WHITE 2 #define COMPUTER 1 #define HUMAN 2 #define NORMAL 1 #define GAMMON 2 #define BACKGAMMON 4 #define COMPI_VS_COMPI 0 #define HUMAN_VS_COMPI 1 #define HUMAN_VS_HUMAN 2 #define LEARN 3 #define PLAY 4 /* for doubler() */ #define RESIGN END_OF_GAME #define END_OF_GAME 10 #define ACCEPT 11 #define ANSWER 1 #define OFFER 2 #define NODOUBLE 0 #define DOUBLE 1 #define FIRSTMOVE 2 /* special board areas */ #define BAR start_pin #define OTHER_BAR end_pin #define FINISHED (25+turn) #define BLACK_BAR 0 #define WHITE_BAR 25 #define DOUBLER 30 #define DICE 31 /* "flags" */ #define NORMAL_GAME 0 #define ROLLOUT 2 #define EDITED_POSITION 3 #define LOADED_POSITION 4 #define COMPUTER_TOURNAMENT 5 #define REPLAY_GAME 6 #define UPPER 1 #define LOWER 2 /* where to put the endgame database */ #ifndef DATABASE #define DATABASE "lib/xgammon.db" #endif extern int break_loop, initialize, end_of_game, end_of_tournament; extern int turn, other, pash, to_move, roll[4]; extern int direction, start_pin, end_pin; typedef struct _Doubler { int value; int owner; } Doubler; extern Doubler doubler; typedef struct _Board { Widget widget; Window window; GC gc; Pixmap pixmap; Pixmap pin_pixmap[41]; /* 32 for pin 9 for bar */ int width, height, stone_width; } BOARD; extern BOARD board; typedef struct _X11Set { Display *dpy; GC gc, stoneGC[2], boardGC, diceGC; Cursor cursor; XFontStruct *doubler_font, *small_font; XColor fg_col, bg_col; Widget toplevel; Widget button_shell, form; Widget quit, file_button, option_button, game_button, menu, entry; Widget text_display, tournament_display; BOARD board; } X11SET; extern X11SET X11Set; typedef void (*MoveFunc)(int with_double); struct _Player { char name[25]; int beginner_of_game; int type; /* human or compi */ int points; int color; int gammons; int backgammons; MoveFunc MoveFunction; BOARD board; X11SET X11Set; } Player[2]; struct _PinTable { int count; int color; } Pin[29], rollout_position[29]; /* 0, 25 = bar, 1 - 24 = board and 26, 27 finished[color] */ /* if you have the dice values 1 and 1 and all stones are on different pin and all completely movable there are almost 2000 possibilities to set your stones, and sice a move contains 4 single steps ... this following list is sturctured in parts of four nodes not concerning if the dice are equal */ typedef struct _Move { int from; int to; } MOVE; MOVE possible_moves[8000], *list; struct _move_hist { int from [4]; int to [4]; int hit [4]; struct _move_hist *next; }; extern struct _move_hist *move_hist; struct _Tournament { unsigned int game_number; unsigned int winning_point; } tournament; struct _RolloutSave { int turn; int doubler_value; int doubler_owner; int roll[2]; } rollout_save; FILE *endgame_database; extern void switch_turn(); xgammon/src/icon.h100644 764 144 5700 7013622221 13102 0ustar delleusers#define xgammon_width 65 #define xgammon_height 52 static char xgammon_bits[] = { 0xe1, 0xb8, 0x15, 0xff, 0x07, 0x03, 0x00, 0x12, 0x00, 0x15, 0x40, 0x96, 0xff, 0x0f, 0x03, 0x00, 0x12, 0x00, 0x09, 0x80, 0xd4, 0xff, 0x1f, 0x01, 0x00, 0x14, 0x00, 0x06, 0x00, 0xe9, 0xff, 0xbf, 0x01, 0x00, 0x2c, 0x00, 0x02, 0x00, 0xea, 0xff, 0xbf, 0x01, 0x00, 0x2c, 0x00, 0x02, 0x00, 0xea, 0xff, 0xbf, 0x01, 0x00, 0x2c, 0x00, 0x02, 0x00, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x28, 0x00, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0x2c, 0x00, 0x01, 0x00, 0xf4, 0xff, 0x7f, 0x01, 0x00, 0x44, 0x00, 0x01, 0x00, 0xe4, 0xff, 0x7f, 0x01, 0x00, 0x44, 0x00, 0x02, 0x00, 0xe6, 0xff, 0x7f, 0x01, 0x00, 0x44, 0x00, 0x06, 0x00, 0xe6, 0xff, 0x7f, 0x02, 0x00, 0x46, 0x00, 0x06, 0x00, 0xc6, 0xff, 0x5f, 0x06, 0x00, 0x46, 0x00, 0x0c, 0x00, 0x83, 0xff, 0x2f, 0x0c, 0x00, 0x83, 0x00, 0x08, 0x80, 0x82, 0xff, 0x27, 0x18, 0xc0, 0x82, 0x00, 0x18, 0x40, 0x82, 0xfe, 0x23, 0xe8, 0x3d, 0x82, 0x00, 0x18, 0x20, 0x82, 0xfc, 0x27, 0x08, 0x02, 0x82, 0x00, 0x18, 0x17, 0x83, 0xfe, 0x2f, 0x08, 0x00, 0x82, 0x00, 0xf0, 0x38, 0x03, 0xff, 0x1f, 0x10, 0x00, 0x01, 0x01, 0x10, 0x40, 0x81, 0xff, 0x3f, 0x10, 0x00, 0x01, 0x01, 0x18, 0x80, 0xc1, 0xff, 0x7f, 0x10, 0x00, 0x01, 0x01, 0x04, 0x00, 0xc1, 0xff, 0x7f, 0x10, 0x00, 0x01, 0x01, 0x02, 0x00, 0xc3, 0xff, 0x7f, 0x10, 0x00, 0x01, 0x01, 0x02, 0x00, 0xe2, 0xff, 0xff, 0x20, 0x80, 0x00, 0x00, 0x02, 0x00, 0xe2, 0xff, 0xff, 0x20, 0x80, 0x00, 0x00, 0x01, 0x00, 0xe4, 0xff, 0xff, 0x20, 0x80, 0x00, 0x00, 0x01, 0x00, 0xc4, 0xff, 0x7f, 0x20, 0x80, 0x00, 0x00, 0x01, 0x00, 0xc4, 0xff, 0x7f, 0x20, 0x80, 0x00, 0x00, 0x02, 0x00, 0xc2, 0xff, 0x7f, 0x20, 0x80, 0x00, 0x00, 0x02, 0x00, 0x82, 0xff, 0x3f, 0x40, 0x40, 0x00, 0x00, 0x02, 0x00, 0x03, 0xff, 0x1f, 0x40, 0x40, 0x00, 0x00, 0x04, 0x00, 0x01, 0xfe, 0x0f, 0x40, 0x40, 0x00, 0x00, 0x08, 0xc0, 0x00, 0xfc, 0x07, 0x40, 0x40, 0x00, 0x00, 0x10, 0x50, 0x00, 0xe4, 0x04, 0x40, 0x40, 0x00, 0x00, 0xe0, 0x38, 0x00, 0xfc, 0x03, 0x80, 0x20, 0x00, 0x00, 0x80, 0x27, 0x00, 0xfe, 0x03, 0x80, 0x20, 0x00, 0x00, 0xe0, 0x38, 0x80, 0xff, 0x0f, 0x80, 0x20, 0x00, 0x00, 0x10, 0x60, 0x80, 0xff, 0x0f, 0x80, 0x20, 0x00, 0x00, 0x08, 0x80, 0xc0, 0xff, 0x1f, 0x80, 0x20, 0x00, 0x00, 0x04, 0x00, 0xe1, 0xff, 0x3f, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0xe2, 0xff, 0x3f, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0xe2, 0xff, 0x3f, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0xe2, 0xff, 0x3f, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00, 0xe4, 0xff, 0x3f, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00, 0xe4, 0xff, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x00, 0xe4, 0xff, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x00, 0xc2, 0xff, 0x1f, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x82, 0xff, 0x0f, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x82, 0xff, 0x0f, 0x00, 0x0a, 0x00, 0x00, 0x04, 0x00, 0x01, 0xfe, 0x03, 0x00, 0x04, 0x00, 0x00, 0x08, 0x80, 0x00, 0xfc, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10, 0x40, 0x00, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00}; xgammon/src/load.l100644 764 144 34557 7013622221 13131 0ustar delleusers/* load.l Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ %{ #include #include #include #include #include "xgammon.h" #include "gammon.h" /* for some irix */ #ifdef irix #define usleep(a) sleep((a/10)) #endif char kind; char *player[2]; int games_replayed; static float fval, *inarray; static int count = 0, endarray; static int found_black, found_white; static int have_tournament = 0; static int wraped = 0; void replay_init_game (); void print_move (MOVE *m); extern float point_values[], prime_length_factor[]; extern int replaying; extern unsigned long delaytime; extern FILE * protokol_file; extern void ShowCompiMove (); extern void DrawEmptyBoard (); extern void DrawBoard (); extern void RedrawAllStones (); extern void RemoveStone (); extern void DrawDice (); extern void DrawDoubler (); extern void open_protokol (); %} %s LOAD %s LOAD_CONFIG %s REPLAY %s GETMOVE %s FIBSLOAD %% .*" and ".*" start a "[0-9]+" point match."\n { char *r = yytext; int i = 1; while (*(r+i) != ' ') i++; player[0] = malloc (i+1); strncpy (player[0], r, i); r = strstr (yytext, " and ") + 5; i = 1; while (*(r+i) != ' ') i++; player[1] = malloc (i+1); strncpy (player[1], r, i); r = r + i + 9; tournament.winning_point = atoi (r); #ifdef DEBUG_REPLAY fprintf (stderr, "player: %s %s\n", player[0], player[1]); fprintf (stderr, "winning_point: %d\n", tournament.winning_point); #endif AppendDialogText (LOWER, yytext); } [A-Za-z0-9]*" rolls "[1-6]" and "[1-6]"."\n { AppendDialogText (LOWER, yytext); roll[0] = *(yytext+yyleng-9) - '0'; roll[1] = *(yytext+yyleng-3) - '0'; if (strncmp (player[1], yytext, strlen (player[1])) == 0) turn = BLACK; else if (strncmp (player[0], yytext, strlen (player[0])) == 0) turn = WHITE; #ifdef DEBUG_REPLAY fprintf (stderr,"roll %c %c turn %d\n", *(yytext+yyleng-9), *(yytext+yyleng-3), turn); #endif DrawDice (turn); XSync (Player[0].X11Set.dpy, 0); while(1) { XEvent event; XtAppNextEvent(app_con, &event); if (event.type == ButtonRelease && event.xbutton.window == Player[0].X11Set.board.window) { XtDispatchEvent (&event); break; } else if (event.type == KeyRelease && event.xkey.window == Player[0].X11Set.board.window) { break; } XtDispatchEvent(&event); } } [A-Za-z0-9]*" rolled "[1-6]", "[A-Za-z0-9]*" rolled "[1-6]\n[a-zA-Z0-9]*" makes the first move."\n { char *r = yytext; count = 0; AppendDialogText (LOWER, yytext); while (*r != ',') r++; roll[0] = *(r-1) - '0'; while (*r != '\n') r++; roll[1] = *(r-1) - '0'; #ifdef DEBUG_REPLAY fprintf (stderr, "initial roll %s", yytext ); fprintf (stderr, "roll %d %d\n", roll[0], roll[1]); #endif if (games_replayed%2 == 0) { char *p; p = player[0]; player[0] = player[1]; player[1] = p; } games_replayed++; if (strncmp ((r+1), player[0], strlen (player[0])) == 0) turn = BLACK; else turn = WHITE; #ifdef DEBUG_REPLAY fprintf (stderr ,"turn %d\n", turn); #endif replay_init_game (); } [a-zA-Z0-9]*" doubles."\n { if (strncmp (player[0], yytext, strlen(player[0])) == 0) { doubler.owner = BLACK; } else if (strncmp (player[1], yytext, strlen(player[1])) == 0) { doubler.owner = WHITE; } AppendDialogText (LOWER, yytext); XSync (Player[0].X11Set.dpy, 0); while(1) { XEvent event; XtAppNextEvent(app_con, &event); if (event.type == ButtonRelease && event.xbutton.window == Player[0].X11Set.board.window) { XtDispatchEvent(&event); break; } else if (event.type == KeyRelease && event.xkey.window == Player[0].X11Set.board.window) { break; } XtDispatchEvent(&event); } } [a-zA-Z0-9]*" accepts the double."\n { if (strncmp (player[0], yytext, strlen(player[0])) == 0 || strncmp (player[1], yytext, strlen(player[1])) == 0) { doubler.value *= 2; DrawDoubler (doubler.value, doubler.owner); #ifdef DEBUG_REPLAY fprintf (stderr,"doubling accepted\n"); #endif } AppendDialogText (LOWER, yytext); } "gives up." { AppendDialogText (LOWER, yytext); #ifdef DEBUG_REPLAY fprintf (stderr,"doubling resign\n"); #endif } [a-zA-Z0-9]*" moves " { if (strncmp (player[0], yytext, strlen(player[0]) - 1) == 0) BEGIN GETMOVE; else if (strncmp (player[1], yytext, strlen(player[1]) - 1) == 0) BEGIN GETMOVE; AppendDialogText (LOWER, yytext); count = 0; #ifdef DEBUG_REPLAY fprintf (stderr,"switching to getmove\n"); #endif } [a-zA-Z0-9]*" can't move." { AppendDialogText (LOWER, yytext); if (turn == BLACK) turn = WHITE; else turn = BLACK; } ([1-9]|1[0-9]|2[0-4])"-"([1-9]|1[0-9]|2[0-4]) { char *to = yytext; int f, t; AppendDialogText (LOWER, yytext); f = atoi (yytext); turn = Pin[f].color; while (*to != '-') to++; to++; t = atoi (to); #ifdef DEBUG_REPLAY fprintf (stderr,"from %d to %d\n", f, t); #endif RemoveStone (f); if (Pin[t].count == 1 && Pin[t].color != turn) { PutStone (Pin[t].color, (turn == BLACK) ? WHITE_BAR : BLACK_BAR); RemoveStone (t); } PutStone (turn, t); XSync (Player[0].X11Set.dpy, 0); usleep (delaytime); } "bar-"([1-9]|1[0-9]|2[0-4]) { int f, t, f_color; AppendDialogText (LOWER, yytext); t = atoi ((yytext+4)); if (t < 7) { f_color = BLACK; f = BLACK_BAR; turn = BLACK; /* for RemoveStone () */ } else { f_color = WHITE; f = WHITE_BAR; turn = WHITE; } #ifdef DEBUG_REPLAY fprintf (stderr,"from (bar) %d to %d\n", f, t); #endif RemoveStone (f); if (Pin[t].count == 1 && Pin[t].color != f_color) { PutStone (Pin[t].color, (f_color == BLACK) ? WHITE_BAR : BLACK_BAR); RemoveStone (t); } PutStone (f_color, t); XSync (Player[0].X11Set.dpy, 0); usleep (delaytime); } ([1-9]|1[0-9]|2[0-4])"-off" { int f, t; AppendDialogText (LOWER, yytext); f = atoi (yytext); if (Pin[f].color == BLACK) { t = 25+BLACK; turn = BLACK; } else { t = 25+WHITE; turn = WHITE; } #ifdef DEBUG_REPLAY fprintf (stderr, "from %d to %d (off)\n", f, t); #endif RemoveStone (f); PutStone (turn, t); XSync (Player[0].X11Set.dpy, 0); usleep (delaytime); } [a-zA-Z0-9]* { AppendDialogText (LOWER, yytext); } [a-zA-Z0-9]* { AppendDialogText (LOWER, yytext); } . { AppendDialogText (LOWER, yytext); } . { AppendDialogText (LOWER, yytext); } \n { AppendDialogText (LOWER, "\n"); } \n { AppendDialogText (LOWER, "\n"); BEGIN REPLAY; } "turn: "(black|white) { if (strncmp( yytext+6, "black", 5) == 0) { turn = BLACK; other = WHITE; direction = 1; start_pin = 0; end_pin = 25; Player[0].beginner_of_game = 1; Player[1].beginner_of_game = 0; } if (strncmp( yytext+6, "white", 5) == 0) { turn = WHITE; other = BLACK; direction = -1; start_pin = 25; end_pin = 0; Player[1].beginner_of_game = 1; Player[0].beginner_of_game = 0; } } "dice values: "[1-6]" "[1-6] { roll[0] = *(yytext+13) - '0'; roll[1] = *(yytext+15) - '0'; roll[0] *= direction; roll[1] *= direction; if (roll[0] == roll[1]) { roll[3] = roll[0]; roll[2] = roll[1]; to_move = 4; pash = 1; } else { roll[2] = roll[3] = 0; pash = 0; to_move = 2; } } "doubler value: "(1|2|4|8|16|32|64) { doubler.value = atoi((yytext+15)); } "last doubler: "(none|black|white) { if (*(yytext+14) == 'b') doubler.owner = BLACK; else if (*(yytext+14) == 'w') doubler.owner = WHITE; else doubler.owner = 0; } "on bar: "(black|white)": "[0-9]+", "(black|white)": "[0-9]+\n { char *r = yytext+8; r = strstr (yytext, "black: ") + strlen ("black: "); if ((Pin[0].count = atoi(r))) Pin[0].color = BLACK; r = strstr (yytext, "white: ") + strlen ("white: "); if ((Pin[25].count = atoi(r))) Pin[25].color = WHITE; found_black += Pin[0].count; found_white += Pin[25].count; } "pin "[0-9]+": "[0-9]+" "(black|white) { int p, m; char *r = yytext+4; p = atoi(r); while (*r != ' ') r++; r++; m = atoi (r); while (*r != ' ') r++; r++; if (strncmp(r, "black", 5) == 0) { Pin[p].color = BLACK; found_black += m; } else if (strncmp(r, "white", 5) == 0) { Pin[p].color = WHITE; found_white += m; } Pin[p].count = m; } ("money-game"|"best of "[0-9]+|[0-9]+" points")" match between "[a-zA-Z0-9]*" and "[a-zA-Z0-9]*":"\n { int i = 1; char *r = strstr(yytext, "between") + 8; if (kind == 'g') { while (*(r+i) != ' ') i++; strncpy (Player[0].name, r, i-1); *(Player[0].name+i) = '\0'; r = r+i+5; i=1; while (*(r+i) != ':') i++; strncpy (Player[1].name, r, i); *(Player[0].name+i) = '\0'; have_tournament = 1; if (strncmp (yytext, "money-game", 10) == 0) { sprintf (add_text, "%s and %s play a money-game match", Player[0].name, Player[1].name); tournament.winning_point = 0; gammon_resource.moneygame = 1; } else { sprintf (add_text, "%s and %s play a %d points match", Player[0].name, Player[1].name, tournament.winning_point); gammon_resource.moneygame = 0; gammon_resource.winat = tournament.winning_point = atoi(yytext); } AppendDialogText (UPPER, add_text); } } [a-zA-Z0-9]*" has "[0-9]+"points, "[a-zA-Z0-9]*" has "[0-9]+"points."\n { char *r = strstr (yytext, "has") + 4, *p; if (strncmp (yytext, Player[0].name, strlen(Player[0].name)) == 0) Player[0].points = atoi(yytext); else if (strncmp (yytext, Player[1].name, strlen(Player[1].name)) == 0) Player[1].points = atoi(yytext); while (*r != ',') r++; r+=2; if (strncmp (r, Player[0].name, strlen(Player[0].name)) == 0) { p = strstr(r, "has") + 4; Player[0].points = atoi(p); } else if (strncmp (r, Player[1].name, strlen(Player[1].name)) == 0) { p = strstr(r, "has") + 4; Player[1].points = atoi(p); } sprintf (add_text, "%s points: %d, %s points: %d", Player[1].name, Player[1].points, Player[0].name, Player[0].points); AppendDialogText (UPPER, add_text); } "point values:" { count = 0; endarray = 24; inarray = (point_values+1); } "prime length factors:" { if (count < 24) { fprintf (stderr, "incomplete array: point_values\n"); } count = 0; endarray = 8; inarray = prime_length_factor; } [0-9]*"."[0-9]* { fval = atof (yytext); if ((count ++) >= endarray) { fprintf (stderr, "too many float values for array %s\n", (endarray == 24) ? "point_values" : "prine_length_factor"); } else { *(inarray++) = fval; } } . ; \n ; %% void load (Widget w, XEvent *e, String *vector, Cardinal *count) { FILE *f; char * filename = "xgammon.save"; int i; if (*vector[0] == 'p') kind = 'p'; /* position */ else if (*vector[0] == 'g') kind = 'g'; /* game */ else if (*vector[0] == 'r') kind = 'r'; /* replay */ else if (*vector[0] == 'm') { /* menu */ if (replaying) kind = 'r'; else kind = 'g'; filename = vector[1]; } f = fopen (filename,"r"); if (!f) { AppendDialogText (LOWER, "Couldn't open save file for reading, sorry!\n"); return; } for (i=0; i<29; i++) { Pin[i].color = 0; Pin[i].count = 0; } found_black = found_white = 0; if (!wraped) { yyin = f; wraped = 1; } else { yyin = f; YY_NEW_FILE; } count = 0; have_tournament = 0; if (kind != 'r') BEGIN LOAD; else { BEGIN REPLAY; games_replayed = 0; } Player[0].points = Player[1].points = 0; if (!gammon_resource.rollout) { AppendDialogText (LOWER, "\ngame aborted\n"); } if (kind != 'r') AppendDialogText (LOWER, "\ntournament restart\nloading position\n\n"); yylex(); fclose (f); if (!replaying) { if (found_white<15) Pin[25+WHITE].count = 15 - found_white; if (found_black<15) Pin[25+BLACK].count = 15 - found_black; if (turn == BLACK) { Player[0].beginner_of_game = 1; Player[1].beginner_of_game = 0; } else { Player[0].beginner_of_game = 0; Player[1].beginner_of_game = 1; } } else { end_of_game = 1; end_of_tournament = 1; break_loop = REPLAY_GAME; initialize = REPLAY_GAME; replaying = 0; return; } if (!gammon_resource.rollout) { DrawEmptyBoard (); DrawBoard (); RedrawAllStones (); DrawDice (turn); DrawDoubler (doubler.value, doubler.owner); sprintf (add_text, "%s rolls %d and %d.\n", Player[turn-1].name, roll[0], roll[1]); AppendDialogText (LOWER, add_text); break_loop = initialize = LOADED_POSITION; end_of_game = 1; } } void print_move (MOVE *m) { int i; for (i=0; i<4; i++) fprintf (stderr,"%d %d\t", (m+i)->from, (m+i)->to); fprintf (stderr,"\n"); } void replay_init_game (void) { int i; DrawEmptyBoard (); DrawBoard (); for (i=0; i<29; i++) { Pin[i].count=0; Pin[i].color=0; } Pin[ 1].color = BLACK; Pin[ 1].count = 2; Pin[12].color = BLACK; Pin[12].count = 5; Pin[17].color = BLACK; Pin[17].count = 3; Pin[19].color = BLACK; Pin[19].count = 5; Pin[ 6].color = WHITE; Pin[ 6].count = 5; Pin[ 8].color = WHITE; Pin[ 8].count = 3; Pin[13].color = WHITE; Pin[13].count = 5; Pin[24].color = WHITE; Pin[24].count = 2; RedrawAllStones (); Pin[(25+BLACK)].color = BLACK; Pin[(25+WHITE)].color = WHITE; doubler.value = 1; doubler.owner = 0; DrawDoubler (doubler.value, doubler.owner); } void load_config (void) { FILE *f; if (!(f = fopen ("xgammon.config", "r"))) { fprintf (stderr, "Couldn't open config file for reading, sorry!\n"); return; } if (!wraped) { yyin = f; wraped = 1; } else { yyin = f; YY_NEW_FILE; } BEGIN LOAD_CONFIG; yylex(); if (count < 8) { fprintf (stderr, "incomplete array: prime_length_factors\n"); } count = 0; fclose (f); } xgammon/src/makefile.1100644 764 144 1563 7020333665 13654 0ustar delleusers #CFLAGS = -Wall -O3 CFLAGS = -g -static CC = gcc LDLIBS = -L/usr/X11R6/lib -lXaw -lXmu -lXext -lXt -lX11 -lm -lfl SRCS = xgammon.c drawing.c allow.c load.c save.c decision.c diawin.c \ misc.c popup.c filemenu.c edit.c rollout.c OBJS = xgammon.o drawing.o allow.o load.o save.o decision.o diawin.o \ misc.o popup.o filemenu.o edit.o rollout.o xgammon: $(OBJS) $(CC) -o xgammon $(OBJS) $(LDLIBS) load.c: load.l flex load.l mv lex.yy.c load.c clean: rm -f *.o rm -f xgammon database: @echo "compile database creating program" $(CC) $(CFLAGS) ../lib/db.c -o ../lib/db @echo "done.." @echo "starting it" @echo "creating the database needed about 3 - 5 hours" @echo "on an old 386sx, where the project was born :-)" @echo "I will tell you, when the database is completed" cd ../lib; db || rm -rf xgammon.db; cd ../src @echo "" @echo "database completed now!" xgammon/src/misc.c100644 764 144 50211 7013622221 13115 0ustar delleusers/* misc.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #include #include #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" extern Cursor gammon_cursor; extern XColor fg_col, bg_col; /* gammon_cursor colors */ extern int from_pin; extern int width, stone_width, height; extern int done_yet, done_hit, current_hit[4]; extern unsigned long delaytime; extern FILE *protokol_file; int moves_set = 0; char protokol_file_name[50]; /* for some irix */ #ifdef irix #define usleep (a) sleep ((a/10)) #endif extern void set_game_kind (); /* decision.c */ extern float evaluate (); /* popup.c */ extern void Info (); /* drawing.c */ extern void DrawDice (); extern void DrawDoubler (); extern void RedrawAllStones (); extern void DrawEmptyBoard (); extern void DrawBoard (); extern void DrawDoubler (); struct _move_hist *move_hist = NULL; long int NaufM[16][7]; long int Binomial[7][7]; void switch_turn (void) { Display *dpy = Player[0].X11Set.dpy; if (turn==BLACK) { turn = WHITE; other = BLACK; direction = -1; start_pin = 25; end_pin = 0; } else { turn = BLACK; other = WHITE; direction = 1; start_pin = 0; end_pin = 25; } done_hit = 0; /* make the cursor look like the stones you move */ if (Player[0].type == HUMAN && Player[1].type == HUMAN) { if (!gammon_resource.other_display) { if (turn == BLACK) XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.fg_col, &Player[0].X11Set.bg_col); else XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.bg_col, &Player[0].X11Set.fg_col); } /* else nothing to recolor */ } } void RollDice (void) { roll[0] = (rand ()%6 + 1) * direction; roll[1] = (rand ()%6 + 1) * direction; if (roll[0] != roll[1]) { roll[2] = 0; /* sure and necessary */ roll[3] = 0; to_move = 2; pash = 0; } else { roll[2] = roll[0]; roll[3] = roll[1]; to_move = 4; pash = 1; } sprintf (add_text, "%s rolls %d and %d.\n", Player[turn-1].name, abs (roll[0]), abs (roll[1])); AppendDialogText (LOWER, add_text); } int end_of_game_test (int color) { int i, k; for (i=start_pin+direction*19; i!=start_pin+direction*25; i+=direction) { if (Pin[i].color == turn) return 0; } /* if we get here lookup if we have to count doubler two or three times */ if (Pin[OTHER_BAR].count) { /* a stone of the opponent on BAR */ doubler.value *= 3; Player[turn-1].backgammons ++; return BACKGAMMON; } for (i = end_pin-direction; i != end_pin-direction*7; i-=direction) { /* a stone in the opponents first quarter */ if (Pin[i].color == other) { doubler.value *= 3; Player[turn-1].backgammons ++; return BACKGAMMON; } } /* other has no stone off */ k = Pin[OTHER_BAR].count; for (i=1; i<25; i++) if (Pin[i].color == other) k += Pin[i].count; if (k == 15) { doubler.value *=2; Player[turn-1].gammons ++; return GAMMON; } return NORMAL; } int complete_blockade (void) { int i; for (i=start_pin+direction; i!=start_pin+direction*7; i+=direction) { if (Pin[i].count == 0 || Pin[i].color == turn || (Pin[i].color != turn && Pin[i].count < 2)) return 0; } return 1; } /* this function checkes, if you make a multible move, if you have to hit an opponents stone on the run */ int have_to_hit (int from, int to) { if (!pash) { if (Pin[from + roll[0]].color == other && Pin[from + roll[1]].color == other) { if (Pin[from + roll[0]].count == 1 && Pin[from + roll[1]].count == 1) { Info ("Please decide witch stone you want to hit"); return 1; } else if (Pin[from + roll[0]].count == 1) { RemoveStone (from + roll[0]); PutStone (other, OTHER_BAR); return 0; } else if (Pin[from + roll[1]].count == 1){ RemoveStone (from + roll[1]); PutStone (other, OTHER_BAR); return 0; } } else return 0; /* will not hit by default */ } else { int i; for (i=1; i<4; i++) { /* to_pin is checked by PlaceStone */ if ((from + i*roll[0]) == to) break; if (Pin[from + i*roll[0]].color == other && ! ((turn==BLACK) ? from + i*roll[0] >= end_pin : from + i*roll[0] <= end_pin)) { RemoveStone (from + i*roll[0]); PutStone (other, OTHER_BAR); } } } return 0; } void free_move_hist (void) { struct _move_hist *d, *h = move_hist; while (h) { d = h; h = h->next; free (d); } } void init_game (void) { int i; from_pin = 0; done_yet = 0; done_hit = 0; if (initialize == NORMAL_GAME || initialize == COMPUTER_TOURNAMENT) { for (i=0; i<29; i++) { Pin[i].count=0; Pin[i].color=0; } Pin[ 1].color = BLACK; Pin[ 1].count = 2; Pin[12].color = BLACK; Pin[12].count = 5; Pin[17].color = BLACK; Pin[17].count = 3; Pin[19].color = BLACK; Pin[19].count = 5; Pin[ 6].color = WHITE; Pin[ 6].count = 5; Pin[ 8].color = WHITE; Pin[ 8].count = 3; Pin[13].color = WHITE; Pin[13].count = 5; Pin[24].color = WHITE; Pin[24].count = 2; Pin[ (25+BLACK)].color = BLACK; /* init BARS */ Pin[ (25+WHITE)].color = WHITE; doubler.value = 1; doubler.owner = 0; tournament.game_number++; if (Player[0].type == HUMAN && Player[1].type == HUMAN) sprintf (add_text,"Starting a new game with %s, ", Player[0].name); else if (Player[0].type == COMPUTER && Player[1].type == COMPUTER) sprintf (add_text,"Starting a new game with xgammon (0)\n"); else if (Player[0].type == HUMAN) sprintf (add_text,"Starting a new game with %s\n", Player[0].name); else sprintf (add_text,"Starting a new game with %s\n", Player[1].name); AppendDialogText (LOWER, add_text); direction = 1; /* get beginner of game */ do { roll[0] = (rand ()%6 + 1); roll[1] = (rand ()%6 + 1); } while (roll[0] == roll[1]); roll[2] = 0; roll[3] = 0; to_move = 2; pash = 0; if (roll[1] > roll[0]) { /* white begins */ turn = BLACK; switch_turn (); /* switch_turn sets turn to white and all the other vars */ roll[0] *= direction; /* must a be */ roll[1] *= direction; roll[2] *= direction; roll[3] *= direction; Player[1].beginner_of_game = 1; Player[0].beginner_of_game = 0; } else if (roll[0] > roll[1]) { turn = WHITE; switch_turn (); Player[0].beginner_of_game = 1; Player[1].beginner_of_game = 0; } DrawEmptyBoard (); DrawBoard (); RedrawAllStones (); DrawDoubler (doubler.value, doubler.owner); sprintf (add_text, "%s rolled %d, %s rolled %d\n", Player[0].name, abs (roll[0]), Player[1].name, abs (roll[1])); AppendDialogText (LOWER, add_text); if (roll[0] < 0) sprintf (add_text, "%s makes the first move.\n", Player[1].name); else sprintf (add_text, "%s makes the first move.\n\n", Player[0].name); AppendDialogText (LOWER, add_text); DrawDice (turn); break_loop = 0; } /* end initialize */ if (move_hist) free_move_hist (); move_hist = NULL; } void AppendMoveString (MOVE *m) { struct _move_hist *new; char f[5], t[5]; int i; if (!m || !(m->from || m->to)) { sprintf (add_text, "%s can't move.\n\n", Player[turn-1].name); } else { sprintf (add_text, "%s moves ", Player[turn-1].name); for (i=0; ifrom != BAR) sprintf (f,"%d-", (m+i)->from); else strcpy (f,"bar-"); strcat (add_text, f); if ((m+i)->to != end_pin) sprintf (t,"%d ", (m+i)->to); else strcpy (t,"off "); strcat (add_text, t); } strcat (add_text, ".\n\n"); } AppendDialogText (LOWER, add_text); if (!m) { XSync (Player[0].X11Set.dpy, 0); if (gammon_resource.other_display) { XSync (Player[1].X11Set.dpy, 0); } usleep (delaytime); } moves_set ++; new = (struct _move_hist *) malloc (sizeof (struct _move_hist)); new->next = move_hist; move_hist = new; if (m) { for (i=0; ifrom[i] = (m+i)->from; if ((m+i)->to != end_pin) move_hist->from[i] = (m+i)->to; else move_hist->to[i] = FINISHED; move_hist->hit[i] = current_hit[i]; } for (i=to_move; i<4; i++) { move_hist->from[i] = 0; move_hist->to[i] = 0; move_hist->hit[i] = 0; } } else { for (i=0; i<4; i++) { move_hist->from[i] = 0; move_hist->to[i] = 0; move_hist->hit[i] = 0; } } } XPoint PinToPosition (int pin) { XPoint p; if (pin == BAR || pin == OTHER_BAR) p.x = width/2 - stone_width/2; else if (pin == FINISHED) p.x = width - stone_width; else if (pin < 7) p.x = width - (pin + 1) * stone_width; else if (pin < 13) p.x = width - (pin + 1) * stone_width - stone_width; else if (pin < 19) p.x = width - (26 - pin) * stone_width - stone_width; else if (pin < 25) p.x = width - (26 - pin) * stone_width; if (pin == FINISHED) p.y = Pin[FINISHED].count * height/2/15; else if (Pin[pin].count < 5) p.y = Pin[pin].count * stone_width; else if (Pin[pin].count < 9) p.y = (Pin[pin].count-5) * stone_width + stone_width/2; else if (Pin[pin].count < 13) p.y = (Pin[pin].count-9) * stone_width + stone_width/4; else p.y = (Pin[pin].count-13) * stone_width + stone_width*3/4; /* for upper half of board */ if (((pin == BAR || pin == OTHER_BAR) && Pin[pin].color == WHITE) || (pin == FINISHED && turn == BLACK) || (pin > 12 && pin != FINISHED)) p.y = height - stone_width - p.y; return p; } int EventToPin (int x, int y) { int p; p = (width - x) / stone_width; switch (p) { case 0: return end_pin; break; case 7: return BAR; break; case 14: return DOUBLER; break; } if ((y - height/2) < 0) { /* upper part of the board */ if (p > 6) return p-1; /* left of bar */ else return p; /* right of bar */ } else { /* lower part of the board */ p = 25 - p; if (p < 19) return p+1; /* left of bar */ else return p; /* right of bar */ } } void AddResult (int whom) { char *gammon_str; Player[whom-1].points += doubler.value; switch (end_of_game) { case NORMAL: gammon_str = ""; break; case GAMMON: gammon_str = "gammon"; break; case BACKGAMMON: gammon_str = "backgammon"; break; } sprintf (add_text, "%s wins the %d. game %s and gets %d points.\n", Player[whom-1].name, tournament.game_number, gammon_str, doubler.value); AppendDialogText (UPPER, add_text); sprintf (add_text, "%s wins the game %s and gets %d points.\n", Player[whom-1].name, gammon_str, doubler.value); AppendDialogText (LOWER, add_text); if (gammon_resource.moneygame) sprintf (add_text, "score in moneygame match: %s-%d %s-%d\n\n", Player[0].name, Player[0].points, Player[1].name, Player[1].points); else if (gammon_resource.winat) sprintf (add_text, "score in %d point match: %s-%d %s-%d\n\n", tournament.winning_point, Player[0].name, Player[0].points, Player[1].name, Player[1].points); AppendDialogText (LOWER, add_text); AppendDialogText (UPPER, add_text); if (gammon_resource.moneygame) return; else if (gammon_resource.winat && Player[whom-1].points >= tournament.winning_point) sprintf (add_text, "%s wins the %d point match %d-%d .\n\n", Player[whom-1].name, tournament.winning_point, Player[0].points, Player[1].points); AppendDialogText (LOWER, add_text); AppendDialogText (UPPER, add_text); AppendDialogText (UPPER, "end of tournament\n\n"); } long int fak (int n) { if (n <= 1) return (1); else return (n * fak (n - 1)); } long int binomial (int n, int m) { return (fak (n) / fak (m) / fak (n - m)); } long int naufm (int n, int m) { if (n < m) return (0); if (m == 1) return (1); return (naufm (n - 1, m) + naufm (n - 1, m - 1)); } void set_naufm () { int i, j; for (i = 1; i < 16; i++) { for (j = 1; j < 7; j++) { NaufM[i][j] = naufm (i, j); }} } void set_binom () { int i, j; for (i = 1; i < 7; i++) { for (j = 1; j < 7; j++) { Binomial[i][j] = binomial (i, j); }} } /* PositionNumber: this function calculates out of a given endgame position the corresponding position number in the endgame database, in a running game pin 6 is set as aim for stones not in the homeboard */ long int PositionNumber (int STARTPIN, int color) { int pin[7]; int sum = 0, s, i, stones; int start, nextpin, local_direction, local_endpin; long int number = 0L; if (color == turn) { local_direction = direction; local_endpin = end_pin; } else { local_direction = -1 * direction; local_endpin = start_pin; } pin[0] = 0; for (i = 1; i < 7; i++) { if (Pin[local_endpin - i * local_direction].color == color) pin[i] = Pin[local_endpin - i * local_direction].count; else pin[i] = 0; } for (i = 1; i < 7; i++) sum += pin[i]; /* put all stones on the 6. pin */ pin[6] += 15 - sum - Pin[25 + color].count; sum = 0; for (i = STARTPIN + 1; i < 7; i++) sum += pin[i]; if (sum == 0) return (0); i = STARTPIN + 1; while (pin[i] == 0 && i < 7) i++; nextpin = i - STARTPIN; number += nextpin; for (start = STARTPIN; start < STARTPIN + nextpin; start++) { for (stones = 1; stones < sum; stones++) { for (s = 1; s < 6 - start + 1; s++) { number += Binomial[6 - start][s] * NaufM[stones][s]; } } } number += PositionNumber (STARTPIN + nextpin, color); return (number); } MOVE *find_best_move () { MOVE *move_return = NULL, *pm = possible_moves; int i, hit[4]; float maxvalue = -10000.0, value; while (pm != list) { for (i = 0; i < to_move; i++) { /* do move */ if ((pm + i)->from + (pm + i)->to) { hit[i] = 0; Pin[ (pm + i)->from].count--; if (!Pin[ (pm + i)->from].count) Pin[ (pm + i)->from].color = 0; if ((pm + i)->to == end_pin) Pin[FINISHED].count++; else { if (Pin[ (pm + i)->to].color == other) { Pin[ (pm + i)->to].color = turn; hit[i] = 1; Pin[OTHER_BAR].count++; Pin[OTHER_BAR].color = other; } else { Pin[ (pm + i)->to].count++; Pin[ (pm + i)->to].color = turn; } } } } #ifdef DEBUG_EVALUATE { int k; MOVE *d = pm; printf ("\n"); for (k = 0; k < 4; k++) { printf ("%2d -> %2d ", d->from, d->to); d++; } printf ("\n"); } #endif value = evaluate (turn); if (value > maxvalue) { maxvalue = value; move_return = pm; } for (i = to_move - 1; i > -1; i--) { /* undo move */ if ((pm + i)->from + (pm + i)->to) { Pin[ (pm + i)->from].count++; Pin[ (pm + i)->from].color = turn; if (hit[i]) { Pin[ (pm + i)->to].color = other; Pin[OTHER_BAR].count--; if (!Pin[OTHER_BAR].count) Pin[OTHER_BAR].color = 0; } else { if ((pm + i)->to == end_pin) Pin[FINISHED].count--; else { Pin[ (pm + i)->to].count--; if (!Pin[ (pm + i)->to].count) Pin[ (pm + i)->to].color = 0; } } } } pm += 4; } #ifdef DEBUG_EVALUATE { int k; MOVE *d = move_return; for (k = 0; k < 4; k++) { printf ("%2d -> %2d ", d->from, d->to); d++; } printf ("\n this is the best move with vlaue %f\n",maxvalue); } #endif return (move_return); } void maildump (void) { FILE *maildumpfile; int i, j; maildumpfile = fopen ("xgammon.maildump", "w"); if (!maildumpfile) { Info ("Couldn't open dump file!\nSorry."); return; } fprintf (maildumpfile, "\n\n"); fprintf (maildumpfile, " 13 14 15 16 17 18 19 20 21 22 23 24\n +------------------------------------------+ X: - score: %d\n", Player[1].points); for (i=0; i<4; i++) { fprintf (maildumpfile, " |"); for (j=12; j>6; j--) { if (Pin[j].color == WHITE && Pin[j].count >= i+1) fprintf (maildumpfile, " X "); else if (Pin[j].color == BLACK && Pin[j].count >= i+1) fprintf (maildumpfile, " O "); else fprintf (maildumpfile, " "); } fprintf (maildumpfile, "| | "); for (j=6; j>0; j--) { if (Pin[j].color == WHITE && Pin[j].count >= i+1) fprintf (maildumpfile, " X "); else if (Pin[j].color == BLACK && Pin[j].count >= i+1) fprintf (maildumpfile, " O "); else fprintf (maildumpfile, " "); } fprintf (maildumpfile, "|\n"); } fprintf (maildumpfile, " |"); for (j=12; j>6; j--) { if (Pin[j].color == WHITE && Pin[j].count == 5) fprintf (maildumpfile, " X "); else if (Pin[j].color == WHITE && Pin[j].count > 5) fprintf (maildumpfile, "%2d ", Pin[j].count); else if (Pin[j].color == BLACK && Pin[j].count == 5) fprintf (maildumpfile, " O "); else if (Pin[j].color == BLACK && Pin[j].count > 5) fprintf (maildumpfile, "%2d ", Pin[j].count); else fprintf (maildumpfile, " "); } fprintf (maildumpfile, "| | "); for (j=6; j>0; j--) { if (Pin[j].color == WHITE && Pin[j].count == 5) fprintf (maildumpfile, " X "); else if (Pin[j].color == WHITE && Pin[j].count > 5) fprintf (maildumpfile, "%2d ", Pin[j].count); else if (Pin[j].color == BLACK && Pin[j].count == 5) fprintf (maildumpfile, " O "); else if (Pin[j].color == BLACK && Pin[j].count > 5) fprintf (maildumpfile, "%2d ", Pin[j].count); else fprintf (maildumpfile, " "); } fprintf (maildumpfile, "|\n"); fprintf (maildumpfile, " v| |BAR| | "); if (gammon_resource.moneygame) fprintf (maildumpfile, "money-game\n"); else fprintf (maildumpfile, "%d-point match\n", gammon_resource.winat); fprintf (maildumpfile, " |"); for (j=13; j<19; j++) { if (Pin[j].color == WHITE && Pin[j].count == 5) fprintf (maildumpfile, " X "); else if (Pin[j].color == WHITE && Pin[j].count > 5) fprintf (maildumpfile, "%2d ", Pin[j].count); else if (Pin[j].color == BLACK && Pin[j].count == 5) fprintf (maildumpfile, " O "); else if (Pin[j].color == BLACK && Pin[j].count > 5) fprintf (maildumpfile, "%2d ", Pin[j].count); else fprintf (maildumpfile, " "); } fprintf (maildumpfile, "| | "); for (j=19; j<25; j++) { if (Pin[j].color == WHITE && Pin[j].count == 5) fprintf (maildumpfile, " X "); else if (Pin[j].color == WHITE && Pin[j].count > 5) fprintf (maildumpfile, "%2d ", Pin[j].count); else if (Pin[j].color == BLACK && Pin[j].count == 5) fprintf (maildumpfile, " O "); else if (Pin[j].color == BLACK && Pin[j].count > 5) fprintf (maildumpfile, "%2d ", Pin[j].count); else fprintf (maildumpfile, " "); } fprintf (maildumpfile, "|\n"); for (i=4; i>0; i--) { fprintf (maildumpfile, " |"); for (j=13; j<19; j++) { if (Pin[j].color == WHITE && Pin[j].count >= i) fprintf (maildumpfile, " X "); else if (Pin[j].color == BLACK && Pin[j].count >= i) fprintf (maildumpfile, " O "); else fprintf (maildumpfile, " "); } fprintf (maildumpfile, "| | "); for (j=19; j<25; j++) { if (Pin[j].color == WHITE && Pin[j].count >= i) fprintf (maildumpfile, " X "); else if (Pin[j].color == BLACK && Pin[j].count >= i) fprintf (maildumpfile, " O "); else fprintf (maildumpfile, " "); } fprintf (maildumpfile, "|\n"); } fprintf (maildumpfile, " +------------------------------------------+ O: - score: %d\n", Player[0].points); fprintf (maildumpfile, " 12 11 10 9 8 7 6 5 4 3 2 1\n\n"); if (turn == BLACK) fprintf (maildumpfile, " BAR: O-%d X-%d", Pin[0].count, Pin[25].count); else fprintf (maildumpfile, " BAR: O-%d X-%d", Pin[25].count, Pin[0].count); fprintf (maildumpfile, " OFF: O-%d X-%d", Pin[26].count, Pin[27].count); fprintf (maildumpfile, " Cube: %d ", doubler.value); if (doubler.owner == BLACK) fprintf (maildumpfile, "(owned by Player O)\n"); else if (doubler.owner == WHITE) fprintf (maildumpfile, "(owned by Player X)\n"); else fprintf (maildumpfile, "(owned by Player none)\n"); fprintf (maildumpfile, "\n\n"); fclose (maildumpfile); Info (" position written to \n xgammon.maildump "); } void open_protokol (void) { if (gammon_resource.protokol) { if (protokol_file) return; /* already open */ sprintf (protokol_file_name,"xgammon.protokol.%d", getpid ()); protokol_file = fopen (protokol_file_name, "w"); } } char *UserName (void) { return getpwuid (getuid ())->pw_name; } xgammon/src/popup.c100644 764 144 24276 7013622221 13341 0ustar delleusers/* popup.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" Widget popup_shell; /* diawin.c */ extern void CreateDialogWindow(); extern void CreateTournamentWindow(); /* drawing.c */ extern void DrawDoubler(); /* xgammon.c */ extern void Quit (); extern void MenuSelect (); extern void restart (); void CreateXGammonPopup (); void ShowComputerAnswerToDoubling (); int DoublePopup (); void Info (); void CreateXGammonPopup (X11SET *X11Set) { Arg from[1]; int i; char *menu1_names[10]; char *menu2_names[10]; char *menu3_names[10]; if (!gammon_resource.other_display) { menu1_names[0] = "save position "; menu1_names[1] = "load position "; menu1_names[2] = "save game "; menu1_names[3] = "load game "; menu1_names[4] = "save as .."; menu1_names[5] = "load .."; menu1_names[6] = NULL; menu2_names[0] = "restart "; menu2_names[1] = "human vs. compi"; menu2_names[2] = "compi vs. compi"; menu2_names[3] = "human vs. human"; menu2_names[4] = "computer finish"; menu2_names[5] = "rollout"; menu2_names[6] = "edit position"; menu2_names[7] = "mail dump"; menu2_names[8] = "replay game"; menu2_names[9] = NULL; } else { menu1_names[0] = "save position "; menu1_names[1] = "load position "; menu1_names[2] = "save game "; menu1_names[3] = "load game "; menu1_names[4] = "save as .."; menu1_names[5] = "load .."; menu1_names[6] = NULL; menu2_names[0] = "restart "; menu2_names[1] = "mail dump"; menu2_names[2] = NULL; } menu3_names[0] = "resign normal"; menu3_names[1] = "resign gammon"; menu3_names[2] = "resign backgammon"; menu3_names[3] = "undo move "; menu3_names[4] = NULL; X11Set->button_shell = XtCreatePopupShell ("XGammon-Buttons", topLevelShellWidgetClass, X11Set->toplevel, NULL, 0); X11Set->form = XtCreateManagedWidget ("form", formWidgetClass, X11Set->button_shell, NULL, 0); /* some buttons to push */ X11Set->quit = XtCreateManagedWidget ("quit", commandWidgetClass, X11Set->form, NULL, 0); XtAddCallback (X11Set->quit, XtNcallback, Quit, NULL); /* the file menu */ XtSetArg (from[0], XtNfromHoriz, X11Set->quit); X11Set->file_button = XtCreateManagedWidget ("file", menuButtonWidgetClass, X11Set->form, from, 1); X11Set->menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, X11Set->file_button, NULL, 0); for (i = 0; menu1_names[i]; i++) { X11Set->entry = XtCreateManagedWidget (menu1_names[i], smeBSBObjectClass, X11Set->menu, NULL, 0); XtAddCallback (X11Set->entry, XtNcallback, MenuSelect, NULL); } /* the option menu */ XtSetArg (from[0], XtNfromHoriz, X11Set->file_button); X11Set->option_button = XtCreateManagedWidget ("options", menuButtonWidgetClass, X11Set->form, from, 1); X11Set->menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, X11Set->option_button, NULL, 0); for (i = 0; menu2_names[i]; i++) { X11Set->entry = XtCreateManagedWidget (menu2_names[i], smeBSBObjectClass, X11Set->menu, NULL, 0); XtAddCallback (X11Set->entry, XtNcallback, MenuSelect, NULL); } /* the game menu */ XtSetArg (from[0], XtNfromHoriz, X11Set->option_button); X11Set->game_button = XtCreateManagedWidget ("game", menuButtonWidgetClass, X11Set->form, from, 1); X11Set->menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, X11Set->game_button, NULL, 0); for (i = 0; menu3_names[i]; i++) { X11Set->entry = XtCreateManagedWidget (menu3_names[i], smeBSBObjectClass, X11Set->menu, NULL, 0); XtAddCallback (X11Set->entry, XtNcallback, MenuSelect, NULL); } /* finally the textwidgets to display some */ CreateTournamentWindow (X11Set); CreateDialogWindow (X11Set); } void ShowComputerAnswerToDoubling (int accept) { char *label_string; Arg arg[5]; Position x, y; Widget toplevel; Widget form, label, ok; if (gammon_resource.other_display) toplevel = Player[turn-1].X11Set.toplevel; else toplevel = Player[0].X11Set.toplevel; /* first here this message */ sprintf (add_text, "%s doubles.\n", Player[turn-1].name); AppendDialogText (LOWER, add_text); XtSetArg (arg[0], XtNx, &x); XtSetArg (arg[1], XtNy, &y); XtGetValues (toplevel, arg, 2); x += width/2; /* in the middle of the board */ y += height/2; XtSetArg (arg[0], XtNx, x); XtSetArg (arg[1], XtNy, y); popup_shell = XtCreatePopupShell ("doubling", transientShellWidgetClass, toplevel, arg, 2); form = XtCreateManagedWidget ("form", formWidgetClass, popup_shell, NULL, 0); if (accept) label_string = " I accept doubling "; else label_string = " I resign "; XtSetArg (arg[0], XtNlabel, label_string); label = XtCreateManagedWidget ("label", labelWidgetClass, form, arg, 1); /* command button is dummmy */ XtSetArg (arg[0], XtNfromVert, label); ok = XtCreateManagedWidget ("ok", commandWidgetClass, form, arg, 1); XtPopup (popup_shell, XtGrabExclusive); WaitForEvent(ButtonRelease); if (accept) { doubler.value *= 2; DrawDoubler (doubler.value, doubler.owner); sprintf (add_text, "%s accepts the double.\n\n", Player[other-1].name); } else { sprintf (add_text, "%s gives up.\n\n", Player[other-1].name); } AppendDialogText (LOWER, add_text); XtPopdown (popup_shell); } /* DoublePopup() this popup is alaways called, when the answer of a human player is expected, the difference in layout is checked via the Player[].type. then the function simply waits for a button event. */ int DoublePopup (void) { Widget toplevel; Widget form, label, resign, accept; Arg arg[2]; Position x, y; char label_string[128]; int ret; if (gammon_resource.other_display) toplevel = Player[other-1].X11Set.toplevel; else toplevel = Player[0].X11Set.toplevel; /* first from here this message */ sprintf (add_text,"%s doubles.\n", Player[turn-1].name); AppendDialogText (LOWER, add_text); XtSetArg(arg[0], XtNx, &x); XtSetArg(arg[1], XtNy, &y); XtGetValues(toplevel, arg, 2); x += width/2; /* in the middle of the board */ y += height/2; XtSetArg(arg[0], XtNx, x); XtSetArg(arg[1], XtNy, y); popup_shell = XtCreatePopupShell ("doubling", transientShellWidgetClass, toplevel, arg, 2); form = XtCreateManagedWidget ("form", formWidgetClass, popup_shell, NULL, 0); if (Player[0].type == HUMAN && Player[1].type == HUMAN) { if (turn == BLACK) strcpy (label_string, " white player: \n do you accept doubling? "); else strcpy (label_string, " black player: \n do you accept doubling? "); } else { strcpy (label_string, " I'd like to double \n do you accept? "); } XtSetArg (arg[0], XtNlabel, label_string); label = XtCreateManagedWidget ("label", labelWidgetClass, form, arg, 1); XtSetArg (arg[0], XtNfromVert, label); resign = XtCreateManagedWidget ("resign", commandWidgetClass, form, arg, 1); XtSetArg (arg[1], XtNfromHoriz, resign); accept = XtCreateManagedWidget ("accept", commandWidgetClass, form, arg, 2); XtPopup(popup_shell, XtGrabExclusive); /* once again an event problem, cause of idontknowwhat or somelikethat, the Callback functions are too slow, to get an event and process it, before the event loop looks for the next one. So, you have to popdown the shell two times or to try this bullshit here. (can't do better, yet) any event other than pressing resign button is accept. */ while (1) { XEvent event; XtAppNextEvent (app_con, &event); if (event.type == ButtonRelease) { if (event.xbutton.window == XtWindow (resign)) { sprintf (add_text, "%s gives up. %s wins %d point\n\n", Player[other-1].name, Player[turn-1].name, doubler.value); AppendDialogText (LOWER, add_text); XtDispatchEvent (&event); ret = RESIGN; break; } else if (event.xbutton.window == XtWindow (accept)) { doubler.value *= 2; DrawDoubler (doubler.value, doubler.owner); sprintf (add_text,"%s accepts the double.\n\n", Player[other-1].name); AppendDialogText (LOWER, add_text); XtDispatchEvent (&event); ret = ACCEPT; break; } } XtDispatchEvent (&event); } XtPopdown (popup_shell); return ret; } void Info (char *message) { Arg arg[3]; Position x, y; Widget toplevel = Player[turn-1].X11Set.toplevel; Widget info_form, info_label, down; XtSetArg (arg[0], XtNx, &x); XtSetArg (arg[1], XtNy, &y); XtGetValues (toplevel, arg, 2); x += width/4; /* almost the center */ y += height/2; XtSetArg (arg[0], XtNx, x); XtSetArg (arg[1], XtNy, y); popup_shell = XtCreatePopupShell ("Info", transientShellWidgetClass, toplevel, arg, 2); info_form = XtCreateManagedWidget ("info_form", formWidgetClass, popup_shell, NULL, 0); XtSetArg (arg[0], XtNlabel, message); info_label = XtCreateManagedWidget ("info_label", labelWidgetClass, info_form, arg, 1); XtSetArg (arg[0], XtNfromVert, info_label); down = XtCreateManagedWidget ("ok", commandWidgetClass, info_form, arg, 1); XtPopup (popup_shell, XtGrabExclusive); while (1) { XEvent event; XtAppNextEvent (app_con, &event); if (event.type == KeyPress) { KeySym k; Modifiers m; k = XtGetActionKeysym (&event, &m); if (k == ' ' || k == XK_Return) { XtPopdown (popup_shell); XtDispatchEvent (&event); break; } } else if (event.type == ButtonRelease && event.xbutton.window == XtWindow (down)) { XtPopdown (popup_shell); XtDispatchEvent (&event); break; } XtDispatchEvent (&event); } } xgammon/src/rollout.c100644 764 144 20245 7013622221 13666 0ustar delleusers/* rollout.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" extern XtAppContext app_con; extern FILE *endgame_database; extern void Quit (); extern void CreateRolloutText (); extern void load (); extern void save (); extern int do_double (); extern int test_move (); extern MOVE *find_best_move (); extern int end_of_game_test (); void RollOut (); void RolloutLoop (void); void RolloutGame (void); void RolloutMove (void); void init_rollout (void); void rollout_roll_dice (); void exec_rollout (); void RollOut (void) { Widget toplevel = Player[0].X11Set.toplevel; char *v[2], *flag = "m"; XEvent event; int i; CreateRolloutText (toplevel); XtRealizeWidget (toplevel); v[0] = flag; v[1] = gammon_resource.position_file; load (0L, 0L, v, 0); for (i=0; i<29; i++) { rollout_position[i].count = Pin[i].count; rollout_position[i].color = Pin[i].color; } rollout_save.turn = turn; rollout_save.doubler_value = doubler.value; rollout_save.doubler_owner = doubler.owner; rollout_save.roll[0] = roll[0]; rollout_save.roll[1] = roll[1]; tournament.winning_point = gammon_resource.num_rollouts; AppendDialogText (LOWER, "xgammon rollout: "); sprintf (add_text, "rollout: %d games\n", gammon_resource.num_rollouts); AppendDialogText (LOWER, add_text); AppendDialogText (LOWER, "points: white 0, black 0\n"); Player[0].points = 0; Player[1].points = 0; XSync (Player[0].X11Set.dpy, 0); RolloutLoop (); while (XtAppPending (app_con)) { /* delete event queue */ XtAppNextEvent (app_con, &event); XtDispatchEvent (&event); } AppendDialogText (LOWER, "rollout done\n(any button or key event will quit.)\n\n"); while (1) { XtAppNextEvent (app_con, &event); if (event.type == ButtonPress || event.type == KeyPress) break; XtDispatchEvent (&event); } Quit (toplevel, 0L, 0L); } void RolloutLoop (void) { FILE *result_file; unsigned int won_games[3] ={0,0,0}; while (tournament.game_number < tournament.winning_point) { init_rollout (); RolloutGame (); Player[turn-1].points += doubler.value; won_games[turn] ++; sprintf (add_text, "done.. won games: black %d, white %d points: black %d, white %d\n",won_games[BLACK], won_games[WHITE], Player[0].points, Player[1].points); AppendDialogText (LOWER, add_text); } result_file = fopen (gammon_resource.position_file, "a"); AppendDialogText(LOWER, "\nrollout complete. result:\n"); fprintf (result_file, "\nrollout result of %d games:\n", tournament.winning_point); sprintf (add_text, "of %d games\n", tournament.winning_point); AppendDialogText (LOWER, add_text); sprintf (add_text, " black won %d games and got %d points.\n", won_games[BLACK], Player[0].points); fprintf (result_file, add_text); AppendDialogText (LOWER, add_text); sprintf (add_text, " white won %d games and got %d points.\n", won_games[WHITE], Player[1].points); fprintf (result_file, add_text); AppendDialogText (LOWER, add_text); sprintf (add_text, " backgammons: black: %d white %d\n", Player[BLACK].backgammons, Player[WHITE].backgammons); fprintf (result_file, add_text); AppendDialogText (LOWER, add_text); sprintf (add_text, " gammons: black: %d white %d\n", Player[BLACK].gammons, Player[WHITE].gammons); fprintf (result_file, add_text); AppendDialogText (LOWER, add_text); sprintf (add_text, " in percent: black won %2.2f%%, white won %2.2f%%\n\n\n", ((float) won_games[BLACK] * 100 / (float) tournament.winning_point), ((float) won_games[WHITE] * 100 / (float) tournament.winning_point)); fprintf (result_file, add_text); AppendDialogText (LOWER, add_text); fclose (result_file); XSync (Player[0].X11Set.dpy, 0); /* and 7 seconds */ } void RolloutGame (void) { end_of_game = 0; while (1) { RolloutMove(); if (end_of_game) break; switch_turn(); /* RolloutMove(); if (end_of_game) break; switch_turn(); */ } } void RolloutMove (void) { int i; if (gammon_resource.doubling) { if (doubler.owner != turn && doubler.value <= 64) { doubler.owner = turn; if (!do_double (OFFER)) { end_of_game = 1; return; } } } rollout_roll_dice(); if (test_move()) { MOVE *this_move; this_move = find_best_move (); for (i=0; ifrom].count--; if (Pin[(this_move+i)->from].count == 0) Pin[(this_move+i)->from].color = 0; if ((this_move+i)->to == end_pin) { if ((end_of_game = end_of_game_test(turn))) return; } else if (Pin[(this_move+i)->to].color == other) { Pin[(this_move+i)->to].color = turn; Pin[OTHER_BAR].count++; Pin[OTHER_BAR].color = other; } else { Pin[(this_move+i)->to].count++; Pin[(this_move+i)->to].color = turn; } } } } void init_rollout (void) { int i; for (i=0; i<29; i++) { Pin[i].count = rollout_position[i].count; Pin[i].color = rollout_position[i].color; } turn = rollout_save.turn; doubler.value = rollout_save.doubler_value; doubler.owner = rollout_save.doubler_owner; /*roll[0] = rollout_save.roll[0]; roll[1] = rollout_save.roll[1]; if (roll[0] != roll[1]) { roll[2] = 0; roll[3] = 0; to_move = 2; pash = 0; } else { roll[2] = roll[0]; roll[3] = roll[1]; to_move = 4; pash = 1; }*/ rollout_roll_dice (); switch_turn(); switch_turn(); /* set vars */ tournament.game_number++; sprintf(add_text,"rollout game number %d\n", tournament.game_number); AppendDialogText(LOWER, add_text); } void rollout_roll_dice (void) { roll[0] = (rand()%6 + 1) * direction; roll[1] = (rand()%6 + 1) * direction; if (roll[0] != roll[1]) { roll[2] = 0; /* sure and necessary */ roll[3] = 0; to_move = 2; pash = 0; } else { roll[2] = roll[0]; roll[3] = roll[1]; to_move = 4; pash = 1; } } /* saves the current position in a (position) save file, and then execs a xgammon with approriate options. this is why: 1. cause of some problems with X* libs xgammon will grow (fast) in memory usage. After about 650 games with certain optins, it will use about 24 Mb space. (This is not an xgammon fault (!?!) Other programs also do, for example play (at least older versions of) xbombs and do a ps -m sometimes). But they are running only short times and don't use that much graphics). This may be fixed some day. 2. you'll get bored with it and your eyes will hurt, and it's slow 3. you can continue playing */ void exec_rollout (void) { int pid; /* execed process */ int ppid = getpid(); /* this process */ static int called_rollout = 0; /* count to make files somewhat unequivocal */ char *argv[8]; char *v[3]; char rollout_save_file[50]; char nr[7]; sprintf (nr, "%d", gammon_resource.num_rollouts); sprintf (rollout_save_file, "xgammon.rollout.%d.save", (ppid + called_rollout++)); v[0] = "r"; v[1] = rollout_save_file; v[2] = NULL; save (0L, 0L, v, 0); argv[0] = "xgammon"; argv[1] = "-rollout"; argv[2] = "-nr"; argv[3] = nr; argv[4] = "-f"; argv[5] = rollout_save_file; argv[6] = "-doubling"; /* yet necessary */ argv[7] = NULL; #ifdef SIGCHLD signal(SIGCHLD, SIG_IGN); #else signal(SIGCLD, SIG_IGN); #endif if ((pid=fork()) == 0) { execvp ("xgammon", argv); } else if (pid>0) { return; } else { /* should not happen */ AppendDialogText(LOWER, "sorry, couldn't fork rollout process\n"); return; } } xgammon/src/save.c100644 764 144 11476 7013622221 13132 0ustar delleusers/* save.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ /*$Id: save.c,v 1.1 1999/10/05 21:37:37 delle Exp delle $*/ #include #include #include #include #include "xgammon.h" #include "gammon.h" extern void print_dialog_text (); extern void Info (); extern int done_yet; extern float point_values[], prime_length_factor[]; void save (Widget w, XEvent *e, String *vector, Cardinal *count) { FILE *save_file; char *filename = "xgammon.save"; int i; char kind = 0; if (done_yet) { Info ("Please don't move before saving"); return; } /* The option 'p' (position) and 'g' (game) don't make that much a diffrence now, but there is planed a replay section, where it shall be possible to step through the game and the two options will be usefull again. The saving is many the times easier to realize. 'r' means to save the result of a rollout. 'm' is saving invoked by menu-click. In the latter cases the save file will not be default. */ if (*vector[0] == 'p') kind = 'p'; else if (*vector[0] == 'g') kind = 'g'; else if (*vector[0] == 'm') { kind = 'g'; filename = vector[1]; } else if (*vector[0] == 'r') { kind = 'p'; filename = vector[1]; } save_file = fopen (filename, "w"); if (!save_file) { AppendDialogText (LOWER, "couldn't open save file!\nsorry!\n"); return; } if (kind == 'g') { print_dialog_text(save_file); if (gammon_resource.moneygame) fprintf (save_file, "money-game match between %s and %s:\n", Player[0].name, Player[1].name); else if (gammon_resource.winat) fprintf (save_file, "%d point match between %s and %s:\n", gammon_resource.winat, Player[0].name, Player[1].name); fprintf (save_file, "%s has %d points, %s has %d points.\n", Player[0].name, Player[0].points, Player[1].name, Player[1].points); fprintf (save_file, "current game number: %d\n", tournament.game_number); } fprintf (save_file, "turn: %s\n", (turn == BLACK) ? "black" : "white"); fprintf (save_file, "dice values: %d %d\n", abs(roll[0]), abs(roll[1])); fprintf (save_file, "doubler value: %d\n", doubler.value); fprintf (save_file, "last doubler: "); if (doubler.owner == BLACK) fprintf (save_file, "black\n"); else if (doubler.owner == WHITE) fprintf (save_file, "white\n"); else fprintf (save_file, "none\n"); fprintf (save_file, "on bar: black: %d, white: %d\n", Pin[0].count, Pin[25].count); for (i=1; i<25; i++) { if (Pin[i].color == WHITE) fprintf (save_file, "pin %d: %d white men\n", i, Pin[i].count); if (Pin[i].color == BLACK) fprintf (save_file, "pin %d: %d black men\n", i, Pin[i].count); } fclose (save_file); if (*vector[0] != 'r' && !gammon_resource.rollout) Info ("saving done\n"); } void sig_save(int n) { FILE *save_file; int i; save_file = fopen ("xgammon.sig_save", "w"); if (!save_file) return; fprintf (save_file, "turn: "); if (turn == BLACK) fprintf (save_file, "black\n"); else fprintf (save_file, "white\n"); fprintf (save_file, "dice values: %d %d\n", roll[0], roll[1]); fprintf (save_file, "doubler value: %d\n", doubler.value); fprintf (save_file, "last doubler: "); if (doubler.owner) { if (doubler.owner == BLACK) fprintf (save_file, "black\n"); else fprintf (save_file, "white\n"); } else { fprintf (save_file, "none\n"); } fprintf (save_file, "on bar: black: %d white: %d\n", Pin[0].count, Pin[25].count); for (i=1; i<25; i++) { if (Pin[i].color == WHITE) fprintf (save_file, "pin %d: %d white men\n", i, Pin[i].count); if (Pin[i].color == BLACK) fprintf (save_file, "pin %d: %d black men\n", i, Pin[i].count); } fclose(save_file); #ifndef AIX fprintf (stderr, "xgammon: %s. Sorry and bye!\n", sys_siglist[n]); #else fprintf (stderr, "xgammon: Caught signal %d. Sorry and bye!\n", n); #endif /*abort ();*/ exit (n); } void save_config (void) { FILE *f; int i; if (!(f = fopen ("xgammon.config", "w"))) { fprintf (stderr, "counldn't write config file\n"); return; } fprintf (f, "point values:\n"); for (i=1; i<13; i++) fprintf (f, "%-2.3f, ", point_values[i]); fprintf (f, "\n"); for (i=13; i<25; i++) fprintf (f, "%-2.3f, ", point_values[i]); fprintf (f, "\n\n"); fprintf (f, "prime length factors:\n"); for (i=0; i<8; i++) fprintf (f, "%-2.3f, ", prime_length_factor[i]); fprintf (f, "\n"); } xgammon/src/xgammon.c100644 764 144 131104 7020335245 13656 0ustar delleusers /* xgammon version 0.97a, a backgammon program Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de 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. 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 COPYING for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" #include "icon.h" /* allow.c */ extern int test_move (); extern int move_is_allowed (); /* desicion.c */ extern MOVE *find_best_move (); extern float evaluate (); extern int do_double (); extern void set_binom (); extern void set_naufm (); /* drawing.c */ extern void DrawBoard (); extern void DrawEmptyBoard (); extern void DrawDice (); extern void DeleteDice (); extern void DrawEmptyDice (); extern void DrawDiceValues (); extern void DrawDoubler (); extern void DrawStone (); extern void RedrawAllStones (); extern void CreatePixmaps (); extern void FreePixmaps (); /* edit.c */ extern void EditPosition (); /* filemenu.c */ extern void File (); extern void CreateSaveDialog (void); /* popup.c */ extern void Info (); extern void CreateXGammonPopup (); extern void ShowComputerAnswerToDoubling (); extern int DoublePopup (); /* misc.c */ extern void init_game (); extern void RollDice (); extern int end_of_game_test (int color); extern int complete_blockade (void); extern void AppendMoveString (); extern void AddResult (int whom); static void PipCount (); extern int EventToPin (); extern XPoint PinToPosition (int pin); extern void maildump (); extern void open_protokol (); /* load.l */ extern void load (); extern void load_config (); /* save.c */ extern void save (); extern void save_config (); extern void sig_save (); /* rollout.c */ extern void RollOut (); extern void exec_rollout (); /* xgammon.c */ void Redraw (); void restart (); void Resign (int how); void ReplayGame (); void Quit (); void MenuSelect (); void UndoMove (); void set_game_kind (); static void CompiFinish (); static void setup_gc (); static void cp_back (); static void PopupButtonShell (); static void ResizeBoard (); static void CreateBoard (); static void checkcmdline (int argc, char *argv[]); static void PlayerInit (); static void TournamentInit (); static void ButtonMove (); static void TakeStone (); static void MoveStone (); static void PlaceStone (); static int HandleHumanDoubling (); static int HandleCompiDoubling (); static void GetHumanMoveEvents (); void HumanStoneMove (); static void CompiLoop (); void HumanLoop (); static void BearOff (void); void ShowCompiMove (); void XGammonGameLoop (); void XGammonAppTournamentLoop (); #ifdef IRIX /* ?? */ void usleep (unsigned long delay) { sginap (80*delay); } #endif #ifdef SUNOS4 /* ?? */ #define usleep(a) sleep((a/10)) #endif XtAppContext app_con; int width, height; /* of the board */ int stone_width, stone_height; static int old_place_x, old_place_y; /* for moving stones */ Doubler doubler; BOARD board; unsigned long delaytime; /* gammon_resource.delaytime * 100000 (microsec / tsec) */ int font_width; static int get_moves = 0, took_one = 0; /* glabal flags */ int end_of_tournament = 0, end_of_game; int initialize = 0, break_loop = 0, doubling_done = 1; int replaying = 0; int turn, other, pash, to_move, roll[4]; int direction, start_pin, end_pin; int from_pin, pip_count_request = 0; int done_hit, current_hit[4]; /* for UndoMove () */ extern int done_yet; extern MOVE current_move[]; MOVE *compi_choice; FILE* protokol_file = NULL; char * greetings = "Welcome to xgammon version 0.98\n (C) 1994-99 Lambert Klasen Detlef Steuer\n We hope you enjoy it\n\n"; XtActionsRec gammon_actions[] = { {"PipCount", PipCount}, {"CompiFinish", CompiFinish}, {"Redraw", Redraw}, {"UndoMove", UndoMove}, {"ResizeBoard", ResizeBoard}, {"Quit", Quit}, {"save", save}, {"load", load}, {"restart", restart}, }; static XtResource gammon_resources[] = { #define offset(field) XtOffsetOf(struct _gammon_resource, field) {"otherdisplay", "OtherDisplay", XtRString, sizeof (char *), offset (other_display), XtRString, (caddr_t) NULL}, {"boardGeometry", "Geometry", XtRString, sizeof (char *), offset (board_geometry), XtRString, (caddr_t) &gammon_resource.board_geometry}, {"boardColor", "Background", XtRPixel, sizeof (Pixel), offset (board_Pixel), XtRPixel, (caddr_t) &gammon_resource.board_Pixel}, {"boardColor", "Background", XtRString, sizeof (char *), offset (board_color), XtRString, (caddr_t) NULL}, {"lightColor", "Background", XtRPixel, sizeof (Pixel), offset (light_Pixel), XtRPixel, (caddr_t) &gammon_resource.light_Pixel}, {"lightColor", "Background", XtRString, sizeof (char *), offset (light_color), XtRString, (caddr_t) NULL}, {"darkColor", "Background", XtRPixel, sizeof (Pixel), offset (dark_Pixel), XtRPixel, (caddr_t) &gammon_resource.dark_Pixel}, {"darkColor", "Background", XtRString, sizeof (char *), offset (dark_color), XtRString, (caddr_t) NULL}, {"barColor", "Foreground", XtRPixel, sizeof (Pixel), offset (bar_Pixel), XtRPixel, (caddr_t) &gammon_resource.bar_Pixel}, {"barColor", "Foreground", XtRString, sizeof (char *), offset (bar_color), XtRString, (caddr_t) NULL}, {"whiteColor", "Background", XtRPixel, sizeof (Pixel), offset (white_Pixel), XtRPixel, (caddr_t) &gammon_resource.white_Pixel}, {"whiteColor", "Background", XtRString, sizeof (char *), offset (white_color), XtRString, (caddr_t) NULL}, {"blackColor", "Foreground", XtRPixel, sizeof (Pixel), offset (black_Pixel), XtRPixel, (caddr_t) &gammon_resource.black_Pixel}, {"blackColor", "Foreground", XtRString, sizeof (char *), offset (black_color), XtRString, (caddr_t) NULL}, {"smallFont", "Font", XtRString, sizeof (char *), offset (small_font), XtRString, (caddr_t) "-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"}, {"doublerFont", "Font", XtRString, sizeof (char *), offset (doubler_font), XtRString, (caddr_t) "-*-helvetica-medium-r-normal-*-24-*-*-*-*-*-*-*"}, {"humanStones", "String", XtRString, sizeof (char *), offset (human_stone), XtRString, (caddr_t) "black"}, {"gamekind", "Gamekind", XtRString, sizeof (char *), offset (gamekind), XtRString, (caddr_t) "hvc"}, {"protokol", "Protokol", XtRBoolean, sizeof (int), offset (protokol), XtRString, "0"}, {"stonesteps", "Stonesteps", XtRInt, sizeof (int), offset (stone_steps), XtRString, "5"}, {"delaytime", "delaytime", XtRInt, sizeof (int), offset (delaytime), XtRString, "10"}, {"watchmove", "Watchmove", XtRBoolean, sizeof (int), offset (watchmove), XtRString, "1"}, {"autoplay", "Autoplay", XtRBoolean, sizeof (int), offset (autoplay), XtRString, "1"}, {"doubling", "Doubling", XtRBoolean, sizeof (int), offset (doubling), XtRString, "1"}, {"getdice", "Getdice", XtRBoolean, sizeof (int), offset (getdice), XtRString, "0"}, {"moneygame", "Moneygame", XtRBoolean, sizeof (int), offset (moneygame), XtRString, "1"}, {"winat", "Winat", XtRInt, sizeof (int), offset (winat), XtRString, "0"}, {"numberOfGames", "NumberOfGames", XtRInt, sizeof (int), offset (number_of_games), XtRString, (caddr_t) &gammon_resource.number_of_games}, {"mutations", "Mutations", XtRInt, sizeof (int), offset (mutations), XtRString, (caddr_t) &gammon_resource.mutations}, {"rollout", "Rollout", XtRBoolean, sizeof (int), offset (rollout), XtRString, "0"}, {"numrollouts", "NumRollouts", XtRInt, sizeof (int), offset (num_rollouts), XtRString, "100"}, {"positionfile", "PositionFile", XtRString, sizeof (char *), offset (position_file), XtRString, "xgammon.save"}, {"database", "Database", XtRString, sizeof (char *), offset (database), XtRString, "lib/xgammon.db"}, {"server", "Server", XtRString, sizeof (char *), offset (server), XtRString, "fraggel65.mdstud.chalmers.se"}, {"port", "Port", XtRInt, sizeof (int), offset (port), XtRString, "4321"}, {"buttonmove", "ButtonMove", XtRBoolean, sizeof (int), offset (button_move), XtRString, "0"} #undef offset }; static XrmOptionDescRec options[] = { {"-otherdisplay", ".otherdisplay", XrmoptionSepArg, NULL}, {"-boardgeometry", ".boardGeometry", XrmoptionSepArg, NULL}, {"-boardcolor", ".boardColor", XrmoptionSepArg, NULL}, {"-bc", ".boardColor", XrmoptionSepArg, NULL}, {"-darkcolor", ".darkColor", XrmoptionSepArg, NULL}, {"-dc", ".darkColor", XrmoptionSepArg, NULL}, {"-lightcolor", ".lightColor", XrmoptionSepArg, NULL}, {"-lc", ".lightColor", XrmoptionSepArg, NULL}, {"-barcolor", ".barColor", XrmoptionSepArg, NULL}, {"-b", ".barColor", XrmoptionSepArg, NULL}, {"-whitecolor", ".whiteColor", XrmoptionSepArg, NULL}, {"-blackcolor", ".blackColor", XrmoptionSepArg, NULL}, {"-doublerfont", ".doublerFont", XrmoptionSepArg, NULL}, {"-smallfont", ".smallFont", XrmoptionSepArg, NULL}, {"-h", ".humanStones", XrmoptionSepArg, NULL}, {"-g", ".gamekind", XrmoptionSepArg, NULL}, {"-gamekind", ".gamekind", XrmoptionSepArg, NULL}, {"-learn", ".gamekind", XrmoptionNoArg, "3"}, {"-play", ".gamekind", XrmoptionNoArg, "4"}, {"-winat", ".winat", XrmoptionSepArg, NULL}, {"-rollout", ".rollout", XrmoptionNoArg, "1"}, {"-n", ".numberOfGames", XrmoptionSepArg, "10"}, {"-m", ".mutations", XrmoptionSepArg, "100"}, {"-nr", ".numrollouts", XrmoptionSepArg, NULL}, {"-f", ".positionfile", XrmoptionSepArg, NULL}, {"-stonesteps", ".stonesteps", XrmoptionSepArg, NULL}, {"-delaytime", ".delaytime", XrmoptionSepArg, NULL}, {"-protokol", ".protokol", XrmoptionNoArg, "1"}, {"-moneygame", ".moneygame", XrmoptionNoArg, "0"}, {"+moneygame", ".moneygame", XrmoptionNoArg, "1"}, {"-watchmove", ".watchmove", XrmoptionNoArg, "0"}, {"+watchmove", ".watchmove", XrmoptionNoArg, "1"}, {"-autoplay", ".autoplay", XrmoptionNoArg, "0"}, {"+autoplay", ".autoplay", XrmoptionNoArg, "1"}, {"-getdice", ".getdice", XrmoptionNoArg, "1"}, {"-doubling", ".doubling", XrmoptionNoArg, "0"}, {"+doubling", ".doubling", XrmoptionNoArg, "1"}, {"-database", ".database", XrmoptionSepArg, NULL}, {"-server", ".server", XrmoptionSepArg, NULL}, {"-port", ".port", XrmoptionSepArg, NULL}, {"-buttonmove", ".buttonmove", XrmoptionNoArg, "0"}, {"+buttonmove", ".buttonmove", XrmoptionNoArg, "1"}, {"-bm", ".buttonmove", XrmoptionNoArg, "0"}, {"+bm", ".buttonmove", XrmoptionNoArg, "1"}, }; int main (int argc, char **argv) { signal (SIGHUP, sig_save); signal (SIGINT, sig_save); signal (SIGQUIT, sig_save); signal (SIGSEGV, sig_save); signal (SIGFPE, sig_save); signal (SIGPIPE, sig_save); signal (SIGTERM, sig_save); /* for debugging */ Player[0].X11Set.toplevel = XtAppInitialize (&app_con, "XGammon", options, XtNumber (options), &argc, argv, NULL, NULL, ZERO); XtGetApplicationResources (Player[0].X11Set.toplevel, (caddr_t) &gammon_resource, gammon_resources, XtNumber (gammon_resources), NULL, (Cardinal) 0); XtAppAddActions (app_con, gammon_actions, XtNumber (gammon_actions)); Player[0].X11Set.dpy = XtDisplay (Player[0].X11Set.toplevel); checkcmdline (argc, argv); /* initialize */ /*load_config ();*/ /* decision config */ set_binom (); /* decision ... */ set_naufm (); srand (time (NULL)); /* rolling */ delaytime = ((unsigned long) gammon_resource.delaytime) * 100000; endgame_database = fopen (gammon_resource.database, "rb"); if (!endgame_database) fprintf (stderr, "endgame database not found\nyou should create one\n"); if (gammon_resource.protokol) open_protokol (); if (gammon_resource.rollout) RollOut (); CreateBoard (0); CreateXGammonPopup (&(Player[0].X11Set)); XtRealizeWidget (Player[0].X11Set.toplevel); PopupButtonShell (Player[0].X11Set.toplevel, Player[0].X11Set.button_shell); Player[0].X11Set.board.window = XtWindow (Player[0].X11Set.board.widget); setup_gc (&Player[0].X11Set); { Arg arg[1]; Pixmap icon; icon = XCreateBitmapFromData (Player[0].X11Set.dpy, RootWindowOfScreen (XtScreen (Player[0].X11Set.toplevel)), xgammon_bits, xgammon_width, xgammon_height); XtSetArg (arg[0], XtNiconPixmap, icon); XtSetValues (Player[0].X11Set.toplevel, arg, 1); } if (gammon_resource.other_display) { /* XtToolkitInitialize (); is already done */ /* app_con = XtCreateApplicationContext (); exists already */ Player[1].X11Set.dpy = XtOpenDisplay (app_con, gammon_resource.other_display, argv[0], argv[0], options, XtNumber (options), &argc, argv); Player[1].X11Set.toplevel = XtAppCreateShell (argv[0], "applicationShellWidgetClass", applicationShellWidgetClass, Player[1].X11Set.dpy, NULL, 0); CreateBoard (1); CreateXGammonPopup (&(Player[1].X11Set)); XtRealizeWidget (Player[1].X11Set.toplevel); PopupButtonShell (Player[1].X11Set.toplevel, Player[1].X11Set.button_shell); Player[1].X11Set.board.window = XtWindow (Player[1].X11Set.board.widget); setup_gc (&Player[1].X11Set); { Arg arg[1]; Pixmap icon; icon = XCreateBitmapFromData (Player[1].X11Set.dpy, RootWindowOfScreen (XtScreen (Player[1].X11Set.toplevel)), xgammon_bits, xgammon_width, xgammon_height); XtSetArg (arg[0], XtNiconPixmap, icon); XtSetValues (Player[1].X11Set.toplevel, arg, 1); } } CreatePixmaps (0); if (gammon_resource.other_display) CreatePixmaps (1); AppendDialogText (UPPER, greetings); PlayerInit (); TournamentInit (); if (!gammon_resource.other_display) { Player[1].X11Set = Player[0].X11Set; } while (1) { XGammonAppTournamentLoop (); restart (); } return 0; } /* XGammonAppTournamentLoop: the main event loop for xgammon */ void XGammonAppTournamentLoop (void) { end_of_tournament = 0; while (!end_of_tournament) { init_game (); XGammonGameLoop (); if (initialize != EDITED_POSITION && initialize != LOADED_POSITION && initialize != REPLAY_GAME) AddResult (turn); if (tournament.winning_point && gammon_resource.winat) { if (Player[0].points >= tournament.winning_point || Player[1].points >= tournament.winning_point) { end_of_tournament = 1; sleep (3); } } } } /* XGammonGameLoop: event loop for a single game */ void XGammonGameLoop (void) { end_of_game = 0; if (initialize != EDITED_POSITION && initialize != LOADED_POSITION) { if (tournament.game_number == 1 && /* make startup look a little nicer */ ((Player[0].beginner_of_game && Player[0].type == COMPUTER) || (Player[1].beginner_of_game && Player[1].type == COMPUTER))) { while (1) { XEvent event; XtAppNextEvent(app_con, &event); if(event.type == Expose && event.xexpose.window == Player[turn-1].X11Set.board.window) { XtDispatchEvent(&event); XSync (Player[0].X11Set.dpy, 0); if (gammon_resource.other_display) XSync (Player[1].X11Set.dpy, 0); break; } XtDispatchEvent(&event); XSync (Player[0].X11Set.dpy, 0); if (gammon_resource.other_display) XSync (Player[1].X11Set.dpy, 0); } } Player[turn-1].MoveFunction (FIRSTMOVE); } else { DrawDice (turn); DrawDoubler (doubler.value, doubler.owner); initialize = NORMAL_GAME; Player[turn-1].MoveFunction (FIRSTMOVE); } while (!end_of_game) { switch_turn (); Player[turn-1].MoveFunction (DOUBLE); } } /* HumanLoop: event loop for a human player */ void HumanLoop (int with_double) { if (Pin[BAR].count && complete_blockade ()) { sprintf (add_text, "%s can't move.\n\n", Player[turn-1].name); AppendDialogText (LOWER, add_text); return; } if (with_double != FIRSTMOVE && gammon_resource.doubling) { doubling_done = 0; if (doubler.owner != turn) { DeleteDice (); DrawEmptyDice (turn); do { if (pip_count_request) pip_count_request = 0; if (HandleHumanDoubling () == RESIGN) { end_of_game = 1; return; } } while (pip_count_request); } doubling_done = 1; } if (with_double != FIRSTMOVE) RollDice (); HumanStoneMove (); } static int HandleHumanDoubling (void) { int double_result; int p = 0; if (doubler.owner == turn || doubler.value == 64) return 0; while (1) { XEvent event; XtAppNextEvent (app_con, &event); if (event.type == ButtonRelease) { /* not Press */ if (event.xbutton.window == Player[turn-1].X11Set.board.window) { p = EventToPin (event.xbutton.x, event.xbutton.y); break; /* other can't break */ } XtDispatchEvent (&event); } else if (event.type == KeyPress) { KeySym k; Modifiers m; k = XtGetActionKeysym (&event, &m); if (k == 'd') p = DOUBLER; XtDispatchEvent (&event); if (event.xkey.window == Player[turn-1].X11Set.board.window) break; } XtDispatchEvent (&event); } if (p == DOUBLER) { doubler.owner = turn; if (Player[other-1].type == COMPUTER) { /* check opponent */ double_result = do_double (ANSWER); ShowComputerAnswerToDoubling (double_result); if (!double_result) return RESIGN; } else { return DoublePopup (); /* human doubles human */ } } if (end_of_game) return RESIGN; /* resign ... menu pressed prevents rolling */ return 0; } void GetHumanMoveEvents (void) { get_moves = 1; while (roll[0]) { XEvent event; XtAppNextEvent (app_con, &event); if (event.type == KeyPress) { KeySym k; Modifiers m; k = XtGetActionKeysym (&event, &m); if (k == 'o' || k == ' ' || k == '\n') { /* want to move off */ BearOff (); } } XtDispatchEvent (&event); if (break_loop) { /* computer shall finish */ break_loop = 0; break; } } get_moves = 0; } void HumanStoneMove (void) { int mc; DrawDice (turn); if ((mc = test_move () )) { if (mc == 1 && gammon_resource.autoplay) { compi_choice = possible_moves; ShowCompiMove (); AppendMoveString (compi_choice); } else GetHumanMoveEvents (); } else AppendMoveString (NULL); } /* CompiLoop: event loop for a computer player */ void CompiLoop (int with_double) { if (Pin[BAR].count && complete_blockade ()) { AppendMoveString (NULL); return; } if (with_double && gammon_resource.doubling) { if (HandleCompiDoubling () == RESIGN) { /* other resigned */ end_of_game = 1; return; } } if (with_double != FIRSTMOVE) RollDice (); DrawDice (turn); XSync (Player[0].X11Set.dpy, 0); if (gammon_resource.other_display) XSync (Player[1].X11Set.dpy, 0); if (!gammon_resource.watchmove) usleep (delaytime); if (test_move ()) { compi_choice = find_best_move (); ShowCompiMove (); AppendMoveString (compi_choice); } else AppendMoveString (NULL); } static int HandleCompiDoubling (void) { int ret = 0; if (doubler.owner == turn || doubler.value == 64) return 0; if (! do_double (OFFER)) return 0; doubler.owner = turn; if (Player[other-1].type == HUMAN) /* check opponent */ return DoublePopup (); else { /* opponent is computer */ if (! do_double (ANSWER)) { /* resigned */ sprintf (add_text, "%s gives up. %s wins %d point\n\n", Player[other-1].name, Player[turn-1].name, doubler.value); ret = RESIGN; } else { /* accepted */ doubler.value *= 2; DrawDoubler (doubler.value, doubler.owner); sprintf (add_text,"%s accepts the double.\n\n", Player[other-1].name); ret = ACCEPT; } AppendDialogText (LOWER, add_text); } return ret; } void ShowCompiMove (void) { XPoint move_start, move_end; int x, y, dx, dy, steps; int i, j; for (i=0; ifrom); if (gammon_resource.watchmove) { move_start = PinToPosition ((compi_choice+i)->from); if ((compi_choice+i)->to != end_pin) move_end = PinToPosition ((compi_choice+i)->to); else move_end = PinToPosition (FINISHED); x = move_start.x; y = move_start.y; if (abs ((move_start.x - move_end.x)) > abs ((move_start.y - move_end.y))) steps = abs (move_start.x - move_end.x)/gammon_resource.stone_steps; else steps = abs (move_start.y - move_end.y)/gammon_resource.stone_steps; DrawStone (x,y); old_place_x = x; old_place_y = y; dx = (move_start.x - move_end.x) * -1 / steps; dy = (move_start.y - move_end.y) * -1 / steps; for (j=0; jto == end_pin) { /* endpin check must be first cause of removing other from endpin, i.e. bar */ PutStone (turn, FINISHED); if ((end_of_game = end_of_game_test (turn))) return; } else if (Pin[ (compi_choice+i)->to].color == other) { current_hit[i] = (compi_choice+i)->to; RemoveStone ((compi_choice+i)->to); PutStone (other, OTHER_BAR); PutStone (turn, (compi_choice+i)->to); } else PutStone (turn, (compi_choice+i)->to); XSync (Player[0].X11Set.dpy, 0); if (gammon_resource.other_display) XSync (Player[1].X11Set.dpy, 0); if (!gammon_resource.watchmove) usleep (delaytime); /* look for events happened while moving */ while (XtAppPending (app_con)) { XEvent event; XtAppNextEvent (app_con, &event); XtDispatchEvent (&event); } } } void cp_back (int x, int y) { Display *dpy = Player[0].X11Set.dpy; Pixmap p = Player[0].X11Set.board.pixmap; Window w = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.board.gc; XCopyArea (dpy, p, w, gc, x, y, stone_width, stone_width, x, y); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; p = Player[1].X11Set.board.pixmap; w = Player[1].X11Set.board.window; gc = Player[1].X11Set.board.gc; XCopyArea (dpy, p, w, gc, x, y, stone_width, stone_width, x, y); } } static void CreateBoard (int player_index) { Display *dpy = Player[player_index].X11Set.dpy; WidgetClass board_class; Arg args[2]; int screen_num = DefaultScreen (dpy); static XtActionsRec board_actions[] = { {"Redraw", Redraw}, {"ResizeBoard", ResizeBoard}, {"TakeStone", TakeStone}, {"MoveStone", MoveStone}, {"PlaceStone", PlaceStone}, {"ButtonMove", ButtonMove}, {NULL, NULL} }; static String no_bm_translations = "#override \n\ : Redraw() \n\ : ResizeBoard() \n\ Button1: MoveStone() \n\ : PlaceStone() \n\ : TakeStone() \n\ "; static String bm_translations = "#override \n\ : Redraw() \n\ : ResizeBoard() \n\ : ButtonMove() \n\ "; static String translations; if (gammon_resource.button_move) translations = bm_translations; else translations = no_bm_translations; /* the board width x height is arbitraryly 15 x 12 that fast I couldn't get separated board geometry and normal Xt -geometry option, so there is this strange and ugly boardgeometry, the reason is, that there is no toplevel width and height before XtRealize. further XParseGeometry doesn't parse very low values like 10x10 or 0x0 */ { int dummy_x, dummy_y; /* of no interest, at least yet */ (void) XParseGeometry (gammon_resource.board_geometry, &dummy_x, &dummy_y, &width, &height); if (width < 150 || height < 120) { width = 150; height = 120; fprintf (stderr,"boardsize should at least be 150x120 pixel\ngeometry values changed\n"); } } if (width > DisplayWidth (dpy, screen_num) - 50 || height > DisplayHeight (dpy, screen_num) - 50) { width = DisplayWidth (dpy, screen_num) - 50; height = DisplayHeight (dpy, screen_num) - 50; } stone_width = stone_height = width/15; if (height < stone_width * 12) stone_width = height/12; /* some kinda screens there are */ width = stone_width * 15; height = stone_width * 12; XtSetArg (args[0], XtNwidth, width); XtSetArg (args[1], XtNheight, height); Player[player_index].X11Set.board.widget = XtCreateManagedWidget ("board", simpleWidgetClass, Player[player_index].X11Set.toplevel, args, 2); if (player_index == 0) { /* first players displays board */ XtOverrideTranslations (Player[player_index].X11Set.board.widget, XtParseTranslationTable (translations)); XtAppAddActions (app_con, board_actions, XtNumber (board_actions)); } else { /* other players displays board */ Arg t[1]; XtTranslations first_board_translations; /* this ensures both board have the same base of translations (via .Xdefaults) */ XtSetArg (t[0], XtNtranslations, first_board_translations); XtGetValues (Player[0].X11Set.board.widget, t, 1); XtSetValues (Player[1].X11Set.board.widget, t, 1); /* now add the hard wired ones of this function */ XtOverrideTranslations (Player[player_index].X11Set.board.widget, XtParseTranslationTable (translations)); XtAppAddActions (app_con, board_actions, XtNumber (board_actions)); } board_class = (WidgetClass) XtClass (Player[player_index].X11Set.board.widget); board_class->core_class.compress_exposure = XtExposeCompressMaximal; board_class->core_class.compress_motion = True; } static void PlayerInit (void) { extern char *UserName(); if (!strcmp (gammon_resource.gamekind, "hvc")) { if (!strcmp (gammon_resource.human_stone, "black")) { Player[0].type = HUMAN; Player[1].type = COMPUTER; Player[0].MoveFunction = HumanLoop; Player[1].MoveFunction = CompiLoop; strcpy (Player[0].name, UserName()); strcpy (Player[1].name, "xgammon"); } else if (!strcmp (gammon_resource.human_stone, "white")) { Player[0].type = COMPUTER; Player[1].type = HUMAN; Player[0].MoveFunction = CompiLoop; Player[1].MoveFunction = HumanLoop; strcpy (Player[0].name, "xgammon"); strcpy (Player[1].name, UserName()); } } else if (!strcmp (gammon_resource.gamekind, "cvc")) { Player[0].type = COMPUTER; Player[1].type = COMPUTER; Player[0].MoveFunction = CompiLoop; Player[1].MoveFunction = CompiLoop; strcpy (Player[0].name, "black"); strcpy (Player[1].name, "white"); initialize = COMPUTER_TOURNAMENT; } else if (!strcmp (gammon_resource.gamekind, "hvh")) { Player[0].type = HUMAN; Player[1].type = HUMAN; Player[0].MoveFunction = HumanLoop; Player[1].MoveFunction = HumanLoop; strcpy (Player[0].name, UserName()); strcpy (Player[1].name, "other"); } Player[0].color = BLACK; Player[1].color = WHITE; } /* TournamentInit; a little too big a name, only set a label and set the cursor */ static void TournamentInit () { Display *dpy = Player[0].X11Set.dpy; Arg c[1]; char *s; static int once = 0; if (gammon_resource.moneygame) { s = "money-game"; tournament.winning_point = 0; sprintf (add_text, "%s and %s start a %s match.\n", Player[0].name, Player[1].name, s); } if (gammon_resource.winat) { s = "points"; tournament.winning_point = gammon_resource.winat; gammon_resource.moneygame = 0; sprintf (add_text, "%s and %s start a %d %s match.\n", Player[0].name, Player[1].name, tournament.winning_point, s); } AppendDialogText (UPPER, add_text); if (once) return; /* prepare the cursor, looks like the stones you move */ Player[0].X11Set.fg_col.pixel = gammon_resource.black_Pixel; Player[0].X11Set.bg_col.pixel = gammon_resource.white_Pixel; XQueryColor (dpy, DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy)), &Player[0].X11Set.fg_col); XQueryColor (dpy, DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy)), &Player[0].X11Set.bg_col); XtSetArg (c[0], XtNcursor, &Player[0].X11Set.cursor); XtGetValues (Player[0].X11Set.board.widget, c, 1); if (!gammon_resource.other_display) { if (Player[0].type == HUMAN) XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.fg_col, &Player[0].X11Set.bg_col); else if (Player[1].type == HUMAN) XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.bg_col, &Player[0].X11Set.fg_col); else XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.fg_col, &Player[0].X11Set.bg_col); } else { XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.fg_col, &Player[0].X11Set.bg_col); dpy = Player[1].X11Set.dpy; Player[1].X11Set.bg_col.pixel = gammon_resource.black_Pixel; Player[1].X11Set.fg_col.pixel = gammon_resource.white_Pixel; XQueryColor (dpy, DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy)), &Player[1].X11Set.fg_col); XQueryColor (dpy, DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy)), &Player[1].X11Set.bg_col); XtSetArg (c[0], XtNcursor, &Player[1].X11Set.cursor); XtGetValues (Player[1].X11Set.board.widget, c, 1); XRecolorCursor (Player[1].X11Set.dpy, Player[1].X11Set.cursor, &Player[1].X11Set.fg_col, &Player[1].X11Set.bg_col); } once = 1; } /* Quit is both, Callback and Action routine. I'm too lazy to invent an extra Callback */ void Quit (Widget w, XEvent *e, String *vector, Cardinal *count) { if (endgame_database) fclose (endgame_database); if (protokol_file) fclose (protokol_file); XtDestroyApplicationContext (XtWidgetToApplicationContext (w)); exit (0); } static void checkcmdline (int argc, char *argv[]) { int option; for (option=1; option 0 with watchmove\n"); } } void setup_gc (X11SET *X11Set) { XGCValues values; XtGCMask valuemask; valuemask = GCForeground|GCBackground|GCFunction; values.function = GXcopy; values.foreground = gammon_resource.black_Pixel; values.background = gammon_resource.board_Pixel; X11Set->gc = XtGetGC (X11Set->board.widget, valuemask, &values); values.foreground = gammon_resource.board_Pixel; values.background = gammon_resource.board_Pixel; X11Set->board.gc = XtGetGC (X11Set->board.widget, valuemask, &values); values.foreground = gammon_resource.black_Pixel; /* black stone */ values.background = gammon_resource.white_Pixel; X11Set->stoneGC[0] = XtGetGC (X11Set->board.widget, valuemask, &values); values.foreground = gammon_resource.white_Pixel; values.background = gammon_resource.black_Pixel; X11Set->stoneGC[1] = XtGetGC (X11Set->board.widget, valuemask, &values); valuemask ^= GCLineWidth|GCCapStyle|GCFont; values.foreground = gammon_resource.black_Pixel; values.background = gammon_resource.white_Pixel; values.line_width = 3; values.cap_style = CapRound; /* the fonts actually used */ if ((X11Set->doubler_font = XLoadQueryFont (X11Set->dpy, gammon_resource.doubler_font)) == NULL) { fprintf (stderr, "couldn't load doubler dice font, using default, sorry\n"); } else values.font = X11Set->doubler_font->fid; X11Set->diceGC = XtGetGC (X11Set->board.widget, valuemask, &values); X11Set->small_font = XLoadQueryFont (X11Set->dpy, gammon_resource.small_font); } void Redraw (Widget w, XEvent *e, String *vector, Cardinal *count) { DrawEmptyBoard (); DrawBoard (); RedrawAllStones (); DrawEmptyDice (turn); if (doubling_done) DrawDiceValues (turn); DrawDoubler (doubler.value, doubler.owner); } static void ResizeBoard (Widget w, XConfigureEvent *e, String *vector, Cardinal *count) { Arg arg[2]; Dimension new_stone_width, new_stone_height; Dimension new_width, new_height; if (gammon_resource.other_display) return; XClearArea (Player[0].X11Set.dpy, Player[0].X11Set.board.window, 0, 0, width, height, 0); /* if (gammon_resource.other_display) XClearArea (Player[0].X11Set.dpy, Player[1].X11Set.board.window, 0, 0, width, height, 0); */ new_stone_width = new_stone_height = e->width/15; new_width = new_stone_width * 15; if (e->height < new_stone_width * 12) { new_stone_width = e->height/12; new_height = new_stone_width * 12; new_width = new_stone_width * 15; } else new_height = new_stone_width * 12; width += (new_width-width); height += (new_height-height); stone_width = new_stone_width; XtSetArg (arg[0], XtNwidth, width); XtSetArg (arg[1], XtNheight, height); XtSetValues (Player[0].X11Set.board.widget, arg, 2); FreePixmaps (); CreatePixmaps (0); if (gammon_resource.other_display) CreatePixmaps (1); Redraw (0L, 0L, (char**) 0L, 0); } void MenuSelect (Widget w, XtPointer junk, XtPointer garbage) { XEvent event; char name[64]; char *v[] = {"p", NULL}; strcpy (name, XtName (w)); if (strncmp (name, "save position", 13) == 0) save (w, 0L, v, 0); else if (strncmp (name, "load position", 13) == 0) load (w, 0L, v, 0); else if (strncmp (name, "load game", 9) == 0) { v[0] = "g"; load (w, 0L, v, 0); } else if (strncmp (name, "save game", 9) == 0 ) { v[0] = "g"; save (w, 0L, v, 0); } else if (strcmp (name, "save as .." ) == 0) CreateSaveDialog (); else if (strcmp (name, "load .." ) == 0) File (); else if (strncmp (name, "restart", 7) == 0) restart (); else if (strncmp (name, "undo move", 9) == 0) UndoMove (0L, 0L, (char **) 0L, 0); else if (strcmp (name, "compi vs. compi" ) == 0) set_game_kind (COMPI_VS_COMPI); else if (strcmp (name, "human vs. compi" ) == 0) set_game_kind (HUMAN_VS_COMPI); else if (strcmp (name, "human vs. human" ) == 0) set_game_kind (HUMAN_VS_HUMAN); else if (strcmp (name, "computer finish" ) == 0) CompiFinish (); else if (strcmp (name, "rollout" ) == 0) exec_rollout (); else if (strcmp (name, "edit position" ) == 0) EditPosition (); else if (strcmp (name, "mail dump" ) == 0) maildump (); else if (strcmp (name, "replay game" ) == 0) ReplayGame (); else if (strcmp (name, "resign normal" ) == 0) Resign (NORMAL); else if (strcmp (name, "resign gammon" ) == 0) Resign (GAMMON); else if (strcmp (name, "resign backgammon") == 0) Resign (BACKGAMMON); while (XtAppPending (app_con)) XtAppNextEvent (app_con, &event); } void ButtonMove (Widget w, XButtonEvent *e) { int p, dp, to; if (!gammon_resource.button_move) return; if (!get_moves) return; p = EventToPin (e->x, e->y); if ((Pin[BAR].count && p != BAR) || ! (Pin[p].count && Pin[p].color == turn)) return; if (pash) { if (turn==BLACK) to = (p+roll[1] < end_pin) ? p+roll[1] : end_pin; else to = (p+roll[1] > end_pin) ? p+roll[1] : end_pin; if (move_is_allowed (p, to)) { /* roll[0] is used as a flag (sorry) */ RemoveStone (p); if (to != end_pin) { if (Pin[to].color == other) { RemoveStone (to); current_hit [done_hit] = to; done_hit++; PutStone (other, OTHER_BAR); } PutStone (turn, to); } else PutStone (turn, FINISHED); } } else { if (e->button == 1) { dp = (roll[0] > roll[1]) ? roll[1] : roll[0]; if (turn==BLACK) { to = (p+dp < end_pin) ? p+dp : end_pin; } else { to = (p+dp > end_pin) ? p+dp : end_pin; } if (move_is_allowed (p, to)) { RemoveStone (p); if (to != end_pin) { if (Pin[to].color == other) { RemoveStone (to); current_hit [done_hit] = to; done_hit++; PutStone (other, OTHER_BAR); } PutStone (turn, to); } else PutStone (turn, FINISHED); } } else if (e->button == 3) { dp = (roll[0] > roll[1]) ? roll[0] : roll[1]; if (turn==BLACK) to = ( p+dp < end_pin) ? p+dp : end_pin; else to = ( p+dp > end_pin) ? p+dp : end_pin; if (move_is_allowed (p, to)) { RemoveStone (p); if (to != end_pin) { if (Pin[to].color == other) { RemoveStone (to); current_hit [done_hit] = to; done_hit++; PutStone (other, OTHER_BAR); } PutStone (turn, to); } else PutStone (turn, FINISHED); } } else if (e->button == 2) { } } } void TakeStone (Widget w, XButtonEvent *e) { int p; if (!get_moves) return; if (gammon_resource.button_move) return; if (gammon_resource.other_display) { if (Player[turn-1].X11Set.board.window != e->window) return; } p = EventToPin (e->x, e->y); if (Pin[BAR].count && p != BAR) { from_pin = 0; return; } if (Pin[p].count && Pin[p].color == turn) { from_pin = p; RemoveStone (p); old_place_x = e->x - stone_width/2; old_place_y = e->y - stone_width/2; DrawStone (old_place_x, old_place_y, turn); took_one = 1; } else { from_pin = 0; } } void MoveStone (Widget w, XButtonEvent *e) { int x, y; if (!took_one) return; if (gammon_resource.button_move) return; x = e->x - stone_width/2; y = e->y - stone_width/2; if (x<0) x = 0; else if (x > width - stone_width) x = width - stone_width; if (y<0) y = 0; else if (y > height - stone_width) y = height - stone_width; cp_back (old_place_x, old_place_y); DrawStone (x, y, turn); old_place_x = x; old_place_y = y; } void PlaceStone (Widget w, XButtonEvent *e) { int p; if (!get_moves) return; if (gammon_resource.button_move) return; if (!took_one) return; took_one = 0; cp_back (old_place_x, old_place_y); p = EventToPin (e->x, e->y); if (!move_is_allowed (from_pin, p)) { PutStone (turn, from_pin); return; } if (p == end_pin) { /* check this first, cause possible removing other from endpin (other bar) */ PutStone (turn, FINISHED); if ((end_of_game = end_of_game_test (turn))) return; } else if (Pin[p].color == other) { RemoveStone (p); current_hit [done_hit] = p; done_hit++; PutStone (other, OTHER_BAR); PutStone (turn, p); } else { PutStone (turn, p); } } void UndoMove (Widget w, XEvent *e, String *vector, Cardinal *count) { int i; for (i=done_yet-1; i> -1; i--) { if (current_move[i].to == end_pin) RemoveStone (FINISHED); else RemoveStone (current_move[i].to); PutStone (turn, current_move[i].from); } for (i=0; ito == end_pin && (m+1)->to == end_pin) { if (pash && (m+2)->to == end_pin && (m+3)->to == end_pin) { can_off = 1; break; } else { can_off = 1; break; } } m += 4; } if (can_off) { compi_choice = m; ShowCompiMove (); AppendMoveString (compi_choice); roll[0] = 0; done_yet = 0; done_hit = 0; } } static void PipCount (Widget w, XEvent *e, String *vector, Cardinal *count) { extern void simple_pipcount (); float pip_count[3]; simple_pipcount (&pip_count); sprintf (add_text, " picount:\n black: %d, white: %d ", abs ((int) pip_count[BLACK]), abs ((int) pip_count[WHITE])); Info (add_text); pip_count_request = 1; } void PopupButtonShell (Widget parent, Widget button_shell) { Position x, y; Dimension w; Arg args[2]; XtSetArg (args[0], XtNwidth, &w); XtGetValues (parent, args, 1); XtSetArg (args[0], XtNx, &x); XtSetArg (args[1], XtNy, &y); XtGetValues (parent, args, 2); x += (Position) (w + 40); if (x<0) x=0; if (y<0) y=0; XtSetArg (args[0], XtNx, x); XtSetArg (args[1], XtNy, y); XtSetValues (button_shell, args, 2); XtPopup (button_shell, XtGrabNone); } void restart (void) { tournament.game_number = 1; Player[0].points = 0; Player[1].points = 0; AppendDialogText (UPPER, "tournament restart:\n"); end_of_tournament = 1; end_of_game = 1; initialize = NORMAL_GAME; break_loop = 1; TournamentInit (); } void Resign (int how) { sprintf (add_text, "%s wants to resign\n", Player[turn-1].name); AppendDialogText (LOWER, add_text); Info ("accept"); AppendDialogText (LOWER, "xgammon accepts\n\n"); switch_turn (); /* for AddResult () */ end_of_game = how; /* for AddResult () */ initialize = NORMAL_GAME; break_loop = 1; } void set_game_kind (int to) { if (to == HUMAN_VS_COMPI) { Player[0].type = HUMAN; Player[1].type = COMPUTER; Player[0].MoveFunction = HumanLoop; Player[1].MoveFunction = CompiLoop; } else if (to == COMPI_VS_COMPI) { Player[0].type = COMPUTER; Player[1].type = COMPUTER; Player[0].MoveFunction = CompiLoop; Player[1].MoveFunction = CompiLoop; } else if (to == HUMAN_VS_HUMAN) { Player[0].type = HUMAN; Player[1].type = HUMAN; Player[0].MoveFunction = HumanLoop; Player[1].MoveFunction = HumanLoop; } } xgammon/src/xgammon.h100644 764 144 4061 7013622230 13617 0ustar delleusers/* xgammon.h Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. 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 COPYING for more details. */ #define WaitForEvent(event_type) while(1) {\ XEvent event;\ XtAppNextEvent(app_con, &event);\ if(event.type == event_type) {\ XtDispatchEvent(&event);\ break;\ }\ XtDispatchEvent(&event);\ } #define dice_width stone_width extern char add_text[]; extern XtAppContext app_con; extern int width, height; extern int stone_width, stone_height; struct _gammon_resource { char *other_display; char *board_geometry; Pixel board_Pixel; char *board_color; Pixel light_Pixel; char *light_color; Pixel dark_Pixel; char *dark_color; Pixel bar_Pixel; char *bar_color; Pixel white_Pixel; char *white_color; Pixel black_Pixel; char *black_color; char *small_font; char *doubler_font; char *human_stone; char *gamekind; int protokol; int stone_steps; int delaytime; int watchmove; int autoplay; int doubling; int getdice; int moneygame; int bestof; int winat; int number_of_games; int mutations; int rollout; int num_rollouts; char *position_file; char *database; char *server; int port; int button_move; } gammon_resource; /* diawin.c */ extern void AppendDialogText (); /* drawing.c */ extern void PutStone (); extern void RemoveStone ();