59template <
size_t N = 3>
61 std::array<std::array<uint32_t, N>, N>
64 std::vector<std::pair<int8_t, int8_t>>
moves = {
76 for (
size_t i = 0; i < N; ++i) {
77 for (
size_t j = 0; j < N; ++j) {
90 inline bool in_range(
const uint32_t value)
const {
return value < N; }
102 uint32_t
get(
size_t i,
size_t j)
const {
111 std::array<std::array<uint32_t, N>, N>
get_state() {
return board; }
122 for (
size_t i = 0; i < N; ++i) {
123 for (
size_t j = 0; j < N; ++j) {
124 board[i][j] = ((i * 3 + j + 1) % (N * N));
132 explicit EightPuzzle(
const std::array<std::array<uint32_t, N>, N> &init)
146 : board(std::move(A.board)) {}
166 board = std::move(A.board);
179 std::vector<EightPuzzle<N>> NewStates;
180 for (
auto &move :
moves) {
181 if (
in_range(zero_pos.first + move.first) &&
182 in_range(zero_pos.second + move.second)) {
184 std::array<std::array<uint32_t, N>, N> new_config = board;
185 std::swap(new_config[zero_pos.first][zero_pos.second],
186 new_config[zero_pos.first + move.first]
187 [zero_pos.second + move.second]);
190 NewStates.emplace_back(new_state);
201 if (check.get_size() != N) {
204 for (
size_t i = 0; i < N; ++i) {
205 for (
size_t j = 0; j < N; ++j) {
206 if (board[i][j] != check.board[i][j]) {
219 for (
size_t i = 0; i < N; ++i) {
220 for (
size_t j = 0; j < N; ++j) {
221 if (board[i][j] != check.board[i][j]) {
222 return board[i][j] < check.board[i][j];
234 for (
size_t i = 0; i < N; ++i) {
235 for (
size_t j = 0; j < N; ++j) {
236 if (board[i][j] != check.board[i][j]) {
237 return board[i][j] < check.board[i][j];
252 for (
size_t i = 0; i < N; ++i) {
253 for (
size_t j = 0; j < N; ++j) {
254 op << SomeState.board[i][j] <<
" ";
287template <
typename Puzzle>
294 std::shared_ptr<Puzzle> state;
307 explicit Info(
const Puzzle &A) : state(std::make_shared<Puzzle>(A)) {}
315 Info(
const Puzzle &A,
size_t h_value,
size_t d)
316 : state(std::make_shared<Puzzle>(A)),
325 : state(std::make_shared<Puzzle>(A.state)),
334 : state(std::make_shared<Puzzle>(std::move(A.state))),
336 depth(std::move(A.depth)) {}
354 state = std::move(A.state);
356 depth = std::move(A.depth);
365 std::shared_ptr<Info> Initial;
366 std::shared_ptr<Info> Final;
371 bool operator()(
const std::shared_ptr<Info> &a,
372 const std::shared_ptr<Info> &b)
const {
373 return *(a->state) < *(b->state);
378 using MapOfPuzzleInfoWithPuzzleInfo =
379 std::map<std::shared_ptr<Info>, std::shared_ptr<Info>,
382 using MapOfPuzzleInfoWithInteger =
385 using SetOfPuzzleInfo =
393 Initial = std::make_shared<Info>(initial);
394 Final = std::make_shared<Info>(
final);
406 std::shared_ptr<Info> FinalState,
407 const MapOfPuzzleInfoWithPuzzleInfo &parent_of) {
409 auto current_state = FinalState;
414 std::vector<Puzzle> answer;
415 while (current_state !=
nullptr) {
416 answer.emplace_back(*current_state->state);
417 current_state = parent_of.find(current_state)->second;
430 const std::function<uint32_t(
const Puzzle &,
const Puzzle &)> &dist,
431 const uint32_t permissible_depth = 30) {
432 MapOfPuzzleInfoWithPuzzleInfo
434 MapOfPuzzleInfoWithInteger g_score;
435 SetOfPuzzleInfo open_list;
436 SetOfPuzzleInfo closed_list;
439 open_list.emplace(Initial);
440 parent_of[Initial] =
nullptr;
441 g_score[Initial] = 0;
443 while (!open_list.empty()) {
445 typename SetOfPuzzleInfo::iterator it_low_f_score;
446 uint32_t min_f_score = 1e9;
447 for (
auto iter = open_list.begin(); iter != open_list.end();
451 uint32_t f_score = (*iter)->heuristic_value + (*iter)->depth;
452 if (f_score < min_f_score) {
453 min_f_score = f_score;
454 it_low_f_score = iter;
459 std::shared_ptr<Info> current_state = *it_low_f_score;
462 if (*(current_state->state) == *(Final->state)) {
463 return Solution(current_state, parent_of);
466 open_list.erase(it_low_f_score);
469 if (current_state->depth >= permissible_depth) {
474 std::vector<Puzzle> total_possible_moves =
475 current_state->state->generate_possible_moves();
477 for (Puzzle &neighbor : total_possible_moves) {
480 std::shared_ptr<Info> Neighbor = std::make_shared<Info>(
481 neighbor, dist(neighbor, *(Final->state)),
482 current_state->depth + 1U);
483 uint32_t temp_g_score = Neighbor->depth;
488 auto closed_list_iter = closed_list.find(Neighbor);
489 if (closed_list_iter != closed_list.end()) {
493 if (Neighbor->depth < (*closed_list_iter)->depth) {
494 closed_list.erase(closed_list_iter);
499 auto neighbor_g_score_iter = g_score.find(Neighbor);
502 if (neighbor_g_score_iter != g_score.end()) {
503 if (neighbor_g_score_iter->second > temp_g_score) {
504 neighbor_g_score_iter->second = temp_g_score;
505 parent_of[Neighbor] = current_state;
508 g_score[Neighbor] = temp_g_score;
509 parent_of[Neighbor] = current_state;
514 auto iter = open_list.find(Neighbor);
515 if (iter == open_list.end()) {
516 open_list.emplace(Neighbor);
517 }
else if ((*iter)->depth > Neighbor->depth) {
518 (*iter)->depth = Neighbor->depth;
521 closed_list.emplace(current_state);
524 return std::vector<Puzzle>(0);
536 using matrix3 = std::array<std::array<uint32_t, 3>, 3>;
537 using row3 = std::array<uint32_t, 3>;
538 using matrix4 = std::array<std::array<uint32_t, 4>, 4>;
539 using row4 = std::array<uint32_t, 4>;
542 puzzle[0] = row3({0, 2, 3});
543 puzzle[1] = row3({1, 5, 6});
544 puzzle[2] = row3({4, 7, 8});
547 ideal[0] = row3({1, 2, 3});
548 ideal[1] = row3({4, 5, 6});
549 ideal[2] = row3({7, 8, 0});
554 auto manhattan_distance =
558 for (
size_t i = 0; i < first.
get_size(); ++i) {
559 for (
size_t j = 0; j < first.
get_size(); ++j) {
560 uint32_t
find = first.
get(i, j);
562 for (
size_t k = 0;
k < second.get_size(); ++
k) {
563 for (
size_t l = 0;
l < second.get_size(); ++
l) {
564 if (find == second.get(k, l)) {
565 std::tie(m, n) = std::make_pair(k, l);
574 ret += (std::max(m, i) - std::min(m, i)) +
575 (std::max(n, j) - std::min(n, j));
588 std::vector<matrix3> answer;
591 matrix3({row3({0, 2, 3}), row3({1, 5, 6}), row3({4, 7, 8})}));
593 matrix3({row3({1, 2, 3}), row3({0, 5, 6}), row3({4, 7, 8})}));
595 matrix3({row3({1, 2, 3}), row3({4, 5, 6}), row3({0, 7, 8})}));
597 matrix3({row3({1, 2, 3}), row3({4, 5, 6}), row3({7, 0, 8})}));
599 matrix3({row3({1, 2, 3}), row3({4, 5, 6}), row3({7, 8, 0})}));
602 std::cout <<
Solution.size() << std::endl;
604 assert(
Solution.size() == answer.size());
608 assert(it->get_state() == answer[i]);
614 puzzle[0] = row3({5, 7, 3});
615 puzzle[1] = row3({2, 0, 6});
616 puzzle[2] = row3({1, 4, 8});
618 ideal[0] = row3({1, 2, 3});
619 ideal[1] = row3({4, 5, 6});
620 ideal[2] = row3({7, 8, 0});
630 std::cout <<
Solution.size() << std::endl;
634 assert(
Solution[0].get_state() == ideal);
636 std::cout << *it << std::endl;
642 puzzle2[0] = row4({10, 1, 6, 2});
643 puzzle2[1] = row4({5, 8, 4, 3});
644 puzzle2[2] = row4({13, 0, 7, 11});
645 puzzle2[3] = row4({14, 9, 15, 12});
648 ideal2[0] = row4({1, 2, 3, 4});
649 ideal2[1] = row4({5, 6, 7, 8});
650 ideal2[2] = row4({9, 10, 11, 12});
651 ideal2[3] = row4({13, 14, 15, 0});
659 search2(Puzzle2, Ideal2);
663 auto manhattan_distance2 =
667 for (
size_t i = 0; i < first.
get_size(); ++i) {
668 for (
size_t j = 0; j < first.
get_size(); ++j) {
669 uint32_t
find = first.
get(i, j);
671 for (
size_t k = 0;
k < second.get_size(); ++
k) {
672 for (
size_t l = 0;
l < second.get_size(); ++
l) {
673 if (find == second.get(k, l)) {
674 std::tie(m, n) = std::make_pair(k, l);
683 ret += (std::max(m, i) - std::min(m, i)) +
684 (std::max(n, j) - std::min(n, j));
691 auto sol2 = search2.a_star_search(manhattan_distance2);
692 std::cout << sol2.size() << std::endl;
695 assert(24 == sol2.size());
697 assert(sol2[0].get_state() == ideal2);
699 for (
auto it = sol2.rbegin(); it != sol2.rend(); ++it) {
700 std::cout << *it << std::endl;
A class defining A* search algorithm. for some initial state and final state.
std::vector< Puzzle > Solution(std::shared_ptr< Info > FinalState, const MapOfPuzzleInfoWithPuzzleInfo &parent_of)
A helper solution: launches when a solution for AyStarSearch is found.
std::vector< Puzzle > a_star_search(const std::function< uint32_t(const Puzzle &, const Puzzle &)> &dist, const uint32_t permissible_depth=30)
AyStarSearch(const Puzzle &initial, const Puzzle &final)
Parameterized constructor for AyStarSearch.
struct machine_learning::aystar_search::AyStarSearch::Info Info
Struct that handles all the information related to the current state.
A class defining EightPuzzle/15-Puzzle game.
EightPuzzle & operator=(EightPuzzle &&A) noexcept
Move assignment operator.
~EightPuzzle()=default
Destructor of EightPuzzle.
std::vector< EightPuzzle< N > > generate_possible_moves()
Find all possible states after processing all possible moves, given the current state of the puzzle.
EightPuzzle()
Default constructor for EightPuzzle.
EightPuzzle & operator=(const EightPuzzle &A)
Copy assignment operator.
bool in_range(const uint32_t value) const
check whether the index value is bounded within the puzzle area
bool operator<(const EightPuzzle< N > &check) const
check whether one board is lexicographically smaller
std::pair< uint32_t, uint32_t > find_zero()
A helper array to evaluate the next state from current state;.
friend std::ostream & operator<<(std::ostream &op, const EightPuzzle< N > &SomeState)
friend operator to display EightPuzzle<>
bool operator==(const EightPuzzle< N > &check) const
check whether two boards are equal
uint32_t get(size_t i, size_t j) const
get the value from i units from right and j units from left side of the board
std::vector< std::pair< int8_t, int8_t > > moves
N x N array to store the current state of the Puzzle.
EightPuzzle(const std::array< std::array< uint32_t, N >, N > &init)
Parameterized Constructor for EightPuzzle.
EightPuzzle(const EightPuzzle< N > &A)
Copy constructor.
std::array< std::array< uint32_t, N >, N > get_state()
Returns the current state of the board.
size_t get_size() const
returns the size of the EightPuzzle (number of row / column)
EightPuzzle(const EightPuzzle< N > &&A) noexcept
Move constructor.
bool operator<=(const EightPuzzle< N > &check) const
check whether one board is lexicographically smaller or equal
double k(double x)
Another test function.
double l(double x)
Another test function.
Functions for A* Search implementation.
Struct that handles all the information related to the current state.
size_t depth
stores h score
size_t heuristic_value
Holds the current state.
Info(const Info &A)
Copy constructor.
Info(const Puzzle &A)
constructor having Puzzle as parameter
Info(const Info &&A) noexcept
Move constructor.
~Info()=default
Destructor for Info.
Info()=default
stores g score
Info & operator=(const Info &A)
copy assignment operator
Info(const Puzzle &A, size_t h_value, size_t d)
constructor having three parameters
Info & operator=(Info &&A) noexcept
move assignment operator
Custom comparator for open_list.