Chess-Plisco

 view release on metacpan or  search on metacpan

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

	$new_castling &= $castling_rights_rook_masks[$to];

	my $captured = ((($move) >> 3) & 0x7);

	# Remove captured piece.
	if ($captured) {
		if (((($move) >> 22) & 0x1)) {
			my $ep_shift = $self->[CP_POS_EN_PASSANT_SHIFT];
			my $capture_mask = $ep_pawn_masks[$ep_shift];
			$self->[$her_idx] ^= $capture_mask;
			$self->[CP_PAWN] ^= $capture_mask;
		} else {
			my $capture_mask = (1 << $to);
			$self->[$her_idx] ^= $capture_mask;
			$self->[$captured] ^= $capture_mask;
		}
	}

	if (CP_PAWN == $piece) {
		$self->[CP_POS_HALFMOVE_CLOCK] = 0;
		if ((!(($to - $from) & 0x9))) {
			$self->[CP_POS_EN_PASSANT_SHIFT] = $from + (($to - $from) >> 1);
		} else {
			$self->[CP_POS_EN_PASSANT_SHIFT] = 0;
		}
	} elsif ($captured) {
		$self->[CP_POS_EN_PASSANT_SHIFT] = 0;
		$self->[CP_POS_HALFMOVE_CLOCK] = 0;
	} else {
		$self->[CP_POS_EN_PASSANT_SHIFT] = 0;
		++$self->[CP_POS_HALFMOVE_CLOCK];
	}

	$self->[$my_idx] ^= $move_mask;
	$self->[$piece] ^= $move_mask;

	# It is better to overwrite the castling rights unconditionally because
	# it safes branches.  There is one edge case, where a pawn captures a
	# rook that is on its initial position.  In that case, the castling
	# rights may have to be updated.
	$self->[CP_POS_CASTLING_RIGHTS] = $new_castling;

	if ($promote) {
		$self->[CP_POS_PAWNS] ^= $to_mask;
		$self->[$promote] ^= $to_mask;
	}

	++$self->[CP_POS_HALFMOVES];
	$self->[CP_POS_TURN] = !$to_move;

	$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) = @_;

	return CP_MAGICMOVESRDB->[$shift][(((($occupancy) & CP_MAGICMOVES_R_MASK->[$shift]) * CP_MAGICMOVES_R_MAGICS->[$shift]) >> 52) & ((1 << (64 - 52)) - 1)];
}

# Position info methods.
sub castlingRights {
	my ($self) = @_;

	return $self->[CP_POS_CASTLING_RIGHTS];
}

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

	return ($self->[CP_POS_CASTLING_RIGHTS] & 1);
}

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

	return (($self->[CP_POS_CASTLING_RIGHTS] & 2));
}

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

	return (($self->[CP_POS_CASTLING_RIGHTS] & 4));
}

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

	return ($self->[CP_POS_CASTLING_RIGHTS] & 8);
}

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

	return $self->[CP_POS_TURN];
}

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

	return $self->[CP_POS_TURN];
}

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

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

			pop @san;
		}

		# Leading garbage?
		if (@san) {
			require Carp;
			Carp::croak(__"Illegal SAN string: leading garbage found!\n");
		}

		$pattern = join '', $piece, 
				$from_file, $from_rank, $to_file, $to_rank, $promote;
	}

	# Get the legal moves.
	my @legal = $self->movesCoordinateNotation($self->legalMoves);

	# Prefix every move with the piece that moves.
	my @pieces = qw(X P N B R Q K);
	foreach my $move (@legal) {
		my $from_square = substr $move, 0, 2;
		my $mover = $self->pieceAtSquare($from_square);
		$move = $pieces[$mover] . $move;
	}

	my @candidates;
	@candidates = grep { /^$pattern$/ } @legal;

	# We must find exactly one candidate.  If we have 0 matches, the move
	# could not be parsed.  If we have more than 1 match, the move was
	# ambiguous.
	if (@candidates != 1 && $move !~ /^[PNBRQK]/) {
		# If no piece was explicitely specified, try again with a pawn.
		$pattern =~ s/^./P/;
		@candidates = grep { /^$pattern$/ } @legal;
	}

	if (!@candidates) {
		require Carp;
		Carp::croak(__"Illegal SAN string: illegal move.\n");
	} elsif (@candidates > 1) {
		require Carp;
		Carp::croak(__"Illegal SAN string: move is ambiguous.\n");
	}

	$move = $candidates[0];
	if ($move !~ /^[PNBRQK]([a-h][1-8])([a-h][1-8])([qrbn])?$/) {
		require Carp;
		Carp::croak(__"Illegal SAN string: syntax error.\n");
	}

	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);
	}
	$fh->print("info nodes: $nodes ($elapsed s, nps: $nps)\n");

	return $nodes;
}

sub coordinatesToShift {
	my (undef, $file, $rank) = @_;

	return ($rank << 3) + $file;
}

sub coordinatesToSquare {
	my (undef, $file, $rank) = @_;

	return chr(97 + $file) . (1 + $rank);
}

sub shiftToCoordinates {
	my (undef, $shift) = @_;

	my $file = $shift & 0x7;
	my $rank = $shift >> 3;

	return $file, $rank;
}

sub squareToCoordinates {
	my (undef, $square) = @_;

	return ord($square) - 97, -1 + substr $square, 1;
}

sub shiftToSquare {
	my (undef, $shift) = @_;

	my $rank = 1 + ($shift >> 3);
	my $file = $shift & 0x7;

	return sprintf '%c%u', $file + ord 'a', $rank;
}

sub squareToShift {
	my ($whatever, $square) = @_;

	if ($square !~ /^([a-h])([1-8])$/) {
		die __x("Illegal square '{square}'.\n", square => $square);
	}

	my $file = ord($1) - ord('a');
	my $rank = $2 - 1;



( run in 2.439 seconds using v1.01-cache-2.11-cpan-75ffa21a3d4 )