]>
git.scottworley.com Git - slidingtile/blob - sliding_tile_lib.cc
1 #include "sliding_tile_lib.h"
16 signed char Step::adjacent
[BOARD_SIZE
][5] = {
35 bool Board::is_valid() const {
36 bool seen
[BOARD_SIZE
];
37 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
41 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
42 if (board
[i
] < 0 || board
[i
] >= BOARD_SIZE
|| seen
[board
[i
]]) {
45 seen
[board
[i
]] = true;
48 // Redundant because pigeon-hole-principle, but check anyway
49 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
58 bool Board::operator==(const Board
& o
) const {
59 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
60 if (board
[i
] != o
.board
[i
]) {
67 bool Board::operator!=(const Board
& o
) const {
68 return !operator==(o
);
71 bool Board::operator<(const Board
& o
) const {
72 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
73 if (board
[i
] < o
.board
[i
]) {
75 } else if (board
[i
] > o
.board
[i
]) {
82 std::istream
& operator>>(std::istream
& is
, Board
& board
) {
83 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
85 is
.setstate(std::istream::failbit
);
88 if (i
> 0 && is
.get() != ',') {
89 is
.setstate(std::istream::failbit
);
94 board
.board
[i
] = numeric
;
96 if (!board
.is_valid()) {
97 is
.setstate(std::istream::failbit
);
102 std::ostream
& operator<<(std::ostream
& os
, const Board
& board
) {
103 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
107 os
<< int(board
.board
[i
]);
112 signed char Board::hole() const {
113 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
118 throw std::runtime_error("Board with no hole");
121 InvertedBoard
Board::invert() const {
123 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
124 inv
.pos
[board
[i
]] = i
;
129 int Board::distance(const Board
& o
) const {
130 return distance(o
.invert());
133 int Board::distance(const InvertedBoard
& invo
) const {
135 for (int i
= 0; i
< BOARD_SIZE
; i
++) {
137 dist
+= std::abs(i
% BOARD_DIM
- invo
.pos
[board
[i
]] % BOARD_DIM
) +
138 std::abs(i
/ BOARD_DIM
- invo
.pos
[board
[i
]] / BOARD_DIM
);
144 Step::Step(Board board
, std::shared_ptr
<Step
> prev
) : board(board
), prev(prev
) {
152 std::vector
<std::shared_ptr
<Step
>> Step::successors(std::shared_ptr
<Step
> shared_this
) const {
153 std::vector
<std::shared_ptr
<Step
>> suc
;
154 signed char hole_pos
= board
.hole();
155 for (int i
= 0; adjacent
[hole_pos
][i
] >= 0; i
++) {
156 suc
.emplace_back(std::make_shared
<Step
>(board
, shared_this
));
157 std::swap(suc
.back()->board
.board
[hole_pos
], suc
.back()->board
.board
[adjacent
[hole_pos
][i
]]);
162 int Step::length() const {
163 if (prev
.get() == nullptr) {
166 return 1 + prev
->length();
169 int Step::cost(const InvertedBoard
& invgoal
) const {
170 return length() + board
.distance(invgoal
) / 2;
173 std::ostream
& operator<<(std::ostream
& os
, const Step
& step
) {
174 if (step
.prev
!= nullptr) {
176 signed char this_hole
= step
.board
.hole();
177 signed char prev_hole
= step
.prev
->board
.hole();
178 os
<< int(step
.board
.board
[prev_hole
]) << " ";
179 switch (this_hole
- prev_hole
) {
180 case -1: os
<< "right"; break;
181 case 1: os
<< "left"; break;
182 case -BOARD_DIM
: os
<< "down"; break;
183 case BOARD_DIM
: os
<< "up"; break;
184 default: os
<< "somehow!"; break;
191 std::shared_ptr
<Step
> find_path(const std::string
& start
, const std::string
& goal
) {
192 std::istringstream iss_start
{start
}, iss_goal
{goal
};
193 Board board_start
, board_goal
;
194 iss_start
>> board_start
;
195 iss_goal
>> board_goal
;
196 if (iss_start
.fail() || !iss_start
.eof()) {
197 throw std::runtime_error("Could not parse the start board: " + start
);
199 if (iss_goal
.fail() || !iss_goal
.eof()) {
200 throw std::runtime_error("Could not parse the goal board: " + goal
);
202 return find_path(board_start
, board_goal
);
205 std::shared_ptr
<Step
> find_path(const Board
& start
, const Board
& goal
) {
206 InvertedBoard invgoal
= goal
.invert();
207 auto heap_greater
= [invgoal
](const std::shared_ptr
<Step
>& a
, const std::shared_ptr
<Step
>& b
) {
208 return a
->cost(invgoal
) > b
->cost(invgoal
);
210 std::priority_queue
<std::shared_ptr
<Step
>,
211 std::vector
<std::shared_ptr
<Step
>>,
212 decltype(heap_greater
)> todo(heap_greater
);
213 std::set
<Board
> seen
;
216 todo
.push(std::make_shared
<Step
>(start
, nullptr));
217 while (!todo
.empty()) {
218 if (todo
.top()->board
== goal
) {
221 std::vector
<std::shared_ptr
<Step
>> successors
= todo
.top()->successors(todo
.top());
222 for (const std::shared_ptr
<Step
>& s
: successors
) {
223 if (seen
.find(s
->board
) == seen
.end()) {
224 seen
.emplace(s
->board
);
226 if (seen
.size() % 10000 == 0) {
227 std::cerr
<< "Examined " << seen
.size() << " boards. Tracking "
228 << Step::count
<< " steps. " << todo
.size()
229 << " waiting. Considering paths of length "
230 << todo
.top()->cost(invgoal
) << std::endl
;
236 throw std::runtime_error("No path from start to goal");