棋盘的绘制和走棋参看博文:中国象棋游戏Chess(1) - 棋盘绘制以及棋子的绘制中国象棋游戏Chess(2)
- 走棋

现在重新整理之前写的代码,并且对于每个棋子的走棋规则都进行了限制,不像之前那样每个棋子都可以走到任意位置。

也实现了红先黑后,并且每一方走一步,交替走棋的功能。

直接看代码:

  1. // Board.h
  2. // Board类实现了棋盘的绘制以及显示
  3. //
  4.  
  5. #ifndef BOARD_H
  6. #define BOARD_H
  7.  
  8. #include <QFrame>
  9. #include "Stone.h"
  10. #include "Step.h"
  11. #include <QVector>
  12.  
  13. class Board : public QFrame
  14. {
  15. Q_OBJECT
  16. public:
  17. explicit Board(QWidget *parent = 0);
  18. ~Board();
  19.  
  20. /*===> 游戏数据 <===*/
  21. Stone _s[32]; // 定义32个棋子
  22. int _r; // 棋子的半径
  23. QPoint _off;
  24. bool _bSide;
  25.  
  26. QVector<Step*> _steps; // 悔棋时使用
  27.  
  28. /*===> 游戏状态 <===*/
  29. int _selectid;
  30. bool _bRedTurn;
  31. void init(bool bRedSide);
  32.  
  33. /*===> 绘图函数 <===*/
  34. virtual void paintEvent(QPaintEvent *);
  35. void DrawBackground(); // 设置背景颜色
  36. void drawPlate(QPainter& p); // 绘制棋盘
  37. void drawPlace(QPainter& p); // 绘制九宫格
  38. void drawInitPosition(QPainter& p); // 绘制炮兵位置上的十字
  39. void drawInitPosition(QPainter& p, int row, int col);
  40. void drawStone(QPainter &p); // 绘制棋子
  41. void drawStone(QPainter &p, int id);
  42.  
  43. /*===> 坐标转换相关函数 <===*/
  44. QPoint center(int row, int col); // 返回棋盘行列对应的像素坐标
  45. QPoint center(int id);
  46. QPoint topLeft(int row, int col);
  47. QPoint topLeft(int id);
  48. QRect cell(int row, int col);
  49. QRect cell(int id);
  50.  
  51. bool getClickRowCol(QPoint pt, int &row, int &col);
  52.  
  53. /*===> 帮助函数 <===*/
  54. QString name(int id);
  55. bool red(int id);
  56. bool sameColor(int id1, int id2);
  57. int getStoneId(int row, int col); // 获取行row列col上的棋子id
  58. void killStone(int id);
  59. void reliveStone(int id);
  60. void moveStone(int moveid, int row, int col);
  61. bool isDead(int id); // 判断id棋子是否死亡
  62.  
  63. /*===> 移动相关函数 <===*/
  64. virtual void mouseReleaseEvent(QMouseEvent *ev); // 鼠标点击象棋并释放鼠标时候触发
  65. void click(QPoint pt);
  66. virtual void click(int id, int row, int col);
  67. void trySelectStone(int id);
  68. void tryMoveStone(int killid, int row, int col);
  69. void moveStone(int moveid, int killid, int row, int col);
  70. void saveStep(int moveid, int killid, int row, int col, QVector<Step*>& steps);
  71. void backOne();
  72. void back(Step* step);
  73. virtual void back();
  74.  
  75. /*===> 移动规则 <===*/
  76. bool canMove(int moveid, int killid, int row, int col);
  77. bool canMoveJiang(int moveid, int killid, int row, int col);
  78. bool canMoveShi(int moveid, int, int row, int col);
  79. bool canMoveXiang(int moveid, int, int row, int col);
  80. bool canMoveChe(int moveid, int, int row, int col);
  81. bool canMoveMa(int moveid, int killid, int row, int col);
  82. bool canMovePao(int moveid, int killid, int row, int col);
  83. bool canMoveBing(int moveid, int killid, int row, int col);
  84.  
  85. bool canSelect(int id);
  86.  
  87. /*===> 移动规则相关的几个帮助函数 <===*/
  88. int relation(int row1, int col1, int row, int col); // 得到两点之间的关系值
  89. bool isBottomSide(int id); // 判断id棋子是否在棋盘下方
  90. // 判断两个点是否在同一条直线上,炮和车走棋的时候需要用到
  91. int getStoneCountAtLine(int row1, int col1, int row2, int col2);
  92.  
  93. signals:
  94.  
  95. public slots:
  96. void slotBack();
  97. };
  98.  
  99. #endif // BOARD_H
  1. // Board.cpp
  2.  
  3. #include "Board.h"
  4. #include <QPainter> // 绘制棋盘需要
  5. #include <QMouseEvent>
  6. #include <QDebug>
  7. #define GetRowCol(__row, __col, __id) \
  8. int __row = _s[__id]._row;\
  9. int __col = _s[__id]._col
  10.  
  11. Board::Board(QWidget *parent) : QFrame(parent)
  12. {
  13. this->_r = 20;
  14. setMinimumSize(_r * 18 + 1, _r * 20 + 1);
  15. init(true);
  16. }
  17.  
  18. Board::~Board()
  19. {
  20.  
  21. }
  22.  
  23. void Board::init(bool bRedSide)
  24. {
  25. for (int i = 0; i < 32; ++i) {
  26. _s[i].init(i);
  27. }
  28. if (bRedSide) {
  29. for (int i = 0; i < 32; ++i) {
  30. _s[i].rotate();
  31. }
  32. }
  33.  
  34. _selectid = -1;
  35. _bRedTurn = true;
  36. _bSide = bRedSide;
  37. update();
  38. }
  39.  
  40. // 绘制棋盘
  41. void Board::paintEvent(QPaintEvent *)
  42. {
  43. DrawBackground(); // 绘制背景颜色
  44.  
  45. int r = height() / 20;
  46. _r = r;
  47. _off = QPoint(r + 1, r + 1);
  48.  
  49. QPainter p(this);
  50. p.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
  51.  
  52. p.save();
  53. drawPlate(p);
  54. p.restore();
  55.  
  56. p.save();
  57. drawPlace(p);
  58. p.restore();
  59.  
  60. p.save();
  61. drawInitPosition(p);
  62. p.restore();
  63.  
  64. p.save();
  65. drawStone(p);
  66. p.restore();
  67. }
  68.  
  69. // 设置背景颜色
  70. void Board::DrawBackground()
  71. {
  72. QPalette p = this->palette();
  73. p.setColor(QPalette::Window, QColor(224, 255, 255));
  74. this->setPalette(p);
  75. }
  76.  
  77. // 绘制棋盘
  78. void Board::drawPlate(QPainter &p)
  79. {
  80. // 绘制10条横线
  81. for (int i = 0; i < 10; ++i) {
  82. if (i == 0 || i == 9) { // 上下边框画笔设置的粗一些
  83. p.setPen(QPen(Qt::black, 3, Qt::SolidLine));
  84. }
  85. else {
  86. p.setPen(QPen(Qt::black, 1, Qt::SolidLine));
  87. }
  88. p.drawLine(center(i, 0), center(i, 8));
  89. }
  90.  
  91. // 绘制9条竖线
  92. for (int i = 0; i < 9; ++i) {
  93. if (i == 0 || i == 8) { // 中间有楚河汉界,不能画通
  94. p.setPen(QPen(Qt::black, 3, Qt::SolidLine));
  95. p.drawLine(center(0, i), center(9, i));
  96. }
  97. else {
  98. p.setPen(QPen(Qt::black, 1, Qt::SolidLine));
  99. p.drawLine(center(0, i), center(4, i));
  100. p.drawLine(center(5, i), center(9, i));
  101. }
  102. }
  103. }
  104.  
  105. // 绘制九宫格
  106. void Board::drawPlace(QPainter &p)
  107. {
  108. p.drawLine(center(0, 3), center(2, 5));
  109. p.drawLine(center(2, 3), center(0, 5));
  110.  
  111. p.drawLine(center(9, 3), center(7, 5));
  112. p.drawLine(center(7, 3), center(9, 5));
  113. }
  114.  
  115. // 绘制炮兵位置上的十字
  116. void Board::drawInitPosition(QPainter &p)
  117. {
  118. drawInitPosition(p, 3, 0);
  119. drawInitPosition(p, 3, 2);
  120. drawInitPosition(p, 3, 4);
  121. drawInitPosition(p, 3, 6);
  122. drawInitPosition(p, 3, 8);
  123.  
  124. drawInitPosition(p, 6, 0);
  125. drawInitPosition(p, 6, 2);
  126. drawInitPosition(p, 6, 4);
  127. drawInitPosition(p, 6, 6);
  128. drawInitPosition(p, 6, 8);
  129.  
  130. drawInitPosition(p, 2, 1);
  131. drawInitPosition(p, 2, 7);
  132.  
  133. drawInitPosition(p, 7, 1);
  134. drawInitPosition(p, 7, 7);
  135. }
  136.  
  137. void Board::drawInitPosition(QPainter& p, int row, int col)
  138. {
  139. QPoint pt = center(row, col);
  140. QPoint off = QPoint(_r / 6, _r / 6);
  141. int len = _r / 3;
  142.  
  143. QPoint ptStart;
  144. QPoint ptEnd;
  145.  
  146. if (col != 0) {
  147. // 左上角
  148. ptStart = QPoint(pt.x() - off.x(), pt.y() - off.y());
  149. ptEnd = ptStart + QPoint(-len, 0);
  150. p.drawLine(ptStart, ptEnd);
  151. ptEnd = ptStart + QPoint(0, -len);
  152. p.drawLine(ptStart, ptEnd);
  153.  
  154. // 左下角
  155. ptStart = QPoint(pt.x() - off.x(), pt.y() + off.y());
  156. ptEnd = ptStart + QPoint(-len, 0);
  157. p.drawLine(ptStart, ptEnd);
  158. ptEnd = ptStart + QPoint(0, +len);
  159. p.drawLine(ptStart, ptEnd);
  160. }
  161.  
  162. if (col != 8) {
  163. // 右下角
  164. ptStart = QPoint(pt.x() + off.x(), pt.y() + off.y());
  165. ptEnd = ptStart + QPoint(+len, 0);
  166. p.drawLine(ptStart, ptEnd);
  167. ptEnd = ptStart + QPoint(0, +len);
  168. p.drawLine(ptStart, ptEnd);
  169.  
  170. // 右上角
  171. ptStart = QPoint(pt.x() + off.x(), pt.y() - off.y());
  172. ptEnd = ptStart + QPoint(+len, 0);
  173. p.drawLine(ptStart, ptEnd);
  174. ptEnd = ptStart + QPoint(0, -len);
  175. p.drawLine(ptStart, ptEnd);
  176. }
  177. }
  178.  
  179. // 绘制棋子
  180. void Board::drawStone(QPainter &p)
  181. {
  182. for (int i = 0; i < 32; ++i) {
  183. drawStone(p, i);
  184. }
  185. }
  186.  
  187. void Board::drawStone(QPainter &p, int id)
  188. {
  189. if (isDead(id)) {
  190. return;
  191. }
  192.  
  193. QColor color;
  194. if (red(id)) {
  195. color = Qt::red;
  196. }
  197. else {
  198. color = Qt::black;
  199. }
  200.  
  201. p.setPen(QPen(QBrush(color), 2));
  202.  
  203. if (id == _selectid) {
  204. p.setBrush(Qt::gray);
  205. }
  206. else {
  207. p.setBrush(Qt::yellow);
  208. }
  209.  
  210. p.drawEllipse(cell(id));
  211.  
  212. p.setFont(QFont("system", _r * 1.2, 700)); // 设置字体大小和类型
  213. p.drawText(cell(id), name(id), QTextOption(Qt::AlignCenter));
  214. }
  215.  
  216. // 返回棋盘行列对应的像素坐标
  217. QPoint Board::center(int row, int col)
  218. {
  219. QPoint pt(_r * col * 2, _r * row * 2);
  220. return pt + _off;
  221. }
  222.  
  223. // 重载center函数,方便调用
  224. QPoint Board::center(int id)
  225. {
  226. return center(_s[id]._row, _s[id]._col);
  227. }
  228.  
  229. QPoint Board::topLeft(int row, int col)
  230. {
  231. return center(row, col) - QPoint(_r, _r);
  232. }
  233.  
  234. QPoint Board::topLeft(int id)
  235. {
  236. return center(id) - QPoint(_r, _r);
  237. }
  238.  
  239. QRect Board::cell(int row, int col)
  240. {
  241. return QRect(topLeft(row, col), QSize(_r * 2 - 1, _r * 2 - 1));
  242. }
  243.  
  244. QRect Board::cell(int id)
  245. {
  246. return QRect(topLeft(id), QSize(_r * 2 - 1, _r * 2 - 1));
  247. }
  248.  
  249. // 判断点击位置属于哪个顶点
  250. // 返回值为bool类型是为了处理点击在棋盘外的情况
  251. bool Board::getClickRowCol(QPoint pt, int &row, int &col)
  252. {
  253. row = pt.y() / (2 * _r) - 1;
  254. col = pt.x() / (2 * _r) - 1;
  255.  
  256. QPoint c = center(row, col);
  257. int dx = c.x() - pt.x();
  258. int dy = c.y() - pt.y();
  259. int dist = dx * dx + dy * dy; // 和鼠标所处矩形左上顶点的距离
  260. if (dist < _r * _r) {
  261. return true;
  262. }
  263.  
  264. row += 1;
  265. c = center(row, col);
  266. dx = c.x() - pt.x();
  267. dy = c.y() - pt.y();
  268. dist = dx * dx + dy * dy; // 和鼠标所处矩形左下顶点的距离
  269. if (dist < _r * _r) {
  270. return true;
  271. }
  272.  
  273. row -= 1;
  274. col += 1;
  275. c = center(row, col);
  276. dx = c.x() - pt.x();
  277. dy = c.y() - pt.y();
  278. dist = dx * dx + dy * dy; // 和鼠标所处矩形右上顶点的距离
  279. if (dist < _r * _r) {
  280. return true;
  281. }
  282.  
  283. row += 1;
  284. c = center(row, col);
  285. dx = c.x() - pt.x();
  286. dy = c.y() - pt.y();
  287. dist = dx * dx + dy * dy; // 和鼠标所处矩形右下顶点的距离
  288. if (dist < _r * _r) {
  289. return true;
  290. }
  291.  
  292. return false;
  293. }
  294.  
  295. QString Board::name(int id)
  296. {
  297. return _s[id].name();
  298. }
  299.  
  300. bool Board::red(int id)
  301. {
  302. return _s[id]._red;
  303. }
  304.  
  305. bool Board::sameColor(int id1, int id2)
  306. {
  307. if (id1 == -1 || id2 == -1) {
  308. return false;
  309. }
  310. return red(id1) == red(id2);
  311. }
  312.  
  313. int Board::getStoneId(int row, int col)
  314. {
  315. for (int i = 0; i < 32; ++i) {
  316. if (_s[i]._row == row &&
  317. _s[i]._col == col && !isDead(i)) {
  318. return i;
  319. }
  320. }
  321. return -1; // 如果不是棋子返回-1
  322. }
  323.  
  324. void Board::killStone(int id)
  325. {
  326. if (id == -1) {
  327. return;
  328. }
  329. _s[id]._dead = true;
  330. }
  331.  
  332. void Board::reliveStone(int id)
  333. {
  334. if (id == -1) {
  335. return;
  336. }
  337. _s[id]._dead = false;
  338. }
  339.  
  340. void Board::moveStone(int moveid, int row, int col)
  341. {
  342. _s[moveid]._row = row;
  343. _s[moveid]._col = col;
  344.  
  345. _bRedTurn = !_bRedTurn;
  346. }
  347.  
  348. bool Board::isDead(int id)
  349. {
  350. if (id == -1) {
  351. return true;
  352. }
  353. return _s[id]._dead;
  354. }
  355.  
  356. void Board::saveStep(int moveid, int killid, int row, int col, QVector<Step*>& steps)
  357. {
  358. GetRowCol(row1, col1, moveid);
  359. Step* step = new Step;
  360. step->_colFrom = col1;
  361. step->_colTo = col;
  362. step->_rowFrom = row1;
  363. step->_rowTo = row;
  364. step->_moveid = moveid;
  365. step->_killid = killid;
  366.  
  367. steps.append(step);
  368. }
  369.  
  370. void Board::backOne()
  371. {
  372. if (this->_steps.size() == 0) {
  373. return;
  374. }
  375.  
  376. Step* step = this->_steps.last();
  377. _steps.removeLast();
  378. back(step);
  379.  
  380. update();
  381. delete step;
  382. }
  383.  
  384. void Board::back(Step* step)
  385. {
  386. reliveStone(step->_killid);
  387. moveStone(step->_moveid, step->_rowFrom, step->_colFrom);
  388. }
  389.  
  390. void Board::back()
  391. {
  392. backOne();
  393. }
  394.  
  395. void Board::mouseReleaseEvent(QMouseEvent *ev)
  396. {
  397. if (ev->button() != Qt::LeftButton) { // 排除鼠标右键点击
  398. return;
  399. }
  400.  
  401. click(ev->pos());
  402. }
  403.  
  404. void Board::click(QPoint pt)
  405. {
  406. // 看有没有点中象棋
  407. // 将pt转化成象棋的行列值
  408. // 判断这个行列值上面有没有棋子
  409. int row, col;
  410. bool bClicked = getClickRowCol(pt, row, col);
  411. if (!bClicked) {
  412. return;
  413. }
  414.  
  415. int id = getStoneId(row, col);
  416. click(id, row, col);
  417.  
  418. }
  419.  
  420. void Board::click(int id, int row, int col)
  421. {
  422. if (this->_selectid == -1) { // 如果点中的棋子之前未被选中
  423. trySelectStone(id);
  424. }
  425. else {
  426. tryMoveStone(id, row, col);
  427. }
  428. }
  429.  
  430. void Board::trySelectStone(int id)
  431. {
  432. if (id == -1) {
  433. return;
  434. }
  435.  
  436. if (!canSelect(id)) {
  437. return;
  438. }
  439.  
  440. _selectid = id;
  441. update();
  442. }
  443.  
  444. void Board::tryMoveStone(int killid, int row, int col)
  445. {
  446. if (killid != -1 && sameColor(killid, _selectid)) {
  447. trySelectStone(killid);
  448. return;
  449. }
  450.  
  451. bool ret = canMove(_selectid, killid, row, col);
  452. if (ret) {
  453. moveStone(_selectid, killid, row, col);
  454. _selectid = -1;
  455. update();
  456. }
  457. }
  458.  
  459. void Board::moveStone(int moveid, int killid, int row, int col)
  460. {
  461. saveStep(moveid, killid, row, col, _steps);
  462.  
  463. killStone(killid);
  464. moveStone(moveid, row, col);
  465. }
  466.  
  467. bool Board::canMove(int moveid, int killid, int row, int col)
  468. {
  469. // 如果moveid和killid颜色相同,则不能移动,还需要换选择
  470. if (_s[moveid]._red == _s[killid]._red) {
  471. _selectid = killid;
  472. update();
  473. return false;
  474. }
  475.  
  476. switch (_s[moveid]._type) {
  477. case Stone::JIANG:
  478. return canMoveJiang(moveid, killid, row, col);
  479.  
  480. case Stone::SHI:
  481. return canMoveShi(moveid, killid, row, col);
  482.  
  483. case Stone::XIANG:
  484. return canMoveXiang(moveid, killid, row, col);
  485.  
  486. case Stone::CHE:
  487. return canMoveChe(moveid, killid, row, col);
  488.  
  489. case Stone::MA:
  490. return canMoveMa(moveid, killid, row, col);
  491.  
  492. case Stone::PAO:
  493. return canMovePao(moveid, killid, row, col);
  494.  
  495. case Stone::BING:
  496. return canMoveBing(moveid, killid, row, col);
  497. }
  498.  
  499. return true;
  500.  
  501. }
  502.  
  503. bool Board::canMoveJiang(int moveid, int killid, int row, int col)
  504. {
  505. // 可直接吃对方将
  506. if (killid != -1 && _s[killid]._type == Stone::JIANG)
  507. {
  508. return canMoveChe(moveid, killid, row, col);
  509. }
  510.  
  511. GetRowCol(row1, col1, moveid);
  512. int r = relation(row1, col1, row, col);
  513. if (r != 1 || r != 10) {
  514. return false;
  515. }
  516.  
  517. if (col < 3 || col > 5) {
  518. return false;
  519. }
  520.  
  521. if (isBottomSide(moveid)) {
  522. if (row < 7) {
  523. return false;
  524. }
  525. }
  526. else {
  527. if (row > 2) {
  528. return false;
  529. }
  530. }
  531.  
  532. return true;
  533. }
  534.  
  535. bool Board::canMoveShi(int moveid, int, int row, int col)
  536. {
  537.  
  538. // 移动步长一个格子对角线
  539. GetRowCol(row1, col1, moveid);
  540. int r = relation(row1, col1, row, col);
  541. if (r != 11) {
  542. return false;
  543. }
  544.  
  545. if (col < 3 || col > 5) {
  546. return false;
  547. }
  548.  
  549. if (isBottomSide(moveid)) {
  550. if (row < 7) {
  551. return false;
  552. }
  553. }
  554. else {
  555. if (row > 2) {
  556. return false;
  557. }
  558. }
  559.  
  560. return true;
  561. }
  562.  
  563. bool Board::canMoveXiang(int moveid, int, int row, int col)
  564. {
  565. GetRowCol(row1, col1, moveid);
  566. int r = relation(row1, col1, row, col);
  567. if (r != 22) { // 象走田,所以r应该等于22
  568. return false;
  569. }
  570.  
  571. // 看象眼有没有棋子
  572. int rEye = (row + row1) / 2;
  573. int cEye = (col + col1) / 2;
  574. if (getStoneId(rEye, cEye) != -1) {
  575. return false;
  576. }
  577.  
  578. // 判断是否在棋盘的下方
  579. if (isBottomSide(moveid)) {
  580. if (row < 4) {
  581. return false;
  582. }
  583. }
  584. else {
  585. if (row > 5) {
  586. return false;
  587. }
  588. }
  589.  
  590. return true;
  591. }
  592.  
  593. bool Board::canMoveChe(int moveid, int, int row, int col)
  594. {
  595. GetRowCol(row1, col1, moveid);
  596. int ret = getStoneCountAtLine(row1, col1, row, col);
  597. if (ret == 0) { // 在一行,并且中间没有棋子
  598. return true;
  599. }
  600.  
  601. return false;
  602. }
  603.  
  604. bool Board::canMoveMa(int moveid, int, int row, int col)
  605. {
  606. GetRowCol(row1, col1, moveid);
  607. int r = relation(row1, col1, row, col);
  608. // 首先判断马要走马字
  609. if (r != 12 && r != 21) {
  610. return false;
  611. }
  612.  
  613. // 判断有没有蹩马腿的情况
  614. if (r == 12) { // 列相差等于2
  615. if (getStoneId(row1, (col + col1) / 2) != -1) {
  616. return false;
  617. }
  618. }
  619. else { // 行相差等于2
  620. if (getStoneId((row + row1) / 2, col1) != -1) {
  621. return false;
  622. }
  623. }
  624. return true;
  625. }
  626.  
  627. bool Board::canMovePao(int moveid, int killid, int row, int col)
  628. {
  629. GetRowCol(row1, col1, moveid);
  630. int ret = getStoneCountAtLine(row, col, row1, col1);
  631. if (killid != -1) { // 如果炮要吃对方的棋子
  632. if (ret == 1) { // 中间有一个棋子,可以走
  633. return true;
  634. }
  635. }
  636. else { // 如果炮不吃棋子
  637. if (ret == 0) { // 中间没有棋子,可以走
  638. return true;
  639. }
  640. }
  641.  
  642. return false;
  643. }
  644.  
  645. bool Board::canMoveBing(int moveid, int, int row, int col)
  646. {
  647. GetRowCol(row1, col1, moveid);
  648. int r = relation(row1, col1, row, col);
  649. // 首先判断兵只能走一步
  650. if (r != 1 && r != 10) {
  651. return false;
  652. }
  653.  
  654. if (isBottomSide(moveid)) { // 下面一方的棋子
  655. if (row > row1) { // 如果目标行大于原始行,相当于并在后退
  656. return false;
  657. }
  658. if (row1 >= 5 && row == row1) { // 还没有过河就想横着走
  659. return false;
  660. }
  661. }
  662. else { // 上面一方的棋子
  663. if (row1 > row) { // 如果目标行小于原始行,相当于兵在后退
  664. return false;
  665. }
  666. if (row <= 4 && row == row1) { // 还没有过河就想横着走
  667. return false;
  668. }
  669. }
  670. return true;
  671. }
  672.  
  673. bool Board::canSelect(int id)
  674. {
  675. return _bRedTurn == _s[id]._red;
  676. }
  677.  
  678. int Board::relation(int row1, int col1, int row, int col)
  679. {
  680. return qAbs(row1 - row) * 10 + qAbs(col1 - col);
  681. }
  682.  
  683. bool Board::isBottomSide(int id)
  684. {
  685. return _bSide == _s[id]._red;
  686. }
  687.  
  688. int Board::getStoneCountAtLine(int row1, int col1, int row2, int col2)
  689. {
  690. int ret = 0;
  691.  
  692. // 首先判断两个棋子是否在同一条直线上,如果不在同一条直线上,直接返回-1
  693. if (row1 != row2 && col1 != col2) {
  694. return -1;
  695. }
  696. if (row1 == row2 && col1 == col2) {
  697. return -1;
  698. }
  699.  
  700. // 计算两个棋子之间的有多少个棋子
  701. if (row1 == row2) { // 在同一行
  702. int min = col1 < col2 ? col1 : col2;
  703. int max = col1 > col2 ? col1 : col2;
  704. for (int col = min + 1; col < max; ++col) {
  705. if (getStoneId(row1, col) != -1) {
  706. ++ret;
  707. }
  708. }
  709. }
  710. else { // 在同一列
  711. int min = row1 < row2 ? row1 : row2;
  712. int max = row1 > row2 ? row1 : row2;
  713. for (int row = min + 1; row < max; ++row) {
  714. if (getStoneId(row, col1) != -1) {
  715. ++ret;
  716. }
  717. }
  718. }
  719.  
  720. return ret;
  721. }
  722.  
  723. void Board::slotBack()
  724. {
  725. back();
  726. }
  1. #ifndef STEP_H
  2. #define STEP_H
  3.  
  4. #include <QObject>
  5.  
  6. class Step : public QObject
  7. {
  8. Q_OBJECT
  9. public:
  10. explicit Step(QObject *parent = 0);
  11. ~Step();
  12.  
  13. int _moveid;
  14. int _killid;
  15. int _rowFrom;
  16. int _colFrom;
  17. int _rowTo;
  18. int _colTo;
  19.  
  20. signals:
  21.  
  22. public slots:
  23. };
  24.  
  25. #endif // STEP_H
  1. // Stone.h
  2. // 棋子类,存储了棋子的基础信息
  3.  
  4. #ifndef STONE_H
  5. #define STONE_H
  6.  
  7. #include <QString>
  8.  
  9. class Stone
  10. {
  11. public:
  12. Stone();
  13. ~Stone();
  14.  
  15. enum TYPE{JIANG, CHE, PAO, MA, BING, SHI, XIANG};
  16. int _row;
  17. int _col;
  18. TYPE _type;
  19.  
  20. int _id;
  21. bool _dead;
  22. bool _red;
  23.  
  24. // 棋子的初始化
  25. void init(int id);
  26.  
  27. // 判断_type返回相应字符串
  28. QString name();
  29.  
  30. void rotate(); // 翻转棋盘
  31.  
  32. };
  33.  
  34. #endif // STONE_H
  1. // Stone.cpp
  2.  
  3. #include "Stone.h"
  4. #include <QDebug>
  5.  
  6. Stone::Stone()
  7. {
  8.  
  9. }
  10.  
  11. Stone::~Stone()
  12. {
  13.  
  14. }
  15.  
  16. void Stone::init(int id)
  17. {
  18. struct {
  19. int row, col;
  20. Stone::TYPE type;
  21. } pos[16] = {
  22. {0, 0, Stone::CHE},
  23. {0, 1, Stone::MA},
  24. {0, 2, Stone::XIANG},
  25. {0, 3, Stone::SHI},
  26. {0, 4, Stone::JIANG},
  27. {0, 5, Stone::SHI},
  28. {0, 6, Stone::XIANG},
  29. {0, 7, Stone::MA},
  30. {0, 8, Stone::CHE},
  31.  
  32. {2, 1, Stone::PAO},
  33. {2, 7, Stone::PAO},
  34. {3, 0, Stone::BING},
  35. {3, 2, Stone::BING},
  36. {3, 4, Stone::BING},
  37. {3, 6, Stone::BING},
  38. {3, 8, Stone::BING},
  39. };
  40.  
  41. //_id = id;
  42. _dead = false;
  43. _red = id < 16;
  44.  
  45. if (id < 16) { // 上方的棋子
  46. this->_row = pos[id].row;
  47. this->_col = pos[id].col;
  48. this->_type = pos[id].type;
  49. }
  50. else { // 下方的棋子
  51. this->_row = 9 - pos[id - 16].row;
  52. this->_col = 8 - pos[id - 16].col;
  53. this->_type = pos[id - 16].type;
  54. }
  55. }
  56.  
  57. QString Stone::name()
  58. {
  59. switch (this->_type)
  60. {
  61. case CHE:
  62. return "车";
  63. case MA:
  64. return "马";
  65. case PAO:
  66. return "炮";
  67. case BING:
  68. return "兵";
  69. case JIANG:
  70. return "将";
  71. case SHI:
  72. return "士";
  73. case XIANG:
  74. return "相";
  75. }
  76. return "错误";
  77. }
  78.  
  79. void Stone::rotate()
  80. {
  81. this->_col = 8 - this->_col;
  82. this->_row = 9 - this->_row;
  83. }
  1. // main.cpp
  2. // Chess游戏主程序
  3. //
  4. // Created by Lucifer Zhang on 2015-07-21.
  5. // Copyright (c) 2015 Lucifer Zhang. All rights reserved.
  6.  
  7. #include <QApplication>
  8. #include "Board.h"
  9.  
  10. int main(int argc, char* argv[])
  11. {
  12. QApplication app(argc, argv);
  13. Board board;
  14. board.show();
  15. return app.exec();
  16. }

工程代码详情:Github

中国象棋游戏Chess(3) - 实现走棋规则的更多相关文章

  1. 中国象棋游戏Chess(2) - 走棋

    之前的文章请看:中国象棋游戏Chess(1) - 棋盘绘制以及棋子的绘制 现在实现走棋的功能. 首先需要获取点击到的棋子,用QWidget中的函数 mouseReleaseEvent 实现函数: vo ...

  2. 中国象棋游戏Chess(1) - 棋盘绘制以及棋子的绘制

    本项目都使用QT来实现绘图,没有任何第三方的资源. 工程详情:Github 首先将棋盘设计为一个类Board // Board.h // Board类实现了棋盘的绘制以及显示 // #ifndef B ...

  3. C/C++编程笔记:C语言打造中国象棋游戏,项目源代码分享!

    中国象棋是起源于中国的一种棋,属于二人对抗性游戏的一种,在中国有着悠久的历史.由于用具简单,趣味性强,成为流行极为广泛的棋艺活动. 它是中国棋文化,也是中华民族的文化瑰宝,它源远流长,趣味浓厚,基本规 ...

  4. 基于HTML5实现的中国象棋游戏

    棋类游戏在桌面游戏中已经非常成熟,中国象棋的版本也非常多.今天这款基于HTML5技术的中国象棋游戏非常有特色,我们不仅可以选择中国象棋的游戏难度,而且可以切换棋盘的样式.程序写累了,喝上一杯咖啡,和电 ...

  5. C#中国象棋+游戏大厅 服务器 + 客户端源码

    来源:www.ajerp.com/bbs C#中国象棋+游戏大厅 服务器 + 客户端源码 源码开源 C#版中国象棋(附游戏大厅) 基于前人大虾的修改版 主要用委托实现 服务器支持在线人数,大厅桌数的设 ...

  6. 【原创】使用HTML5+canvas+JavaScript开发的原生中国象棋游戏及源码分享

    目前已经实现的功能: V1.0 : 实现棋子的布局,画布及游戏场景的初始化V2.0 : 实现棋子的颜色改变V3.0 :实现所有象棋的走棋规则V4.0 : 实现所有棋子的吃子功能 GItHub源码下载地 ...

  7. GMchess Linux下的中国象棋游戏

    gmchess,一款Linux下的中国象棋程序

  8. cocos2dx 3.2 的中国象棋游戏

    改编来源:http://cn.cocos2d-x.org/tutorial/lists?id=103 在cocos2dx官网看到了这么个教程,是cocos2dx 2.x版本的,于是用 cocos2dx ...

  9. 亲自动手实现Python+pygame中国象棋游戏

    功能1:实现游戏整体界面显示 一.创建基本的结构 代码如下: import time import pygame def main(): # 初始化pygame pygame.init() # 创建用 ...

随机推荐

  1. ROS_Kinetic_29 kamtoa simulation学习与示例分析(一)

    致谢源代码网址:https://github.com/Tutorgaming/kamtoa-simulation kamtoa simulation学习与示例分析(一) 源码学习与分析是学习ROS,包 ...

  2. 《Shazam It! Music Recognition Algorithms, Fingerprinting, and Processing》译文

    最近看到一篇老外写的博客,简单介绍了shazam的工作原理.图非常好,所以就把它翻译成中文,希望对搞听歌识曲的人有帮助. 你可能遇到这样的场景:在酒吧或者餐厅听到你非常熟悉的歌,也许你曾经听过无数次, ...

  3. VMware 下的CentOS6.7 虚拟机与Windows7通信

    在有网络的情况下,VMware 虚拟机使用桥接模式(Bridged) 和NAT方式,会自动通信,但是在没有网络的情况下怎么办呢?对,是的,使用host-only模式,如何设置呢? 注:将Windows ...

  4. SpriteKit:在场景过渡中暂停动画

    Pausing Scenes During a Transition 你应该意识到两个重要的SKTrnsition属性在场景之间的过渡中. 它们是pausesIncomingScene和pausesO ...

  5. SSO 基于Cookie+fliter实现单点登录 实例解析(一)

    接上文,SSO的理论讲解,接下来实践实践! 1.使用Cookie解决单点登录 技术点: 1.设置Cookie的路径为setPath("/").即Tomcat的目录下都有效 2.设置 ...

  6. 《java入门第一季》之对文件和字符串进行MD5加密工具类

    上一篇介绍了MD5加密算法,之前写的代码有些冗余,而且可读性很差.今天把对文本数据的加密,以及获取文件的md5值做一个封装类.代码如下: package com.itydl.utils; import ...

  7. Java在Linux下 不能处理图形的解决办法 Can't connect to X11 window server

    java在图形处理时调用了本地的图形处理库.在利用Java作图形处理(比如:图片缩放,图片签名,生成报表)时,如果运行在windows上不会出问题.如果将程序移植到Linux/Unix上的时候有可能出 ...

  8. java操作XML文件--读取内容

          先把问题贴出来:编写一个可以解析xml及修改xml内容的工具类       由于我以前做过Android应用程序开发,之前也解析过xml文件,所以,这道题不是很难,这篇文章我先解决第一个问 ...

  9. Cocos2D v3.4.9粒子效果不能显示的原因分析及解决办法

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在游戏App中为了衬托气氛我们往往使用一些特殊的图形效果,粒子 ...

  10. Struts2处理流程性需求的一种解决方案

    在应用程序设计中,经常出现如下的需求. 查看用户填写的数据,而且数据是分页填写. 看下面这个情况 用户的信息有三页,分别是Form abc. 现在的问题是,后面的逻辑该如何设计. 如果把,FormAB ...