主代码
#include "stdafx.h" #include "FiveChess.h" #include "ServerSocket.h"
#include "FiveChessView.h"
#ifdef _DEBUG
#define new DEBUG_NEW #undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
///////////////////////////////////////////////////////////////////////////// //
CServerSocket
CServerSocket::CServerSocket() { }
CServerSocket::~CServerSocket() { }
// Do not edit the following lines, which are needed by ClassWizard. #if 0
BEGIN_MESSAGE_MAP(CServerSocket, CSocket) //{{AFX_MSG_MAP(CServerSocket) //}}
AFX_MSG_MAP END_MESSAGE_MAP() #endif // 0
///////////////////////////////////////////////////////////////////////////// //
CServerSocket member functions
BOOL CServerSocket::Init(UINT port,CFiveChessView*view)
{ m_uPort=port; m_view=view; if(Create(m_uPort)==FALSE)
//创建socket { AfxMessageBox("Server Socket Create Error");
return FALSE; } if(this->Listen()==FALSE)
//监听socket { AfxMessageBox("Server Listen Error"); return FALSE; } return TRUE; }
void CServerSocket::OnAccept(int nErrorCode)
//接受客户端连接的消息 { CSocket::OnAccept(nErrorCode); m_view->ProcessPendingAccept();
//调用视图类中的接受连接处理函数 }
2)客户端套接字的实现 #include "stdafx.h" #include "FiveChess.h" #include "ClientSocket.h" #include"FiveChessView.h"
4
#ifdef _DEBUG
#define new DEBUG_NEW #undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
///////////////////////////////////////////////////////////////////////////// // CClientSocket
CClientSocket::CClientSocket() { m_aSessionIn=NULL; m_aSessionOut=NULL; m_sfSocketFile=NULL; m_bInit=false; m_bClose=false; }
CClientSocket::~CClientSocket() { if(m_aSessionIn) delete m_aSessionIn; if(m_aSessionOut) delete m_aSessionOut; if(m_sfSocketFile) delete m_sfSocketFile; }
// Do not edit the following lines, which are needed by ClassWizard. #if 0
BEGIN_MESSAGE_MAP(CClientSocket, CSocket) //{{AFX_MSG_MAP(CClientSocket) //}}AFX_MSG_MAP END_MESSAGE_MAP() #endif // 0
///////////////////////////////////////////////////////////////////////////// // CClientSocket member functions
void CClientSocket::OnReceive(int nErrorCode)//数据接收消息的处理函数 { CSocket::OnReceive(nErrorCode);
do
{ CMessg temp; temp.Serialize(*m_aSessionIn);//输入数据的串行化
m_view->m_sMsgList+=temp.m_strText+"\r\n";//加入新的对话内容 //把新的对话内容显示在主视图窗口的一个edit 控件中。
m_view->m_outputedit.SetWindowText(m_view->m_sMsgList); //把Edit窗口中显示的内容滚到当前的位置
m_view->m_iLineCurrentPos=m_view->m_outputedit.GetLineCount(); m_view->m_outputedit.LineScroll(m_view->m_iLineCurrentPos); //判断对方发送过来的数据是否是落子的位置
if(m_view->m_match.CanDown(temp.m_x,temp.m_y,m_view->m_who%2+1)) { //是对方发送的落子信息 m_view->m_turn=temp.m_turn;//该轮到我走棋了
m_view->Invalidate(FALSE);//刷新视图,显示对方的走子位置 //对方是否赢了
if(m_view->m_match.IsWin(m_view->m_who%2+1,temp.m_x,temp.m_y))
{ m_view->m_bWin=TRUE;//对方赢了
m_view->m_bOver=TRUE; m_view->Invalidate(FALSE);
AfxMessageBox("你输了");//显示输棋的对话框
m_view->m_outputedit.SetWindowText(m_view->m_sMsgList); m_view->m_iLineCurrentPos=m_view->m_outputedit.GetLineCount(); m_view->m_outputedit.LineScroll(m_view->m_iLineCurrentPos); } } } while(!m_aSessionIn->IsBufferEmpty()); }
void CClientSocket::Init(CFiveChessView*view)//socket串行化数据的初始工作 { m_sfSocketFile=new CSocketFile(this); m_aSessionIn=new CArchive(m_sfSocketFile,CArchive::load); m_aSessionOut=new CArchive(m_sfSocketFile,CArchive::store); m_bClose=false; this->m_view=view; }
BOOL CClientSocket::SendMessage(CMessg*msg)//发送数据到对方 { if(m_aSessionOut!=NULL) {
msg->Serialize(*m_aSessionOut);//输出串行化
m_aSessionOut->Flush();//直接发送
return TRUE; } else {
//对方关闭了连接
m_bClose=true; CloseSocket();
// m_view->CloseSessionSocket(); return FALSE; } }
void CClientSocket::CloseSocket() { if(m_aSessionIn) { delete m_aSessionOut; m_aSessionIn=NULL; }
if(m_sfSocketFile) { delete m_aSessionOut; m_sfSocketFile=NULL; }
Close(); m_bInit=false; m_bClose=true; }
void CClientSocket::OnClose(int nErrorCode)//对方关闭了Socket的消息处理
{ m_bClose=true; CloseSocket(); CSocket::OnClose(nErrorCode); }
int CClientSocket::GetLocalHostName(CString&sHostName)//获得本地计算机名称 { char szHostName[256]; int nRetCode; nRetCode=gethostname(szHostName,sizeof(szHostName));
if(nRetCode!=0) { //产生错误 sHostName=_T("没有取得"); return GetLastError(); }
7
sHostName=szHostName; return 0; }
int CClientSocket::GetIPAddress(const CString&sHostName,CString&slpAddress)//获得本地ip { struct hostent FAR*lpHostEnt=gethostbyname(sHostName); if(lpHostEnt==NULL) { //产生错误 slpAddress=_T(""); return GetLastError(); }
//获取IP LPSTR lpAddr=lpHostEnt->h_addr_list[0]; if(lpAddr) { struct in_addr inAddr; memmove(&inAddr,lpAddr,4); //转换为标准格式 slpAddress=inet_ntoa(inAddr); if(slpAddress.IsEmpty()) slpAddress=_T("没有取得"); } return 0; }
int CClientSocket::GetIPAddress(const
CString&sHostName,BYTE&f0,BYTE&f1,BYTE&f2,BYTE&f3)//获得本地IP { struct hostent FAR*lpHostEnt=gethostbyname(sHostName); if(lpHostEnt==NULL)
{ //产生错误 f0=f1=f2=f3=0; return GetLastError(); } //获取IP LPSTR lpAddr=lpHostEnt->h_addr_list[0]; if(lpAddr) { struct in_addr inAddr; memmove(&inAddr,lpAddr,4); f0=inAddr.S_un.S_un_b.s_b1; f1=inAddr.S_un.S_un_b.s_b2; f2=inAddr.S_un.S_un_b.s_b3;
8
f3=inAddr.S_un.S_un_b.s_b4; }
return 0;
}
8
f3=inAddr.S_un.S_un_b.s_b4; }
return 0;
}
2、棋盘、棋子画法及服务器端、客户端处理函数的实现
#include "stdafx.h" #include "FiveChess.h"
#include "FiveChessDoc.h" #include "FiveChessView.h" #include "ClientSocket.h" #include "ClientDlg.h" #include "ServerDlg.h" #include "MsgEdit.h"
#ifdef _DEBUG
#define new DEBUG_NEW #undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////////////////////////// // CFiveChessView
IMPLEMENT_DYNCREATE(CFiveChessView, CView)
BEGIN_MESSAGE_MAP(CFiveChessView, CView) //{{AFX_MSG_MAP(CFiveChessView) ON_COMMAND(ID_Setclient, OnSetclient) ON_COMMAND(ID_Setserver, OnSetserver) ON_WM_LBUTTONDOWN() ON_WM_SIZE() ON_WM_DESTROY() //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// //
CFiveChessView construction/destruction
CFiveChessView::CFiveChessView() { // TODO: add construction code here m_bIsClient=FALSE; m_bIsInit=FALSE; m_bOver=FALSE; m_bWin=FALSE; m_turn=1; //服务器先走,黑棋 gridHeight=gridWid=30; this->m_inputedit.SetParent(this); }
CFiveChessView::~CFiveChessView() { }
BOOL CFiveChessView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); }
///////////////////////////////////////////////////////////////////////////// // CFiveChessView drawing
///////////////////////////////////////////////////////////////////////////// // CFiveChessView printing
BOOL CFiveChessView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); }
void CFiveChessView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing }
void CFiveChessView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{ // TODO: add cleanup after printing }
///////////////////////////////////////////////////////////////////////////// // CFiveChessView diagnostics
#ifdef _DEBUG
void CFiveChessView::AssertValid() const { CView::AssertValid(); }
void CFiveChessView::Dump(CDumpContext& dc) const { CView::Dump(dc); }
CFiveChessDoc* CFiveChessView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFiveChessDoc))); return (CFiveChessDoc*)m_pDocument; }
#endif //_DEBUG
///////////////////////////////////////////////////////////////////////////// // CFiveChessView message handlers
void CFiveChessView::OnDraw(CDC*pDC) {
CFiveChessDoc *pDoc=GetDocument(); ASSERT_VALID(pDoc); CBrush back(RGB(125,125,20)); //绘制棋盘的刷子 pDC->SelectObject((CBrush*)&back); CRect rect; rect.left=LEFTDIS; rect.right=LEFTDIS+(LW-1)*gridWid; rect.top=TOPDIS; rect.bottom=TOPDIS+(LW-1)*gridWid; pDC->FillRect(&rect,&back); //绘制棋盘 CPen pen(PS_SOLID,2,RGB(25,25,255)); ////绘制网格线的笔 pDC->SelectObject((CPen*)&pen); int i,j;
CPoint pos; for(i=0;i<LW;i++) //竖值的线 { pos.x=LEFTDIS+gridWid*i; pos.y=TOPDIS; pDC->MoveTo(pos); pos.y=TOPDIS+(LW-1)*gridWid; pDC->LineTo(pos); } for(i=0;i<LW;i++) //水平的线 { pos.x=LEFTDIS; pos.y=TOPDIS+gridWid*i; pDC->MoveTo(pos); pos.x=LEFTDIS+(LW-1)*gridWid; pDC->LineTo(pos); } CBrush whitebrush(RGB(255,255,255)); //绘制黑棋的刷子 CBrush blackbrush(RGB(0,0,0)); //绘制白棋的刷子 for(i=0;i<LW;i++) //扫描整个棋盘 for(j=0;j<LW;j++) { if(m_match.chessboard[i][j]==1) //黑棋 { pDC->SelectObject((CBrush*)&blackbrush); pDC->Ellipse( j*gridWid+LEFTDIS-gridWid/2, i*gridWid+TOPDIS-gridWid/2, j*gridWid+LEFTDIS+gridWid/2, i*gridWid+TOPDIS+gridWid/2); } else if(m_match.chessboard[i][j]==2) //白棋 {
pDC->SelectObject((CBrush*)&whitebrush); pDC->Ellipse( j*gridWid+LEFTDIS-gridWid/2, i*gridWid+TOPDIS-gridWid/2, j*gridWid+LEFTDIS+gridWid/2, i*gridWid+TOPDIS+gridWid/2); } else if(m_match.chessboard[i][j]==3) { CBrush redbrush(RGB(255,0,0)); //用红色的刷子显示关键的5个棋子 pDC->SelectObject((CBrush*)&redbrush);
12
pDC->Ellipse( j*gridWid+LEFTDIS-gridWid/2, i*gridWid+TOPDIS-gridWid/2, j*gridWid+LEFTDIS+gridWid/2, i*gridWid+TOPDIS+gridWid/2); } } CRect dst; this->GetWindowRect(rect); //移动两个动态的CEdit控件,作为输入对话框和显示对话框 m_outputedit.MoveWindow(CRect(10,rect.bottom-200,rect.right-10,rect.bottom-140),false); m_inputedit.MoveWindow(CRect(10,rect.bottom-140,rect.right-10,rect.bottom-100),false); }
void CFiveChessView::OnSetserver() //菜单项"开启服务器"的消息处理函数 { CServerDlg dlg; if(dlg.DoModal()==IDOK) //服务器端口设置对话框 { m_bIsClient=FALSE; //做游戏的服务器端 m_bIsInit=TRUE; //已经初始化 m_port=dlg.m_iPort; //得到输入的端口号 m_ListenSocket.Init(m_port,this); //开始监听端口 } }
void CFiveChessView::OnSetclient() //菜单项"连接服务器"的消息处理函数 {
CClientDlg dlg;
int ret=dlg.DoModal(); //设置服务器的IP和端口 if(ret==IDOK) //用户点击了"确定" { m_bIsClient=TRUE; //做游戏的服务器端 m_bIsInit=TRUE; //已经初始化 m_port=dlg.m_iPort; //得到用户输入的服务器端的端口 for(int i=0;i<4;i++) m_bIP[i]=dlg.m_bIP[i]; //得到用户输入的服务器端的IP地址
this->m_ip.Format("%d.%d.%d.%d",dlg.m_bIP[0],dlg.m_bIP[1],dlg.m_bIP[2],dlg.m_bIP[3]); m_ClientSocket.Create(); //创建会话socket if(m_ClientSocket.Connect(LPCSTR(m_ip),m_port)) //连接到服务器端 { m_ClientSocket.Init(this); //初始化会话socket m_who=2; //客户端用白子
AfxMessageBox("成功的连接到服务器,可以开始游戏了"); } else { m_ClientSocket.Close(); //连接失败 AfxMessageBox("client connection failed"); } } }
void CFiveChessView::ProcessPendingAccept() //处理客户端socket连接的函数 {
if(m_ListenSocket.Accept(m_ClientSocket)==FALSE) //分配一个会话socket { AfxMessageBox("Sever Listen Socket Error"); return; } else { m_who=1; //服务器端用黑棋,黑棋先行 m_ClientSocket.Init(this); //初始化会话socket m_outputedit.SetWindowText("有人进来了"); AfxMessageBox("有人进来了"); } }
void CFiveChessView::GetLocalIP() //得到本机的IP地址,调用CClientSocket中的静态函数 { static BOOL first=TRUE; if(first==TRUE) {
CClientSocket::GetLocalHostName(m_sLocalName);
CClientSocket::GetIPAddress(m_sLocalName,m_bIP[0],m_bIP[1],m_bIP[2],m_bIP[3]); m_ip.Format("%d.%d.%d.%d",m_bIP[0],m_bIP[1],m_bIP[2],m_bIP[3]); first=FALSE; } }
void CFiveChessView::SendInputMsg(CString in) //在聊天输入框中输入对话的消息函数 {
// AfxMessageBox("Input Edit"); if(!m_bIsInit) //如果网络还没有连接好则不准输入 { //AfxMessageBox("NO Connection");
return;
} CMessg msg; in.TrimRight(" "); m_inputedit.SetWindowText(" "); if(in.GetLength()>2) { m_sMsgList+=in+"\r\n"; //添加聊天的内容 m_outputedit.SetWindowText(m_sMsgList); //输出到聊天显示框 m_iLineCurrentPos=m_outputedit.GetLineCount(); m_outputedit.LineScroll(m_iLineCurrentPos); //滚动到当前的位置 msg.m_strText=in; m_ClientSocket.SendMessage(&msg);//发送聊天的内容到另外一端 } }
void CFiveChessView::OnInitialUpdate() //初始化 { CView::OnInitialUpdate(); static bool oninitialupdatchaving=false; //只需要初始化调用一次 if(oninitialupdatchaving==false) { if(::AfxSocketInit()==FALSE) //winsock 初始化 { AfxMessageBox("socket init error"); } GetLocalIP(); //得到本机的IP地址 CRect rect; this->GetWindowRect(rect); //创建两个动态的CEdit控件,作为输入对话框和显示对话框 m_outputedit.Create(ES_MULTILINE|WS_CHILD|WS_VISIBLE|WS_TABSTOP| WS_BORDER|ES_READONLY,CRect(10,rect.bottom-200,rect.right-10,rect.bottom-140),this,1); m_inputedit.Create(ES_MULTILINE|WS_CHILD|WS_VISIBLE|WS_TABSTOP| WS_BORDER|ES_AUTOVSCROLL,CRect(10,rect.bottom-140,rect.right-10,rect.bottom-100),this,2); } }
void CFiveChessView::OnLButtonDown(UINT nFlags,CPoint point) //处理鼠标左键按下的消息 { if(m_bOver==TRUE) //比赛是否已经结束
{ if(AfxMessageBox("你想要重新开始游戏吗",MB_YESNO)==IDYES) { //重新开始游戏 m_bIsClient=FALSE; m_bIsInit=FALSE; m_turn=1; m_bOver=false; m_match.Clear(); m_bWin=FALSE; Invalidate(FALSE); return; } }
if(m_turn==m_who) //轮到本机走棋 { m_POS[0]=(int)((point.y-TOPDIS)/30.0+0.5); m_POS[1]=(int)((point.x-LEFTDIS)/30.0+0.5); if(m_match.CanDown(m_POS[1],m_POS[0],m_who)==TRUE)//这个位置是否可以落子 { Invalidate(FALSE); //重新绘制棋子和棋盘 m_turn=m_who%2+1; //轮到对方走棋 CMessg msg; msg.m_turn=m_turn; msg.m_x=m_POS[1]; msg.m_y=m_POS[0]; m_ClientSocket.SendMessage(&msg); //发送落子的位置 if(m_match.IsWin(m_who,m_POS[1],m_POS[0])) //判断是否赢棋 { m_bWin=TRUE; m_bOver=TRUE; Invalidate(FALSE); AfxMessageBox("你赢了!"); m_sMsgList+="你赢了!"; m_outputedit.SetWindowText(m_sMsgList+"\r\n"); } } }
16
else {
m_sMsgList+="不该你走棋\r\n";
m_outputedit.SetWindowText(m_sMsgList); }
CView::OnLButtonDown(nFlags,point); }
void CFiveChessView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); // TODO: Add your message handler code here }
3、游戏规则及胜负判定
#include "stdafx.h" #include "FiveChess.h" #include "Match.h"
#ifdef _DEBUG #undef THIS_FILE
static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif
////////////////////////////////////////////////////////////////////// // Construction/Destruction
//////////////////////////////////////////////////////////////////////
Match::Match() { for(int i=0;i<LW;i++) for(int j=0;j<LW;j++) { chessboard[i][j]=0; } }
Match::~Match() {
17
}
void Match::Clear() { for(int i=0;i<LW;i++) for(int j=0;j<LW;j++) { chessboard[i][j]=0; } }
BOOL Match::CanDown(int x,int y,int who)//判断在x,y位置是否能落子 { CString str;
// str.Format("x:%d y:%d chessboard:%d",x,y,chessboard[]); // AfxMessageBox(str); if(x<0||x>=LW||y<0||y>=LW) return FALSE; if(chessboard[y][x]!=0) return FALSE; chessboard[y][x]=who; return TRUE; }
BOOL Match::IsWin(int who,int x,int y) { int i=0; int j=0; //水平方向 for(i=y,j=(x-4>=0?x-4:0);j<(x+4>=LW?LW-1:x+4);j++) { while(i>=0&&i<LW&&j>=0&&j<LW&&chessboard[i][j]!=who) j++; int count=0; while(i>=0&&i<LW&&j>=0&&j<LW&&chessboard[i][j++]==who) count++; if(count>=5) { j--;j--; while(count--) chessboard[i][j--]=3;//标记胜出的几颗棋子 return true; } } //垂直方向 for(j=x,i=(y-4>=0?y-4:0);i<(y+4>=LW?LW-1:y+4);i++) {
while(i>=0&&i<LW&&j>=0&&j<LW&&chessboard[i][j]!=who) i++; int count=0; while(i>=0&&i<LW&&j>=0&&j<LW&&chessboard[i++][j]==who) count++; if(count>=5) { i--;i--; while(count--) chessboard[i--][j]=3;//标记胜出的几颗棋子 return true; } } //西北方向 for(j=(x-4>=0?x-4:0),i=(y-4>=0?y-4:0);j<(x+4>=LW?LW-1:x+4)&&i<(y+4>=LW?LW-1:y+4);i++,j++) { while(i>=0&&i<LW&&j>=0&&j<LW&&chessboard[i][j]!=who) i++,j++; int count=0; while(i>=0&&i<LW&&j>=0&&j<LW&&chessboard[i][j]==who) { i++; j++; count++; } if(count>=5) { i--;
j--; while(count--) { chessboard[i][j]=3;//标记胜出的几颗棋子 i--; j--; } return true; } } //东北方向 for(j=(x-4>=0?x-4:0),i=(y+4<LW?y+4:LW-1);j<(x+4>=LW?LW-1:x+4)&&i>=0;i--,j++)
{ while(i>=0&&i<LW&&j>=0&&j<LW&&chessboard[i][j]!=who) i--,j++; int count=0; while(i>=0&&i<LW&&j>=0&&j<LW&&chessboard[i][j]==who) { i--; j++; count++; } if(count>=5) { j--;i++; while(count--) { chessboard[i][j]=3;//标记胜出的几颗棋子 i++; j--; } return true; } }
return false;
}