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 )