C++ 基于CSock的远程五子棋对弈程序
来源:互联网 发布:长得像白人 知乎 编辑:程序博客网 时间:2024/04/29 12:43
一、程序说明
基于CSock的远程五子棋对弈程序设计
(1)按Socket异步网络通信方式设计具有C/S模式的数据传输模块;
(2)在服务器与客户端各设计一个五子棋棋盘,用于博弈。
(3)博弈开始双方选定黑白棋子,按规则下子,两端同时显示棋局状态,并计时,
超时者判负。
(4)当任何方向上某一色棋子连成五个,判定该方赢棋。
二、程序界面
三、 程序分析
1.设计思想
(1)五子棋软件即可作为服务器端也可以作为客户端,需要在程序中同时顾及软件作
为服务器或客户端的两种情况。
(2)当五子棋作为服务器开启时,就开始在某个端口(本系统采用了1234端口)下监听客户端的连接请求,再开启另一个五子棋软件,输入服务器的IP地址并请求连接,当服务器响应客户端请求时,就可以开始游戏了。
(3)程序进行CSocket来进行数据交流,传递落子坐标。
(4)设计各种自定义算法,如棋盘棋子绘制、落子距离计算、胜负判断、状态变化等。
2.系统设计步骤
(1)程序基于Visual Studio 2010开发,以“MFC应用程序”作为程序开发模板。利用Windwos平台的消息驱动机制,设定当用户执行了某些操作(如点击按钮)时则触发特定函数。
(2)系统的使用需要同时具备服务器与客户端两个角色,服务器要先于客户端开启。
(3)开启五子棋软件,将其设为服务器。服务器端建立一个CMySocket继承于CSocket,增添自定义变量:关联窗口指针(CWnd *pWnd;),自定义函数:窗口绑定函数(void AttachCWnd(CWnd *pW);),以适应本系统实际情况。Create一个CMySocket对象在某个指定端口下(如本系统使用的1234端口)监听(listen)是否有客户端程序请求连接,套接字类型采用流式套接字(SOCK_STREAM)。调用accept阻塞,等待客户端连接。在这时如果有另一个五子棋软件作为客户端初始化一个Socket请求连接(connect)服务器,服务器对该请求进行应答。如果连接成功,则客户端与服务器端的连接就建立了。
(4)当两个玩家之间(服务器与客户端之间)的连接建立起来后,就可以开始游戏了。程序通过m_status来表示当前软件是作为服务器或客户端而存在。自定义结构体Point来存储玩家的落子坐标,然后利用SOCKET来传递给另一位玩家。此外,因为当玩家落子后,需要等到另一位玩家传递来落子坐标后才可以再次落子,通过canPlayChess来控制这种变化。
//用来标识类型,服务器、未指定、客户端enum status{SERVER=-1,INITIAL=0,CLIENT=1};//标明当前状态是客户端还是服务器端,服务器=-1,客户端=1,未指定=0enum status m_status;//落子坐标 struct Point{ int x; int y; };//标识当前是否能落子BOOL canPlayChess;
(5)自定义CSokcet类的以下虚函数,用来处理当“客户端请求连接,玩家关闭游戏、接收消息”等动作。
virtual void OnAccept(int nErrorCode);virtual void OnClose(int nErrorCode);virtual void OnReceive(int nErrorCode);
例如当有一方玩家关闭游戏或连接断开时,则 void CMySocket::OnClose(int nErrorCode)
函数将被触发,另一方玩家将弹出对话框进行提示。
四、 系统的具体实现
1. 本系统在Windows8.1系统下基于Visual Studio 2010开发,系统既可以作为服务器与也可以充当客户端。
2. 界面绘制模块:
界面的绘制主要包括窗口界面设置、棋盘绘制、棋子绘制等。主要运用的是CDC。
绘制棋盘代码:
CDC *cdc=GetDC();CPen di;di.CreatePen(PS_SOLID,1.3,RGB(0,0,0));cdc->SelectObject(&di);//画棋盘横线for(int i=0;i<ROW;i++){ cdc->MoveTo(WIDTH,WIDTH+WIDTH*i); cdc->LineTo(WIDTH*ROW,WIDTH+WIDTH*i);}//画棋盘竖线for(int j=0;j<ROW;j++){ cdc->MoveTo(WIDTH+WIDTH*j,WIDTH); cdc->LineTo(WIDTH+WIDTH*j,WIDTH*ROW);}
添加黄色背景代码:
CPaintDC dc(this); CDC dcMem; dcMem.CreateCompatibleDC(&dc); CBitmap bmpBackground; bmpBackground.LoadBitmap(IDB_BACK); BITMAP bitmap; bmpBackground.GetBitmap(&bitmap); CBitmap* pbmpPri = dcMem.SelectObject(&bmpBackground); dc.StretchBlt(WIDTH/2,WIDTH/2,WIDTH*(ROW-1)+WIDTH, WIDTH*(ROW-1)+WIDTH, &dcMem,0,0,bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
棋子绘制代码:
void CgameDlg::drawChessPiece(double a,double b,int m_status){ int x=(int)a+1; int y=(int)b+1; double width=WIDTH/2-2; CDC *cdc=GetDC(); CPen di; di.CreatePen(PS_SOLID,1,RGB(0,0,0)); cdc->SelectObject(&di);//定义画笔 CBrush brush; //如果当前状态是服务器,则画黑子 if(m_status==SERVER) { brush.CreateSolidBrush(RGB(0,0,0)); }else{ //当前状态是客户端,则画白子 brush.CreateSolidBrush(RGB(255,255,255)); } cdc->SelectObject(&brush); cdc->Ellipse(x*WIDTH-width,y*WIDTH-width,x*WIDTH+width,y*WIDTH+width; Points[(int)a][(int)b]=m_status;}
3.网络设置模块:
下图为网络设置界面。当用户选中“作为服务器”按钮并点击确定后,将Create一个CMySocket对象在1234端口下监听(listen)是否有客户端程序请求连接,套接字类型采用流式套接字(SOCK_STREAM)。调用accept阻塞,等待客户端连接。
这时如果再开启另一个五子棋软件,并选中“作为客户端”按钮,输入服务器的IP地址,点击确定,客户端将初始化一个Socket请求连接(connect)服务器,服务器对该请求进行应答。如果连接成功,则客户端与服务器端的连接就建立了。
void CgameDlg::OnBnClickedSet(){ // TODO: 在此添加控件通知处理程序代码 CSet cset; //如果没有按确认键则退出程序 if(cset.DoModal() != IDOK) { return; } //作为服务器 if(!cset.isServer) { if(IDOK==AfxMessageBox("确定开始侦听客户端的连接请求吗",MB_OKCANCEL)) { m_socket.AttachCWnd(this); //端口1234,流式套接字 BOOL isSuccess=m_socket.Create(1234,SOCK_STREAM); if(isSuccess){ m_socket.Listen(); MessageBox("已开始侦听"); SetWindowText("五子棋——正在等待客户端连接"); return; } WORD error=m_socket.GetLastError(); CString s; s.Format("服务器开启失败\r\n错误代代码:%d",error); MessageBox(s); } }else{ //作为客户端 if(IDOK==AfxMessageBox("确定连接到服务器吗",MB_OKCANCEL)) { SetWindowText("五子棋——正在连接服务器"); CString msg; DWORD error; m_socket.AttachCWnd(this); if(!m_socket.Create()) { error = GetLastError(); msg.Format("创建Socket失败\r\n错误代号:%d",error); goto msgbox; } //连接服务器 if(!m_socket.Connect(cset.m_ip,1234)) { error = GetLastError(); msg.Format("连接服务器失败\r\n错误代号:%d",error);msgbox: MessageBox(msg); return; } m_status=CLIENT; MessageBox("已连接好友,可以开始游戏啦!"); SetWindowText("五子棋(白子)——等待对方下子"); canPlayChess=false; //开启定时任务 SetTimer(1,1000,NULL); m_hint="对方剩余思考时间:"; } }}
4.网络通讯模块:
当用户鼠标点击时,将触发OnLButtonDown(UINT nFlags, CPoint point)函数,由参数point可以得到鼠标点击的X轴和Y轴坐标值。然后再来根据judge(double &x,double &y)函数来获取该坐标值该对应棋盘中的哪一个点,在该点绘制棋子,然后再向另一位玩家发送该坐标信息,或者是判定该点击无效。
void CgameDlg::OnLButtonDown(UINT nFlags, CPoint point){ // TODO: 在此添加消息处理程序代码和/或调用默认值 if(!canPlayChess || m_status==INITIAL) { return; } long x=point.x; long y=point.y; if(x>=WIDTH && x<=WIDTH*ROW && y>=WIDTH && y<=WIDTH*ROW) { double a=x/(WIDTH*1.0)-1; double b=y/(WIDTH*1.0)-1; if(judge(a,b)) { if(Points[(int)a][(int)b]!=INITIAL) { return; } drawChessPiece(a,b,m_status); point.x=a; point.y=b; if(m_status==SERVER) { if(!sc->Send((char *)&point,sizeof(point))) { MessageBox("发送数据失败"); return; } }else if(m_status==CLIENT){ if(!m_socket.Send((char *)&point,sizeof(point))) { MessageBox("发送数据失败"); return; } } if(!isWin(m_status)) { if(m_status==SERVER) { SetWindowText("五子棋(黑子)——等待对方下子"); }else{ SetWindowText("五子棋(白子)——等待对方下子"); } canPlayChess=false; m_hint="对方剩余思考时间:"; THINK_TIME=31; } } }}
5.倒计时模块
用于设置一个定时任务,动态改变一个静态文本的内容,从而实现倒计时的效果。在需要的时候可以调用KillTimer(1);取消定时任务。
void CgameDlg::OnTimer(UINT_PTR nIDEvent){ // TODO: 在此添加消息处理程序代码和/或调用默认值 if(nIDEvent==1) { THINK_TIME--; if(THINK_TIME==0) { if(m_status==SERVER) { if(canPlayChess) { SetWindowText("五子棋(黑子)——思考时间超时,对方获胜"); }else{ SetWindowText("五子棋(黑子)——对方思考时间超时,你已获胜"); } }else{ if(canPlayChess) { SetWindowText("五子棋(白子)——思考时间超时,对方获胜"); }else{ SetWindowText("五子棋(白子)——对方思考时间超时,你已获胜"); } } canPlayChess=false; KillTimer(1); } m_thinkTime.Format("%d",THINK_TIME); UpdateData(FALSE); } DialogEx::OnTimer(nIDEvent);}
代码下载地址,包括实验报告:基于CSock的远程五子棋对弈程序
- C++ 基于CSock的远程五子棋对弈程序
- 基于PyQt5的五子棋编程(人机对弈)
- java 控制台小程序:实现五子棋对弈
- 五子棋人机对弈
- 【java】五子棋人机对弈
- 五子棋 人机对弈
- C和WIN32 API 的五子棋 程序
- 五子棋 人人加人机对弈
- 黑红五子棋之人人对弈
- 一个五子棋C程序
- 高级对弈程序如Crafty(使用C语言编写)使用了特殊的数据结构
- 使用WPF技术实现基于MSN协议的五子棋程序
- [MFC] 入门级demo:基于MFC的五子棋程序
- 利用开源HTML5引擎lufylegend.js结合javascript实现的五子棋人机对弈
- C语言编写五子棋程序
- [原创]五子棋人机对弈算法设计
- 【java】java swing:五子棋人机对弈
- C实现的五子棋
- SQL中的case when then else end用法
- Linux将中文目录名改为英文
- 基本添加和遍历
- 反射(通过反射写一个通用的设置某个对象的某个属性为指定的值)
- 海量数据解决方案 知识总结
- C++ 基于CSock的远程五子棋对弈程序
- rhel7 install mysql
- 利用栈的中序遍历二叉树的非递归算法
- JAVA 中BIO,NIO,AIO的理解
- jQuery 删除、复制和替换元素
- 传统IO
- XMPP聊天之Openfire后台的安装和配置
- 初识ListView
- java 接口 抽象类 继承 重载 重写 多态