shithub: moonfish

ref: e5ea84bb37694b5474fbf6073cc5852a14d68f8b
dir: /search.c/

View raw version
#include <time.h>

#include "moonfish.h"

static int moonfish_evaluate(struct moonfish_chess *chess, struct moonfish_nnue *nnue)
{
	int features[18] = {0};
	int x, y;
	int i, j;
	unsigned char piece, color, type;
	int scale;
	int *white_values, *black_values;
	int hidden[10], score;
	
	scale = 0;
	
	for (y = 0 ; y < 8 ; y++)
	for (x = 0 ; x < 8 ; x++)
	{
		piece = chess->board[(x + 1) + (y + 2) * 10];
		if (piece == moonfish_empty) continue;
		
		color = (piece >> 4) - 1;
		type = (piece & 0xF) - 1;
		
		white_values = nnue->values[color][type][63 - (x + y * 8)];
		black_values = nnue->values[color ^ 1][type][x + y * 8];
		
		scale += white_values[0];
		scale -= black_values[0];
		
		for (i = 0 ; i < 9 ; i++)
		{
			features[i] += white_values[i + 1];
			features[i + 9] += black_values[i + 1];
		}
	}
	
	for (i = 0 ; i < 10 ; i++)
	{
		hidden[i] = 0;
		for (j = 0 ; j < 18 ; j++)
			hidden[i] += nnue->layer1[i * 18 + j] * moonfish_tanh(features[j]) / 127;
	}
	
	score = 0;
	for (i = 0 ; i < 10 ; i++)
		score += moonfish_tanh(hidden[i]) * nnue->layer2[i] / 127;
	
	return score * 360 + scale * nnue->scale * 360 / 256;
}

static int moonfish_search(struct moonfish_chess *chess, struct moonfish_nnue *nnue, int alpha, int beta, int depth)
{
	int x, y;
	struct moonfish_move moves[32];
	struct moonfish_move *move;
	int score;
	
	if (depth <= 0)
	{
		score = moonfish_evaluate(chess, nnue);
		if (depth <= -3) return score;
		
		if (score >= beta) return beta;
		if (score > alpha) alpha = score;
	}
	
	for (y = 0 ; y < 8 ; y++)
	for (x = 0 ; x < 8 ; x++)
	{
		moonfish_moves(chess, moves, (x + 1) + (y + 2) * 10);
		
		for (move = moves ; move->piece != moonfish_outside ; move++)
		{
			if (depth <= 0 && move->captured == moonfish_empty) continue;
			if (move->captured == moonfish_their_king) return moonfish_omega * (depth + 10);
			
			moonfish_play(chess, move);
			score = -moonfish_search(chess, nnue, -beta, -alpha, depth - 1);
			moonfish_unplay(chess, move);
			
			if (score >= beta) return beta;
			if (score > alpha) alpha = score;
		}
	}
	
	return alpha;
}

#ifdef MOONFISH_HAS_PTHREAD

#include <stdlib.h>
#include <string.h>

struct moonfish_search_info
{
	pthread_t thread;
	struct moonfish_move move;
	struct moonfish_chess chess;
	struct moonfish_nnue *nnue;
	int depth;
	int score;
};

static void *moonfish_start_search(void *data)
{
	struct moonfish_search_info *info;
	info = data;
	info->score = -moonfish_search(&info->chess, info->nnue, -100 * moonfish_omega, 100 * moonfish_omega, info->depth);
	return NULL;
}

static int moonfish_best_move_depth(struct moonfish *ctx, struct moonfish_move *best_move, int depth)
{
	int x, y;
	struct moonfish_move *move, moves[32];
	int best_score;
	int count, i;
	struct moonfish_search_info *infos;
	int result;
	
	infos = malloc(256 * sizeof *infos);
	count = 0;
	best_score = -200 * moonfish_omega;
	
	for (y = 0 ; y < 8 ; y++)
	for (x = 0 ; x < 8 ; x++)
	{
		moonfish_moves(&ctx->chess, moves, (x + 1) + (y + 2) * 10);
		
		for (move = moves ; move->piece != moonfish_outside ; move++)
		{
			moonfish_play(&ctx->chess, move);
			
			if (!moonfish_validate(&ctx->chess))
			{
				moonfish_unplay(&ctx->chess, move);
				continue;
			}
			
			infos[count].move = *move;
			infos[count].chess = ctx->chess;
			infos[count].nnue = &ctx->nnue;
			infos[count].depth = depth;
			
			result = pthread_create(&infos[count].thread, NULL, &moonfish_start_search, infos + count);
			if (result)
			{
				free(infos);
				fprintf(stderr, "%s: %s\n", ctx->argv0, strerror(result));
				exit(1);
			}
			
			moonfish_unplay(&ctx->chess, move);
			
			count++;
		}
	}
	
	for (i = 0 ; i < count ; i++)
	{
		result = pthread_join(infos[i].thread, NULL);
		if (result)
		{
			free(infos);
			fprintf(stderr, "%s: %s\n", ctx->argv0, strerror(result));
			exit(1);
		}
		
		if (infos[i].score > best_score)
		{
			*best_move = infos[i].move;
			best_score = infos[i].score;
		}
	}
	
	free(infos);
	return best_score;
}

#else

static int moonfish_best_move_depth(struct moonfish *ctx, struct moonfish_move *best_move, int depth)
{
	int x, y;
	struct moonfish_move moves[32];
	struct moonfish_move *move;
	int score, best_score;
	
	best_score = -200 * moonfish_omega;
	
	for (y = 0 ; y < 8 ; y++)
	for (x = 0 ; x < 8 ; x++)
	{
		moonfish_moves(&ctx->chess, moves, (x + 1) + (y + 2) * 10);
		
		for (move = moves ; move->piece != moonfish_outside ; move++)
		{
			moonfish_play(&ctx->chess, move);
			
			if (!moonfish_validate(&ctx->chess))
			{
				moonfish_unplay(&ctx->chess, move);
				continue;
			}
			
			score = -moonfish_search(&ctx->chess, &ctx->nnue, -100 * moonfish_omega, 100 * moonfish_omega, depth);
			moonfish_unplay(&ctx->chess, move);
			
			if (score > best_score)
			{
				*best_move = *move;
				best_score = score;
			}
		}
	}
	
	return best_score;
}

#endif

int moonfish_best_move(struct moonfish *ctx, struct moonfish_move *best_move, int d)
{
	time_t t, t0, t1;
	int i;
	int score;
	
	d /= 4;
	t0 = time(NULL);
	
	for (i = 0 ; i < 8 ; i++)
	{
		t = time(NULL);
		score = moonfish_best_move_depth(ctx, best_move, i);
		
		t1 = time(NULL);
		if ((t1 - t) * 32 > d - (t1 - t0)) break;
	}
	
	return score;
}