MFC随机博弈黑白棋

随机博弈黑白棋

随机博弈黑白棋

TxyITxs | 随机博弈黑白棋 | 2019.04.21

摘要

通过随机落子,实现黑白棋的博弈。无任何落子规则,棋子死活与围棋中棋子的死活一致,即存在至少一口气。动态模拟双方博弈,但棋盘无落子位置时停止。

设计思路

主要基于时钟来实现动态博弈,考虑博弈的持续性数据修改,黑白双方需要互斥访问数据以及正确界面绘制,通过设置两个时钟,一个时钟主要负责界面背景,棋盘网格,黑白棋子绘制,绘制完后,释放数据使用权;另一个时钟主要负责博弈落子(即修改数据),通过在可落子位置随机选择一个,然后释放数据使用权。

棋盘数据使用N*N大小的一维数组Tdata存储,棋子坐标(x,y)对应的数组通过x*N+y计算。棋盘所用可落子位置通过向量vector<CPoint>Tpos来存储,通过随机产生一个索引来得到一个落子位置,然后将该索引对应Tpos的位置删除,修改Tdata中对应位置的值。

1. UI设计

1.1 利用基于对环框的MFC程序框架来搭建UI界面,主要涉及到界面背景色绘制,棋盘网格绘制,以及通过访问数据绘制棋子。

1.2 棋盘背景绘制

void TChessBgUI(CClientDC *dc)

{

CPen pen(PS_SOLID, 1, RGB(0, 0, 0));

CBrush *pbrush = CBrush::FromHandle((HBRUSH)GetStockObject(GRAY_BRUSH));

dc->SelectObject(&pen);

dc->SelectObject(pbrush);

CRect bg;

GetClientRect(bg);

dc->FillRect(bg, pbrush);

}

1.3 棋盘网格绘制,绘制的起始位置CPoint Tst,绘制的结束位置CpointTed,网格间距Tchline,网格的大小N*N。

void TChessUI(CClientDC *dc)

{

CPen pen(PS_SOLID, 1, RGB(0, 0, 0));

dc->SelectObject(&pen);

for (int i = Tst.x; i <= Ted.x; i += Tchline)

{

dc->MoveTo(i, Tst.y);

dc->LineTo(i, Ted.y);

}             

for (int j = Tst.y; j <= Ted.y; j += Tchline)

{

dc->MoveTo(Tst.x, j);

dc->LineTo(Ted.x, j);

}

}

 

1.4 绘制棋子

void TshowLayout(CClientDC *dc)

{

CPen pen(PS_SOLID, 1, RGB(0, 0, 0));

CBrush *pbrush = NULL;

dc->SelectObject(&pen);

int PieceSize = 10;

for (int i = 0; i < Tcount; i++)

{

for (int j = 0; j < Tcount; j++)

{

        if (Tdata[i*Tcount + j] ==1)

        {

               pbrush = CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH));

        dc->SelectObject(pbrush);

        dc->Ellipse(Tst.x+Tchline*i-PieceSize, Tst.y+Tchline *j- PieceSize, Tst.x + Tchline*i + PieceSize, Tst.y + Tchline *j + PieceSize);

        }

        if (Tdata[i*Tcount + j] == -1)

        {

               pbrush = CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH));

        dc->SelectObject(pbrush);

        dc->Ellipse(Tst.x + Tchline*i - PieceSize, Tst.y + Tchline *j - PieceSize, Tst.x + Tchline*i + PieceSize, Tst.y + Tchline *j + PieceSize);

        }

}

}

}

2.数据存储

  2.1 全局变量,需要初始化。

vector<int> Tdata;数值0、1、-1,0代表该位置为空,1代表白棋,-1代表黑棋

       vector<CPoint> Tpos;棋盘可落子位置

       int Tcount =19;棋盘大小

       int Tchline = 30;网格间距

       CPoint  Tst;棋盘起始位置

       CPoint Ted;1棋盘结束位置

       int Twhite = -1;先手指示器

       bool Ttime = false;时钟调度指示器

3.博弈算法

3.1 随机落子模拟

void SimulationData()

{

default_random_engine dre;//随机数引擎

dre.seed((unsigned)time(NULL));

int pos = -1;

if(!Tpos.empty())

{

pos = dre() % Tpos.size();

if (Twhite==1)

{

        Tdata[Tpos[pos].x*Tcount + Tpos[pos].y] = 1;

        Twhite = -Twhite;//此时指示需提子的棋子颜色,以及下次落子的颜色

}

else if(Twhite == -1)

{

        Tdata[Tpos[pos].x*Tcount + Tpos[pos].y] = -1;

        Twhite = -Twhite;

}

Tpos.erase(Tpos.begin() + pos);

}

}

 

随机索引位置的产生,利用C++ 11新特性,使用随机数random类来产生,头文件#include<random>。

 

 

 

3.2  提子过程,将棋盘上Twhite指示的棋子的死子提出,增加棋盘落子可用位置;

 

void grape()

{

if (Twhite == 0)return;

else

{

vector<CPoint> grap;

vector<bool> visi;

visi.resize(Tcount*Tcount, false);

grap.clear();

for (int i = 0; i < Tcount; i++)

{

        for (int j = 0; j < Tcount; j++)

        {

               if (Tdata[i*Tcount + j] == Twhite)

               {

                   visi.resize(Tcount*Tcount, false);  

                    if (TisLive(i, j,visi) == false)

                             grap.push_back(CPoint(i, j));

               }

        }

}

while (!grap.empty())

{

        CPoint p=grap.front();

        Tdata[p.x*Tcount+p.y] = 0;

        Tpos.push_back(p);

        grap.erase(grap.begin());

}

}

 }

 

3.3 提子过程需要判断棋子的死活,利用深度搜索算法,判断棋子s(x,y)的死活,则需判断其四邻接棋子的死活,若s,为活棋,无需提子,返回ture,若s为死棋,则返回false;通过递归来实现。

bool TisLive(unsigned int i, unsigned int j, vector<bool>& visi)

{

if (i<0 || i>Tcount || j<0 || j>Tcount)

              return false;

       else if (Tdata[i*Tcount + j] == -Twhite)

       {

              return false;

       }

       else if (Tdata[i*Tcount + j] == 0)

       {

              return true;

       }

       else if(Tdata[i*Tcount+j]==Twhite&&visi[i*Tcount + j]==false)

       {

              visi[i*Tcount + j] = true;

              if (TisLive(i - 1, j,visi))

return true;

              if(TisLive(i, j - 1, visi))

 return true;

              if(TisLive(i+1, j, visi))  

return true;

              if(TisLive(i , j+ 1, visi))

 return true;

       }

      

        else return false;
        return false;

      }

3.4 onTimer函数

       在初始化函数中设置两个时钟;

      SetTimer(0, 1000, NULL);
      SetTimer(1, 10, NULL);

       两个时钟总用一个onTimer,通过nIDEvent来识别执行此函数的时钟。一个时钟负责UI绘制,一个时钟模拟数据变化。

void CWhiteBlackChessDlg::OnTimer(UINT_PTR nIDEvent)
{

    CClientDC dc(this);
    switch (nIDEvent)
    {
    case 0:
    {
        if (Ttime)
        {    
                SimulationData();
                grape();
                Ttime = false;
        }
    }
        break;
    case 1:
    {    
        
        if (!Ttime)
        {        
            TChessBgUI(&dc);
            TChessUI(&dc);
            TshowLayout(&dc);
            Ttime = true;        
            if (Tpos.empty())
            {
                KillTimer(0);    
                KillTimer(1);
            }
        }
    }break;
    default:break;
    }
    CDialogEx::OnTimer(nIDEvent);
}

 

3.5 初始化函数

void TInit()
    {
        Tdata.resize(Tcount*Tcount,0);
        Tpos.resize(Tcount*Tcount);
        Tst.SetPoint(30, 30);
        Ted.SetPoint(Tchline * Tcount, Tchline * Tcount);
        for (int i = 0; i < Tcount; i++)
        {
            for (int j = 0; j < Tcount; j++)
                Tpos[i*Tcount + j] = CPoint(i, j);
        }
    }

总结

  1. 在实践过程中,动态模拟的持续性,采用面向过程的算法设计思路,常常导致程序阻塞,因为动态模拟需要使用循环,这可能导致数据一直动态修改,由于循环,导致无法执行到界面绘制代码,界面的控制信息无法捕捉和执行,鉴于这种情况,可以采用时钟或者多线程来实现。
  2. UI界面采用了模块化设计思路,对程序的复用提供了可能;
  3. 可以利用该框架,重写提子或落子函数,模拟自然界中的动态变化现象,可以通过直观UI看到变化情况。
  4. 目前程序尚不完善。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/484452.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

7-3 喊山 (30 分)

搞了好几天心态的一道题&#xff0c;还是菜&#xff0c;原因就是想复杂了&#xff0c;第一次遇到了内存超限的问题&#xff0c;把邻接矩阵由二维数组换成了vector才过的。 7-3 喊山 (30 分) 喊山&#xff0c;是人双手围在嘴边成喇叭状&#xff0c;对着远方高山发出“喂—喂喂…

章鱼有9个大脑能编辑基因,智商高到无法理解,为何没发展出文明

来源&#xff1a;科学杂志按照进化论的观点&#xff0c;生物演化出脊椎&#xff0c;是发展出更高智商的敲门砖。因为脊椎让生物体内的神经高度集中&#xff0c;反应速度明显加快&#xff0c;并且还有利于大脑向更加高级的结构演化。事实也确实如此&#xff0c;如果盘点世界上最…

Python运算符与编码

while循环 1.基本循环while 条件: 循环体如果条件为真&#xff0c;那么循环则执行如果条件为假&#xff0c;那么循环不执行 while循环代码体现形式while 3>2:print(在人间) num 1  while num<101:  print(num)  num num 1 break 终止  continue 跳出本次循环,…

Windows坐标系统

坐标映射方式是设备环境中的一个重要属性&#xff0c;默认值为MM_TEXT&#xff0c;即左上角为原点&#xff0c;右方为x轴正方向&#xff0c;下方为y轴正方向&#xff0c;这种坐标系使用的单位是像素&#xff0c;其好处是窗口中的每一点的坐标不会因为窗口大小而改变。 映射方法…

7-1 公路村村通 (30 分)

现有村落间道路的统计数据表中&#xff0c;列出了有可能建设成标准公路的若干条道路的成本&#xff0c;求使每个村落都有公路连通所需要的最低成本。 输入格式: 输入数据包括城镇数目正整数N&#xff08;≤1000&#xff09;和候选道路数目M&#xff08;≤3N&#xff09;&#…

华为徐文伟:用数学和系统工程方法推进未来网络研究

来源&#xff1a;华为在2021第五届未来网络发展大会上&#xff0c;来自产业界、学术界、研究机构等领域的专家、行业领袖&#xff0c;围绕网络操作系统、6G通信、网络安全、工业互联网等热点话题&#xff0c;共同探讨新型网络技术的攻关与变革。华为董事、战略研究院院长徐文伟…

Windows框架

#include<Windows.h> #include<tchar.h> #include"resource.h" //全局变量 LPSTR g_MainFrame "主框架"; LPSTR g_ClientFrame "客户区框架"; LPSTR g_ChildFrame[] { "子框架1","子框架2" }; LRESULT CALL…

7-4 最短工期 (25 分)

参考链接&#xff1a;https://blog.csdn.net/tianwei0822/article/details/88642441 一个项目由若干个任务组成&#xff0c;任务之间有先后依赖顺序。项目经理需要设置一系列里程碑&#xff0c;在每个里程碑节点处检查任务的完成情况&#xff0c;并启动后续的任务。现给定一个…

对我国6G早期研究布局的几点建议

来源&#xff1a;赛迪智库众所周知&#xff0c;5G网络技术无法满足2030年及未来的移动通信需求。第六代无线移动通信网络&#xff08;6G&#xff09;将引入全球覆盖、高频谱效率和能源效率、高智能性和安全性等新的性能指标和用例等&#xff0c;以解决快速增长的通信需求。虽然…

springmvc中@RequestMapping的使用

通过RequestMapping注解可以定义不同的处理器映射规则。 1.1 URL路径映射 RequestMapping(value"/item")或RequestMapping("/item")。 value的秩是数组&#xff0c;可以将多个url映射到同一个方法。 1.2 窄化请求映射 在class上添加RequestMapping(url)指定…

7-2 城市间紧急救援 (25 分)

作为一个城市的应急救援队伍的负责人&#xff0c;你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候&#xff0c;你的任务是带领你的…

Win32 多文档多视图

#include<Windows.h> #include<tchar.h> #include"resource.h" //全局变量 LPSTR g_MainFrame "主框架"; LPSTR g_ClientFrame "客户区框架"; LPSTR g_ChildFrame[] { "子框架1","子框架2" }; //主窗口和子…

【前沿技术】严重事故!实习生删除字节跳动所有轻量级机器学习模型

来源&#xff1a;智能研究院昨晚脉脉上有网友爆料&#xff0c;字节跳动一位实习生删除了公司所有轻量级别的机器学习模型&#xff01;什么是lite模型&#xff1f;该楼主表示&#xff0c;lite模型就是公司内几乎所有GB大小以下的机器学习模型&#xff0c;且全部被删除了&#xf…

7-1 是否同一棵二叉搜索树 (30分)

给定一个插入序列就可以唯一确定一棵二叉搜索树。然而&#xff0c;一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{2, 1, 3}和{2, 3, 1}插入初始为空的二叉搜索树&#xff0c;都得到一样的结果。于是对于输入的各种插入序列&#xff0c;你需要判断它们…

Linux基础命令---文本显示od

od 将指定文件的内容以八进制、十进制、十六进制等编码方式显示。此命令的适用范围&#xff1a;RedHat、RHEL、Ubuntu、CentOS、SUSE、openSUSE、Fedora。 1、语法 od [选项] file od [-abcdfilosx]... [FILE] [[]OFFSET[.][b]] od --traditional [OPTION]... [FILE] [[]OF…

MFC TabCtrl用法

基于对话框的MFC程序, 在主对话框中添加TabCtrl控件,CTabCtrl 类型的变量m_tabctrl; 插入3对话框&#xff0c;并设置属性styleChild,BorderNone,创建三个对话框类CDialog1&#xff0c;CDialog2&#xff0c;CDialog3&#xff1b;在主对话框中创建三个对话框类的全局对象 m_dg1,m…

机器人行业研究报告:智能化造就新时代,自动化生产成刚需

来源&#xff1a;东莞证券作者&#xff1a;黄秀瑜核心观点智能转型时代&#xff0c;机器人前景可期。智能化时代到来&#xff0c;工业机器人和服务 机器人逐渐普及。疫情后制造业走出低迷&#xff0c;中国工业机器人月产量创新 高。全球老龄化问题日益严重&#xff0c;中国作为…

7-2 是否完全二叉搜索树 (30分)

将一系列给定数字顺序插入一个初始为空的二叉搜索树&#xff08;定义为左子树键值大&#xff0c;右子树键值小&#xff09;&#xff0c;你需要判断最后的树是否一棵完全二叉树&#xff0c;并且给出其层序遍历的结果。 输入格式&#xff1a; 输入第一行给出一个不超过20的正整数…

bzoj 1596 电话网络

Description Farmer John决定为他的所有奶牛都配备手机&#xff0c;以此鼓励她们互相交流。不过&#xff0c;为此FJ必须在奶牛们居住的N(1 < N < 10,000)块草地中选一些建上无线电通讯塔&#xff0c;来保证任意两块草地间都存在手机信号。所有的N块草地按1..N 顺次编号。…

读取BMP格式数据

#pragma once #include<afx.h> class DigitalImage { private: //指针数据类型&#xff0c;需要动态分配数据大小&#xff0c;并初始化数据 char m_FileName[100]; //文件头 LPBITMAPFILEHEADER m_lpBitmapFileHender; //除位图文件头的所有数据 LPBYTE…