view release on metacpan or search on metacpan
lib/Chess/Plisco/Engine/Constants.pm
lib/Chess/Plisco/Engine/InputWatcher.pm
lib/Chess/Plisco/Engine/LimitsType.pm
lib/Chess/Plisco/Engine/Position.pm
lib/Chess/Plisco/Engine/TimeControl.pm
lib/Chess/Plisco/Engine/TimeControl/MovesToGo.pm
lib/Chess/Plisco/Engine/TranspositionTable.pm
lib/Chess/Plisco/Engine/Tree.pm
lib/Chess/Plisco/Engine/Tree.pod
lib/Chess/Plisco/Engine/Win32Wrapper.pm
lib/Chess/Plisco/Macro.pm
lib/Chess/Plisco/Macro.pod
lib/Chess/Plisco/Macro/abs.pm
lib/Chess/Plisco/Macro/attacked.pm
lib/Chess/Plisco/Macro/clearButMostSet.pm
lib/Chess/Plisco/Macro/countIsolatedTrailingZbits.pm
lib/Chess/Plisco/Macro/countTrailingZbits.pm
lib/Chess/Plisco/Macro/moveAttacked.pm
lib/Chess/Plisco/Macro/movePinned.pm
lib/Chess/Plisco/Macro/movesFromMask.pm
lib/Chess/Plisco/Macro/promotionMovesFromMask.pm
lib/Chess/Plisco/Macro/valueFromTT.pm
lib/Chess/Plisco/Macro/valueToTT.pm
lib/Chess/Plisco/Tablebase.pm
lib/Chess/Plisco/Tablebase/Syzygy.pm
lib/Chess/Plisco/Tablebase/Syzygy.pod
lib/Chess/Plisco/Tutorial.pod
perlcritic.rc
scripts/debug-log-to-graphviz.pl
scripts/extract-scores.pl
scripts/fastchess-parse.pl
scripts/full-search.pl
scripts/gen-positions.pl
## Library
See the [tutorial](lib/Chess/Plisco/Tutorial.pod) for a gentle introduction
to the library. When installed, you can also try the command
`perldoc Chess::Plisco::Tutorial`.
Reference documentation is available for:
* [Chess::Plisco](lib/Chess/Plisco.pod) (`perldoc Chess::Plisco`)
* [Chess::Pllisco::Macro](lib/Chess/Plisco/Macro.pod) (`perldoc Chess::Plisco::Macro`).
* [Chess::Plisco::EPD](lib/Chess/Plisco/EPD.pod) (`perldoc Chess::Plisco::EPD`)
* [Chess::Plisco::EPD::Record](lib/Chess/Plisco/EPD/Record.pod) (`perldoc Chess::Plisco::EPD::Record`)
* [Chess::Plisco::Tablebase::Syzygy](lib/Chess/Plisco/Tablebase/Syzygy.pod) (`perldoc Chess::Plisco::Tablebase::Syzygy`).
## Engine
### Running the Engine
The chess engine is started with the command "plisco". You can also run it
from inside the repository like this:
What happens, if you run the embedded engine from a cloned source code
repository?
```shell
perl -Ilib ./bin/plisco
```
That works. But it invokes the source code filter on-the-fly. The source
code filter parses the code with the notoriously slow module
[PPI](https://metacpan.org/pod/PPI) and replaces "macros" (see
[Chess::Plisco::Macro](https://metacpan.org/dist/Chess-Plisco/view/lib/Chess/Plisco/Macro.pod))
with the code that is actually executed. Inlining.
In order to speed up the installed module, there is a script `expand-macros`
in the top-level directory that runs a whole directory of Perl source files
through that source filter and expands them in place. This is one step in the
build workflow. Therefore, the published releases of `Chess-Plisco` do not
have this start-up penalty and compile relatively fast. There is still a
noticeable delay that comes from pre-computing relatively large lookup tables.
Releases of `Chess-Plisco` are created with the help of
See the L<lib/Chess/Plisco/Tutorial.pod> for a gentle
introduction to the library. When installed, you can also try the
command C<perldoc Chess::Plisco::Tutorial>.
Reference documentation is available for:
=over
=item * L<lib/Chess/Plisco.pod> (C<perldoc Chess::Plisco>)
=item * L<lib/Chess/Plisco/Macro.pod>
(C<perldoc Chess::Plisco::Macro>).
=item * L<lib/Chess/Plisco/EPD.pod>
(C<perldoc Chess::Plisco::EPD>)
=item * L<lib/Chess/Plisco/EPD/Record.pod>
(C<perldoc Chess::Plisco::EPD::Record>)
=item * L<lib/Chess/Plisco/Tablebase/Syzygy.pod>
(C<perldoc Chess::Plisco::Tablebase::Syzygy>).
the code, and this is what C<Chess-Plisco> is using for inlining.
What happens, if you run the embedded engine from a cloned source code
repository?
perl -Ilib ./bin/plisco
That works. But it invokes the source code filter on-the-fly. The source
code filter parses the code with the notoriously slow module
LL<https://metacpan.org/pod/PPI> and replaces "macros" (see
LL<https://metacpan.org/dist/Chess-Plisco/view/lib/Chess/Plisco/Macro.pod>)
with the code that is actually executed. Inlining.
In order to speed up the installed module, there is a script
C<expand-macros> in the top-level directory that runs a whole directory
of Perl source files through that source filter and expands them in
place. This is one step in the build workflow. Therefore, the published
releases of C<Chess-Plisco> do not have this start-up penalty and compile
relatively fast. There is still a noticeable delay that comes from
pre-computing relatively large lookup tables.
lib/Chess/Plisco.pm view on Meta::CPAN
# misrepresented as being the original code.
#
# 3. This notice may not be removed or altered from any source distribution.
# Make Dist::Zilla happy.
# ABSTRACT: Representation of a chess position with move generator, legality checker etc.
# Welcome to the world of spaghetti code! It is deliberately ugly because
# trying to avoid function/method call overhead is one of the major goals.
# In the future it may make sense to try to make the code more readable by
# more extensive use of Chess::Plisco::Macro.
package Chess::Plisco;
$Chess::Plisco::VERSION = 'v1.0.3';
use strict;
use integer;
use Locale::TextDomain qw('Chess-Plisco');
use Scalar::Util qw(reftype);
use Config;
# Macros from Chess::Plisco::Macro are already expanded here!
use base qw(Exporter);
# Colours.
use constant CP_WHITE => 0;
use constant CP_BLACK => 1;
# Piece constants.
use constant CP_NO_PIECE => 0;
use constant CP_PAWN => 1;
lib/Chess/Plisco.pod view on Meta::CPAN
=item Zobrist Keys
=item Syzygy endgame table probing
=back
For a gentler introduction, please see L<Chess::Plisco::Tutorial>. The rest
of this document contains reference documentation only.
If performance is key for you, you are strongly advised to have a look at
L<Chess::Plisco::Macro> which documents macros resp. inline functions that
speed up tasks that can be done with L<Chess::Plisco> significantly.
The class exports a number of constants that can either be imported
individually, by export tag, or all at once by the export tag ':all'. All
constants are prefixed with 'CP_' and you will have little reason to not
import all constants.
=head2 Internals
An instance of a B<Chess::Plisco> is a blessed array reference. You can
lib/Chess/Plisco.pod view on Meta::CPAN
signatures.
If you want a different seed, you should override the constant
L</CP_RANDOM_SEED>.
=back
=head1 PROPERTIES
You can access individual properties either by using index constants or by
using accessor macros from L<Chess::Plisco::Macro>. All accessor macros
can be assigned to; they are L-values. But you are strongly advised
to modify properties of a B<Chess::Plisco> instance only with the methods
documented here.
For getting or setting the bitboard of all white pieces, you have
these options:
$whites_pieces = $pos->[CP_W_PIECES];
$white_pieces = cp_w_pieces $pos;
$white_pieces = cp_w_pieces($pos);
$pos->[CP_W_PIECES] = $white_pieces;
cp_w_pieces $pos = $white_pieces;
cp_w_pieces($pos) = $white_pieces;
The macros (all starting with "cp_") are only available when you have loaded
L<Chess::Plisco::Macro>, see there for more information.
All elements of the position array are documented below under
L</Accessor Indices (:accessors)>.
=head1 EXPORT TAGS
The module exports only constants, all prefixed with "CP_".
Note that (lowercase) macros "cp_" are defined by using
L<Chess::Plisco::Macro>.
=head2 All Constants (:all)
You can import all constants with the export tag ":all".
=head2 Accessor Indices (:accessors)
The array indices were carefully selected so that the following conditions are met:
=over 4
lib/Chess/Plisco.pod view on Meta::CPAN
=head3 CP_A1 .. CP_H8
Shifts for all squares of the chess board.
=head2 Magic Moves Resp. Magic Bitboard Constants (:magicmoves)
These are all large data tables that are used internally for the magic
bitboards that generate the attack masks for the sliding pieces (queens,
bishops, and rooks). See the source if you are curious. Otherwise just import
them if you want to use the macros C<cp_mm_bmagic()> and C<cp_mm_rmagic()>
from L<Chess::Plisco::Macro>.
=head3 CP_MAGICMOVES_B_MAGICS
Internal.
=head3 CP_MAGICMOVES_R_MAGICS
Internal.
=head3 CP_MAGICMOVES_B_MASK
lib/Chess/Plisco.pod view on Meta::CPAN
for using them. So I decided to write a library that was well tested and
fast enough, and that library is now B<Chess::Plisco>. The first letter
P stands for Perl.
=head1 COPYRIGHT
Copyright (C) 2021-2026 Guido Flohr <guido.flohr@cantanea.com>.
=head1 SEE ALSO
L<Chess::Plisco::Macro>, perl(1)
lib/Chess/Plisco/Engine/Position.pm view on Meta::CPAN
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
package Chess::Plisco::Engine::Position;
$Chess::Plisco::Engine::Position::VERSION = 'v1.0.3';
use strict;
use integer;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
use base qw(Chess::Plisco Exporter);
# Additional fields.
use constant CP_POS_SIGNATURE => CP_POS_USR1;
use constant CP_POS_REVERSIBLE_CLOCK => CP_POS_USR2;
use constant CP_POS_GAME_PHASE => CP_POS_USR3;
use constant CP_POS_OPENING_SCORE => CP_POS_USR4;
use constant CP_POS_ENDGAME_SCORE => CP_POS_USR5;
use constant CP_POS_POPCOUNT => CP_POS_USR6;
lib/Chess/Plisco/Engine/TranspositionTable.pm view on Meta::CPAN
# http://www.wtfpl.net/ for more details.
# Rename that back to TranspositionTable, once done.
package Chess::Plisco::Engine::TranspositionTable;
$Chess::Plisco::Engine::TranspositionTable::VERSION = 'v1.0.3';
use strict;
use integer;
use Time::HiRes qw(gettimeofday tv_interval);
# Macros from Chess::Plisco::Macro are already expanded here!
use Chess::Plisco::Engine::Constants;
# The transposition table is organised into clusters, which in turn contain
# 4 buckets.
use constant CLUSTER_CAPACITY => 4;
# We store the keys separately from the actual entries, because that is easier
# to scan. The layout of a cluster is then like this:
# key0 16 bit
lib/Chess/Plisco/Engine/Tree.pm view on Meta::CPAN
package Chess::Plisco::Engine::Tree;
$Chess::Plisco::Engine::Tree::VERSION = 'v1.0.3';
use strict;
use integer;
use Locale::TextDomain ('Chess-Plisco');
use List::Util qw(min);
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
use Chess::Plisco::Engine::Position qw(CP_POS_REVERSIBLE_CLOCK CP_POS_POPCOUNT);
use Chess::Plisco::Engine::Constants;
use Time::HiRes qw(tv_interval ualarm gettimeofday);
use constant DEBUG => $ENV{DEBUG_PLISCO_TREE};
use constant CP_POS_SIGNATURE => Chess::Plisco::Engine::Position::CP_POS_SIGNATURE();
use constant CP_POS_REVERSIBLE_CLOCK => Chess::Plisco::Engine::Position::CP_POS_REVERSIBLE_CLOCK();
lib/Chess/Plisco/Macro.pm view on Meta::CPAN
# Copyright (C) 2021-2026 Guido Flohr <guido.flohr@cantanea.com>,
# all rights reserved.
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
package Chess::Plisco::Macro;
$Chess::Plisco::Macro::VERSION = 'v1.0.3';
use strict;
use Filter::Util::Call;
use PPI::Document;
sub _define;
sub _define_from_file;
sub preprocess;
sub _extract_arguments;
sub _split_arguments;
lib/Chess/Plisco/Macro.pod view on Meta::CPAN
=head1 NAME
Chess::Plisco::Macro - Macros/inline functions for Chess::Plisco
=head1 SYNOPSIS
use integer;
use Chess::Plisco qw(:all);
use Chess::Plisco::Macro;
my $white_pieces = cp_pos_white_pieces(Chess::Plisco->new);
my $bitboard = '0x8080808080808080';
my $popcount;
cp_bitboard_popcount $bitboard, $popcount;
cp_bitboard_popcount($bitboard, $popcount); # You can also use parentheses ...
print "There are $popcount bits set in $bitboard.\n";
=head1 DESCRIPTION
The module L<Chess::Plisco::Macro> is a source filter. It makes a number
of macros respectively inline functions available that can be invoked without
any subroutine call overhead. In fact, all invocations of these macros are
translated into constant expressions at compile-time.
All the functionality available in the module is also available as instance
or class methods of L<Chess::Plisco>. You should only use the macros
defined here if you have to squeeze out the last bit of performance from
your code, for example, when writing a chess engine. Otherwise, using the
macros has only disadvantages:
lib/Chess/Plisco/Macro.pod view on Meta::CPAN
If the parentheses were omitted in the macro definition, strange precedence
problems in the expanded code would occur instead. In other words, it is
not possible to fix both problems at once. In doubt, macros are wrapped
into parentheses and it is therefore usually safer to also use parentheses,
when you want to use macros as arguments to subroutines. The correct test
code would look like this:
is(cp_pos_material($pos), 0, "material test");
=head2 Do not Create References to Macros
The macro calls will be replaced at compile-time with other code. Therefore,
it is not possible to create a reference to a macro. Doing so may or may not
cause a compile-time error but it will never do what you wanted.
=head2 Do not Use the String Form of C<eval>
You should not do that anyway but with macros it would not even work because
the source code filter cannot know whether a string constant is really code.
The same applies to using the L<Benchmark> module. If you want to benchmark
the macros, you either have to translate them first with C<preprocess()>
before (see below), or somehow wrap it into a function call. Doing the latter
will probably eat up the performance gain the macros give you.
=head2 Expect Errors
Macros are expanded with the use of L<PPI::Document> and so the technique
shares all limitations of L<PPI::Document>.
And some more esoteric usages will probaly also not work.
=head1 FUNCTIONS
=over 4
=item B<preprocess>
You should only use one single function of this module, the function
C<preprocess()> that does the actual translation of your code. Example:
require Chess::Plisco::Macro;
open my $fh, '<', 'YourModule.pm' or die;
print Chess::Plisco::Macro::preprocess(join '', <$fh>);
This will dump the translated source code of F<YourModule.pm> on standard
output.
=back
=head1 MACROS
Note that the source filter is theoretically able to inline constants (that
are macros without arguments) as well but this feature is not used because
it does not have any advantage over the regular L<constant> pragma of Perl.
=head2 Macros for L<Chess::Plisco> Instances
=over 4
=item B<cp_pos_white_pieces(POS)>
Same as L<Chess::Plisco/whitePieces>.
=item B<cp_pos_black_pieces(POS)>
Same as L<Chess::Plisco/blackPieces>.
lib/Chess/Plisco/Macro.pod view on Meta::CPAN
=item B<cp_pos_material(POS)>
Same as L<Chess::Plisco/material>.
=item B<cp_pos_last_move(POS)>
Same as L<Chess::Plisco/lastMove>.
=back
=head2 Move Macros
These macros operate on scalar moves for L<Chess::Plisco> which are just
plain integers. They do I<not> work for instances of a
L<Chess::Plisco::Move>!
=over 4
=item B<cp_move_to(MOVE)>
Same as L<Chess::Plisco/moveTo>.
lib/Chess/Plisco/Macro.pod view on Meta::CPAN
Same as L<Chess::Plisco/moveUncompress>.
This macro has been added in version 1.0.2.
=item B<cp_move_coordinate_notation(MOVE)>
Same as L<Chess::Plisco/moveCoordinateNotation>.
=back
=head2 Macros for Magic Moves Resp. Magic Bitboards
=over 4
=item B<cp_mm_bmagic(SHIFT, OCCUPANCY)>
Same as L<Chess::Plisco/bMagic>.
=item B<cp_mm_rmagic(SHIFT, OCCUPANCY)>
Same as L<Chess::Plisco/rMagic>.
=back
=head2 Bitboard Macros
=over 4
=item B<cp_bitboard_popcount(BITBOARD, COUNT)>
Count the number of bits set in B<BITBOARD> and store it in B<COUNT>.
Example:
cp_bitboard_popcount $bitboard, $count;
lib/Chess/Plisco/Macro.pod view on Meta::CPAN
=item B<cp_bitboard_count_isolated_trailing_zbits(BITBOARD)>
Same as L<Chess::Plisco/bitboardCountIsolatedTrailingZbits>.
=item B<cp_bitboard_more_than_one_set(BITBOARD)>
Same as L<Chess::Plisco/bitboardMoreThanOneSet>.
=back
=head2 Miscellaneous Macros
=over 4
=item B<cp_coordinates_to_shift(FILE, RANK)>
Calculate a bit shift offset (0-63) for the square that B<FILE> (0-7) and
B<RANK> (0-7) point to.
=item B<cp_shift_to_coordinates(SHIFT)>
lib/Chess/Plisco/Tablebase/Syzygy.pm view on Meta::CPAN
# This file is heavily inspired by python-chess.
use strict;
use integer;
use List::Util qw(reduce);
use Locale::TextDomain qw('Chess-Plisco');
use Scalar::Util qw(reftype);
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my $TBPIECES = 7;
use constant PD_INDEXTABLE => 0;
use constant PD_SIZETABLE => 1;
use constant PD_DATA => 2;
use constant PD_OFFSET => 3;
use constant PD_SYMLEN => 4;
use constant PD_SYMPAT => 5;
use constant PD_BLOCKSIZE => 6;
lib/Chess/Plisco/Tablebase/Syzygy.pm view on Meta::CPAN
my $idx = $self->_encodePawn($self->{files}->[$f]->{norm}->[$bside], $p, $self->{files}->[$f]->{factor}->[$bside]);
$res = $self->_decompressPairs($self->{files}->[$f]->{precomp}->[$bside], $idx);
}
return $res - 2;
}
package Chess::Plisco::Tablebase::Syzygy::DtzTable;
$Chess::Plisco::Tablebase::Syzygy::DtzTable::VERSION = 'v1.0.3';
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
use base qw(Chess::Plisco::Tablebase::Syzygy::Table);
use constant TBZ_MAGIC => "\xd7\x66\x0c\xa5";
use constant WDL_TO_MAP => [1, 3, 0, 2, 0];
use constant PA_FLAGS => [8, 0, 0, 0, 4];
use constant PD_INDEXTABLE => 0;
lib/Chess/Plisco/Tablebase/Syzygy.pm view on Meta::CPAN
}
package Chess::Plisco::Tablebase::Syzygy;
$Chess::Plisco::Tablebase::Syzygy::VERSION = 'v1.0.3';
use File::Basename qw(basename);
use File::Globstar qw(globstar);
use Locale::TextDomain qw('Chess-Plisco');
use Tie::Cache::LRU;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
use base qw(Chess::Plisco::Tablebase);
use constant TBW_SUFFIX => 'rtbw';
use constant TBZ_SUFFIX => 'rtbz';
use constant WDL_TO_DTZ => [-1, -101, 0, 101, 1];
sub new {
my ($class, $directory, %__options) = @_;
lib/Chess/Plisco/Tutorial.pod view on Meta::CPAN
=head3 C<Chess::Plisco> Instances
Unlike most Perl objects, instances of C<Chess::Plisco> are blessed
array references. This design decision was taken because accessing
accessing array elements is faster than accessing hash elements. But
there is no need to remember the exact ordering of the array. You can
either use dedicated macros that operate directly on
C<Chess::Plisco> instances or use constants for the indexes:
use Chess::Plisco (:all);
use Chess::Plisco::Macro;
$pos = Chess::Plisco->new;
# Equivalent!
$w_pieces = $pos->[CP_POS_WHITE_PIECES];
$pos->[CP_POS_WHITE_PIECES] = $_pieces;
$w_pieces = cp_pos_white_pieces $pos;
cp_pos_white_pieces $pos = $w_pieces;
=head3 Pieces
lib/Chess/Plisco/Tutorial.pod view on Meta::CPAN
$pos->SAN($move);
# Nxe7#
$pos->LAN($move);
# Nf5xe7#
$pos->moveCoordinateNotation($move);
# d5e7
In general, you will prefer printing moves in Standard Algebraic Notation.
=head2 Using Macros
When dealing with chess programming you often find yourself executing
small operations many times, more than often millions of times. You can,
of course, write subroutines for these operations but the calling
overhead sums up and contributes significantly to the execution time of
your code.
Even writing these routines in C does not help at all because the
calling overhead is large compared to the execution time of the function
body.
This is why the module C<Chess::Plisco::Macro> exists. It makes a lot
of small helper functions available, the names of which all begin with
C<cp_>. You can use them more or less like functions but they are inlined
into your code at compile-time.
But this is only necessary, when performance is important. For normal
purposes, you can just use regular instance methods instead of macros.
But when you want to use the macros, there are a couple of caveats that you
have to keep in mind:
=head3 Use C<Chess::Plisco::Macro> and(!) C<Chess::Plisco>
The macros in C<Chess::Plisco::Macro> make use of constants defined in
C<Chess::Plisco>. If you do not import these constants, you will get
strange errors. You should therefore start your own code with this
boilerplate:
use strict;
use integer;
use Chess::Plisco qw(:all);
use Chess::Plisco::Macro;
=head3 Use C<integer>
Some of the macros will only work on integers. You must therefore always
C<use integer> in the scope of your code. Not doing so will result in
errors!
If you need floating point arithmetics, activate them only in the limited
scope of a block:
lib/Chess/Plisco/Tutorial.pod view on Meta::CPAN
no integer;
printf "avg. loss in centipedes: %g\n", $score / 100;
}
=head3 Do Not Use Here Documents
The translation currently chokes on here documents (E<lt>E<lt>EOF ...). So
sorry, I have to check out once again how to make L<PPI::Document> round-trip
safe.
=head3 Do not Create References to Macros
Macros are not Perl subroutines. They are more or less stupidly replaced
with chunks of code. Things like C<my $sub = \&cp_pos_white_pieces> may or
may not cause a syntax error but they will never do what you expect.
=head3 Be Prepared for Errors
The macro expansion internally makes use of C<PPI::Document> and it
therefore shares all of that module's inevitable limitations. And it
adds a fair amount of its own shortcomings. The macro approach is rather
an experiment than a production-ready general-purpose tool.
lib/Chess/Plisco/Tutorial.pod view on Meta::CPAN
my $pos = Chess::Plisco->new;
my $white_pawns = $pos->[CP_POS_WHITE_PIECES] & $self->[CP_POS_PAWNS];
my $count = $pos->bitboardPopcount($white_pawns);
print "There are $count white pawns on the board.\n";
Using macros looks a little bit strange at first glance but that strangeness
is unavoidable:
use Chess::Plisco;
use Chess::Plisco::Macro;
my $pos = Chess::Plisco->new;
my $white_pawns = cp_pos_white_pieces($pos) & cp_pos_pawns($pos);
my $count;
cp_bitboard_popcount $white_pawns, $count;
print "There are $count white pawns on the board.\n";
The important line is the last but one. The macro C<cp_bitboard_popcount>
counts the number of bits set in an integer, and this is exactly what
you need here. But you have to give the variable that should hold the
lib/Chess/Plisco/Tutorial.pod view on Meta::CPAN
=head3 Iterating Bitboards
Task: Print the square for every white pawn on the board.
=head4 Conventional and Slow Approach
Iterating over a bitboard can be done in an intuitive and straight-forward way:
use integer;
use Chess::Plisco qw(:all);
use Chess::Plisco::Macro;
my $white_pawn_mask = cp_pos_white_pieces($pos) & cp_pos_pawns($pos);
foreach my $shift (0 .. 63) {
my $shift_mask = 1 << $shift;
if ($shift_mask & $white_pawn_mask) {
my $square = cp_shift_to_square $shift;
print "There is a white pawn on $square.\n";
}
lib/Chess/Plisco/Tutorial.pod view on Meta::CPAN
corresponding bit is set in the bitboard. There is nothing wrong with this
approach and it is actually reasonably fast.
=head4 Efficient and Fast Approach
But there is a another technique that achieves the same result and is often
faster:
use integer;
use Chess::Plisco qw(:all);
use Chess::Plisco::Macro;
my $pos = Chess::Plisco->new;
my $white_pawn_mask = cp_pos_white_pieces($pos) & cp_pos_pawns($pos);
while ($white_pawn_mask) {
my $shift = cp_bitboard_count_trailing_zbits $shift_mask;
my $square = cp_shift_to_square $shift;
print "There is a white pawn on $square.\n";
lib/Chess/Plisco/Tutorial.pod view on Meta::CPAN
In array context, you get the piece and the colour, in scalar context just the
piece. The piece is one of C<CP_NO_PIECE>, C<CP_PAWN>, C<CP_KNIGHT>, C<CP_BISHOP>,
C<CP_QUEEN>, or C<CP_KING>, and the colour one of C<CP_WHITE>, C<CP_BLACK>,
or C<undef> if there is no piece at all at the specified location.
=head3 Castling State
The castling state is encoded with other state information in one single
integer as a bit mask. It is highly recommended that you use the dedicated
methods from L<Chess::Plisco> or the macros from L<Chess::Plisco::Macro> for it:
$white_can_castle_king_side = cp_pos_white_king_side_castling_right $pos;
# or $white_can_castle_king_side = $pos->whiteKingSideCastlingRight;
$white_can_castle_queen_side = cp_pos_white_queen_side_castling_right $pos;
# or $white_can_castle_queen_side = $pos->whiteQueenSideCastlingRight;
$black_can_castle_king_side = cp_pos_black_king_side_castling_right $pos;
# or $black_can_castle_king_side = $pos->blackKingSideCastlingRight;
$black_can_castle_queen_side = cp_pos_black_queen_side_castling_right $pos;
# or $black_can_castle_queen_side = $pos->blackKingSideCastlingRight;
perlcritic.rc view on Meta::CPAN
; Copyright (C) 2021 Guido Flohr <guido.flohr@cantanea.com>,
; all rights reserved.
; This program is free software. It comes without any warranty, to
; the extent permitted by applicable law. You can redistribute it
; and/or modify it under the terms of the Do What the Fuck You Want
; to Public License, Version 2, as published by Sam Hocevar. See
; http://www.wtfpl.net/ for more details.
; How can that be disabled just for lib/Chess/Position/Macro/*.pm?
[-TestingAndDebugging::RequireUseStrict]
scripts/full-search.pl view on Meta::CPAN
#! /usr/bin/env perl
use strict;
use v5.10;
use List::Util qw(max min);
use Chess::Plisco::Engine::Position;
use Chess::Plisco::Engine::Constants;
use Chess::Plisco::Macro;
sub search;
sub qsearch;
sub print_line;
my ($depth, @fen) = @ARGV;
if (!$depth || $depth < 1 || $depth >> MAX_PLY) {
warn "Usage: $0 DEPTH [FEN]\n\n";
scripts/gen-positions.pl view on Meta::CPAN
use strict;
use v5.10;
use List::Util qw(shuffle);
use Chess::Plisco qw(:all);
use Chess::Plisco::Macro;
sub generate_board;
sub empty_pos;
sub print_positions;
my @files = @ARGV;
my @endgames;
foreach my $file (@files) {
t/01expand-placeholders.t view on Meta::CPAN
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use Test::More;
use PPI::Document;
# Do not "use" the module because we do not want to acti
require Chess::Plisco::Macro;
my %placeholders = (
'$m' => [PPI::Token::Symbol->new('$move')],
'$v' => [PPI::Token::Number->new(32)],
);
my $code = '(($m) = (($m) & ~0x3f) | (($v) & 0x3f))';
my $cdoc = PPI::Document->new(\$code);
Chess::Plisco::Macro::_expand_placeholders($cdoc, %placeholders);
is $cdoc->content, '(($move) = (($move) & ~0x3f) | ((32) & 0x3f))';
done_testing;
t/01pre-process.t view on Meta::CPAN
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use Test::More;
# Do not "use" the module because we do not want to activate the source filter.
require Chess::Plisco::Macro;
my ($code);
$code = 'cp_move_to($move)';
is Chess::Plisco::Macro::preprocess($code), '((($move) >> 15) & 0x3f)', $code;
$code = 'cp_move_to $move';
is Chess::Plisco::Macro::preprocess($code), '((($move) >> 15) & 0x3f)', $code;
$code = 'cp_move_to($move); return;';
is Chess::Plisco::Macro::preprocess($code),
'((($move) >> 15) & 0x3f); return;', $code;
$code = 'cp_move_to $move; return;';
is Chess::Plisco::Macro::preprocess($code),
'((($move) >> 15) & 0x3f); return;', $code;
$code = 'cp_move_set_to($move, 32);';
is Chess::Plisco::Macro::preprocess($code),
'(($move) = (($move) & ~0x1f8000) | ((32)) << 15);', $code;
done_testing;
t/02bit-twiddling.t view on Meta::CPAN
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More tests => 35;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my ($bitboard, $count);
$bitboard = 0x88;
{ my $_b = $bitboard; for ($count = 0; $_b; ++$count) { $_b &= $_b - 1; } };
is $count, 2, 'popcount 0x88';
is $bitboard, 0x88, 'popcount 0x88';
$bitboard = 0xffff_ffff_ffff_ffff;
{ my $_b = $bitboard; for ($count = 0; $_b; ++$count) { $_b &= $_b - 1; } };
t/02clamp.t view on Meta::CPAN
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More;
use Chess::Plisco;
# Macros from Chess::Plisco::Macro are already expanded here!
# The array elements are:
#
# - in
# - lo
# - hi
# - out
my @tests = (
[127, 128, 255, 128],
[128, 128, 255, 128],
t/02piece-at.t view on Meta::CPAN
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More tests => 6 * 64;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
# The array elements are:
#
# - square
# - file (0 .. 7)
# - rank (0 .. 7)
# - shift (0 .. 63)
my @tests = (
# 1st rank.
['a1', 0, 0, 0, CP_ROOK, CP_WHITE],
t/02square-conversion.t view on Meta::CPAN
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More tests => 12 * 64;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
# The array elements are:
#
# - square
# - file (0 .. 7)
# - rank (0 .. 7)
# - shift (0 .. 63)
my @tests = (
# 1st rank.
['a1', 0, 0, 0],
t/02square-conversion.t view on Meta::CPAN
"squareToShift $square";
is $class->coordinatesToSquare($file, $rank), $square,
"coordinatesToSquare $square";
is $class->coordinatesToShift($file, $rank), $shift,
"coordinatesToShift $square";
is_deeply [$class->shiftToCoordinates($shift)], [$file, $rank],
"shiftToCoordinates $shift";
is_deeply [$class->squareToCoordinates($square)], [$file, $rank],
"squareToCoordinates $shift";
# Macros.
is(chr(97 + ($shift & 0x7)) . (1 + ($shift >> 3)), $square,
"cp_shift_to_square $square");
is((((substr $square, 1) - 1) << 3) + ord($square) - 97, $shift,
"cp_square_to_shift $square");
is(chr(97 + $file) . (1 + $rank), $square,
"cp_coordinates_to_square $square");
is((($rank << 3) + $file), $shift,
"cp_coordinates_to_shift $square");
is_deeply([($shift & 0x7, $shift >> 3)], [$file, $rank],
"cp_shift_to_coordinates $shift");
t/03attacked.t view on Meta::CPAN
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More;
use Data::Dumper;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my ($pos, @moves, @expect);
my @tests = (
{
name => 'attacked by white pawn',
square => 'd4',
fen => '7k/2n5/2p1R3/8/8/2P2Bq1/2K5/8 b - - 0 1',
attacked => 1,
},
t/03fen-writer.t view on Meta::CPAN
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More;
use Data::Dumper;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my ($pos, @moves, @expect);
my @tests = (
# Basic functionality.
{
name => 'start position, round-trip',
pos => 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
fen => 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
},
t/03in-check.t view on Meta::CPAN
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More;
use Data::Dumper;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my ($pos, @moves, @expect);
my @tests = (
{
name => 'start position',
},
{
name => 'check by black knight',
fen => '4k3/8/8/8/8/4n3/8/3K4 w - - 0 1',
t/03move-attacked.t view on Meta::CPAN
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More;
use Data::Dumper;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my ($pos, @moves, @expect);
my @tests = (
{
name => 'black king on f8 attacked by white queen on h8',
move => 'e8f8',
fen => 'r3k2Q/p1ppqp2/bn2p1pb/3PN3/1p2P3/2N4p/PPPBBPPP/R3K2R b KQq - 0 2',
attacked => 1,
},
t/03move-pinned.t view on Meta::CPAN
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More;
use Data::Dumper;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my ($pos, @moves, @expect);
my @tests = (
{
name => 'white rook pinned by rook on same file',
move => 'e4g4',
fen => '8/4r2k/8/8/4R3/8/4K3/8 w - - 0 1',
pinned => 1,
},
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More tests => 13;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my ($pos, $move, $from, $to);
$pos = Chess::Plisco->new;
$move = 0;
$from = (((substr 'e2', 1) - 1) << 3) + ord('e2') - 97;
$to = (((substr 'e4', 1) - 1) << 3) + ord('e4') - 97;
(($move) = (($move) & ~0x7e00) | (($from)) << 9);
(($move) = (($move) & ~0x1f8000) | (($to)) << 15);
t/03parse-move.t view on Meta::CPAN
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use Test::More;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my $fen;
my ($pos, $move);
$pos = Chess::Plisco->new;
$move = $pos->parseMove('e2e4');
ok $move, 'e2e4 from start position';
$pos = Chess::Plisco->new;
t/03parse-san.t view on Meta::CPAN
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use Test::More;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my $fen;
my $pos = Chess::Plisco->new;
# Regular white piece move.
is $pos->moveCoordinateNotation($pos->parseMove("Nc3")), "b1c3", "Nc3";
is $pos->moveCoordinateNotation($pos->parseMove("b1c3")), "b1c3", "b1c3";
is $pos->moveCoordinateNotation($pos->parseMove("Nb1-c3")), "b1c3", "Nb1-c3";
t/04check-check.t view on Meta::CPAN
# and/or modify it under the terms of the Do What the Fuck You Want
# to Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
use strict;
use integer;
use Test::More;
use Data::Dumper;
use Chess::Plisco qw(:all);
# Macros from Chess::Plisco::Macro are already expanded here!
my ($pos, @moves, @expect);
my @tests = (
# Castlings.
{
name => 'white pawn checks on f5',
fen => '8/8/4k3/5P2/8/8/8/4K3 b - - 0 1',
checkers => [(1 << (CP_F_MASK & CP_5_MASK))],
},