前面文章中贴出的代码比较零乱,这里把完整的代码贴出来,方便大家参考。
共分三个文件:
// SokoState_v1.h -- SokoState类的头文件,第一版
#ifndef _SOKOSTATE_H
#define _SOKOSTATE_H
#include <iostream>
#include <vector>
#include <stack>
using std::vector;
using std::stack;
using std::ostream;
using std::istream;
const int MIN_ROWS = 4;
const int MAX_ROWS = 16;
const int MIN_COLS = 4;
const int MAX_COLS = 16;
class SokoState
{
public:
SokoState() : rows_(0), cols_(0) {}
void nextStep(vector<SokoState>&) const;
bool isTarget() const;
bool operator< (const SokoState& other) const;
friend ostream& operator<< (ostream& os, const SokoState& s);
friend istream& operator>> (istream& is, SokoState& s);
void printAnswer(ostream& os) const;
private:
struct Point
{
int x_, y_;
Point(int x, int y) : x_(x), y_(y) {}
Point up() const { return Point(x_-1, y_); }
Point down() const { return Point(x_+1, y_); }
Point left() const { return Point(x_, y_-1); }
Point right() const { return Point(x_, y_+1); }
};
enum MapChar {
CharWall = 'W', // Wall障碍物
CharBox = 'B', // Box箱子,不在目的地
CharSpace = 'S', // Space空地,没有任何东西
CharDest = 'D', // Dest目的地
CharInDest = 'I', // 已放在目的地上的箱子
CharSoko = 'K', // Soko推箱子的人,不在目的地
CharSokoInDest = 'O', // Soko推箱子的人,恰好在目的地
CharError = 'E' // 错误状态
};
enum MapFlag {
FlagWall = 0x01, // 是否障碍物
FlagBox = 0x02, // 是否有箱子
FlagDest = 0x04, // 是否目的地
FlagSoko = 0x08 // 是否有人
};
bool isWall(Point p) const
{ return (map_[p.x_][p.y_] & FlagWall) != 0; }
bool isBox(Point p) const
{ return (map_[p.x_][p.y_] & FlagBox) != 0; }
bool isDest(Point p) const
{ return (map_[p.x_][p.y_] & FlagDest) != 0; }
bool isSoko(Point p) const
{ return (map_[p.x_][p.y_] & FlagSoko) != 0; }
bool isSpace(Point p) const
{ return !isWall(p) && !isBox(p); }
bool isPureSpace(Point p) const
{ return isSpace(p) && !isSoko (p); }
unsigned char mapChar(Point p) const;
bool moveBox(SokoState& r, Point box, Point soko, Point nBox,
char d) const;
void checkSoko(stack<Point>& ps, Point p);
void stateEq();
struct SokoStep //用于记录每一步箱子的移动
{
int x_;
int y_;
char d_; // direction: R,L,U,D
SokoStep(int x, int y , char d) : x_(x), y_(y), d_(d) {}
friend ostream& operator<< (ostream& os, const SokoStep& s)
{
os << "[" << s.x_ << ", " << s.y_ << ", " << s.d_ << "]";
return os;
}
};
int rows_, cols_;
unsigned char map_[MAX_ROWS][MAX_COLS];
vector<SokoStep> steps_;
};
#endif
// SokoState_v1.cpp -- SokoState类的实现文件,第一版
#include <iterator>
#include <string>
#include <memory>
#include <stdexcept>
#include "SokoState_v1.h"
using namespace std;
inline unsigned char SokoState::mapChar(Point p) const
{
if (isWall(p))
return CharWall;
else if (isBox(p))
return isDest(p) ? CharInDest : CharBox;
else if (isSoko(p))
return isDest(p) ? CharSokoInDest : CharSoko;
else if (isDest(p))
return CharDest;
else
return CharSpace;
}
void SokoState::checkSoko(stack<Point>& ps, Point p)
{
if (isPureSpace(p))
{
map_[p.x_][p.y_] |= FlagSoko;
ps.push(p);
}
}
void SokoState::stateEq()
{
int i, j;
for (i = 1; i < rows_-1; i++)
{
for (j = 1; j < cols_-1; j++)
{
if (isSoko(Point(i, j))) break;
}
if (j < cols_-1) break;
}
stack<Point> points;
Point p(i, j);
points.push(p);
while (!points.empty())
{
p = points.top();
points.pop();
checkSoko(points, p.up());
checkSoko(points, p.down());
checkSoko(points, p.left());
checkSoko(points, p.right());
}
}
bool SokoState::moveBox(SokoState& r, Point box, Point soko, Point nBox,
char d) const
{
if (!isSoko(soko) || !isSpace(nBox))
return false;
r = *this;
for (int i = 0; i < r.rows_; i++) //清除soko标志
{
for (int j = 0; j < r.cols_; j++)
{
r.map_[i][j] &= ~FlagSoko;
}
}
r.map_[box.x_][box.y_] &= ~FlagBox; //移动箱子
r.map_[box.x_][box.y_] |= FlagSoko;
r.map_[nBox.x_][nBox.y_] |= FlagBox;
r.stateEq();
r.steps_.push_back(SokoStep(box.x_, box.y_, d));
return true;
}
void SokoState::nextStep(vector<SokoState>& vs) const
{
SokoState newState;
for (int i = 1; i < rows_-1; i++)
{
for (int j = 1; j < cols_-1; j++)
{
Point p(i, j);
if (!isBox(p))
continue;
if (moveBox(newState, p, p.down(), p.up(), 'U'))
vs.push_back(newState);
if (moveBox(newState, p, p.up(), p.down(), 'D'))
vs.push_back(newState);
if (moveBox(newState, p, p.right(), p.left(), 'L'))
vs.push_back(newState);
if (moveBox(newState, p, p.left(), p.right(), 'R'))
vs.push_back(newState);
}
}
}
bool SokoState::isTarget() const
{
for (int i = 1; i < rows_-1; i++)
{
for (int j = 1; j < cols_-1; j++)
{
Point p(i, j);
if (isDest(p) != isBox(p))
return false;
}
}
return true;
}
void SokoState::printAnswer(ostream& os) const
{
copy(steps_.begin(), steps_.end(), ostream_iterator<SokoStep>(os, " "));
}
bool SokoState::operator< (const SokoState& other) const
{
if (rows_ < other.rows_)
return true;
if (rows_ > other.rows_)
return false;
if (cols_ < other.cols_)
return true;
if (cols_ > other.cols_)
return false;
for (int i = 0; i < rows_; i++)
{
for (int j = 0; j < cols_; j++)
{
if (map_[i][j] < other.map_[i][j])
return true;
if (map_[i][j] > other.map_[i][j])
return false;
}
}
return false;
}
ostream& operator<< (ostream& os, const SokoState& s)
{
for (int i = 0; i < s.rows_; i++)
{
for (int j = 0; j < s.cols_; j++)
{
os << s.mapChar(SokoState::Point(i, j));
}
os << "/n";
}
os << "------------------------" << endl;
return os;
}
istream& operator>> (istream& is, SokoState& s)
{
is >> s.rows_;
if (s.rows_ < MIN_ROWS || s.rows_ > MAX_ROWS)
{
throw invalid_argument("rows of soko game error.");
}
is >> s.cols_;
if (s.cols_ < MIN_COLS || s.cols_ > MAX_COLS)
{
throw invalid_argument("cols of soko game error.");
}
string str;
getline(is, str); // 滤过第一行的换行
for (int i = 0; i < s.rows_; i++)
{
getline(is, str);
for (int j = 0; j < s.cols_; j++)
{
s.map_[i][j] = 0;
switch (str[j]) {
case SokoState::CharBox :
s.map_[i][j] |= SokoState::FlagBox;
break;
case SokoState::CharWall :
s.map_[i][j] |= SokoState::FlagWall;
break;
case SokoState::CharSpace :
break;
case SokoState::CharDest :
s.map_[i][j] |= SokoState::FlagDest;
break;
case SokoState::CharInDest :
s.map_[i][j] |= SokoState::FlagDest | SokoState::FlagBox;
break;
case SokoState::CharSoko :
s.map_[i][j] |= SokoState::FlagSoko;
break;
case SokoState::CharSokoInDest :
s.map_[i][j] |= SokoState::FlagSoko | SokoState::FlagDest;
break;
default :
throw invalid_argument(
string("char of soko game error: ") + str );
}
}
}
s.stateEq();
return is;
}
// soko.cpp -- 推箱子主程序
#include <iostream>
#include "BreadthFirstSearch.hpp"
#include "SokoState_v1.h"
using namespace std;
bool printAnswer(const SokoState& s)
{
s.printAnswer(cout);
cout << endl;
return true;
}
int main(int argc, char *argv[])
{
SokoState initState;
cin >> initState;
cout << initState;
OrderCheckDup<SokoState> checkDup;
int n = BreadthFirstSearch(initState, printAnswer, checkDup);
if (n == 0)
{
cout << "No answer." << endl;
}
return 0;
}