1.棋子“马”算法简要分析
棋子“马”的计算可移动区域算法简介:
1,求出8个待选位置,8个位置的偏移是(-2,-1)(-2,1)(2,-1)(2,1)
(1,-2)(1,2)(-1,-2)(-1,2)存在关系:|x|+|y|=3
2,判断待选位置是否在棋盘内
3,判断中间是否有卡位的棋子
4,位置上是否已存在同色棋子
算法实现过程如下,注释比较详细:
Item newItem;
for (int i = -2; i<=2; i++) { for(int j = -2; j<=2; j++) { if (qAbs(i) + qAbs(j) == 3) { QPoint newPoint = item.m_pt + QPoint(i,j); //当该点在棋盘内,可继续搜索 if (newPoint.x() >= 0 && newPoint.x() <= 8 && newPoint.y()>=0 && newPoint.y() <= 9) { ; } else { continue; }
//求该方向行走路线的 卡位元素位置 //相对当前点4个卡位位置计算 QPoint ptDirect(0,0); if (qAbs(i) > qAbs(j)) { if (i>0) { ptDirect = QPoint(1,0); } else { ptDirect = QPoint(-1,0); } } else { if (j>0) { ptDirect = QPoint(0,1); } else { ptDirect = QPoint(0,-1); } }
//在棋盘中马的卡位元素位置 QPoint ptHit = item.m_pt + ptDirect;
//目标点卡位位置有棋子 if (findItemAtLogicPoint(ptHit,newItem)) { //卡位 continue; }
//目标点卡位位置无棋子,但是目标点是同色棋子 if (findItemAtLogicPoint(newPoint ,newItem) && item.m_color == newItem.m_color) { //有本组item continue; } moveableArea.append(newPoint); } } }
2. 绘制棋子可移动位置:
要绘制出棋子可移动位置其实就是将之前moveableArea中的QPoint标记出来。
QVector<QPoint> moveableArea; //获取已选择棋子的可移动区域getMoveableArea(m_selectedItem,moveableArea);
绘制棋子可移动位置与绘制棋子类似,可参考Qt 中国象棋第二节的绘制棋子部分,文末附有链接。
void MainWindow::drawMoveableArea(QPainter &painter, const QVector<QPoint> moveableArea){ for(int i = 0; i < moveableArea.size(); i++) { QRect rcTarget( START_X + moveableArea[i].x()*55.5, START_Y + moveableArea[i].y()*56, 53,50);
painter.drawPixmap(rcTarget,m_moveableAreaImage); }}
效果如下:
3. 其他逻辑调整
鼠标事件这里是整个业务的核心;添加定时器事件,用于将选中的棋子进行提示。
//鼠标点击,走棋、吃棋等逻辑void MainWindow::mousePressEvent(QMouseEvent *e){
//获得鼠标点击位置所对应的棋子 QPoint pt; pt.setX( (e->pos().x() - START_X ) / RECT_WIDTH); pt.setY( (e->pos().y() - START_Y ) / RECT_HEIGHT);
//是否有选中的棋子 if(m_bExistSelectedItem) { //再次点击已经选择的棋子,什么也不做 if (pt == m_selectedItem.m_pt) { return; }
//点击其它棋子 Item clickedItem; if (findItemAtLogicPoint(pt,clickedItem)) { //点击的同色的另外一个棋子,改选 if ( (m_bIsRedTurn && clickedItem.m_color == COLOR_RED) || (!m_bIsRedTurn && clickedItem.m_color != COLOR_RED)) { //改选棋子后,清除原有的落子提示 m_moveableArea.clear(); update();
setItemShow(m_selectedItem, true); m_selectedItem = clickedItem;
//获取已选择棋子的可移动区域 getMoveableArea(m_selectedItem,m_moveableArea); update(); return; } }
//绘制落子提示 getMoveableArea(m_selectedItem,m_moveableArea); //获取已选择棋子的可移动区域 update();
//点击的异色棋子,判断是否能走能吃 QVector<QPoint> moveableArea; getMoveableArea(m_selectedItem,moveableArea); //获取已选择棋子的可移动区域
if(moveableArea.contains(pt)) { //包含当前鼠标点中的棋子,则能吃 bool bDeleteSHUAI = false; deleteItemAtLogicPoint(pt,bDeleteSHUAI); //吃掉 changeItemLogicPoint(m_selectedItem.m_pt,pt); //绘制新的棋子位置 m_moveableArea.clear(); //清除落子提示// update(); //发送重新绘图事件
if(bDeleteSHUAI) { QString str = m_bIsRedTurn?QStringLiteral("红方胜利!"):QStringLiteral("黑方胜利!"); QMessageBox::information(NULL, "GAME OVER ",str, QMessageBox::Yes , QMessageBox::Yes); newGame(); return ; }
m_bExistSelectedItem = false; m_bIsRedTurn = !m_bIsRedTurn; update(); return ;
} } else //当前没有选中棋子 { Item clickedItem; if(findItemAtLogicPoint(pt,clickedItem)) //知道了我是谁、我在哪 { if( (m_bIsRedTurn && clickedItem.m_color == COLOR_RED) || (!m_bIsRedTurn && clickedItem.m_color == COLOR_BLACK)) { m_selectedItem = clickedItem; m_bExistSelectedItem = true;
getMoveableArea(m_selectedItem,m_moveableArea); //获取已选择棋子的可移动区域 update(); return; } }
}}
void MainWindow::timerEvent(QTimerEvent *){ for (int i = 0; i<m_items.size(); i++) { if (m_items[i].m_pt == m_selectedItem.m_pt) { m_items[i].m_bShow = !m_items[i].m_bShow; } }}
后记总结:
这一个小项目在参考源码的情况下陆陆续续写了近两周,有些惭愧啊。
个人技能的增长需要不断去学习新的知识并将学到的东西不断提炼和总结,最后变成自己的东西才算是真正的学会,不然就像【知道了那么多道理却依然过不好这一生一样!】
之前项目文章回顾: