Chess-Plisco

 view release on metacpan or  search on metacpan

lib/Chess/Plisco/Engine/Position.pm  view on Meta::CPAN

	$zk_update ^= $zk_pieces[((($piece) << 7) | (($to_move) << 6) | ($to)) - 128];

	my $promote = ((($move) >> 6) & 0x7);
	if ($promote) {
		$zk_update ^= $zk_pieces[(((CP_PAWN) << 7) | (($to_move) << 6) | ($to)) - 128];
		$zk_update ^= $zk_pieces[((($promote) << 7) | (($to_move) << 6) | ($to)) - 128];
	}

	if ($piece == CP_PAWN && (!(($to - $from) & 0x9))) {
		$zk_update ^= $zk_ep_files[$from & 0x7];
	}

	$zk_update ^= $zk_colour;

	$self->[CP_POS_GAME_PHASE] += $move_phase_deltas[
		($captured << 3) | $promote
	];

	my $score_index = ($move & 0x3fffff & ~(1 << (CP_MOVE_COLOUR_OFFSET))) | ($to_move << (CP_MOVE_COLOUR_OFFSET));
	$self->[CP_POS_OPENING_SCORE] += $opening_deltas[$score_index];
	$self->[CP_POS_ENDGAME_SCORE] += $endgame_deltas[$score_index];

	my $new_castling =  $self->[CP_POS_CASTLING_RIGHTS];
	my $castling_changed = $new_castling != $castling;
	if ($castling_changed) {
		$zk_update ^= $zk_castling[$castling]
			^ $zk_castling[$new_castling];
	}

	$self->[CP_POS_SIGNATURE] ^= $zk_update;

	if (!($self->[CP_POS_HALFMOVE_CLOCK])
	    || $castling_changed) {
		$self->[CP_POS_REVERSIBLE_CLOCK] = 0;
	} else {
		++$self->[CP_POS_REVERSIBLE_CLOCK];
	}

	return $state;
}

sub evaluate {
	my ($self) = @_;

	my $material = $self->[CP_POS_MATERIAL];
	my $white_pieces = $self->[CP_POS_WHITE_PIECES];
	my $black_pieces = $self->[CP_POS_BLACK_PIECES];
	my $pawns = $self->[CP_POS_PAWNS];
	my $knights = $self->[CP_POS_KNIGHTS];
	my $bishops = $self->[CP_POS_BISHOPS];
	my $rooks = $self->[CP_POS_ROOKS];
	my $queens = $self->[CP_POS_QUEENS];
	my $kings = $self->[CP_POS_KINGS];

	# We simply assume that a position without pawns is in general a draw.
	# If one side is a minor piece ahead, it is considered a draw, when there
	# are no rooks or queens on the board.  Important exception is KBB vs KN.
	# But in that case the material delta is B + B - N which is greater
	# than B.  On the other hand KBB vs KB is a draw and the material balance
	# in that case is exactly one bishop.
	# These simple formulas do not take into account that there may be more
	# than two knights or bishops for one side on the board but in the
	# exceptional case that this happens, the result would be close enough
	# anyway.
	#
	# FIXME! Just call insufficientMaterial?
	if (!$pawns) {
		my $delta = (do {	my $mask = $material >> CP_INT_SIZE * CP_CHAR_BIT - 1;	($material + $mask) ^ $mask;});
		if ($delta < CP_PAWN_VALUE
		    || (!$rooks && !$queens
		        && (($delta <= CP_BISHOP_VALUE)
		            || ($delta == 2 * CP_KNIGHT_VALUE)
			        || ($delta == CP_KNIGHT_VALUE + CP_BISHOP_VALUE)))) {
			return 0;
		}
	}

	my $op_phase = $self->[CP_POS_GAME_PHASE];

	$op_phase = TOTAL_PHASE if $op_phase > TOTAL_PHASE;
	my $eg_phase = TOTAL_PHASE - $op_phase;

	my $score = ($self->[CP_POS_OPENING_SCORE] * $op_phase
		+ $self->[CP_POS_ENDGAME_SCORE] * $eg_phase) / TOTAL_PHASE;

	return ($self->[CP_POS_TURN]) ? -$score : $score;
}



sub openingDelta {
	my ($self, $index) = @_;

	return $opening_deltas[$index];
}

sub endgameDelta {
	my ($self, $index) = @_;

	return $endgame_deltas[$index];
}

# This is only for debugging.
sub formatMoves {
	my ($self, @moves) = @_;

	my @formatted;
	foreach my $move (@moves) {
		push @formatted, $self->moveCoordinateNotation($move);
	}

	return @formatted;
}

# And this is only implemented for testing.
sub signature {
	shift->[CP_POS_SIGNATURE];
}

1;



( run in 0.846 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )