使用Qt开发中国象棋(五):走棋

        在整个游戏中,走棋是最复杂的部分,也是最麻烦的。开发这个程序,大概花了三分之一的时间在这个上面。在这个游戏中,走棋是通过鼠标点击事件来完成的,当然也可以通过拖动鼠标事件来弄。假设我们自己先走,整个走棋的逻辑如下:

        (1)点击鼠标。

        (2)ChessBoard类调用mousePressEvent并激发doMove信号。在该事件处理函数中,我们只处理鼠标左键单击事件。

void ChessBoard::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        int row = 0;
        int column = 0;
        getPixmapIndex(event->pos().x(), event->pos().y(), row, column);

        int sq = getChessmanIndex(row, column, fliped);
        emit doMove(sq);
    }
}

        (3)调用MainWindow的doMove槽。如果该局未结束,则可以走棋。此外还会根据游戏的模式和走棋方进行判断。

void MainWindow::doMove(int index)
{
    if (chessHandler->getCurrentTurn() == g_gameSettings.getCompetitorSide() &&
        g_gameSettings.getGameType() != COMPITITOR_HUMAN)
    {
        return;
    }

    if (chessHandler->getGameResult() == -1)
    {
        chessHandler->doMove(index);
    }
}

        (4)调用逻辑层ChessHandle的doMove方法。该方法包括死棋检测,重复局面检测,走法合理性判断,生成走棋字符串,更新zobrist值等等。激发refreshGame信号。里面的更多细节,限于篇幅,就不列举了,后面会介绍个中细节。

void ChessHandler::doMove(int index)
{
    assert(index >= 0x33 && index <= 0xcb);
    int fromPos = SRC(currentMoveInfo.move);
    int toPos = DST(currentMoveInfo.move);

    if (fromPos == index || toPos == index)
    {
        return;
    }

    bool legal = false;
    if (currentTurn == RED)
    {
        legal = redDoMove(index);
    }
    else
    {
        legal = blackDoMove(index);
    }

    if (legal)
    {
        if (SRC(currentMoveInfo.move) > 0 && DST(currentMoveInfo.move) > 0)
        {
            applyMove();

            if (g_gameSettings.getGameType() == COMPITITOR_MACHINE)
            {
                //电脑走棋
                computerMove();
            }
        }
        else
        {
            //发送网络消息
            if (g_gameSettings.getGameType() == COMPITITOR_NETWORK)
            {
                sendMoveInfoMsg();
            }

            emit refreshGame(EVENT_UPDATE_MOVE);
        }
    }
    else
    {
        if (currentMoveInfo.movingChessman > 0)
        {
            emit refreshGame(EVENT_ILLEGAL_MOVE);
        }
    }
}

        (5)MainWindow中调用ProcessEvent,根据不同的参数进行不同的处理。如走棋合法会调用processUpdateMoveEvent,在该方法中会更新着法列表,显示走棋的路迹,更新某些按钮的状态。否则会调用processIllegalMoveEvent,播放提示音。

void MainWindow::processUpdateMoveEvent()
{
    MoveInfo info = chessHandler->getCurrentMoveInfo();
    int gameResult = chessHandler->getGameResult();

    //如果移动了完整的一步,则需要先更新整个棋盘
    if (SRC(info.move) > 0 && DST(info.move) > 0)
    {
        chessBoard->loadPixmap(chessHandler->getChessman());
        addToStepList(info);
        if (gameResult == -1 && g_gameSettings.getStepTime() > 0)
        {
            stepOverCond.wakeAll();
        }
    }

    if (isSameSide(lastMoveInfo.movingChessman, info.movingChessman))
    {
        chessBoard->showMoveRoute(lastMoveInfo.movingChessman, lastMoveInfo.move, false);
    }
    chessBoard->showMoveRoute(info.movingChessman, info.move, true);
    chessBoard->update();

    playTipSound(info, gameResult);

    if (gameResult != -1)
    {
        if (gameResult != 0)
        {
            updateGeneralDisplay(gameResult);
        }

        showResult(gameResult);
    }

    lastMoveInfo = info;
    gameOver = gameResult != -1;
    ui->actionUndo->setEnabled(chessHandler->getLstMoveInfo().size() > 0);
}

void MainWindow::processIllegalMoveEvent()
{
    QSound::play(AUDIO_ILLEGAL);
}
        整个走棋基本就是这个逻辑,也不是很复杂。中国象棋真正复杂的地方是机器走棋的算法,在这个游戏中,没有涉及到这么复杂的算法。曾经以为自己坚持不下来,毕竟要花两百多个小时的时间,还是很需要耐心的。心情浮躁的话,很可能坚持不下来。当我硬着头皮做完走棋的功能,发现已经完成了一半,如果半途而废的话,前面的努力就全白费了。想到这里,便一鼓作气的完成了剩下的工作。虽说做这个东西没什么用,但至少也算是考验一下自己的意志和耐性吧。个人感觉这个东西太需要耐心了,不能太浮躁。
源代码下载链接: http://download.csdn.net/detail/zxywd/9172917

        


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值