|
|
@ -26,34 +26,52 @@ |
|
|
|
/// 16. By performing such a search on each block in the layout, we can get all the next-step
|
|
|
|
/// layouts, which have a minimum of 0 and a maximum of 68.
|
|
|
|
|
|
|
|
/// For a single block, search for the situation after it has moved one grid, `addr` is its current
|
|
|
|
/// position information, which is (0 ~ 19) * 3. When moving up and down, judge the value of `addr`
|
|
|
|
/// to confirm whether it is out of bounds; when moving left and right, get its remainder to `4`
|
|
|
|
/// to judge whether it will be out of bounds. After confirming that it will not cross the boundary,
|
|
|
|
/// it is necessary to judge whether it will collide with other blocks after moving, that is, the
|
|
|
|
/// target position needs to be empty, which is represented as `000` in the RawCode, and the template
|
|
|
|
/// will be used to perform bit operations here to confirm whether it is feasible.
|
|
|
|
|
|
|
|
/// Finally, in order to improve efficiency, the `filter` option is added. For the direction of the
|
|
|
|
/// last movement, it will be ignored in the next search, so as to optimize BFS. After confirming
|
|
|
|
/// that it can be moved, the moved layout can be directly obtained by means of bit operations, and
|
|
|
|
/// a mask will be obtained at the same time, which marks the moved block as `111`, which will speed
|
|
|
|
/// up subsequent calculations. The generated layout will be inserted into the cache, and after the
|
|
|
|
/// BFS search for each block is completed, the core will use the callback function to output these
|
|
|
|
/// results.
|
|
|
|
|
|
|
|
#include <cstdint> |
|
|
|
#include <utility> |
|
|
|
#include <functional> |
|
|
|
|
|
|
|
class Core { |
|
|
|
public: |
|
|
|
/// Release with code and mask
|
|
|
|
typedef std::function<void(uint64_t, uint64_t)> release_t; |
|
|
|
|
|
|
|
/// Core interface
|
|
|
|
void next_cases(uint64_t code, uint64_t mask); |
|
|
|
explicit Core(release_t release_func) : release(std::move(release_func)) {} |
|
|
|
|
|
|
|
private: |
|
|
|
struct cache_t { |
|
|
|
uint64_t code; |
|
|
|
uint64_t mask; /// 000 or 111
|
|
|
|
int filter; /// UP | DOWN | LEFT | RIGHT
|
|
|
|
int addr; /// (0 ~ 19) * 3
|
|
|
|
}; |
|
|
|
namespace klotski { |
|
|
|
class Core { |
|
|
|
public: |
|
|
|
/// Release with code and mask
|
|
|
|
typedef std::function<void(uint64_t, uint64_t)> release_t; |
|
|
|
|
|
|
|
int cache_size = 1; |
|
|
|
cache_t cache[16]{}; |
|
|
|
release_t release; // release function
|
|
|
|
/// Core interface
|
|
|
|
void next_cases(uint64_t code, uint64_t mask); |
|
|
|
explicit Core(release_t release_func) : release(std::move(release_func)) {} |
|
|
|
|
|
|
|
void move_1x1(uint64_t code, int addr); |
|
|
|
void move_1x2(uint64_t code, int addr); |
|
|
|
void move_2x1(uint64_t code, int addr); |
|
|
|
void move_2x2(uint64_t code, int addr); |
|
|
|
inline void cache_insert(Core::cache_t next_case); |
|
|
|
}; |
|
|
|
private: |
|
|
|
struct cache_t { |
|
|
|
uint64_t code; |
|
|
|
uint64_t mask; /// (000) or (111)
|
|
|
|
int filter; /// UP | DOWN | LEFT | RIGHT
|
|
|
|
int addr; /// (0 ~ 19) * 3
|
|
|
|
}; |
|
|
|
|
|
|
|
int cache_size = 1; |
|
|
|
cache_t cache[16]{}; |
|
|
|
release_t release; // release function
|
|
|
|
|
|
|
|
void move_1x1(uint64_t code, int addr); |
|
|
|
void move_1x2(uint64_t code, int addr); |
|
|
|
void move_2x1(uint64_t code, int addr); |
|
|
|
void move_2x2(uint64_t code, int addr); |
|
|
|
inline void cache_insert(cache_t next_case); |
|
|
|
}; |
|
|
|
} |
|
|
|