20200603黑白棋

我们的实现目标如下图所示:(不是五子棋)

步骤:1画背景;2画线(横纵各9根);3画棋子(8*8=64个)

掌握:绘图技巧、封装思想

New Project:创建棋盘类Chess,不要 ✔ 界面(不能用设计模式,只能用代码绘制ui界面了)

(1)画背景

1.1 启用绘图事件

protected:    void paintEvent(QPaintEvent *);

背景加载成功!

优先使用构造函数,也能实现该功能。

(1)对象被创建的时候,立马自动触发调用构造函数
(2)不用进行函数之间的切换,省了资源开销,提高效率

供别人随意改变背景:公共方法改变私有变量

头文件中增加:

private:
    QString bg_filename;
    void Init();

一般情况下,变量通常都是私有的。可以采用方法的形式让外界访问,这体现了面向对象的方式。

方法:void ChangeBGImage(const QString filename); //加const的原因: 防止传进去后被改变

方法的实现如下:驼峰命名法

(2)画线

2.1 设置颜色、样式、宽度等,提供一个统一的外部接口(方法)

初始化中给默认值

窗体一改变,立马给它赋值(按比例缩放),测试一下:

同理可得:横线和纵线组成的棋盘格。

(3)画棋子

先找规律

用棋子铺满整个格子:

把64个格子的数据(黑OR白)进行保存

public:
    enum ChessType{Empty=0,White, Black}; //棋子类型:0不显示;1白色;2黑色
private:
    int chessData[8][8]; //保存棋子数据的容器   //需要初始化,不然里面会有随机数
//(3)画棋子QString chessFilename;//棋子名字for(int i=0;i<8;i++){for(int j=0;j<8;j++){if(chessData[i][j] == White){chessFilename = "../20200603/Images/white.PNG";}else if(chessData[i][j] == Black){chessFilename = "../20200603/Images/black.PNG";}else{chessFilename.clear();continue;}painter.drawPixmap(startX + i* gridWidth, startY + j * gridHeight, gridWidth, gridHeight, QPixmap(chessFilename));}}

规则:中心四个点要占住

—————————分割线—————————分割线—————————分割线—————————

(4)接下来实现:鼠标点击事件,得出在哪里落棋子

备注:一定要刷新,不然鼠标点击后棋子不能及时出现。

同理 ChangeBGImage()和ChangeLine()中也要增加刷新语句 this->update();

(5)增加位点,增加界面:

5.1 先定义信号,并在鼠标点击事件里发送该信号。

signals:
    void SignalSendChessData(int i,int j);//发送点击的坐标
5.2 改变棋盘的显示值
public:
    void setChessStatus(void *p);//外面传一个数组进来

实现该方法:

void Chess::setChessStatus(void *p){
    memcpy(chessData, p, sizeof(int)*8*8);//把外面的拷贝过来
    this->update();
}

5.3 代码优化,将业务逻辑分开:初始化棋盘 void InitChess();————private:

转移 Init() 中的部分代码块,实现该方法,记得调用

void Chess::InitChess(){//初始化棋盘数据数组memset(chessData, 0, sizeof(int)*64);//memeset编译不出错,但这种方式不利于人理解。//我们用for循环也可以实现数组的清零for(int i = 0; i < 8;i++){for(int j = 0; j < 8;j++){chessData[i][j] = Empty;}}chessData[3][3] = Black;//指定位置落棋子chessData[4][3] = White;chessData[3][4] = White;chessData[4][4] = Black;
}

5.4 设计UI界面

右击 ---> 添加新文件,Qt设计师界面类QWidget

接下来:设计窗体

用到Frame容器和Grid Layout布局方式

Frame属性设置:frameShape为Box,frameShadow为Raised。

先把3个水平布局,整体再栅格布局。如果觉得太宽太高的话,可以先在属性里把最大宽度/最大高度定死 maximumSize,然后去布局。

把之前的棋盘类导入新界面中,成功实现如下:

QWidget 缩小这么多没有意义:可以在*.ui文件中改变minimumSize的值。

    //黑白棋吃子规则,返回值是能吃子的个数
    //x, y: 棋盘二维数组坐标位置     //chess: 棋子状态 //currentRole: 枚举变量(Empty, Black, White)
    //eatChess: true代表吃子,false只是判断有子可吃,默认为true
    int judgeRule(int x, int y, void *chess, Chess::ChessType currentRole, bool eatCehss);
int ChessForm::judgeRule(int x, int y, void *chess, Chess::ChessType currentRole, bool eatCehss){//棋盘的八个方向int dir[8][2] = {{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}};int temp_x = x, temp_y = y;  //临时保存棋盘数组坐标位置int i = 0, eatNum = 0;  //初始化数据typedef int (*p)[8];  //自定义类型p chessFlag = p(chess);  //类型转换if(chessFlag[temp_x][temp_y] != Chess::Empty)  //如果此方格内已有棋子,返回;return 0;//棋盘的八个方向for(i = 0; i < 8; i++){temp_x += dir[i][0]; temp_y += dir[i][1];  //准备判断相邻棋子//如果没有出界,且相邻棋子是对方棋子,才有吃子的可能if((temp_x <8 && temp_x >=0 && temp_y <8 && temp_y >=0)&& (chessFlag[temp_x][temp_y] !=currentRole) && (chessFlag[temp_x][temp_y] != Chess::Empty)){temp_x += dir[i][0];temp_y += dir[i][1];while(temp_x < 8 && temp_x >=0 && temp_y <8 && temp_y >=0){if(chessFlag[temp_x][temp_y] == Chess::Empty)//遇到空位,跳出break;if(chessFlag[temp_x][temp_y] == currentRole)  //找到自己的棋子,代表可以吃子{if(eatCehss = true)//确定吃子{chessFlag[x][y] = currentRole;//开始点标志为自己的棋子temp_x -=dir[i][0]; temp_y -=dir[i][1];//后退一步while((temp_x != x)||(temp_y !=y)){   //只要没有回到开始的位置就执行chessFlag[temp_x][temp_y] = currentRole;//标志为自己的棋子temp_x -=dir[i][0]; temp_y -=dir[i][1];//继续后退一步eatNum++;//累计}}else  //不吃子,只是判断这个位置能不能吃子{temp_x -=dir[i][0]; temp_y -=dir[i][1];//后退一步while((temp_x != x)||(temp_y !=y)){  //只计算可以吃子的个数temp_x -=dir[i][0]; temp_y -=dir[i][1];//继续后退一步eatNum++;}}break;//跳出循环}  //没有找到自己的棋子,就向前走一步temp_x += dir[i][0]; temp_y += dir[i][1];//向前走一步}}   //如果这个方向不能吃子,就换一个方向temp_x = x; temp_y = y;}return eatNum;  //返回能吃子的个数}

加载窗体背景:

设计界面:Label, LCDNumber(digitCount=2), PushButton

谁先谁后显示:ComboBox9(白子先,黑子先),

初始化可以用上述方式实现,也可用下面的“方法”来实现:

    void RoleInit(const QString whiteFilename, const QString blackFilename);

1)把界面初始化,分别实现。点击“人人对战”,设置谁先下。

 void setRole(Chess::ChessType currentRole);  //设置谁先下
    Chess::ChessType currentRole;

2)把棋盘初始化

2.1 一开始默认情况下,棋盘是没有的。——注释相关语句

2.2 把chess.cpp中“初始化棋盘数据数组”的代码复制过来

        int formChessData[8][8]; //窗体中的,跟棋盘中的不一样
        void setChessInit(); //对棋盘初始化

运行代码Ctrl +R,结果显示如下:(LCD应显示2和2)

选择“白子先”,点击“人人对战”,如下:(LCD应显示2和2)

选择“黑子先”,点击“人人对战”,如下:(LCD应显示2和2)

绑定,处理信号

connect(myChess,SIGNAL(SignalSendChessData(int,int)),this,SLOT(doProcessChessData(int,int)));

上图说明:主窗体收到棋盘发送过来的信号

上图说明了吃子规则的实现

————————————————————分割线————————————————————

1. 角色切换:黑白子切换

2. 数据统计:白子多少个,黑子多少个

void ChessForm::RoleChange(){if(currentRole == Chess::White){currentRole = Chess::Black;}else{currentRole = Chess::White;}//界面显示随变if(currentRole == Chess::Black){ui->label2->setVisible(true);ui->label1->setVisible(false);}else{ui->label1->setVisible(true);ui->label2->setVisible(false);}
}

结果如下:

接下来做数据统计,并显示在LCD上

void ChessForm::ChessShow(){int blackCount=0, whiteCount=0;for(int i=0; i<8; i++){for(int j=0; j<8; j++){if(formChessData[i][j] == Chess::White){whiteCount++;}else if(formChessData[i][j] == Chess::Black){blackCount++;}}}ui->lcdNum1->display(whiteCount);ui->lcdNum2->display(blackCount);
}

注意:点击“人人对战”时,初始显示应为2和2

黑白棋子统计显示结果如下:

——————————分割线——————————分割线——————————

人机对战:Button转到槽(一开始,人先下白子)

    enum PKType{PVP,PVC,NVN};
    PKType currentPK;
机器下子:对空白处遍历,判断在哪里下子(LCD显示数目也要对)

后续:人下不了了就交给机器下,直到对方都下不了了,再根据黑白棋数目判断结果

弹出消息对话框告知用户。

等后面学了TCP/UDP后,来实现网络对战。

Qt开发自学13_黑白棋相关推荐

  1. HTML5 游戏开发实战 | 黑白棋

    黑白棋,又叫反棋(Reversi).奥赛罗棋(Othello).苹果棋.翻转棋.黑白棋在西方和日本很流行.游戏通过相互翻转对方的棋子,最后以棋盘上谁的棋子多来判断胜负.黑白棋的棋盘是一个有8×8方格的 ...

  2. android 双人黑白棋开发博客,黑白棋 - 软件资讯 - 课堂党年级博客

    黑白棋叫反棋(Reversi).奥赛罗棋(Othello)苹棋翻转棋黑白棋西本流行游戏通相互翻转棋棋盘谁棋判断胜负 黑白棋棋盘8*8格棋盘棋棋空格间像围棋交叉点始棋盘两白两黑四棋交叉放置黑棋总先 自颜 ...

  3. Qt开发自学7_倒计时和动画显示

    20200530 实现目标:LCD倒计时完毕后,全屏播放动画 布局:TextLabel.LCDNumber, Ctrl+G   栅格布局(二分天下)后,把任何一个隐藏,另一个就全屏 头文件中定义:(1 ...

  4. 【181007】VC++黑白棋游戏完整版游戏源码

    C++开发的BWChess黑白棋游戏,界面差不多,功能挺多的, 编译界面如上所示,可以与电脑下棋也可以人与人对战,可以提醒,记录对战排行榜. 源码下载地址:点击下载 备用下载地址:点击下载

  5. 用Qt 编写黑白棋程序

    用Qt 编写黑白棋程序 前言:这是继三天学习c++后,学习了两天Qt 做的项目. 软件设计开发流程: 瀑布模型: 可行性分析 时间: 共8天(其中前两天学习Qt3.1 与Qt4.3.5,中间编程,最后 ...

  6. Windows Phone 游戏——黑白棋 开发总结

    小的时候非常喜欢玩这个游戏,这就是我为什么开发这么一款游戏的原因.目前在Windows Phone平台下似乎还没有看见这款游戏,或许有,但是我没见过. 这是这款游戏在Windows Phone应用商店 ...

  7. 基于DevCloud进行黑白棋实时对战游戏开发实践【华为云至简致远】

    [摘要] 本次实践让我体验到了全程在云上创建弹性云服务器ECS,配置云服务器环境,在DevCloud平台上一站式进行项目管理.代码托管.代码检查.流水线.编译.构建.部署.测试.发布的流程.基本做到了 ...

  8. 基于Python的Reversi黑白棋游戏设计与开发

    摘 要 黑白棋是一个相当易学,而且很受欢迎的游戏.近年来,随着机器性能的提高和相关理论的完善,人工智能这一领域变得越来越重要,在实际生活中的运用也越来越广泛.为了学习简单的人工智能,我决定用Pytho ...

  9. 黑白棋算法简单实现与基于Qt的GUI编程的综合应用

    一.序言: 最近学习了Qt的界面编程,包括了QObject.QWidget.QIODevice.QMessageBox.QTcpSockt.QTcpServer.QFile.QFileInfo.QDa ...

最新文章

  1. Calabash探索3-Calabash进阶
  2. 将jsp页面转化为图片或pdf(一)(qq:2798641729)
  3. SAP Fiori + Vue = ?
  4. c#编写的MD5加密类
  5. Visual C++ MFC——基于Shell的Windows GUI小程序DEMO(打开计算器|打开记事本|IP查询|Windows激活状态查询)
  6. Tensorflow源码解析6 -- TensorFlow本地运行时
  7. 课堂破冰游戏“猜猜他是谁”
  8. html网页毕业论文,HTML网页设计毕业论文.pdf
  9. 1m照片的宽和高是多少_jpg图片容量1M是多少KB
  10. 花生采摘(peanuts)
  11. html地图多点标记,高德地图多点标记自定义地图
  12. ZOJ--1005:Jugs(dfs)
  13. 如何申请免费的云主机
  14. 启用Desktop Central Cloud:以SaaS方式拥抱UEM !
  15. 【牛客刷题】java编程笔试题(更新)
  16. python读取枚举_一文读懂Python 枚举
  17. 关于新书《修炼之道:.NET开发要点精讲》的各种说明
  18. 如何从小白起步成为百万博主|配音运营工具必不可少
  19. 我为什么而工作? 文/江湖一剑客
  20. C++ Fun和Do题解

热门文章

  1. 数据之道读书笔记-06面向“自助消费”的数据服务建设
  2. Cris 玩转大数据系列之 Hadoop HA 实现
  3. matlab 控制系统仿真实验代码
  4. C语言编程计算下列算式的值
  5. mysql无法执行二进制文件_kail系统64,mysql64,出现-bash: bin/mysqld: 无法执行二进制文...
  6. 使用Java实现发送微信消息(附源码)_此程序在手再也不怕对象跟你闹了
  7. Redis实现抢红包
  8. android手机屏AMOLED如何驱动?
  9. 云计算、大数据和人工智能知识普及
  10. 高数中一点导数大于0,能否推出函数在0这个去心邻域单增?