shithub: moonfish

Download patch

ref: 575be7e3a63fadd2aa6a349c5e3e0f9b9e115e0f
parent: d651ab6474d4380fb93500bb9e5ee681b51ac21f
author: zamfofex <zamfofex@twdb.moe>
date: Mon Dec 18 21:56:10 EST 2023

avoid threefold repetition (when winning)

--- a/README.md
+++ b/README.md
@@ -35,6 +35,7 @@
 - no good move ordering heuristic
 - no support for `go infinite` or `go mate`
 - no move name or FEN validation (may lead to potential exploits)
+- games with too many moves may cause a buffer overflow
 
 download
 ---
--- a/chess.c
+++ b/chess.c
@@ -624,3 +624,68 @@
 	if (!moonfish_finished(chess)) return 0;
 	return moonfish_check(chess) ^ 1;
 }
+
+static int moonfish_equals(struct moonfish_chess *a, struct moonfish_chess *b)
+{
+	int x, y;
+	
+	if (a->white != b->white) return 0;
+	if (a->score != b->score) return 0;
+	
+	if (a->castle.white_oo != b->castle.white_oo) return 0;
+	if (a->castle.white_ooo != b->castle.white_ooo) return 0;
+	if (a->castle.black_oo != b->castle.black_oo) return 0;
+	if (a->castle.black_ooo != b->castle.black_ooo) return 0;
+	
+	for (y = 0 ; y < 8 ; y++)
+	for (x = 0 ; x < 8 ; x++)
+		if (a->board[(x + 1) + (y + 2) * 10] != b->board[(x + 1) + (y + 2) * 10])
+			return 0;
+	
+	return 1;
+}
+
+void moonfish_repetition_account(struct moonfish_repetition *repetition, struct moonfish_chess *chess, int count)
+{
+	struct moonfish_repetition_entry *entry;
+	
+	entry = repetition->entries;
+	
+	for (;;)
+	{
+		if (entry->count == -1) break;
+		if (moonfish_equals(&entry++->chess, chess)) break;
+	}
+	
+	if (entry->count == -1)
+	{
+		entry->chess = *chess;
+		entry->count = 0;
+		entry[1].count = -1;
+	}
+	
+	entry->count += count;
+	
+	if (entry->count != 0) return;
+	
+	for (;;)
+	{
+		entry[0] = entry[1];
+		entry++;
+		if (entry->count == -1) break;
+	}
+}
+
+int moonfish_repetition(struct moonfish_repetition *repetition)
+{
+	struct moonfish_repetition_entry *entry;
+	
+	entry = repetition->entries;
+	
+	for (;;)
+	{
+		if (entry->count == -1) return 0;
+		if (entry->count >= 3) return 1;
+		entry++;
+	}
+}
--- a/main.c
+++ b/main.c
@@ -33,6 +33,7 @@
 	ctx->argv0 = argv[0];
 	ctx->cpu_count = -1;
 	moonfish_chess(&ctx->chess);
+	ctx->repetition.entries[0].count = -1;
 	
 	for (;;)
 	{
@@ -140,6 +141,8 @@
 				return 1;
 			}
 			
+			moonfish_repetition_account(&ctx->repetition, &ctx->chess, 1);
+			
 			arg = strtok(NULL, "\r\n\t ");
 			if (arg != NULL && !strcmp(arg, "moves"))
 			{
@@ -147,6 +150,7 @@
 				{
 					moonfish_from_uci(&ctx->chess, &move, arg);
 					moonfish_play(&ctx->chess, &move);
+					moonfish_repetition_account(&ctx->repetition, &ctx->chess, 1);
 				}
 			}
 		}
--- a/moonfish.h
+++ b/moonfish.h
@@ -47,9 +47,21 @@
 	int score;
 };
 
+struct moonfish_repetition_entry
+{
+	struct moonfish_chess chess;
+	int count;
+};
+
+struct moonfish_repetition
+{
+	struct moonfish_repetition_entry entries[512];
+};
+
 struct moonfish
 {
 	struct moonfish_chess chess;
+	struct moonfish_repetition repetition;
 	char *argv0;
 	int cpu_count;
 };
@@ -82,5 +94,8 @@
 int moonfish_checkmate(struct moonfish_chess *chess);
 int moonfish_stalemate(struct moonfish_chess *chess);
 int moonfish_finished(struct moonfish_chess *chess);
+
+void moonfish_repetition_account(struct moonfish_repetition *repetition, struct moonfish_chess *chess, int count);
+int moonfish_repetition(struct moonfish_repetition *repetition);
 
 #endif
--- a/search.c
+++ b/search.c
@@ -84,6 +84,7 @@
 	int i, j;
 	struct moonfish_search_info infos[32];
 	int result;
+	int repetition;
 #ifdef __MINGW32__
 	SYSTEM_INFO info;
 #endif
@@ -109,6 +110,8 @@
 	moves = move_array;
 	best_score = -200 * moonfish_omega;
 	
+	repetition = moonfish_repetition(&ctx->repetition) * 2;
+	
 	for (y = 0 ; y < 8 ; y++)
 	for (x = 0 ; x < 8 ; x++)
 	{
@@ -158,7 +161,14 @@
 			return -200 * moonfish_omega;
 		}
 		
-		if (moonfish_stalemate(&ctx->chess))
+		if (repetition != 2)
+		{
+			moonfish_repetition_account(&ctx->repetition, &ctx->chess, 1);
+			repetition = moonfish_repetition(&ctx->repetition);
+			moonfish_repetition_account(&ctx->repetition, &ctx->chess, -1);
+		}
+		
+		if (moonfish_stalemate(&ctx->chess) || repetition == 1)
 		{
 			if (best_score < 0)
 			{
--