第一次改代码
看到文章 http://coolshell.cn/articles/10476.html
文章对应代码在: https://github.com/chenshuo/recipes/blob/master/puzzle/huarong.cc
学习C++, 也自己实现一个华容道。 脑袋一拍就出来下面的代码
class chessboard;
class chess;
class chess {
public:
virtual void to_right (chessboard &board) = 0;
virtual void to_left (chessboard &board) = 0;
virtual void to_up (chessboard &board) = 0;
virtual void to_down (chessboard &board) = 0;
protected:
int x_;
int y_;
int width_;
int height_;
};
enum direction {
up, down, right, left
};
class chessboard {
public:
virtual void move (chess &c, const direction &d) = 0;
};
第二次改代码
接口不好用, 尤其是main 函数中, 根本不能用。 考虑不够周全, 只考虑了对象(棋子和棋盘)的交互。 没有关注 棋子的集合, 棋盘的集合等等。
在写main 函数的时候, 不停的改接口, 直到面目全非。
回过头来,看main 函数发现只需要知道
1)初始化棋盘: 把每个棋子放到棋盘的某个位子
2)棋盘的状态(棋盘上棋子的分布位子), 并把这些状态放到std容器中 (实现需要)
3) 当前状态走一步后所有的有效状态
4)如何有效的区分这个状态是否已经出现过。
5) 不喜欢enum 里有 Shape:kInvalid 这个。 能了个类型的继承来, 不知道是否有效?
6) unordered_set 一直编译不过, 看下文档说需要 定义对应类型的 std::hash, std:equal_to
而上下左右的移动, 和怎么表示棋子在棋盘上(主要用与移动是否有效), main 函数是不需要知道的。 对应的代码是
enum direction {
up, down, right, left
};
struct board_map {
int board_[max_row][max_col];
};
另外: 代码还不能正常工作, 需要增加 chessboard.is_solved (曹操是否已经跑了)& can_move_steps (去所有有效的下一步) 函数
第三次修改
实现了部分功能。
由于chess 的继承,以及需要shared_ptr 中申请新的chess 初始化新的棋盘, 太麻烦了, 决定不要了。
加了chess_id 放棋子的信息, 方便多了。
实现棋子移动, 很多代码, 实现也很容易出错。
第四次修改
经过调试, 用string 代替 board_mask 类型终于跑出结果。 想想很容易的事情, 自己写也很累。
运行的很慢。 和参考文档中“耗时约几十毫秒”, 不是一个数量级的。
文档中的代码运行
time ./a.out
sizeof(Mask) = 20, sizeof(State) = 124
found solution with 116 steps
real 0m0.026s
user 0m0.024s
sys 0m0.000s
我写的
time ./BFS_huarongdao >/dev/null 2>&1
real 13m30.522s
user 12m59.717s
sys 0m30.474s
终于能跑出正确结果了。
正确跑后 第1次修改 目标跑的快的, 在1分钟内吧, 不然没耐心了。
统计下尝试移动的步骤: 我的程序有 10804822次。 参考程序需要 24027 次。 先从这里入手。 可能原因: seen 判断是否重复有问题。
查到问题所在, 用宽高位置表示没有问题, 棋子的顺序,影响棋盘的mask, 程序会认为当前局面没 有出现过。
排序棋子后, 24050次完成查找。 用时也在3秒多
$ time ./BFS_huarongdao >b 2>&1
real 0m3.116s
user 0m2.220s
sys 0m0.884s
优化性能, 工具gprof
1) 用unordered_set 代替 set。 效果不明显。 可能在数据量小 , 24K数据。
2) 用gprof 测试性能。 从结果上看, 我包的结构体和类有搜索结果外太多的信息
3) 简化数据结构后, 能在1秒内完成
real 0m0.961s
user 0m0.952s
sys 0m0.008s
4) 用vector 代替 deque后放chess后
real 0m0.216s
user 0m0.212s
sys 0m0.000s
$ time ./BFS_huarongdao
real 0m0.035s
user 0m0.032s
sys 0m0.004s