]>
git.scottworley.com Git - slidingtile/blob - sliding_tile_lib.cc
1 #include "sliding_tile_lib.h"
15 signed char Step::adjacent
[BOARD_SIZE
][5] = {
34 bool Board::is_valid() const {
35 bool seen
[BOARD_SIZE
];
36 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
40 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
41 if (board
[i
] < 0 || board
[i
] >= BOARD_SIZE
|| seen
[board
[i
]]) {
44 seen
[board
[i
]] = true;
47 // Redundant because pigeon-hole-principle, but check anyway
48 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
57 bool Board::operator==(const Board
& o
) const {
58 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
59 if (board
[i
] != o
.board
[i
]) {
66 bool Board::operator!=(const Board
& o
) const {
67 return !operator==(o
);
70 bool Board::operator<(const Board
& o
) const {
71 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
72 if (board
[i
] < o
.board
[i
]) {
74 } else if (board
[i
] > o
.board
[i
]) {
81 std::istream
& operator>>(std::istream
& is
, Board
& board
) {
82 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
84 is
.setstate(std::istream::failbit
);
87 if (i
> 0 && is
.get() != ',') {
88 is
.setstate(std::istream::failbit
);
93 board
.board
[i
] = numeric
;
95 if (!board
.is_valid()) {
96 is
.setstate(std::istream::failbit
);
101 std::ostream
& operator<<(std::ostream
& os
, const Board
& board
) {
102 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
106 os
<< int(board
.board
[i
]);
111 signed char Board::hole() const {
112 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
117 throw std::runtime_error("Board with no hole");
120 InvertedBoard
Board::invert() const {
122 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
123 inv
.pos
[board
[i
]] = i
;
128 int Board::distance(const Board
& o
) const {
129 return distance(o
.invert());
132 int Board::distance(const InvertedBoard
& invo
) const {
134 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
135 dist
+= std::abs(i
% BOARD_DIM
- invo
.pos
[board
[i
]] % BOARD_DIM
) +
136 std::abs(i
/ BOARD_DIM
- invo
.pos
[board
[i
]] / BOARD_DIM
);
141 Step::Step(Board board
, std::shared_ptr
<Step
> prev
) : board(board
), prev(prev
) {}
143 std::vector
<std::shared_ptr
<Step
>> Step::successors(std::shared_ptr
<Step
> shared_this
) const {
144 std::vector
<std::shared_ptr
<Step
>> suc
;
145 signed char hole_pos
= board
.hole();
146 for (int i
= 0; adjacent
[hole_pos
][i
] >= 0; i
++) {
147 suc
.emplace_back(std::make_shared
<Step
>(board
, shared_this
));
148 std::swap(suc
.back()->board
.board
[hole_pos
], suc
.back()->board
.board
[adjacent
[hole_pos
][i
]]);
153 int Step::length() const {
154 if (prev
.get() == nullptr) {
157 return 1 + prev
->length();
160 int Step::cost(const InvertedBoard
& invgoal
) const {
161 return length() + board
.distance(invgoal
) / 2;
164 std::ostream
& operator<<(std::ostream
& os
, const Step
& step
) {
165 if (step
.prev
!= nullptr) {
167 signed char this_hole
= step
.board
.hole();
168 signed char prev_hole
= step
.prev
->board
.hole();
169 os
<< int(step
.board
.board
[prev_hole
]) << " ";
170 switch (this_hole
- prev_hole
) {
171 case -1: os
<< "right"; break;
172 case 1: os
<< "left"; break;
173 case -BOARD_DIM
: os
<< "down"; break;
174 case BOARD_DIM
: os
<< "up"; break;
175 default: os
<< "somehow!"; break;
182 std::shared_ptr
<Step
> find_path(const std::string
& start
, const std::string
& goal
) {
183 std::istringstream iss_start
{start
}, iss_goal
{goal
};
184 Board board_start
, board_goal
;
185 iss_start
>> board_start
;
186 iss_goal
>> board_goal
;
187 if (iss_start
.fail() || !iss_start
.eof()) {
188 throw std::runtime_error("Could not parse the start board: " + start
);
190 if (iss_goal
.fail() || !iss_goal
.eof()) {
191 throw std::runtime_error("Could not parse the goal board: " + goal
);
193 return find_path(board_start
, board_goal
);
196 std::shared_ptr
<Step
> find_path(const Board
& start
, const Board
& goal
) {
197 InvertedBoard invgoal
= goal
.invert();
198 auto heap_greater
= [invgoal
](const std::shared_ptr
<Step
>& a
, const std::shared_ptr
<Step
>& b
) {
199 return a
->cost(invgoal
) > b
->cost(invgoal
);
201 std::priority_queue
<std::shared_ptr
<Step
>,
202 std::vector
<std::shared_ptr
<Step
>>,
203 decltype(heap_greater
)> todo(heap_greater
);
204 std::set
<Board
> seen
;
207 todo
.push(std::make_shared
<Step
>(start
, nullptr));
208 while (!todo
.empty()) {
209 if (todo
.top()->board
== goal
) {
212 std::vector
<std::shared_ptr
<Step
>> successors
= todo
.top()->successors(todo
.top());
213 for (const std::shared_ptr
<Step
>& s
: successors
) {
214 if (seen
.find(s
->board
) == seen
.end()) {
215 seen
.emplace(s
->board
);
217 if (seen
.size() % 10000 == 0) {
218 std::cerr
<< "Examined " << seen
.size() << " boards. " << todo
.size()
219 << " waiting. Considering paths of length "
220 << todo
.top()->cost(invgoal
) << std::endl
;
226 throw std::runtime_error("No path from start to goal");