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的远程五子棋对弈程序

0 0
原创粉丝点击