22#ifndef __PBeFS_SlidingTile
23 #define __PBeFS_SlidingTile
76 constexpr Word128(
void )
noexcept =
default;
80 constexpr Word128( std::uint64_t l ) noexcept :
lo( l ) {}
84 constexpr Word128( std::uint64_t l , std::uint64_t h ) noexcept
85 :
lo( l ) ,
hi( h ) {}
89 explicit constexpr operator std::uint64_t(
void )
const noexcept {
97 return(
Word128( a.lo & b.lo , a.hi & b.hi ) );
101 return(
Word128( a.lo | b.lo , a.hi | b.hi ) );
105 return(
Word128( a.lo ^ b.lo , a.hi ^ b.hi ) );
109 return(
Word128( ~a.lo , ~a.hi ) );
118 return(
Word128( 0 , a.lo << ( n - 64 ) ) );
119 return(
Word128( a.lo << n , ( a.hi << n ) | ( a.lo >> ( 64 - n ) ) ) );
128 return(
Word128( a.hi >> ( n - 64 ) , 0 ) );
129 return(
Word128( ( a.lo >> n ) | ( a.hi << ( 64 - n ) ) , a.hi >> n ) );
137 return( a.lo ? std::countr_zero( a.lo ) : 64 + std::countr_zero( a.hi ) );
169template<
int W ,
int H >
182 static_assert( ( W >= 2 ) && ( H >= 2 ) && (
cells <= 25 ) ,
183 "SlidingTile: the packed state holds at most 25 cells" );
198 for(
int i = 0 ; i <
cells ; ++i )
199 b[ i ] =
static_cast< std::uint8_t
>( i );
211 : f_start(
pack( check( start ) ) ) , f_goal(
pack( check( goal ) ) ) {
212 if( parity( start ) != parity( goal ) )
213 throw( std::invalid_argument(
"SlidingTile::SlidingTile: the goal is "
214 "not reachable from the start" ) );
215 for(
int c = 0 ; c <
cells ; ++c )
216 v_goal_cell[ goal[ c ] ] = c;
217 for(
int t = 1 ; t <
cells ; ++t )
218 for(
int c = 0 ; c <
cells ; ++c )
219 v_md[ t ][ c ] = distance( c , v_goal_cell[ t ] );
220 for(
int b = 0 ; b <
cells ; ++b ) {
221 const int r = b / W , k = b % W;
222 Moves & o = v_moves[ b ];
224 o.cell[ o.n++ ] = b - W;
226 o.cell[ o.n++ ] = b - 1;
228 o.cell[ o.n++ ] = b + 1;
230 o.cell[ o.n++ ] = b + W;
245 return( s == f_goal );
252 if constexpr(
cells <= 16 )
253 return( ADS::splitmix64( s ) );
255 return( ADS::splitmix64( s.lo ^ ADS::splitmix64( s.hi ) ) );
263 for(
int c = 0 ; c <
cells ; ++c )
264 h += v_md[
tile( s , c ) ][ c ];
275 const int b =
blank( s );
276 const Moves & o = v_moves[ b ];
277 for(
int i = 0 ; i < o.n ; ++i ) {
278 const int c = o.cell[ i ];
279 const int t =
tile( s , c );
282 f( child , 1 , h + v_md[ t ][ b ] - v_md[ t ][ c ] );
294 const int b =
blank( s );
295 const Moves & o = v_moves[ b ];
296 for(
int i = 0 ; i < o.n ; ++i ) {
297 const int c = o.cell[ i ];
300 const int t =
tile( s , c );
303 f( child , 1 , h + v_md[ t ][ b ] - v_md[ t ][ c ] , std::uint8_t( b ) );
310 [[nodiscard]]
static constexpr std::size_t
num_features(
void )
noexcept {
319 for(
int c = 0 ; c <
cells ; ++c )
320 if(
const int t =
tile( s , c ) )
321 f( std::size_t( t *
cells + c ) );
336 using std::countr_zero;
337 const int i = countr_zero( d ) /
bits;
338 const int k =
tile( d , i );
341 f( std::size_t( k *
cells + i ) );
342 f( std::size_t( k *
cells + j ) );
350 return( std::size_t(
cells ) * 2 );
358 const std::size_t t = i /
cells , c = i %
cells;
359 return( t * 2 + ( c / W >= H / 2 ? 1 : 0 ) );
366 int p[ 4 ] = { 0 , 0 , 0 , 0 };
367 for(
int c = 0 ; c <
cells ; ++c )
368 if(
const int t =
tile( s , c ) ; ( t >= 1 ) && ( t <= 3 ) )
370 return( ( std::uint64_t( p[ 1 ] ) *
cells + p[ 2 ] ) *
cells + p[ 3 ] );
376 [[nodiscard]]
static constexpr std::size_t
num_nblocks(
void )
noexcept {
384 int p[ 3 ] = { 0 , 0 , 0 };
385 for(
int c = 0 ; c <
cells ; ++c )
386 if(
const int t =
tile( s , c ) ; t <= 2 )
388 return( nblock_id( p[ 0 ] , p[ 1 ] , p[ 2 ] ) );
396 const int p2 = int( b %
cells );
399 if( ( p0 == p1 ) || ( p0 == p2 ) || ( p1 == p2 ) )
401 const Moves & o = v_moves[ p0 ];
402 for(
int i = 0 ; i < o.n ; ++i ) {
403 const int c = o.cell[ i ];
405 f( nblock_id( c , p0 , p2 ) );
408 f( nblock_id( c , p1 , p0 ) );
410 f( nblock_id( c , p1 , p2 ) );
420 for(
int c = 0 ; c <
cells ; ++c ) {
421 ps[
tile( s , c ) ] = c;
422 pt[
tile( t , c ) ] = c;
425 for(
int k = 1 ; k <
cells ; ++k )
426 h += distance( ps[ k ] , pt[ k ] );
438 requires(
cells <= 20 ) {
440 for(
int c = 0 ; c <
cells ; ++c )
441 pos[
tile( s , c ) ] = c;
442 std::uint64_t rank = 0;
443 std::uint32_t used = 0;
444 for(
int k = 0 ; k <
cells ; ++k ) {
445 const std::uint32_t below = used & ( ( 1u << pos[ k ] ) - 1u );
446 rank = rank * std::uint64_t(
cells - k ) +
447 std::uint64_t( pos[ k ] - std::popcount( below ) );
448 used |= 1u << pos[ k ];
457 return(
int( std::uint64_t( s >> (
bits * c ) ) & c_tile ) );
467 for(
int k = 1 ; k <
bits ; ++k )
470 using std::countr_zero;
471 return( countr_zero( t ) /
bits );
479 for(
int c = 0 ; c <
cells ; ++c )
489 for(
int c = 0 ; c <
cells ; ++c )
490 b[ c ] =
static_cast< std::uint8_t
>(
tile( s , c ) );
498 std::istringstream in( text );
500 for(
int c = 0 ; c <
cells ; ++c ) {
502 if( ! ( in >> t ) || ( t < 0 ) || ( t >=
cells ) )
503 throw( std::invalid_argument(
"SlidingTile::parse: bad board" ) );
504 b[ c ] =
static_cast< std::uint8_t
>( t );
506 return( check( b ) );
513 for(
int r = 0 ; r < H ; ++r ) {
514 for(
int k = 0 ; k < W ; ++k ) {
515 const int t =
tile( s , r * W + k );
519 os << ( t < 10 ?
" " :
" " ) << t;
532 int cell[ 4 ] = { 0 , 0 , 0 , 0 };
536 static constexpr std::uint64_t c_tile = ( std::uint64_t( 1 ) <<
bits ) - 1;
541 for(
int c = 0 ; c <
cells ; ++c )
549 static int distance(
int a ,
int b )
noexcept {
550 return( std::abs( a / W - b / W ) + std::abs( a % W - b % W ) );
556 static std::size_t nblock_id(
int p0 ,
int p1 ,
int p2 )
noexcept {
557 return( ( std::size_t( p0 ) *
cells + p1 ) *
cells + p2 );
564 std::uint32_t seen = 0;
565 for( std::uint8_t t : b ) {
566 if( ( t >=
cells ) || ( ( seen >> t ) & 1u ) )
567 throw( std::invalid_argument(
"SlidingTile::check: not a permutation" )
578 static int parity(
const board_type & b )
noexcept {
579 int inv = 0 , blank_row = 0;
580 for(
int i = 0 ; i <
cells ; ++i ) {
585 for(
int j = i + 1 ; j <
cells ; ++j )
586 if( b[ j ] && ( b[ j ] < b[ i ] ) )
589 return( ( W % 2 == 1 ? inv : inv + blank_row ) % 2 );
596 int v_goal_cell[
cells ] = {};
598 Moves v_moves[
cells ];
Header file for the concepts a search problem has to satisfy in order to be searched by the algorithm...
the sliding-tile puzzle on a board of at most 25 cells
Definition SlidingTile.h:170
static constexpr std::size_t num_nblocks(void) noexcept
the number of nblocks: one per triple of cells, not all of them used
Definition SlidingTile.h:376
void for_each_successor(state_type s, cost_type h, F &&f) const
calls f( t , 1 , h( t ) ) for each successor t of s
Definition SlidingTile.h:274
void for_each_feature(state_type s, F &&f) const
calls f( t W H + c ) for each tile t != 0 in each cell c of s
Definition SlidingTile.h:318
static void print(std::ostream &os, state_type s)
prints a board, one row per line
Definition SlidingTile.h:512
std::uint64_t abstract_state(state_type s) const noexcept
the abstract state of AHDA*: the cells of tiles 1, 2 and 3
Definition SlidingTile.h:365
static constexpr int width
Definition SlidingTile.h:178
std::size_t nblock(state_type s) const noexcept
the nblock of PBNF: the cells of the blank and of tiles 1 and 2
Definition SlidingTile.h:383
static board_type parse(const std::string &text)
reads a board: W H numbers, the tiles cell by cell, 0 for the blank
Definition SlidingTile.h:497
state_type initial_state(void) const noexcept
the start board
Definition SlidingTile.h:237
static constexpr std::size_t num_features(void) noexcept
the number of features: one per pair ( tile , cell )
Definition SlidingTile.h:310
std::uint64_t perfect_hash(state_type s) const noexcept
the lexicographic rank of the permutation of the cells of the tiles
Definition SlidingTile.h:437
static constexpr std::size_t num_abstract_features(void) noexcept
the number of abstract features: one per pair ( tile , half board )
Definition SlidingTile.h:348
std::uint64_t hash(state_type s) const noexcept
the hash of a board: its packed integer, mixed
Definition SlidingTile.h:251
std::conditional_t< cells<=16, std::uint64_t, Word128 > state_type
a packed board
Definition SlidingTile.h:187
static constexpr int cells
Definition SlidingTile.h:180
static constexpr std::size_t abstract_feature(std::size_t i) noexcept
the abstract feature of a feature: the tile and the half of its cell
Definition SlidingTile.h:356
static board_type korf_goal(void)
the goal of Korf (1985): the blank in the first cell, then 1 , 2 , ...
Definition SlidingTile.h:196
cost_type heuristic(state_type s) const noexcept
the Manhattan distance of s from the goal
Definition SlidingTile.h:261
bool is_goal(state_type s) const noexcept
true if s is the goal board
Definition SlidingTile.h:244
static int blank(state_type s) noexcept
the cell of the blank in s, i.e., of the zero field of the integer
Definition SlidingTile.h:465
static constexpr int bits
Definition SlidingTile.h:185
std::array< std::uint8_t, cells > board_type
a board
Definition SlidingTile.h:190
void for_each_nblock_successor(std::size_t b, F &&f) const
calls f( b' ) for each abstract successor b' of the nblock b
Definition SlidingTile.h:395
int cost_type
the cost type
Definition SlidingTile.h:189
static board_type unpack(state_type s) noexcept
unpacks a word into a board
Definition SlidingTile.h:487
void for_each_feature_change(state_type s, state_type t, F &&f) const
calls f( k W H + c ) and f( k W H + b ) for the tile k that the move from s to its successor t slides...
Definition SlidingTile.h:332
SlidingTile(const board_type &start, const board_type &goal=korf_goal())
constructor, taking the start and the goal boards
Definition SlidingTile.h:209
cost_type pairwise_heuristic(state_type s, state_type t) const noexcept
the heuristic of PA*SE: the sum of the displacements of the tiles
Definition SlidingTile.h:417
void for_each_successor(state_type s, cost_type h, std::uint8_t op, F &&f) const
as above, but without the successor that op, the cell where the blank was, leads back to; the operato...
Definition SlidingTile.h:292
static state_type pack(const board_type &b) noexcept
Definition SlidingTile.h:477
static int tile(state_type s, int c) noexcept
the tile in the cell c of s
Definition SlidingTile.h:456
static constexpr int height
Definition SlidingTile.h:179
namespace for the Parallel Best-First Search library
Definition AStar.h:83
SlidingTile< 3, 3 > EightPuzzle
the 8-puzzle
Definition SlidingTile.h:604
SlidingTile< 5, 5 > TwentyFourPuzzle
the 24-puzzle
Definition SlidingTile.h:606
SlidingTile< 4, 4 > FifteenPuzzle
the 15-puzzle
Definition SlidingTile.h:605
an unsigned integer of 128 bits, as two words of 64
Definition SlidingTile.h:71
friend constexpr Word128 operator&(Word128 a, Word128 b) noexcept
Definition SlidingTile.h:96
friend constexpr int countr_zero(Word128 a) noexcept
the number of trailing zero bits, 128 if a is 0
Definition SlidingTile.h:136
friend constexpr Word128 operator^(Word128 a, Word128 b) noexcept
Definition SlidingTile.h:104
constexpr Word128(void) noexcept=default
friend constexpr bool operator==(const Word128 &a, const Word128 &b) noexcept=default
friend constexpr Word128 operator>>(Word128 a, int n) noexcept
the shift to the right by n bits,
Definition SlidingTile.h:124
constexpr Word128(std::uint64_t l) noexcept
the integer of value l
Definition SlidingTile.h:80
std::uint64_t hi
the bits 64 to 127
Definition SlidingTile.h:74
constexpr Word128(std::uint64_t l, std::uint64_t h) noexcept
the integer of the words l and h
Definition SlidingTile.h:84
friend constexpr Word128 operator|(Word128 a, Word128 b) noexcept
Definition SlidingTile.h:100
friend constexpr Word128 operator~(Word128 a) noexcept
Definition SlidingTile.h:108
friend constexpr Word128 operator<<(Word128 a, int n) noexcept
the shift to the left by n bits,
Definition SlidingTile.h:114
std::uint64_t lo
the bits 0 to 63
Definition SlidingTile.h:73
Word128 & operator|=(Word128 b) noexcept
Definition SlidingTile.h:132