www.pudn.com > renju_src.rar > RenjuView.cpp


// RenjuView.cpp : implementation of the CRenjuView class 
// 
 
#include "stdafx.h" 
#include "Renju.h" 
 
#include "RenjuDoc.h" 
#include "RenjuView.h" 
 
#include "LinkDialog.h" 
 
//#include  
 
#pragma comment(lib, "winmm.lib") 
 
#define ID_TIMER 1 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CRenjuView 
 
IMPLEMENT_DYNCREATE(CRenjuView, CView) 
 
BEGIN_MESSAGE_MAP(CRenjuView, CView) 
	//{{AFX_MSG_MAP(CRenjuView) 
	ON_WM_PAINT() 
	ON_COMMAND(ID_ACTION_LINK, OnActionLink) 
	ON_UPDATE_COMMAND_UI(ID_ACTION_LINK, OnUpdateActionLink) 
	ON_COMMAND(ID_ACTION_DISLINK, OnActionDislink) 
	ON_UPDATE_COMMAND_UI(ID_ACTION_DISLINK, OnUpdateActionDislink) 
	ON_COMMAND(ID_ACTION_SURRENDER, OnActionSurrender) 
	ON_UPDATE_COMMAND_UI(ID_ACTION_SURRENDER, OnUpdateActionSurrender) 
	ON_WM_SETCURSOR() 
	ON_WM_LBUTTONDOWN() 
	ON_COMMAND(ID_ACTION_NEW, OnActionNew) 
	ON_UPDATE_COMMAND_UI(ID_ACTION_NEW, OnUpdateActionNew) 
	ON_COMMAND(ID_MUSIC_MUSIC, OnMusicMusic) 
	ON_UPDATE_COMMAND_UI(ID_MUSIC_MUSIC, OnUpdateMusicMusic) 
	ON_WM_TIMER() 
	//}}AFX_MSG_MAP 
	ON_MESSAGE(WM_USER_NEWGAME, OnNewGame) 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CRenjuView construction/destruction 
 
CRenjuView::CRenjuView() 
{ 
	// TODO: add construction code here 
	m_bMusicOn = FALSE; 
	m_pListenSocket = NULL; 
	m_pClientSocket = NULL; 
	m_pClientSocket2 = NULL; 
	m_bMyTurn = FALSE; 
	m_bLinked = FALSE; 
	m_bOpponentWin = FALSE; 
	m_bInGame = FALSE; 
	ResetCoords(); 
	CreateListenSocket();	 
} 
 
CRenjuView::~CRenjuView() 
{ 
	DestroyListenSocket(); 
	DestroyClientSocket(); 
	DestroyClientSocket2(); 
	m_bLinked = FALSE; 
 
	if(m_bMusicOn) 
		KillTimer(ID_TIMER); 
} 
 
BOOL CRenjuView::PreCreateWindow(CREATESTRUCT& cs) 
{ 
	// TODO: Modify the Window class or styles here by modifying 
	//  the CREATESTRUCT cs 
	return CView::PreCreateWindow(cs); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CRenjuView drawing 
 
void CRenjuView::OnDraw(CDC* pDC) 
{ 
	CRenjuDoc* pDoc = GetDocument(); 
	ASSERT_VALID(pDoc); 
	// TODO: add draw code for native data here 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CRenjuView diagnostics 
 
#ifdef _DEBUG 
void CRenjuView::AssertValid() const 
{ 
	CView::AssertValid(); 
} 
 
void CRenjuView::Dump(CDumpContext& dc) const 
{ 
	CView::Dump(dc); 
} 
 
CRenjuDoc* CRenjuView::GetDocument() // non-debug version is inline 
{ 
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CRenjuDoc))); 
	return (CRenjuDoc*)m_pDocument; 
} 
#endif //_DEBUG 
 
///////////////////////////////////////////////////////////////////////////// 
// CRenjuView message handlers 
 
void CRenjuView::OnPaint()  
{ 
	//GetParent()->SetWindowText(_T("Renju")); 
	CPaintDC dc(this); // device context for painting 
 
	CBitmap bitmap; 
	bitmap.LoadBitmap (IDB_BKWOOD); 
 
	CDC dcMem; 
	dcMem.CreateCompatibleDC(&dc); 
	CBitmap* pOldBitmap = dcMem.SelectObject(&bitmap); 
 
	CRect rect(0, 0, 0, 0); 
	GetClientRect(&rect); 
 
	dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &dcMem, 
				  0, 0, 640, 640, SRCCOPY); 
 
	for(int i = 1; i <= DIVISIONS; i++) 
	{ 
		dc.MoveTo(CELLSIZE, i * CELLSIZE); 
		dc.LineTo(DIVISIONS * CELLSIZE, i * CELLSIZE); 
		dc.MoveTo(i * CELLSIZE, CELLSIZE); 
		dc.LineTo(i * CELLSIZE, DIVISIONS * CELLSIZE); 
	} 
 
	dc.SelectStockObject(BLACK_BRUSH); 
 
	int nRadius = 4; 
	dc.Ellipse(CELLSIZE + CELLSIZE * 3 - nRadius, 
			   CELLSIZE + CELLSIZE * 3 - nRadius, 
			   CELLSIZE + CELLSIZE * 3 + nRadius, 
			   CELLSIZE + CELLSIZE * 3 + nRadius); 
 
	dc.Ellipse(CELLSIZE + CELLSIZE * (DIVISIONS - 3 - 1) - nRadius, 
			   CELLSIZE + CELLSIZE * 3 - nRadius, 
			   CELLSIZE + CELLSIZE * (DIVISIONS - 3 - 1) + nRadius, 
			   CELLSIZE + CELLSIZE * 3 + nRadius); 
	 
	dc.Ellipse(CELLSIZE + CELLSIZE * (DIVISIONS / 2) - nRadius, 
			   CELLSIZE + CELLSIZE * (DIVISIONS / 2) - nRadius, 
			   CELLSIZE + CELLSIZE * (DIVISIONS / 2) + nRadius, 
			   CELLSIZE + CELLSIZE * (DIVISIONS / 2) + nRadius); 
	 
	dc.Ellipse(CELLSIZE + CELLSIZE * 3 - nRadius, 
			   CELLSIZE + CELLSIZE * (DIVISIONS - 3 - 1) - nRadius, 
			   CELLSIZE + CELLSIZE * 3 + nRadius, 
			   CELLSIZE + CELLSIZE * (DIVISIONS - 3 - 1) + nRadius); 
	 
	dc.Ellipse(CELLSIZE + CELLSIZE * (DIVISIONS - 3 - 1) - nRadius, 
			   CELLSIZE + CELLSIZE * (DIVISIONS - 3 - 1) - nRadius, 
			   CELLSIZE + CELLSIZE * (DIVISIONS - 3 - 1) + nRadius, 
			   CELLSIZE + CELLSIZE * (DIVISIONS - 3 - 1) + nRadius); 
 
	dc.SelectStockObject(NULL_BRUSH); 
 
	CPen pen(PS_SOLID, 4, RGB(0, 0, 0)); 
	CPen* pOldPen = dc.SelectObject(&pen); 
 
	CRect rectFrame(CELLSIZE, CELLSIZE, DIVISIONS * CELLSIZE + 2, DIVISIONS * CELLSIZE + 2); 
	rectFrame.InflateRect(5, 5); 
	dc.Rectangle(&rectFrame); 
 
	dc.SelectObject(pOldPen); 
	dc.SelectObject(pOldBitmap); 
 
	DrawPieces(); 
	// Do not call CView::OnPaint() for painting messages 
} 
 
void CRenjuView::OnActionLink()  
{ 
	// TODO: Add your command handler code here 
	CLinkDialog dlg; 
 
	if(dlg.DoModal() == IDOK) 
	{ 
		GetParent()->SetWindowText(_T("Renju - Waiting for reply")); 
		CreateClientSocket(dlg.m_strAddress); 
	} 
} 
 
void CRenjuView::OnUpdateActionLink(CCmdUI* pCmdUI)  
{ 
	// TODO: Add your command update UI handler code here 
	pCmdUI->Enable(!m_bLinked); 
} 
 
void CRenjuView::OnActionDislink()  
{ 
	// TODO: Add your command handler code here 
	int result = AfxMessageBox(_T("Are you sure you want to disconnect?"), 
								MB_YESNO); 
	if(result == IDYES) 
	{ 
		int buf[3] = {DISCONNECT, 0, 0}; 
		m_pClientSocket->Send(buf, 3 * sizeof(int)); 
		m_bLinked = FALSE; 
		m_bInGame = FALSE; 
		DestroyClientSocket(); 
		GetParent()->SetWindowText(_T("Renju - Ready")); 
	} 
} 
 
void CRenjuView::OnUpdateActionDislink(CCmdUI* pCmdUI)  
{ 
	// TODO: Add your command update UI handler code here 
	pCmdUI->Enable(m_bLinked); 
} 
 
void CRenjuView::OnActionSurrender()  
{ 
	// TODO: Add your command handler code here 
	int result = AfxMessageBox(_T("Are you sure you want to surrender?"), 
								MB_YESNO); 
	if(result == IDYES) 
	{ 
		m_bMyTurn = FALSE; 
		m_bInGame = FALSE; 
		int buf[3] = {SURRENDER, 0, 0}; 
		if(m_pClientSocket->Send(buf, 3 * sizeof(int)) == SOCKET_ERROR) 
		{ 
			AfxMessageBox(_T("Connection interrupted!\n" 
							"Cannot connect to your partner.")); 
			m_bLinked = FALSE; 
			m_bInGame = FALSE; 
			DestroyClientSocket(); 
			GetParent()->SetWindowText(_T("Renju - Ready")); 
			return; 
		} 
		GetParent()->SetWindowText(_T("Renju - Game over")); 
	} 
} 
 
void CRenjuView::OnUpdateActionSurrender(CCmdUI* pCmdUI)  
{ 
	// TODO: Add your command update UI handler code here 
	pCmdUI->Enable(m_bLinked && m_bInGame);	 
} 
 
void CRenjuView::OnActionNew()  
{ 
	// TODO: Add your command handler code here 
	int buf[3] = {NEWGAME, 0, 0}; 
	if(m_pClientSocket->Send(buf, 3 * sizeof(int)) == SOCKET_ERROR) 
	{ 
		AfxMessageBox(_T("Connection interrupted!\n" 
						"Cannot connect to your partner.")); 
		m_bLinked = FALSE; 
		DestroyClientSocket(); 
		GetParent()->SetWindowText(_T("Renju - Ready")); 
		return; 
	} 
	GetParent()->SetWindowText(_T("Renju - Waiting for reply")); 
} 
 
void CRenjuView::OnUpdateActionNew(CCmdUI* pCmdUI)  
{ 
	// TODO: Add your command update UI handler code here 
	pCmdUI->Enable(m_bLinked && !m_bInGame); 
} 
 
void CRenjuView::OnMusicMusic()  
{ 
	// TODO: Add your command handler code here 
	m_bMusicOn = !m_bMusicOn; 
	if(m_bMusicOn) 
	{ 
		PlayBGMusic(_T("bgmusic.mid")); 
		SetTimer(ID_TIMER, m_midi.GetMidiLen() + 500, NULL); 
	} 
	else 
	{ 
		KillTimer(ID_TIMER); 
		PlayBGMusic(NULL); 
	} 
} 
 
void CRenjuView::OnUpdateMusicMusic(CCmdUI* pCmdUI)  
{ 
	// TODO: Add your command update UI handler code here 
	pCmdUI->SetCheck(m_bMusicOn); 
} 
 
void CRenjuView::PlayBGMusic(LPCSTR FileName) 
{ 
	m_midi.Open(FileName); 
	m_midi.Play(); 
} 
 
void CRenjuView::CreateListenSocket() 
{ 
	if(m_pListenSocket) 
		DestroyListenSocket(); 
 
	m_pListenSocket = new CListenSocket(this); 
 
	if(!m_pListenSocket->Create(PORT_NUM)) 
	{ 
		DestroyListenSocket(); 
		AfxMessageBox(_T("Port creation failed!\n" 
						"Please try again later.")); 
		return; 
	} 
 
	if(!m_pListenSocket->Listen()) 
	{ 
		DestroyClientSocket(); 
		AfxMessageBox(_T("Due to socket problems on your machine,\n" 
						"you cannot respond to incoming request.\n" 
						"You can only request a new game to others.")); 
	} 
} 
 
void CRenjuView::DestroyListenSocket() 
{ 
	if(m_pListenSocket) 
	{ 
		delete m_pListenSocket; 
		m_pListenSocket = NULL; 
	} 
} 
 
void CRenjuView::CreateClientSocket(CString& strAddress) 
{ 
	if(m_pClientSocket) 
		DestroyClientSocket(); 
 
	m_pClientSocket = new CClientSocket(this); 
		 
	if(!m_pClientSocket->Create()) 
	{ 
		DestroyClientSocket(); 
		GetParent()->SetWindowText(_T("Renju - Ready")); 
		AfxMessageBox(_T("Port creation failed!\n" 
						"Please try again later.")); 
		return; 
	} 
 
	while(!m_pClientSocket->Connect(strAddress, PORT_NUM)) 
	{ 
		if(AfxMessageBox(_T("Cannot reach your partner right now.\n"), 
			MB_RETRYCANCEL) == IDCANCEL) 
		{ 
			DestroyClientSocket(); 
			GetParent()->SetWindowText(_T("Renju - Ready")); 
			return; 
		} 
	} 
} 
 
void CRenjuView::DestroyClientSocket() 
{ 
	if(m_pClientSocket) 
	{ 
		delete m_pClientSocket; 
		m_pClientSocket = NULL; 
	} 
} 
 
void CRenjuView::DestroyClientSocket2() 
{ 
	if(m_pClientSocket2) 
	{ 
		delete m_pClientSocket2; 
		m_pClientSocket2 = NULL; 
	} 
} 
 
void CRenjuView::RequestAccepted(int accept) 
{ 
	if(!m_pClientSocket) 
	{ 
		m_pClientSocket = new CClientSocket(this); 
 
		if(!m_pListenSocket->Accept(*m_pClientSocket)) 
		{ 
			DestroyClientSocket(); 
			GetParent()->SetWindowText(_T("Renju - Ready")); 
			AfxMessageBox(_T("You cannot accept this request!")); 
		} 
 
		if(accept == IDYES) 
		{ 
			int buf[3] = {ACCEPT, 0, 0}; 
			if(m_pClientSocket->Send(buf, 3 * sizeof(int)) == SOCKET_ERROR) 
			{ 
				AfxMessageBox(_T("Connection interrupted!\n" 
								"Cannot open the new game.")); 
				m_bLinked = FALSE; 
				m_bInGame = FALSE; 
				DestroyClientSocket(); 
				GetParent()->SetWindowText(_T("Renju - Ready")); 
				return; 
			} 
			m_bMyTurn = TRUE; 
			m_bLinked = TRUE; 
			m_bOpponentWin = FALSE; 
			m_bInGame = TRUE; 
			ResetCoords(); 
			m_nColor = 1; 
			GetParent()->SetWindowText(_T("Renju - Your turn")); 
		} 
		else 
		{ 
			int buf[3] = {DECLINE, 0, 0}; 
			m_pClientSocket->Send(buf, 3 * sizeof(int)); 
			GetParent()->SetWindowText(_T("Renju - Ready")); 
			DestroyClientSocket(); 
		} 
		return; 
	} 
 
	if(m_pClientSocket2) 
		DestroyClientSocket2(); 
 
	m_pClientSocket2 = new CClientSocket(this); 
 
	if(!m_pListenSocket->Accept(*m_pClientSocket2)) 
	{ 
		DestroyClientSocket2(); 
		GetParent()->SetWindowText(_T("Renju - Ready")); 
		AfxMessageBox(_T("You cannot accept this request!")); 
	} 
 
	int buf[3] = {DECLINE, 0, 0}; 
	m_pClientSocket2->Send(buf, 3 * sizeof(int)); 
	GetParent()->SetWindowText(_T("Renju - Ready")); 
	DestroyClientSocket2(); 
} 
 
// process the new game request 
LRESULT CRenjuView::OnNewGame(WPARAM wParam, LPARAM lParam) 
{ 
	int result = AfxMessageBox(_T("Do you want to play a new game?"), 
								MB_YESNO); 
	if(result == IDYES) 
	{ 
		int buf[3] = {ACCEPT, 0, 0}; 
		if(m_pClientSocket->Send(buf, 3 * sizeof(int)) == SOCKET_ERROR) 
		{ 
			AfxMessageBox(_T("Connection interrupted!\n" 
						"Cannot open the new game.")); 
			m_bLinked = FALSE; 
			m_bInGame = FALSE; 
			DestroyClientSocket(); 
			GetParent()->SetWindowText(_T("Renju - Ready")); 
			return 1; 
		} 
		m_bMyTurn = TRUE; 
		m_bLinked = TRUE; 
		m_bOpponentWin = FALSE; 
		m_bInGame = TRUE; 
		ResetCoords(); 
		m_nColor = 1; 
		GetParent()->SetWindowText(_T("Renju - Your turn")); 
	} 
	else 
	{ 
		int buf[3] = {NONEWGAME, 0, 0}; 
		if(m_pClientSocket->Send(buf, 3 * sizeof(int)) == SOCKET_ERROR) 
		{ 
			AfxMessageBox(_T("Connection interrupted!\n" 
						"Cannot open the new game.")); 
			m_bLinked = FALSE; 
			m_bInGame = FALSE; 
			DestroyClientSocket(); 
			GetParent()->SetWindowText(_T("Renju - Ready")); 
			return 1;  
		} 
		GetParent()->SetWindowText(_T("Renju - Game over")); 
	} 
	return 0; 
} 
 
// zero set the array 
void CRenjuView::ResetCoords() 
{ 
	for(int i = 0; i < DIVISIONS; i++) 
	{ 
		for(int j = 0; j < DIVISIONS; j++) 
			m_nCoords[i][j] = 0; 
	} 
 
	Invalidate(FALSE); 
	UpdateWindow(); 
} 
 
// change the cursor according to whose turn it is 
BOOL CRenjuView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)  
{ 
	if(nHitTest == HTCLIENT && m_bLinked && m_bInGame) 
	{ 
		if((m_bMyTurn && (m_nColor == 1)) || 
			(!m_bMyTurn && (m_nColor == -1))) 
			::SetCursor(AfxGetApp()->LoadCursor(IDC_BLACK)); 
		else 
			::SetCursor(AfxGetApp()->LoadCursor(IDC_WHITE)); 
		 
		return TRUE; 
	} 
 
	return CView::OnSetCursor(pWnd, nHitTest, message); 
} 
 
void CRenjuView::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	if(m_bLinked && m_bMyTurn) 
	{ 
		int x = (point.x - CELLSIZE / 2) / CELLSIZE; 
		int y = (point.y - CELLSIZE / 2) / CELLSIZE; 
		if(x >= 0 && x < DIVISIONS && y >= 0 && y < DIVISIONS) 
		{ 
			if(m_nCoords[x][y] == 0) 
			{	 
				CRect invalidOldRect((m_ptLastStep.x + 1) * CELLSIZE - CELLSIZE / 2, 
									 (m_ptLastStep.y + 1) * CELLSIZE - CELLSIZE / 2, 
									 (m_ptLastStep.x + 1) * CELLSIZE + CELLSIZE / 2, 
									 (m_ptLastStep.y + 1) * CELLSIZE + CELLSIZE / 2); 
 
				InvalidateRect(&invalidOldRect, FALSE); 
 
				PlaySound(_T("down.wav"), NULL, SND_FILENAME | SND_ASYNC); 
				m_ptLastStep.x = x; 
				m_ptLastStep.y = y; 
				m_nCoords[x][y] = m_nColor; 
				m_bMyTurn = FALSE; 
				 
				CRect invalidRect((x + 1) * CELLSIZE - CELLSIZE / 2, 
								  (y + 1) * CELLSIZE - CELLSIZE / 2, 
								  (x + 1) * CELLSIZE + CELLSIZE / 2, 
								  (y + 1) * CELLSIZE + CELLSIZE / 2); 
 
				InvalidateRect(&invalidRect, FALSE); 
 
				int buf[3] = {0, x, y}; 
				if(IsWin(x, y)) 
				{ 
					if(m_nColor == -1) 
					{ 
						if(m_bOpponentWin) 
						{ 
							buf[0] = EVEN;	// even and game over 
							m_bInGame = FALSE; 
							GetParent()->SetWindowText(_T("Renju - Game over")); 
						} 
						else 
						{ 
							buf[0] = ULOSE;	// white win and game over 
							m_bInGame = FALSE; 
							GetParent()->SetWindowText(_T("Renju - Game over")); 
						} 
					} 
					else 
					{ 
						buf[0] = IWIN;		// black temp win, waiting for white's last step 
						GetParent()->SetWindowText(_T("Renju - Opponent's turn")); 
					} 
				} 
				else 
				{ 
					if(m_bOpponentWin) 
					{ 
						buf[0] = UWIN;		// I lose and game over 
						m_bInGame = FALSE; 
						GetParent()->SetWindowText(_T("Renju - Game over")); 
					} 
					else 
					{ 
						GetParent()->SetWindowText(_T("Renju - Opponent's turn")); 
						buf[0] = COORDS;	// nobody wins, just an ordinary step 
					} 
				} 
 
				if(m_pClientSocket->Send(buf, 3 * sizeof(int)) == SOCKET_ERROR) 
				{ 
					AfxMessageBox(_T("Connection interrupted!\n" 
								"Cannot continue with the game.")); 
					m_bLinked = FALSE; 
					m_bInGame = FALSE; 
					DestroyClientSocket(); 
					GetParent()->SetWindowText(_T("Renju - Ready")); 
					return; 
				} 
				// show game result messagebox if gameover 
				if(buf[0] == EVEN) 
				{ 
					AfxMessageBox(_T("Even game!")); 
				} 
				else if(buf[0] == ULOSE) 
				{ 
					AfxMessageBox(_T("Congratulations!\n" 
									"You won this game.")); 
				} 
				else if(buf[0] == UWIN) 
				{ 
					AfxMessageBox(_T("Sorry!\n" 
									"You lost this game.")); 
				} 
			} 
		} 
		else 
		{ 
			::MessageBeep(MB_ICONEXCLAMATION); 
		} 
	} 
	CView::OnLButtonDown(nFlags, point); 
} 
 
BOOL CRenjuView::IsWin(int x, int y) 
{ 
	int xMin=max(0, x - 4); 
	int xMax=min(DIVISIONS - 1, x + 4); 
	int yMin=max(0, y - 4); 
	int yMax=min(DIVISIONS - 1, y + 4); 
 
	int i, j, p, q, sum1, sum2, sum3, sum4; 
 
	for(j=xMin; j<=xMax-4; j++) 
	{ 
		for(i=j, sum1=0; ixMin && j>yMin; i--, j--); 
	for(; i<=xMax-4 && j<=yMax-4; i++, j++) 
	{ 
		for(sum3=0, p=i, q=j; pxMin && j=yMin+4; i++, j--) 
	{ 
		for(sum4=0, p=i, q=j; p