Chess-Plisco

 view release on metacpan or  search on metacpan

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

	$self->[CP_POS_MATERIAL] += $material_deltas[$to_move | ($promote << 1) | ($captured << 4)];
	$self->[CP_POS_LAST_MOVE] = $move;
}

sub doMove {
	my ($self, $move) = @_;

	my @check_info = $self->inCheck;
	return if !$self->checkPseudoLegalMove($move, @check_info);

	my @backup = @$self;

	$self->move($move);

	return \@backup;
}

sub undoMove {
	my ($self, $backup) = @_;

	@$self = @$backup;
}

sub bMagic {
	my ($self, $shift, $occupancy) = @_;

	return CP_MAGICMOVESBDB->[$shift][(((($occupancy) & CP_MAGICMOVES_B_MASK->[$shift]) * CP_MAGICMOVES_B_MAGICS->[$shift]) >> 55) & ((1 << (64 - 55)) - 1)];
}

sub rMagic {
	my ($self, $shift, $occupancy) = @_;

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

	return $self->__parseUCIMove($1, $2, $3);
}

sub perft {
	my ($self, $depth) = @_;

	my $nodes = 0;

	my @check_info = $self->inCheck;
	my @moves = $self->pseudoLegalMoves;
	my @backup = @$self;
	foreach my $move (@moves) {
		next if !checkPseudoLegalMove($self, $move, @check_info);
		$self->move($move);

		if ($depth > 1) {
			$nodes += perft($self, $depth - 1);
		} else {
			++$nodes;
		}

		@$self = @backup;
	}

	return $nodes;
}

sub perftWithOutput {
	my ($self, $depth, $fh) = @_;

	return if $depth <= 0;

	require Time::HiRes;
	my $started = [Time::HiRes::gettimeofday()];

	my $nodes = 0;

	my @check_info = $self->inCheck;
	my @moves = $self->pseudoLegalMoves;
	my @backup = @$self;
	foreach my $move (@moves) {
		next if !$self->checkPseudoLegalMove($move, @check_info);
		my $movestr = $self->moveCoordinateNotation($move);
		$fh->print("$movestr: ");

		$self->move($move);

		my $subnodes;
		if ($depth > 1) {
			$subnodes = $self->perft($depth - 1);
		} else {
			$subnodes = 1;
		}

		$nodes += $subnodes;
		$fh->print("$subnodes\n");

		@$self = @backup;
	}

	no integer;

	my $elapsed = Time::HiRes::tv_interval($started, [Time::HiRes::gettimeofday()]);

	my $nps = '+INF';
	if ($elapsed) {
		$nps = int (0.5 + $nodes / $elapsed);
	}

lib/Chess/Plisco.pod  view on Meta::CPAN


=item B<move(MOVE>)

Does the move B<MOVE> which must be legal because no legality check is
performed.

Unlike B<doMove()>, the method does not return state information that can be
used to later undo the move. The caller is responsible for that. A typical
pattern looks like this:

    my @backup = @$position; # A shallow copy is sufficient.
    foreach my $move ($position->legalMoves) {
        my $state = $position->move($move);
        # ... do something with $position.
        @$position = @backup;
    }

Consequently, there is no B<unmove()> method.

=item B<SEE(MOVE)>

Does a static exchange evaluation SEE for move B<MOVE>.  B<MOVE> B<must> be
a capture, a promotion, a move giving check, or any combination of it.  It
returns the raw material balance expected from the move.

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

	}

	my $legal = 0;
	my $moveno = 0;
	my $pv_found;
	my $is_null_window = $beta - $alpha == 1;
	my $best_move = 0;
	my $print_current_move = $ply == 1 && $self->{print_current_move};
	my $signature_slot = $self->{history_length} + $ply;
	my @check_info = $position->inCheck;
	my @backup = @$position;
	foreach my $move (@moves) {
		next if !$position->checkPseudoLegalMove($move, @check_info);
		my @line;
		$position->move($move, 1);
		$signatures->[$signature_slot] = $position->[CP_POS_SIGNATURE];
		my $nodes_before = $self->{nodes}++;
		$self->printCurrentMove($move, $legal) if $print_current_move;
		my $score;
		if (DEBUG) {
			my $cn = $position->moveCoordinateNotation($move);

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

				\@line, $pv_node ? PV_NODE : NON_PV_NODE, 0, $tt_pvs,
				$min_probe_ply);
		}

		++$legal;
		++$moveno;
		if (DEBUG) {
			my $cn = $position->moveCoordinateNotation($move);
			$self->indent($ply, "move $cn: value $score");
		}
		@$position = @backup;
		if (DEBUG) {
			pop @{$self->{line}};
		}
		my $root_move;
		if ($node_type == ROOT_NODE) {
			$root_move = $self->{root_moves}->{$move & 0xffff_ffff};
			# The constants for the time management are taken from Stockfish
			# and they use their own units which seem to be 3.5-4.0 centipawns.
			$root_move->{average_score} =
				$root_move->{average_score} != -INF ? ($score + $root_move->{average_score}) >> 1 : $score;

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

			$captures{$move} = $see if $see >= -80;
		}
	}

	my @captures = sort { $captures{$b} <=> $captures{$a} || $b <=> $a } keys %captures;
	@moves = (@tt, @promotions, @checks, @captures);

	my $signatures = $self->{signatures};
	my $signature_slot = $self->{history_length} + $ply;
	my @check_info = $position->inCheck;
	my @backup = @$position;

	my $legal = 0;
	my $best_move = 0;
	foreach my $move (@moves) {
		next if !$position->checkPseudoLegalMove($move, @check_info);
		$position->move($move, 1);
		$signatures->[$signature_slot] = $position->[CP_POS_SIGNATURE];
		if (DEBUG) {
			my $cn = $position->moveCoordinateNotation($move);
			push @{$self->{line}}, $cn;

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

		++$legal;
		if (DEBUG) {
			$self->indent($ply, "recurse quiescence search");
		}
		my $score = -quiesce($self, $ply + 1, -$beta, -$alpha, $node_type, $min_probe_ply);
		if (DEBUG) {
			my $cn = $position->moveCoordinateNotation($move);
			$self->indent($ply, "move $cn: value: $score");
			pop @{$self->{line}};
		}
		@$position = @backup;
		if ($score > $best_value) {
			$best_value = $score;

			if ($score > $alpha) {
				$best_move = $move;

				if ($score < $beta) {
					if (DEBUG) {
						$self->indent($ply, "raise quiescence alpha to $alpha");
					}

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

	# First determine whether we are winning or losing.
	my $winning = $wdl > 0;
	if ($wdl == 0) {
		# In case of a draw, we want to escape there, if we are behind.
		my $static_eval = $pos->evaluate;
		$winning = $static_eval > 0;
	}

	# Pass 1. Probe all root moves.
	my $root_moves = $self->{root_moves};
	my @backup = @$pos;

	# Pass 2.
	# Discard all moves that change the outcome of the game.  They cannot be
	# part of the PV.
	#
	# We want to order the moves by the DTZ of the position after the move
	# has been made.
	foreach my $move (keys %{$root_moves}) {
my $san = $pos->SAN($move);
		$pos->move($move);

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


			if ($is_draw) {
				$root_moves->{$move}->{tb_rank} = 0;
			} else {
				$root_moves->{$move}->{tb_rank} = $dtz;
			}
		}

		$root_moves->{$move}->{tb_abs_dtz} = $hmc - 1 + abs $dtz;

		UNDO_MOVE: @$pos = @backup; # Undo move.
	}

	if ($self->{tb_50_move_rule}) {
		my (@drawing, @rule50, @other);
		foreach my $move (keys %{$root_moves}) {
			my $root_move = $root_moves->{$move};

			if ($root_move->{tb_rank} == 0) {
				push @drawing, $move;
			} elsif ($root_move->{tb_abs_dtz} > 100) {



( run in 0.999 second using v1.01-cache-2.11-cpan-63428c044ed )