]> git.scottworley.com Git - slidingtile/commitdiff
find_path
authorScott Worley <scottworley@scottworley.com>
Sat, 9 Jan 2016 19:44:08 +0000 (11:44 -0800)
committerScott Worley <scottworley@scottworley.com>
Sat, 9 Jan 2016 19:44:08 +0000 (11:44 -0800)
sliding_tile.cc
sliding_tile_lib.cc
sliding_tile_lib.h
sliding_tile_lib_test.cc

index 572a6e38bad9857fedd11524c715b3d24de6ef37..cfa7425b72964340748900700cbc3199587842a2 100644 (file)
@@ -1,9 +1,12 @@
 #include "sliding_tile_lib.h"
 #include "gflags/gflags.h"
 
+#include <iostream>
+
 DEFINE_string(start, "", "The starting tile positions.  0 is the hole.");
 DEFINE_string(goal, "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0", "The desired tile positions.  0 is the hole.");
 
 int main(int argc, char** argv) {
   gflags::ParseCommandLineFlags(&argc, &argv, false);
+  std::cout << *find_path(FLAGS_start, FLAGS_goal);
 }
index 5284dab95e4d4f707310f4fab44f996fdd8f56f8..9f6bfc9ff62dffa6b776a74350ed1ad110384d65 100644 (file)
@@ -4,9 +4,14 @@
 #include <istream>
 #include <memory>
 #include <ostream>
+#include <queue>
+#include <set>
+#include <sstream>
 #include <stdexcept>
 #include <vector>
 
+#include <iostream>
+
 signed char Step::adjacent[BOARD_SIZE][5] = {
   1,   4,   -1,  -1,  -1,
   0,   2,   5,   -1,  -1,
@@ -133,16 +138,29 @@ int Board::distance(const InvertedBoard& invo) const {
   return dist;
 }
 
-std::vector<Step*> Step::successors(std::shared_ptr<Step> shared_this) const {
-  std::vector<Step*> suc;
+Step::Step(Board board, std::shared_ptr<Step> prev) : board(board), prev(prev) {}
+
+std::vector<std::shared_ptr<Step>> Step::successors(std::shared_ptr<Step> shared_this) const {
+  std::vector<std::shared_ptr<Step>> suc;
   signed char hole_pos = board.hole();
-  for (int i = 0; adjacent[hole_pos][i] > 0; i++) {
-    suc.emplace_back(new Step{board, shared_this});
+  for (int i = 0; adjacent[hole_pos][i] >= 0; i++) {
+    suc.emplace_back(std::make_shared<Step>(board, shared_this));
     std::swap(suc.back()->board.board[hole_pos], suc.back()->board.board[adjacent[hole_pos][i]]);
   }
   return suc;
 }
 
+int Step::length() const {
+  if (prev.get() == nullptr) {
+    return 0;
+  }
+  return 1 + prev->length();
+}
+
+int Step::cost(const InvertedBoard& invgoal) const {
+  return length() + board.distance(invgoal) / 2;
+}
+
 std::ostream& operator<<(std::ostream& os, const Step& step) {
   if (step.prev != nullptr) {
     os << *step.prev;
@@ -160,3 +178,50 @@ std::ostream& operator<<(std::ostream& os, const Step& step) {
   }
   return os;
 }
+
+std::shared_ptr<Step> find_path(const std::string& start, const std::string& goal) {
+  std::istringstream iss_start{start}, iss_goal{goal};
+  Board board_start, board_goal;
+  iss_start >> board_start;
+  iss_goal >> board_goal;
+  if (iss_start.fail() || !iss_start.eof()) {
+    throw std::runtime_error("Could not parse the start board: " + start);
+  }
+  if (iss_goal.fail() || !iss_goal.eof()) {
+    throw std::runtime_error("Could not parse the goal board: " + goal);
+  }
+  return find_path(board_start, board_goal);
+}
+
+std::shared_ptr<Step> find_path(const Board& start, const Board& goal) {
+  InvertedBoard invgoal = goal.invert();
+  auto heap_greater = [invgoal](const std::shared_ptr<Step>& a, const std::shared_ptr<Step>& b) {
+    return a->cost(invgoal) > b->cost(invgoal);
+  };
+  std::priority_queue<std::shared_ptr<Step>,
+                      std::vector<std::shared_ptr<Step>>,
+                      decltype(heap_greater)> todo(heap_greater);
+  std::set<Board> seen;
+
+  seen.emplace(start);
+  todo.push(std::make_shared<Step>(start, nullptr));
+  while (!todo.empty()) {
+    if (todo.top()->board == goal) {
+      return todo.top();
+    }
+    std::vector<std::shared_ptr<Step>> successors = todo.top()->successors(todo.top());
+    for (const std::shared_ptr<Step>& s : successors) {
+      if (seen.find(s->board) == seen.end()) {
+        seen.emplace(s->board);
+        todo.push(s);
+        if (seen.size() % 10000 == 0) {
+          std::cerr << "Examined " << seen.size() << " boards.  " << todo.size()
+                    << " waiting.  Considering paths of length "
+                    << todo.top()->cost(invgoal) << std::endl;
+        }
+      }
+    }
+    todo.pop();
+  }
+  throw std::runtime_error("No path from start to goal");
+}
index 1b56da4c80a7e4fbc18947abc4a6f193c0eb057c..de2ca1f7fb077295cccb7ae41ee6a5527f4ba2ef 100644 (file)
@@ -4,6 +4,7 @@
 #include <istream>
 #include <memory>
 #include <ostream>
+#include <string>
 #include <vector>
 
 const int BOARD_DIM = 4;
@@ -28,12 +29,20 @@ std::istream& operator>>(std::istream& is, Board& board);
 std::ostream& operator<<(std::ostream& os, const Board& board);
 
 struct Step {
+  Step(Board board, std::shared_ptr<Step> prev);
+
   Board board;
   std::shared_ptr<Step> prev;
-  std::vector<Step*> successors(std::shared_ptr<Step> shared_this) const;
+
+  std::vector<std::shared_ptr<Step>> successors(std::shared_ptr<Step> shared_this) const;
+  int length() const;
+  int cost(const InvertedBoard& invgoal) const;
+
   static signed char adjacent[BOARD_SIZE][5];
 };
 std::ostream& operator<<(std::ostream& os, const Step& step);
 
+std::shared_ptr<Step> find_path(const std::string& start, const std::string& goal);
+std::shared_ptr<Step> find_path(const Board& start, const Board& goal);
 
 #endif /* _SLIDING_TILE_LIB_H */
index 5597a1b3bcb1b638fec2b1041a4cccdd10336177..25b0e76f55dcc4455cba1daa9dac8e45dfd9daa6 100644 (file)
@@ -6,6 +6,7 @@
 #include <sstream>
 
 using testing::Field;
+using testing::Pointee;
 
 TEST(Step, Adjacency) {
        const signed char LEFT  = -1;
@@ -141,20 +142,20 @@ TEST(Board, MaxDistance) {
 
 TEST(Step, TwoSuccessors) {
   auto s = std::make_shared<Step>(Step{{{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0}}, nullptr});
-  std::vector<Step*> suc = s->successors(s);
+  std::vector<std::shared_ptr<Step>> suc = s->successors(s);
   EXPECT_THAT(suc, testing::UnorderedElementsAre(
-    Field(&Step::board, Board{{1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,15}}),
-    Field(&Step::board, Board{{1,2,3,4,5,6,7,8,9,10,11,0,13,14,15,12}})));
+    Pointee(Field(&Step::board, Board{{1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,15}})),
+    Pointee(Field(&Step::board, Board{{1,2,3,4,5,6,7,8,9,10,11,0,13,14,15,12}}))));
 }
 
 TEST(Step, FourSuccessors) {
   auto s = std::make_shared<Step>(Step{{{1,2,3,4,5,0,6,7,8,9,10,11,12,13,14,15}}, nullptr});
-  std::vector<Step*> suc = s->successors(s);
+  std::vector<std::shared_ptr<Step>> suc = s->successors(s);
   EXPECT_THAT(suc, testing::UnorderedElementsAre(
-    Field(&Step::board, Board{{1,2,3,4,0,5,6,7,8,9,10,11,12,13,14,15}}),
-    Field(&Step::board, Board{{1,2,3,4,5,6,0,7,8,9,10,11,12,13,14,15}}),
-    Field(&Step::board, Board{{1,0,3,4,5,2,6,7,8,9,10,11,12,13,14,15}}),
-    Field(&Step::board, Board{{1,2,3,4,5,9,6,7,8,0,10,11,12,13,14,15}})));
+    Pointee(Field(&Step::board, Board{{1,2,3,4,0,5,6,7,8,9,10,11,12,13,14,15}})),
+    Pointee(Field(&Step::board, Board{{1,2,3,4,5,6,0,7,8,9,10,11,12,13,14,15}})),
+    Pointee(Field(&Step::board, Board{{1,0,3,4,5,2,6,7,8,9,10,11,12,13,14,15}})),
+    Pointee(Field(&Step::board, Board{{1,2,3,4,5,9,6,7,8,0,10,11,12,13,14,15}}))));
 }
 
 TEST(Step, Output) {