shithub: moonfish

Download patch

ref: e1d99b2f93cc7a4e68d957a6f0d45dc693247cb6
parent: 70bd1665792632bc3007dfb07024a072010ff975
author: zamfofex <zamfofex@twdb.moe>
date: Thu Mar 20 11:08:19 EDT 2025

simplify move generation

--- a/chess.c
+++ b/chess.c
@@ -5,27 +5,17 @@
 
 #include "moonfish.h"
 
-static void moonfish_force_promotion(struct moonfish_chess *chess, struct moonfish_move **moves, int from, int to, int promotion)
+static void moonfish_force_promotion(struct moonfish_move **moves, int from, int to, int piece)
 {
 	(*moves)->from = from;
 	(*moves)->to = to;
-	(*moves)->chess = *chess;
-	(*moves)->chess.board[to] = promotion;
-	(*moves)->chess.board[from] = moonfish_empty;
-	(*moves)->chess.passing = 0;
-	(*moves)->chess.white ^= 1;
-	
-	if (from == 21 || to == 21) (*moves)->chess.ooo[0] = 0;
-	if (from == 28 || to == 28) (*moves)->chess.oo[0] = 0;
-	if (from == 91 || to == 91) (*moves)->chess.ooo[1] = 0;
-	if (from == 98 || to == 98) (*moves)->chess.oo[1] = 0;
-	
+	(*moves)->piece = piece;
 	(*moves)++;
 }
 
-static void moonfish_force_move(struct moonfish_chess *chess, struct moonfish_move **moves, int from, int to)
+static void moonfish_force_move(struct moonfish_move **moves, int from, int to, struct moonfish_chess *chess)
 {
-	moonfish_force_promotion(chess, moves, from, to, chess->board[from]);
+	moonfish_force_promotion(moves, from, to, chess->board[from]);
 }
 
 static void moonfish_deltas(struct moonfish_chess *chess, struct moonfish_move **moves, int from, int *deltas, int count, int n)
@@ -39,7 +29,7 @@
 			to += *deltas * n;
 			if (chess->board[to] == moonfish_outside) break;
 			if (chess->board[to] / 16 == chess->board[from] / 16) break;
-			moonfish_force_move(chess, moves, from, to);
+			moonfish_force_move(moves, from, to, chess);
 			if (chess->board[to] != moonfish_empty) break;
 		}
 		deltas++;
@@ -89,44 +79,16 @@
 	return moonfish_check(&other);
 }
 
-static void moonfish_castle_low(struct moonfish_chess *chess, struct moonfish_move **moves, int from)
+static void moonfish_castle(struct moonfish_chess *chess, struct moonfish_move **moves, int from, int to, int dy)
 {
-	int to;
-	
-	if (!chess->ooo[chess->white ^ 1]) return;
-	
-	to = from - 3;
 	while (to != from) {
-		if (chess->board[to++] != moonfish_empty) return;
+		if (chess->board[to] != moonfish_empty) return;
+		to -= dy;
 	}
-	if (moonfish_check(chess)) return;
-	if (moonfish_attacked(chess, from, from - 1)) return;
-	if (moonfish_attacked(chess, from, from - 2)) return;
 	
-	moonfish_force_move(chess, moves, from - 4, from - 1);
-	(*moves)--;
-	(*moves)->chess.white = chess->white;
-	moonfish_force_move(&(*moves)->chess, moves, from, from - 2);
-}
-
-static void moonfish_castle_high(struct moonfish_chess *chess, struct moonfish_move **moves, int from)
-{
-	int to;
-	
-	if (!chess->oo[chess->white ^ 1]) return;
-	
-	to = from + 2;
-	while (to != from) {
-		if (chess->board[to--] != moonfish_empty) return;
-	}
 	if (moonfish_check(chess)) return;
-	if (moonfish_attacked(chess, from, from + 1)) return;
-	if (moonfish_attacked(chess, from, from + 2)) return;
-	
-	moonfish_force_move(chess, moves, from + 3, from + 1);
-	(*moves)--;
-	(*moves)->chess.white = chess->white;
-	moonfish_force_move(&(*moves)->chess, moves, from, from + 2);
+	if (moonfish_attacked(chess, from, from + dy)) return;
+	moonfish_force_move(moves, from, from + dy * 2, chess);
 }
 
 static void moonfish_pawn_moves(struct moonfish_chess *chess, struct moonfish_move **moves, int from, int to)
@@ -134,25 +96,21 @@
 	int color;
 	
 	if (to > 30 && to < 90) {
-		moonfish_force_move(chess, moves, from, to);
+		moonfish_force_move(moves, from, to, chess);
 		return;
 	}
 	
 	color = chess->board[from] & 0xF0;
-	moonfish_force_promotion(chess, moves, from, to, color | moonfish_queen);
-	moonfish_force_promotion(chess, moves, from, to, color | moonfish_rook);
-	moonfish_force_promotion(chess, moves, from, to, color | moonfish_bishop);
-	moonfish_force_promotion(chess, moves, from, to, color | moonfish_knight);
+	moonfish_force_promotion(moves, from, to, color | moonfish_queen);
+	moonfish_force_promotion(moves, from, to, color | moonfish_rook);
+	moonfish_force_promotion(moves, from, to, color | moonfish_bishop);
+	moonfish_force_promotion(moves, from, to, color | moonfish_knight);
 }
 
 static void moonfish_pawn_capture(struct moonfish_chess *chess, struct moonfish_move **moves, int from, int to)
 {
-	int dy;
-	
 	if (to == chess->passing) {
-		dy = chess->white ? 10 : -10;
-		moonfish_force_move(chess, moves, from, to);
-		(*moves)[-1].chess.board[to - dy] = moonfish_empty;
+		moonfish_force_move(moves, from, to, chess);
 		return;
 	}
 	
@@ -170,8 +128,7 @@
 	if (chess->board[from + dy] == moonfish_empty) {
 		moonfish_pawn_moves(chess, moves, from, from + dy);
 		if ((chess->white ? from < 40 : from > 80) && chess->board[from + dy * 2] == moonfish_empty) {
-			moonfish_force_move(chess, moves, from, from + dy * 2);
-			(*moves)[-1].chess.passing = from + dy;
+			moonfish_force_move(moves, from, from + dy * 2, chess);
 		}
 	}
 	
@@ -193,7 +150,6 @@
 	
 	struct moonfish_move *moves0;
 	int piece;
-	int i, count;
 	
 	moves0 = moves;
 	piece = chess->board[from];
@@ -203,24 +159,55 @@
 	moonfish_deltas(chess, &moves, from, deltas[piece % 16 - 1], steps[piece % 16 - 1], 1);
 	moonfish_deltas(chess, &moves, from, deltas[piece % 16 - 1], steps[piece % 16 - 1], -1);
 	
-	if (piece % 16 == moonfish_pawn) moonfish_move_pawn(chess, &moves, from);
+	if (piece % 16 == moonfish_pawn) {
+		moonfish_move_pawn(chess, &moves, from);
+	}
 	
 	if (piece % 16 == moonfish_king) {
-		
-		moonfish_castle_high(chess, &moves, from);
-		moonfish_castle_low(chess, &moves, from);
-		
-		count = moves - moves0;
-		
-		for (i = 0 ; i < count ; i++) {
-			moves0[i].chess.oo[chess->white ^ 1] = 0;
-			moves0[i].chess.ooo[chess->white ^ 1] = 0;
-		}
+		if (chess->oo[chess->white ^ 1]) moonfish_castle(chess, &moves, from, from + 2, 1);
+		if (chess->ooo[chess->white ^ 1]) moonfish_castle(chess, &moves, from, from - 3, -1);
 	}
 	
 	return moves - moves0;
 }
 
+void moonfish_play(struct moonfish_chess *chess, struct moonfish_move *move)
+{
+	int dy;
+	int passing;
+	
+	passing = chess->passing;
+	chess->passing = 0;
+	
+	if (move->piece % 16 == moonfish_pawn) {
+		dy = chess->white ? 10 : -10;
+		if (move->to == passing) chess->board[move->to - dy] = moonfish_empty;
+		if (move->to - move->from == dy * 2) chess->passing = move->to - dy;
+	}
+	
+	if (move->piece % 16 == moonfish_king) {
+		chess->oo[chess->white ^ 1] = 0;
+		chess->ooo[chess->white ^ 1] = 0;
+		if (move->to - move->from == 2) {
+			chess->board[move->to - 1] = chess->board[move->to + 1];
+			chess->board[move->to + 1] = moonfish_empty;
+		}
+		if (move->to - move->from == -2) {
+			chess->board[move->to + 1] = chess->board[move->to - 2];
+			chess->board[move->to - 2] = moonfish_empty;
+		}
+	}
+	
+	if (move->from == 28 || move->to == 28) chess->oo[0] = 0;
+	if (move->from == 98 || move->to == 98) chess->oo[1] = 0;
+	if (move->from == 21 || move->to == 21) chess->ooo[0] = 0;
+	if (move->from == 91 || move->to == 91) chess->ooo[1] = 0;
+	
+	chess->board[move->from] = moonfish_empty;
+	chess->board[move->to] = move->piece;
+	chess->white ^= 1;
+}
+
 void moonfish_chess(struct moonfish_chess *chess)
 {
 	static int pieces[] = {moonfish_rook, moonfish_knight, moonfish_bishop, moonfish_queen, moonfish_king, moonfish_bishop, moonfish_knight, moonfish_rook};
@@ -254,7 +241,6 @@
 {
 	char *alphabet;
 	int x, y;
-	int piece;
 	
 	alphabet = "abcdefgh";
 	
@@ -272,13 +258,11 @@
 	
 	name[4] = 0;
 	
-	piece = move->chess.board[move->to];
-	
-	if (piece != chess->board[move->from]) {
-		if (piece % 16 == moonfish_queen) name[4] = 'q';
-		if (piece % 16 == moonfish_rook) name[4] = 'r';
-		if (piece % 16 == moonfish_bishop) name[4] = 'b';
-		if (piece % 16 == moonfish_knight) name[4] = 'n';
+	if (move->piece != chess->board[move->from]) {
+		if (move->piece % 16 == moonfish_queen) name[4] = 'q';
+		if (move->piece % 16 == moonfish_rook) name[4] = 'r';
+		if (move->piece % 16 == moonfish_bishop) name[4] = 'b';
+		if (move->piece % 16 == moonfish_knight) name[4] = 'n';
 		name[5] = 0;
 	}
 }
@@ -349,12 +333,15 @@
 	struct moonfish_move moves[32];
 	int x, y;
 	int i, count;
+	struct moonfish_chess other;
 	
 	for (y = 0 ; y < 8 ; y++) {
 		for (x = 0 ; x < 8 ; x++) {
 			count = moonfish_moves(chess, moves, (x + 1) + (y + 2) * 10);
 			for (i = 0 ; i < count ; i++) {
-				if (moonfish_validate(&moves[i].chess)) return 0;
+				other = *chess;
+				moonfish_play(&other, moves + i);
+				if (moonfish_validate(&other)) return 0;
 			}
 		}
 	}
@@ -366,14 +353,17 @@
 {
 	struct moonfish_move moves[32];
 	int i, count;
+	struct moonfish_chess other;
 	
 	count = moonfish_moves(chess, moves, from);
 	
 	for (i = 0 ; i < count ; i++) {
-		if (moves[i].to == to && moonfish_validate(&moves[i].chess)) {
-			*found = moves[i];
-			return 0;
-		}
+		if (moves[i].to != to) continue;
+		other = *chess;
+		moonfish_play(&other, moves + i);
+		if (!moonfish_validate(&other)) continue;
+		*found = moves[i];
+		return 0;
 	}
 	
 	return 1;
@@ -510,6 +500,7 @@
 	struct moonfish_move moves[32];
 	int xi0, yi0, xi1, yi1;
 	int i, count;
+	struct moonfish_chess other;
 	
 	xi0 = 0, xi1 = 8;
 	yi0 = 0, yi1 = 8;
@@ -527,7 +518,7 @@
 			for (i = 0 ; i < count ; i++) {
 				
 				if (chess->board[moves[i].from] % 16 != type) continue;
-				if (promotion && promotion != moves[i].chess.board[moves[i].to] % 16) continue;
+				if (promotion && promotion != moves[i].piece % 16) continue;
 				if (moves[i].to % 10 != x1) continue;
 				if (moves[i].to / 10 - 1 != y1) continue;
 				
@@ -540,7 +531,9 @@
 					}
 				}
 				
-				if (!moonfish_validate(&moves[i].chess)) continue;
+				other = *chess;
+				moonfish_play(&other, moves + i);
+				if (!moonfish_validate(&other)) continue;
 				if (check && !moonfish_check(chess)) continue;
 				if (check == 2 && !moonfish_checkmate(chess)) continue;
 				if (found) return 1;
@@ -765,6 +758,7 @@
 	int to_x, to_y;
 	int from_x, from_y;
 	int i, count;
+	struct moonfish_chess other;
 	
 	from_x = move->from % 10 - 1;
 	from_y = move->from / 10 - 2;
@@ -793,9 +787,9 @@
 		*name++ = moonfish_to_file(to_x);
 		*name++ = to_y + '1';
 		
-		if (move->chess.board[move->to] % 16 != moonfish_pawn) {
+		if (move->piece % 16 != moonfish_pawn) {
 			*name++ = '=';
-			*name++ = names[move->chess.board[move->to] % 16 - 2];
+			*name++ = names[move->piece % 16 - 2];
 		}
 		
 		*name = 0;
@@ -842,11 +836,13 @@
 	*name++ = moonfish_to_file(to_x);
 	*name++ = to_y + '1';
 	
-	if (moonfish_checkmate(&move->chess)) {
+	other = *chess;
+	moonfish_play(&other, move);
+	if (moonfish_checkmate(&other)) {
 		if (~check & 1) *name++ = '#';
 	}
 	else {
-		if (moonfish_check(&move->chess)) {
+		if (moonfish_check(&other)) {
 			if (~check & 2) *name++ = '+';
 		}
 	}
--- a/main.c
+++ b/main.c
@@ -61,7 +61,7 @@
 		moonfish_root(info->root, &chess);
 		for (j = 0 ; j < count ; j++) {
 			moonfish_to_uci(&chess, pv + j, name);
-			chess = pv[j].chess;
+			moonfish_play(&chess, pv + j);
 			printf(" %s", name);
 		}
 		printf("\n");
@@ -243,9 +243,13 @@
 			}
 			
 			moonfish_root(root, &chess0);
-			if (moonfish_equal(&chess0, &chess)) moonfish_reroot(root, &move.chess);
-			
-			chess = move.chess;
+			if (moonfish_equal(&chess0, &chess)) {
+				moonfish_play(&chess, &move);
+				moonfish_reroot(root, &chess);
+			}
+			else {
+				moonfish_play(&chess, &move);
+			}
 		}
 	}
 	
--- a/moonfish.h
+++ b/moonfish.h
@@ -84,12 +84,10 @@
 
 /* represents a move that may be made on a given position */
 struct moonfish_move {
-	
-	/* the position after the move is played */
-	struct moonfish_chess chess;
-	
 	/* square indices of where the piece moved from and to */
 	unsigned char from, to;
+	/* the piece that moved (or the promotion piece) */
+	unsigned char piece;
 };
 
 /* represents cross-search state */
@@ -178,6 +176,9 @@
 /* on failure (i.e. invalid move), this will return 1, and the move the pointer points to will not be usable */
 /* note: this will ignore underpromotions (always promotes to queen when a pawn reaches the last rank) */
 int moonfish_move(struct moonfish_chess *chess, struct moonfish_move *move, int from, int to);
+
+/* plays the move on the given position, updating it */
+void moonfish_play(struct moonfish_chess *chess, struct moonfish_move *move);
 
 /* returns whether the game ended due to either checkmate or stalemate */
 /* note: 0 means false (i.e. not finished) */
--- a/search.c
+++ b/search.c
@@ -176,6 +176,7 @@
 	int count, i;
 	int child_count;
 	struct moonfish_move moves[32];
+	struct moonfish_chess other;
 	
 	node->children = NULL;
 	child_count = 0;
@@ -195,14 +196,17 @@
 			
 			for (i = 0 ; i < count ; i++) {
 				
-				if (!moonfish_validate(&moves[i].chess)) continue;
+				other = *chess;
+				moonfish_play(&other, moves + i);
+				
+				if (!moonfish_validate(&other)) continue;
 				moonfish_node(node->children + child_count);
 				node->children[child_count].parent = node;
 				node->children[child_count].from = (x + 1) + (y + 2) * 10;
 				node->children[child_count].index = i;
 				
-				node->children[child_count].score = moonfish_score(&moves[i].chess);
-				if (!moves[i].chess.white) node->children[child_count].score *= -1;
+				node->children[child_count].score = moonfish_score(&other);
+				if (chess->white) node->children[child_count].score *= -1;
 				
 				child_count++;
 			}
@@ -232,7 +236,7 @@
 {
 	struct moonfish_move move;
 	moonfish_node_move(node, chess, &move);
-	*chess = move.chess;
+	moonfish_play(chess, &move);
 }
 
 #ifndef moonfish_no_threads
@@ -565,7 +569,7 @@
 		}
 		
 		moonfish_node_move(node, &chess, moves + j);
-		chess = moves[j].chess;
+		moonfish_play(&chess, moves + j);
 		
 		best_score = INT_MAX;
 		best_node = NULL;
--- a/tools/analyse.c
+++ b/tools/analyse.c
@@ -407,7 +407,7 @@
 						strcpy(ply.best, arg);
 					}
 					if (pv > 1) {
-						ply.chess = move.chess;
+						moonfish_play(&ply.chess, &move);
 						i = 1;
 						continue;
 					}
@@ -414,7 +414,7 @@
 					moonfish_to_san(&ply.chess, &move, san, 0);
 					length = strlen(san);
 					if (i + length > sizeof fancy->pv - 2) break;
-					ply.chess = move.chess;
+					moonfish_play(&ply.chess, &move);
 					fancy->pv[i++] = ' ';
 					strcpy(fancy->pv + i, san);
 					i += length;
@@ -612,7 +612,7 @@
 	if (fancy->offset < 0) fancy->offset = 0;
 }
 
-static void moonfish_play(struct moonfish_fancy *fancy, struct moonfish_move *move)
+static void moonfish_fancy_play(struct moonfish_fancy *fancy, struct moonfish_move *move)
 {
 	struct moonfish_ply *ply, *next;
 	int i, count;
@@ -687,10 +687,11 @@
 	if (move == NULL) return;
 	moonfish_to_san(&fancy->plies[fancy->i].chess, move, fancy->plies[fancy->i].san, 1);
 	
-	ply->chess = move->chess;
+	ply->chess = fancy->plies[fancy->i].chess;
+	moonfish_play(&ply->chess, move);
 	
 	if (i + 1 < fancy->count && ply->chess.white == ply[1].chess.white) {
-		moonfish_play(fancy, NULL);
+		moonfish_fancy_play(fancy, NULL);
 		fancy->i = i;
 	}
 	
@@ -818,7 +819,7 @@
 		
 		for (;;) {
 			if (moonfish_pgn(file, &fancy->plies[fancy->i].chess, &move, fancy->i == 0 ? 1 : 0)) break;
-			moonfish_play(fancy, &move);
+			moonfish_fancy_play(fancy, &move);
 		}
 		
 		for (i = 0 ; i < fancy->count ; i++) {
@@ -1036,7 +1037,7 @@
 					fprintf(stderr, "invalid best move: %s\n", fancy->plies[fancy->i].best);
 					return 1;
 				}
-				moonfish_play(fancy, &move);
+				moonfish_fancy_play(fancy, &move);
 			}
 			continue;
 		}
@@ -1066,7 +1067,7 @@
 		/* handle mouse up or mouse down: if it forms a valid move, play it on the board */
 		if (ch0 == 0x20 || ch0 == 0x23) {
 			if (!moonfish_move_from(&fancy->plies[fancy->i].chess, &move, fancy->x, fancy->y, x1, y1)) {
-				moonfish_play(fancy, &move);
+				moonfish_fancy_play(fancy, &move);
 				continue;
 			}
 		}
--- a/tools/chat.c
+++ b/tools/chat.c
@@ -154,7 +154,7 @@
 	char name[6];
 	int i;
 	
-	moonfish_to_fen(&move->chess, fen);
+	moonfish_to_fen(chess, fen);
 	moonfish_to_uci(chess, move, name);
 	
 	for (i = 0 ; fen[i] != 0 ; i++) {
@@ -253,7 +253,10 @@
 		
 		if (moonfish_from_san(&chess, &move, message)) continue;
 		
-		if (moonfish_finished(&move.chess)) {
+		moonfish_to_uci(&chess, &move, name);
+		moonfish_play(&chess, &move);
+		
+		if (moonfish_finished(&chess)) {
 			
 			moonfish_write_fen(tls, &chess, &move, channel);
 			moonfish_chess(&chess);
@@ -266,9 +269,6 @@
 			continue;
 		}
 		
-		moonfish_to_uci(&chess, &move, name);
-		chess = move.chess;
-		
 		names = realloc(names, strlen(names) + strlen(name) + 2);
 		if (names == NULL) {
 			perror("realloc");
@@ -310,7 +310,7 @@
 		moonfish_write_text(tls, "\r\n");
 		
 		moonfish_write_fen(tls, &chess, &move, channel);
-		chess = move.chess;
+		moonfish_play(&chess, &move);
 		
 		if (moonfish_finished(&chess)) {
 			
--- a/tools/perft.c
+++ b/tools/perft.c
@@ -13,6 +13,7 @@
 	int x, y;
 	long int perft;
 	int i, count;
+	struct moonfish_chess other;
 	
 	if (depth == 0) return 1;
 	
@@ -22,9 +23,10 @@
 		for (x = 0 ; x < 8 ; x++) {
 			count = moonfish_moves(chess, moves, (x + 1) + (y + 2) * 10);
 			for (i = 0 ; i < count ; i++) {
-				if (moonfish_validate(&moves[i].chess)) {
-					perft += moonfish_perft(&moves[i].chess, depth - 1);
-				}
+				other = *chess;
+				moonfish_play(&other, moves + i);
+				if (!moonfish_validate(&other)) continue;
+				perft += moonfish_perft(&other, depth - 1);
 			}
 		}
 	}
--