shithub: moonfish

Download patch

ref: 7cef241c0a17871d4f4eb529e27037660a6ba94f
parent: 37a2e71e1621e7584996fa035e73b71eae57ea06
author: zamfofex <zamfofex@twdb.moe>
date: Tue May 7 06:14:40 EDT 2024

rearrange documentation

--- a/README.md
+++ b/README.md
@@ -5,24 +5,41 @@
 ===
 
 [![builds.sr.ht status](https://builds.sr.ht/~zamfofex/moonfish/commits/main.svg)](https://builds.sr.ht/~zamfofex/moonfish/commits/main)
+[![Lichess classical rating](https://lichess-shield.vercel.app/api?username=munfish&format=classical)](https://lichess.org/@/munfish/perf/classical)
 [![Lichess rapid rating](https://lichess-shield.vercel.app/api?username=munfish&format=rapid)](https://lichess.org/@/munfish/perf/rapid)
 [![Lichess blitz rating](https://lichess-shield.vercel.app/api?username=munfish&format=blitz)](https://lichess.org/@/munfish/perf/blitz)
-[![Lichess bullet rating](https://lichess-shield.vercel.app/api?username=munfish&format=bullet)](https://lichess.org/@/munfish/perf/bullet)
 
-**moonfish** is a very simple and small chess bot written in C 89 (ANSI C).
+**moonfish** is a simple chess bot written in C 89 (ANSI C).
 
 You may [play moonfish on Lichess]! You don’t need a Lichess account, just make sure to choose “real time” and select a fast enough time control.
 
 [play moonfish on Lichess]: <https://lichess.org/?user=munfish#friend>
 
+table of contents
+---
+
+- [features](#features) and [limitations](#limitations)
+- [download](#download)
+- [compiling from source](#compiling-from-source) (for UNIX and clones)
+- using moonfish’s tools
+  - [using “play” and “analyse”](#using-play-and-analyse)
+  - [using “book”](#using-book) (for adding simple opening book support to bots without it by wrapping them)
+  - [using “battle” and “ribbon”](#using-battle-and-ribbon) (for setting up tournaments between bots)
+  - [using “ugi-uci” and “uci-ugi”](#using-ugi-uci-and-uci-ugi) (for using UCI bots in UGI programs and vice-versa)
+  - [using “chat”](#using-chat) and [using “lichess”](#using-lichess) (for integrating with IRC and Lichess)
+- compiling on other systems
+  - [compiling on Plan 9](#compiling-on-plan-9)
+  - [compiling on Windows](#compiling-on-windows)
+  - [porting to other systems](#porting-moonfish)
+- [license](#license)
+
 features
 ---
 
-- simple HCE based on PSTs
+- simple evaluation based on PSTs
 - alpha/beta pruning search
 - cute custom UCI TUIs
 - custom Lichess integration
-- threaded search
 - custom UGI/UCI translators
 - custom IRC integration
 
@@ -39,12 +56,12 @@
 download
 ---
 
-Pre‐compiled executables for Linux of moonfish (and its tools) may be found at <https://moonfish.neocities.org>
+Pre‐compiled executables for Linux of moonfish (and some of its tools) may be found at <https://moonfish.neocities.org> (Windows binaries are also provided.)
 
 compiling from source
 ---
 
-Building on UNIX should be easy. Make sure you have GNU `make` and a C compiler like GCC, then run the following command.
+Building on UNIX (and clones) should be easy. Make sure you have GNU Make and a C compiler like GCC, then run the following command.
 
 ~~~
 make moonfish
@@ -52,60 +69,61 @@
 
 Conversely, you may also invoke your compiler by hand. (Feel free to replace `cc` with your compiler of choice.)
 
-Note: If your C implementation doesn’t support pthreads, but supports C11 threads, you may pass in `-Dmoonfish_c11_threads`.
-
-Note: If your C implementation doesn’t support threads at all, you may pass in `-Dmoonfish_no_threads`.
-
 ~~~
 cc -ansi -O3 -pthread -D_POSIX_C_SOURCE=199309L -o moonfish chess.c search.c main.c
 ~~~
 
-The two UCI TUIs, called “play” and “analyse”, may also be compiled.
+Note: If your C implementation doesn’t support pthreads, but supports C11 threads, you may pass in `-Dmoonfish_c11_threads`.
 
-~~~
-make play analyse
-~~~
+Note: If your C implementation doesn’t support threads at all, you may pass in `-Dmoonfish_no_threads`.
 
-The UGI/UCI translators may also be compiled:
+using “play” and “analyse”
+---
 
 ~~~
-make ugi-uci uci-ugi
+make play analyse
 ~~~
 
-The CLI tools, called “battle” and “ribbon” to (respectively) play a single game between two bots and to play a tournament between any given number of bots may also be compiled.
+“play” and “analyse” are TUI that allows you to play against and analyse with UCI bots respectively.
 
-~~~
-make battle ribbon
-~~~
+After compiling and running them, you may use the mouse to click and move pieces around. (So, they require mouse support from your terminal.)
 
-The IRC/UCI bot integration may also be compiled:
+To play against a UCI bot, use `./play` followed by the command of whichever bot you want to play against. The color of your pieces will be decided randomly by default.
 
 ~~~
-make chat
-~~~
+# (start a game against Stockfish)
+./play stockfish
 
-The opening book utility may also be compiled:
+# (start a game against Leela)
+./play lc0
 
+# (start a game against moonfish)
+./play ./moonfish
 ~~~
-make book
-~~~
 
-All such programs may also be compiled by using the default target, `all`. Note the the Lichess integration requires LibreSSL (for libtls) and cJSON. (The other programs require no external libraries.)
+To analyse a game with a UCI bot, use `./analyse` followed optionally by the UCI options you want to specify, and then the command of whichever bot you want to use for analysis. (Though note that moonfish currently does not have analysis capabilities.)
 
 ~~~
-make
-~~~
+# (analyse a game using Stockfish)
+./analyse stockfish
 
-using moonfish
----
+# (analyse a game using Stockfish, showing win/draw/loss evaluation)
+./analyse UCI_ShowWDL=true stockfish
 
-moonfish is a UCI bot, which means you may select it and use it with any UCI program (though see “limitations” above). You may invoke `./moonfish` to start its UCI interface.
+# (analyse a game using Leela)
+./analyse lc0
 
-However, note that moonfish comes with its own UCI TUIs, called “play” and “analyse”. You may use them with any UCI bot you’d like!
+# (analyse a game using Leela, showing win/draw/loss evaluation)
+./analyse lc0 --show-wdl
+~~~
 
-using “book”
+using "book"
 ---
 
+~~~
+make book
+~~~
+
 Opening book support for moonfish is handled with the “book” utility. You specify a opening book file name to it as well as the command for a UCI bot, and it will intercept that bot’s communication with the GUI to make it play certain openings.
 
 The format for opening book files is very simple: One opening per line with move names in either SAN or UCI format separated by spaces. (Move numbers are no allowed.) Empty lines are ignores, `#` is used for comments. Check out the `book.txt` file for an example.
@@ -117,41 +135,15 @@
 ./book --file=book.txt ./moonfish
 ~~~
 
-using “play” and “analyse”
+using “battle” and “ribbon”
 ---
 
-To play against a UCI bot, use `./play` followed by the command of whichever bot you want to play against. The color of your pieces will be decided randomly by default.
-
 ~~~
-# (start a game against Stockfish)
-./play stockfish
-
-# (start a game against Leela)
-./play lc0
-
-# (start a game against moonfish)
-./play ./moonfish
+make battle ribbon
 ~~~
 
-To analyse a game with an UCI bot, use `./analyse` followed optionally by the UCI options you want to specify, and thethe command of whichever bot you want to use for analysis. (Though note that moonfish currently does not have analysis capabilities.)
+The CLI tools, called “battle” and “ribbon” can be used to (respectively) play a single game between two bots and to play a tournament between any given number of bots.
 
-~~~
-# (analyse a game using Stockfish)
-./analyse stockfish
-
-# (analyse a game using Stockfish, showing win/draw/loss evaluation)
-./analyse UCI_ShowWDL=true stockfish
-
-# (analyse a game using Leela)
-./analyse lc0
-
-# (analyse a game using Leela, showing win/draw/loss evaluation)
-./analyse lc0 --show-wdl
-~~~
-
-using “battle”
----
-
 The “battle” CLI may be used to have two UCI or UGI bots play against each other. Each bot has to be specified between brackets (these ones: `[` and `]`).
 
 ~~~
@@ -176,8 +168,7 @@
 
 In order to use a UGI bot, you may also pass in `--protocol=ugi` to that bot, like `./battle [ --protocol=ugi some-bot ] [ stockfish ]`. If both bots are UGI, then the game is not assumed to be chess, and the bot playing as p1 will be queried for the status of the game.
 
-using “ribbon”
----
+- - -
 
 “ribbon” is a CLI for setting up a round‐robin tournament between multiple bots with the help of the “battle” program mentioned above and a makefile (currently requiring GNU Make).
 
@@ -231,12 +222,29 @@
 do : ; done
 ~~~
 
-using the IRC integration
+using “ugi-uci“ and “uci-ugi”
 ---
 
-It is also possible to use the IRC integration, called “chat” to play with a UCI bot through IRC. The bot will connect to a given network through TLS and then start responding to move names such as “e4” written on given channels.
+~~~
+make ugi-uci uci-ugi
+~~~
 
+`ugi-uci` may be used to let a UGI GUI communicate with a UCI bot, and conversely, `uci-ugi` may be used to let a UCI GUI communicate with a UGI bot.
+
+Simply pass the command of the bot as arguments to either of these tools, and it’ll translate it to be used by the respective GUI.
+
+Note that if the GUI sends a `uci`/`gui` command to the bot that is the same as its protocol, no translation will happen, and the commands will be passed in verbatim between them.
+
+using “chat”
+---
+
 ~~~
+make chat
+~~~
+
+moonfish’s IRC integration, called “chat” may be used to play with a UCI bot through IRC. The bot will connect to a given network through TLS and then start responding to move names such as “e4” written on given channels.
+
+~~~
 # have moonfish play on a given channel
 ./chat -N irc.example.net -C '#my-channel' ./moonfish
 
@@ -248,15 +256,40 @@
 
 [Libera Chat]: <https://libera.chat>
 
-using the UGI/UCI translators
+using “lichess”
 ---
 
-`ugi-uci` may be used to let a UGI GUI communicate with a UCI bot, and conversely, `uci-ugi` may be used to let a UCI GUI communicate with a UGI bot.
+~~~
+make lichess
+~~~
 
-Simply pass the command of the bot as arguments to either of these tools, and it’ll translate it to be used by the respective GUI.
+In order to integrate a UCI bot with [Lichess], it is possible to use “lichess”. Simply write `./lichess` followed by your bot’s command. The Lichess bot token may be specified with the `lichess_token` environment variable.
 
-Note that if the GUI sends a `uci`/`gui` command to the bot that is the same as its protocol, no translation will happen, and the commands will be passed in verbatim between them.
+[Lichess]: <https://lichess.org>
 
+~~~
+# (use Stockfish as a Lichess bot)
+lichess_token=XXX ./lichess stockfish
+
+# (use moonfish as a Lichess bot)
+lichess_token=XXX ./lichess ./moonfish
+~~~
+
+compiling on Plan 9
+---
+
+Note: [NPE] is required.
+
+[NPE]: <https://git.sr.ht/~ft/npe>
+
+After installing NPE, each file may be compiled and linked as expected. (Note: A `mkfile` isn’t provided.)
+
+~~~
+6c -I/sys/include/npe chess.c search.c main.c
+6l -o moonfish chess.6 search.6 main.6
+moonfish
+~~~
+
 compiling on Windows
 ---
 
@@ -267,6 +300,13 @@
 [cutechess]: <https://github.com/cutechess/cutechess>
 [C11 threads in VS]: <https://devblogs.microsoft.com/cppblog/c11-threads-in-visual-studio-2022-version-17-8-preview-2/>
 [MinGW]: <https://mingw-w64.org>
+
+porting moonfish
+---
+
+The only pieces of functionality the moonfish depends on that are not specified entirely in C89 are pthreads (POSIX threads) and `clock_gettime`. POSIX threads are not required, and may be substituted by C11 threads or even disabled altogether with compile-time macros. (See [“compiling from source”](#compile-from-source)) `clock_gettime` is required and cannot be replaced, however.
+
+Porting moonfish to a different platform should be a matter of simply providing a “mostly C89-compliant” environment alongside `clock_gettime` and pthreads. Of course, moonfish doesn’t make use of *all* C89 features, so it is not necessary to have features that it doesn’t use. [Compiling on Plan 9](#compiling-on-plan-9), for example, works through NPE, which provides something close enough to C89 for moonfish to work.
 
 license
 ---
--- a/moonfish.h
+++ b/moonfish.h
@@ -4,8 +4,57 @@
 #ifndef MOONFISH
 #define MOONFISH
 
+/* moonfish is a very simple chess bot written in C 89 (ANSI C) */
+
+/* in moonfish, pieces are each represented as a single 8-bit integer (char) */
+/* (note: only two hex digits fit in an 8-bit number) */
+
+/* the first hex digit of the integer represents the piece's color (1 for white, 2 for black) */
+/* whereas the second hex digit of the integer represents the piece's type (within its color) */
+/* this allows the piece type to be extracted with "p % 16" */
+/* and likewise for its color to be extracted with "p / 16" */
+/* (a special value (0xFF) is used for squares without pieces) */
+
+/* the board is represented coceptually as a 10-wide, 12-tall array */
+/* the actual board itself is represented within the 8 x 8 area centered on this array */
+/* (a special value (0x00) is used for pieces outside of the board) */
+
+/* the array itself is flattened into a 1D array with 120 elements */
+/* so the index into the array may be obtained from coordinatse using the following formula: */
+/* index = (x + 1) + (y + 2) * 8 */
+/* where "x" (file) and "y" (rank) are integers in the range 0..7 (inclusive) */
+
+/* "x = 0" represents the "a" file, "x = 8" represents the "h" file */
+/* "y = 0" represents the 1st rank, "y = 8" represents the 8th rank (from white's perspective) */
+/* e.g. "x = 0 ; y = 0" represents "a1", and "index = 17" */
+/* e.g. "x = 3 ; y = 5" represents "d6", and "index = 60" */
+/* e.g. "x = 5 ; y = 3" represents "f4", and "index = 46" */
+/* e.g. "x = 8 ; y = 8" represents "h8", and "index = 89" */
+
+/* diagram (for starting position) */
+/* i = 00..07 : 0x[00 00 00 00 00 00 00 00] */
+/* i = 08..15 : 0x[00 00 00 00 00 00 00 00] */
+/* i = 16..23 : 0x[00 14 12 15 16 12 14 00] */
+/* i = 24..31 : 0x[00 11 11 11 11 11 11 00] */
+/* i = 32..39 : 0x[00 FF FF FF FF FF FF 00] */
+/* i = 40..47 : 0x[00 FF FF FF FF FF FF 00] */
+/* i = 48..55 : 0x[00 FF FF FF FF FF FF 00] */
+/* i = 56..63 : 0x[00 FF FF FF FF FF FF 00] */
+/* i = 64..71 : 0x[00 21 21 21 21 21 21 00] */
+/* i = 72..79 : 0x[00 24 22 25 26 22 24 00] */
+/* i = 80..87 : 0x[00 00 00 00 00 00 00 00] */
+/* i = 88.119 : 0x[00 00 00 00 00 00 00 00] */
+/* (squares with 00 are outside of the board, squares with FF are empty) */
+
+/* note: white pieces are shown on the top, because they squares closest to white have a lower index */
+/* whereas the pieces closest to black have a higher index */
+/* this makes so that the board is flipped when displayed naively! (be careful) */
+
+/* the board is not just an 8 x 8 array because of an optisation that can be performed when generating moves */
+
 enum
 {
+	/* white pieces */
 	moonfish_white_pawn = 0x11,
 	moonfish_white_knight = 0x12,
 	moonfish_white_bishop = 0x13,
@@ -13,6 +62,7 @@
 	moonfish_white_queen = 0x15,
 	moonfish_white_king = 0x16,
 	
+	/* black pieces */
 	moonfish_black_pawn = 0x21,
 	moonfish_black_knight = 0x22,
 	moonfish_black_bishop = 0x23,
@@ -20,6 +70,7 @@
 	moonfish_black_queen = 0x25,
 	moonfish_black_king = 0x26,
 	
+	/* piece types (without colors) */
 	moonfish_pawn = 1,
 	moonfish_knight = 2,
 	moonfish_bishop = 3,
@@ -27,13 +78,18 @@
 	moonfish_queen = 5,
 	moonfish_king = 6,
 	
+	/* special values within the board representation */
 	moonfish_outside = 0,
 	moonfish_empty = 0xFF,
 	
+	/* constants for search */
+	/* depth: the maximum depth considerable feasibly reachable (in practice, it's much lower!) */
+	/* omega: high value (used as integral infinity) */
 	moonfish_depth = 50,
 	moonfish_omega = 5000000
 };
 
+/* bitfield booleans representing castling rights */
 struct moonfish_castle
 {
 	unsigned int white_oo:1, white_ooo:1;
@@ -40,62 +96,161 @@
 	unsigned int black_oo:1, black_ooo:1;
 };
 
+/* represents a chess position */
 struct moonfish_chess
 {
+	/* 10 x 12 array board representation */
 	unsigned char board[120];
+	
+	/* whether it's white's turn (a boolean) */
+	/* 1 means white's turn */
+	/* 0 means black's turn */
 	unsigned char white;
+	
+	/* square index of a pawn that may be captured via e.p. */
+	/* or zero if there is no such pawn */
 	unsigned char passing;
+	
+	/* castling rights */
 	struct moonfish_castle castle;
+	
+	/* PST score for the position */
 	int score;
 };
 
+/* represents a possible move in a specific position */
+/* note: a move will only be sensibly useful in the position that it is meant for! */
+/* using a move on a position that it is not meant for might cause weird things */
 struct moonfish_move
 {
+	/* indices of the squares the piece is moving from and to */
 	unsigned char from, to;
+	
+	/* integer representing the piece that is moving */
 	unsigned char piece;
+	
+	/* represents the piece that a pawn promotes to (if the move is a promotion) */
+	/* if the move is not a promotion, then "promotion == piece" */
 	unsigned char promotion;
+	
+	/* integer representing the captured piece (or "moonfish_empty" if the move isn't a capture) */
 	unsigned char captured;
+	
+	/* square index of the pawn that may have been captured via e.p. *before* this move was played (or zero if there was no such pawn) */
 	unsigned char passing;
+	
+	/* castling rights *before* the move was played */
 	struct moonfish_castle castle;
+	
+	/* PST score of the position *before* the move was played */
 	int score;
 };
 
+/* opaque analysis struct */
+/* a value may be created (with "malloc") by using the functions below, and then freed by using "free" */
+/* this contains information that may be used during analysis that may be kept across evaluations of positions */
 struct moonfish_analysis;
 
+/* initialises the position and sets up the initial position */
+/* note: this must be called *first* even if you want to use "moonfish_from_fen" */
 void moonfish_chess(struct moonfish_chess *chess);
 
+/* given a chess position, generates all moves for the piece at the square with the given index */
+/* the moves are stored in "moves", so it must be able to fit the moves for the given piece */
+/* note: an array of moves of size 32 is always enough (since its impossible to have a piece have more moves available than that in chess) */
+/* note: this might generate a move that leaves the king in check (which is invalid!) */
+/* note: it will not generate any other kind of invalid move */
+/* to filter out invalid moves, you may use "moonfish_validate" below on the position *after* playing the given move */
 void moonfish_moves(struct moonfish_chess *chess, struct moonfish_move *moves, unsigned char from);
+
+/* assumes that a move (with the given "from" and "to" indices) is valid in the given position and creates it */
+/* the generated move is stored in the given move pointer */
+/* this will ignore underpromotions (always promotes to queen when the pawn reaches the last rank) */
 void moonfish_force_move(struct moonfish_chess *chess, struct moonfish_move *move, unsigned char from, unsigned char to);
 
+/* play or unplay ("makes" or "unmakes") a given move by mutating the given position */
+/* note: a move must be played on the position it is meant for! */
+/* note: a move must be unplayed on the position that resulted from playing it! */
+/* that means move playing/unplaying must be balanced (surrounded by playing/unplaying the same move) */
 void moonfish_play(struct moonfish_chess *chess, struct moonfish_move *move);
 void moonfish_unplay(struct moonfish_chess *chess, struct moonfish_move *move);
 
+/* tries to find the best move in the given position in at most the given time */
+/* the move is stored in the "move" pointer, and the score for the position is returned */
+/* the move found is the best for the player whose turn it is on the given position */
+/* likewise, the score returned is from the perspective of the player whose turn it is */
 int moonfish_best_move_time(struct moonfish_analysis *analysis, struct moonfish_move *move, long int time);
+
+/* same as above, but tries to optimises the time spent searching for the given time left on each player's clock */
 int moonfish_best_move_clock(struct moonfish_analysis *analysis, struct moonfish_move *move, long int our_time, long int their_time);
+
+/* if a score is too large (i.e. "score >= moonfish_omega"), it will instead represent a "checkmate in X" evaluation */
+/* this function will obtain such "X" from the given score in that case */
 int moonfish_countdown(int score);
 
+/* creates an analysis, which may be used to analyse many positions */
+/* note: in the future, the analysis might hold information across analyses (such as a transposition table) */
+/* but currently, that is not implemented */
+/* the analysis is created using "malloc", so don't forget to call "free" on it once you don't need it anymore */
+/* the analysis will be set up for analysing the initial position (but you may change this, see below) */
+/* the give "argv0" is used to report errors if necessary */
+/* a reference to "argv0" is kept, so it should be available for as long as the analysis is being used */
+/* on the case of an error (while creating the analysis, or even just using it), the program will be stopped with "exit" */
 struct moonfish_analysis *moonfish_analysis(char *argv0);
+
+/* sets up an existing analysis (created with the function above) to analyse the given position */
+/* a reference to the given position pointer will not be kept */
 void moonfish_new(struct moonfish_analysis *analysis, struct moonfish_chess *chess);
 
+/* creates a move from UCI notation */
+/* the move is stored in "move" */
+/* the given move it is not validated! (so make sure the move is actually valid) */
 void moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
+
+/* converts a move to UCI notation */
+/* the name is stored in the given "char" pointer (including the trailing NUL), so make sure you pass in a pointer that can fit it */
+/* a "char" array of size 6 is always enough to fit a given move name */
 void moonfish_to_uci(struct moonfish_move *move, char *name);
 
+/* returns whether an iinvalid move was just played (i.e. whether the opponent king is attacked on the given position) */
+/* return 0: the opponent king is attacked, an invalid move was just played */
+/* return 1: the opponent king is not attacked, an invalid move was not just played */
 int moonfish_validate(struct moonfish_chess *chess);
+
+/* returns whether player to play is in check (i.e. whether the current player's king is attacked on the given position) */
 int moonfish_check(struct moonfish_chess *chess);
 
 #ifndef moonfish_mini
 
+/* tries to find the best move on the position with a given depth */
+/* similar to "moonfish_best_move_time" and "moonfish_best_move_clock" */
 int moonfish_best_move_depth(struct moonfish_analysis *analysis, struct moonfish_move *move, int depth);
 
+/* uses the position from the given FEN, mutating the given position */
+/* returns 0 if the FEN could be parsed */
+/* returns 1 if the FEN could not be parsed (the position becomes unusable then!) */
+/* validation is very loose, so the FEN should be known to be good, otherwise this might cause unexpected results */
 int moonfish_from_fen(struct moonfish_chess *chess, char *fen);
+
+/* converts the given position to FEN */
+/* the FEN is stored in the given "char" array, so it must be able to fit the FEN (including trailing NUL) */
 void moonfish_to_fen(struct moonfish_chess *chess, char *fen);
 
+/* similar to "moonfish_from_uci" and "moonfish_to_uci", but for SAN instead */
+/* SAN parsing is very loose, so it will accept many forms, including UCI */
+/* on succes, SAN parsing will return 0, on failure, it will return 1 (and the move is unchanged) */
+/* parsing is somewhat robust, so you can trust it won't succeed with an invalid move */
 int moonfish_from_san(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
 void moonfish_to_san(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
 
+/* similar to "moonfish_force_move", but this will perform validation, and only return 0 for a valid move */
+/* on failure (i.e. invalid move), it will return 1, and the move is not usable */
 int moonfish_move(struct moonfish_chess *chess, struct moonfish_move *move, unsigned char from, unsigned char to);
 
+/* returns whether the game ended due to either checkmate or stalemate */
 int moonfish_finished(struct moonfish_chess *chess);
+
+/* returns whether the game ended due to respectively checkmate or stalemate */
 int moonfish_checkmate(struct moonfish_chess *chess);
 int moonfish_stalemate(struct moonfish_chess *chess);
 
--