📄 bwchessdlg.cpp
字号:
// BWChessDlg.cpp : implementation file
#include "stdafx.h"
#include <math.h>
#include <mmsystem.h>//播放声音的头文件
#include "BWChess.h"
#include "SetupDlg.h"
#include "AboutDlg.h"
#include "Globalvar0.h"
#include "HelperAPI.h" //定义了3个对话框函数
#include "BWChessDlg.h"
#include "RecorDdlg.h"
#include "BestDlg.h"
#include <time.h>
#include "SettingDlg.h"
#include "Demo.h"
#include "windows.h"
#include "Message1.h"
#include "ip1.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CBWChessDlg dialog
BOOL PlaySounds(UINT IDSoundRes, WORD wFlag)//播放声音
{ //PlaySound 是标准函数<win.h>
if (g_bSoundOn)
if (PlaySound(MAKEINTRESOURCE(IDSoundRes),//播放的声音资源
AfxGetInstanceHandle(),//指明实例
wFlag|SND_RESOURCE|SND_NODEFAULT))//标志位:不默认,使用实例包含的资源
return TRUE;
return FALSE;
}
CBWChessDlg::CBWChessDlg(CWnd* pParent ): CDialog(IDD_BWCHESS_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);//载入图标 to m_hIcon ,不载入则使用默认图标
m_pMenu = new CMenu();//菜单
m_PaintNum=0;
hAccelerator=::LoadAccelerators(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_ACC));
//载入加速键
g_nCanHintTimeB= 3;
g_nCanHintTimeW= 3;
g_nStrollSpeed= 2;
//获得时间和速度
g_nStrollSpeed=abs(g_nStrollSpeed);
g_nStrollSpeed%=3;//速度分为3种:低 中 高
g_nCanHintTimeB=abs(g_nCanHintTimeB);
g_nCanHintTimeB%=31;
if(g_nCanHintTimeB<3)
g_nCanHintTimeB=3;
g_nCanHintTimeW=abs(g_nCanHintTimeW);
g_nCanHintTimeW%=31;
if(g_nCanHintTimeW<3)
g_nCanHintTimeW=3;
//读注册表(关于英雄榜)
g_nTime1 =AfxGetApp()->GetProfileInt(pSettings, _T("Time1"), 0);
g_nTime2 =AfxGetApp()->GetProfileInt(pSettings, _T("Time2"), 0);
g_nTime3 =AfxGetApp()->GetProfileInt(pSettings, _T("Time3"), 0);
g_nMark1 =AfxGetApp()->GetProfileInt(pSettings, _T("Mark1"), 0);
g_nMark2 =AfxGetApp()->GetProfileInt(pSettings, _T("Mark2"), 0);
g_nMark3 =AfxGetApp()->GetProfileInt(pSettings, _T("Mark3"), 0);
g_strName1 =AfxGetApp()->GetProfileString(pSettings, _T("Name1"), _T("Anonymous"));
g_strName2 =AfxGetApp()->GetProfileString(pSettings, _T("Name2"), _T("Anonymous"));
g_strName3 =AfxGetApp()->GetProfileString(pSettings, _T("Name3"), _T("Anonymous"));
//写入注册表(关于英雄榜)
CString str;
str.LoadString (IDS_AUTHOR);//载入字符串 “庞长才 制作”
AfxGetApp()->WriteProfileString(_T("Author"), _T("Shuker"), str);
AfxGetApp()->WriteProfileInt(pSettings, _T("Time1"), g_nTime1);
AfxGetApp()->WriteProfileInt(pSettings, _T("Time2"), g_nTime2);
AfxGetApp()->WriteProfileInt(pSettings, _T("Time3"), g_nTime3);
AfxGetApp()->WriteProfileInt(pSettings, _T("Mark1"), g_nMark1);
AfxGetApp()->WriteProfileInt(pSettings, _T("Mark2"), g_nMark2);
AfxGetApp()->WriteProfileInt(pSettings, _T("Mark3"), g_nMark3);
AfxGetApp()->WriteProfileString(pSettings, _T("Name1"), g_strName1);
AfxGetApp()->WriteProfileString(pSettings, _T("Name2"), g_strName2);
AfxGetApp()->WriteProfileString(pSettings, _T("Name3"), g_strName3);
}
CBWChessDlg::~CBWChessDlg()//释放资源
{ //以下为new对应的资源
delete m_pMenu;
}
void CBWChessDlg::InitParams()
{
for (int i=0; i<NUM;i++)
for (int j=0; j<NUM; j++)
kernel[i][j] = 0; //0 for none,1 for white,2 for black,棋盘的初态
kernel[3][3]=kernel[4][4]=2;//开局的
kernel[3][4]=kernel[4][3]=1;// 4颗子
m_CurPt.x = m_CurPt.y =-1;//放子的位置(初态)
num_black=2;//黑白子
num_white=2;//的颗数
m_PassedTime=0;//黑棋流逝的时间
m_PassedTime0=0;//白棋流逝的时间
m_bGameOver = FALSE;//游戏是否已经结束
//m_byColor是本程序的核心变量!!!!!!!!!!!!!!!
m_byColor = 0; //代表棋手的颜色,在使用之前代表前一个棋手的颜色,
//使用完之后代表当前棋手的颜色,因此使用之前要将其取反 1:黑 0:白
m_Skip=0;//对方是否无子可下,即对方是否跳过不下
g_nStoneNum=0;//格子的个数
m_TimerOn=0;//时间是否在计数
m_HintOnce=0;//是否提示
m_PeekOnce=0;//是否查看可下棋的位置
m_IsGameStart=0;//游戏是否已经开始
m_ListInfo.ResetContent();//清空列表
m_HintTime0=0;//白棋点击的次数
m_HintTime1=0;//黑棋点击的次数
ListInfo.destroy();//stack 类,清空信息空栈
m_UndoPoint.Destroy();//undo类,清空悔棋信息空栈
}
void CBWChessDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CBWChessDlg)
//以下部分是将控件与变量联系起来
DDX_Control(pDX, IDC_TIME_CHINESE0, m_Time0);//白棋用时
DDX_Control(pDX, IDC_INFO, m_Info);//走棋信息
DDX_Control(pDX, IDC_LISTINFO, m_ListInfo);//走棋信息列表
DDX_Control(pDX, IDC_WNUM, m_Wnum);//白棋数目
DDX_Control(pDX, IDC_TIME_CHINESE, m_Time);//黑棋用时
DDX_Control(pDX, IDC_BNUM, m_Bnum);////黑棋数目
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CBWChessDlg, CDialog)//消息映射函数
//{{AFX_MSG_MAP(CBWChessDlg)
ON_WM_PAINT()//窗口内画图
ON_WM_LBUTTONDOWN() //鼠标左击
ON_COMMAND(IDM_NEW, OnNew) //菜
ON_COMMAND(IDM_EXIT, OnExit) //单
ON_COMMAND(IDM_ABOUT, OnAbout) //命令
ON_WM_SETCURSOR()
ON_WM_QUERYDRAGICON()
ON_WM_SYSCOMMAND()
ON_WM_CONTEXTMENU()//弹出菜单
ON_WM_TIMER()
ON_COMMAND(IDM_UNDO, OnUndo)//以下全为菜单命令
ON_COMMAND(IDM_BEST, OnBest)
ON_COMMAND(IDM_HINT, OnHint)
ON_COMMAND(IDM_CANPLACE, OnCanplace)
ON_COMMAND(IDM_SETTING, OnSetting)
ON_COMMAND(IDM_OPEN, OnOpen)
ON_COMMAND(IDM_SAVE, OnSave)
ON_COMMAND(IDM_SAVEINFO, OnSaveinfo)
ON_COMMAND(IDM_DEMO, OnDemo)
ON_COMMAND(ID_Onhost, OnHost)
ON_COMMAND(ID_Onconnect, OnConnect)
ON_COMMAND(ID_Unlink, OnUnlink)
ON_COMMAND(IDM_REPLAY, OnReplay)
//}}AFX_MSG_MAP
ON_LBN_DBLCLK(IDC_LISTINFO , OnListDoubleClicked)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBWChessDlg message handlers
BOOL CBWChessDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // Set big icon,m_hIcon是图标变量
SetIcon(m_hIcon, FALSE); // Set small icon
CBitmap bitmap;
bitmap.LoadBitmap(IDB_EMPTY);
BITMAP bm;
bitmap.GetBitmap(&bm);
m_wStoneWidth=(unsigned short) bm.bmWidth; //bmWidth,bm.bmHeight
m_wStoneHeight=(unsigned short)bm.bmHeight;
CBitmap bitmap1;
bitmap1.LoadBitmap(IDB_F1_2);
bitmap1.GetBitmap(&bm);
m_wFrameWidth=(unsigned short)bm.bmWidth; //bmWidth,bm.bmHeight
m_wFrameHeight=(unsigned short)bm.bmHeight;
//获取系统的相关信息
int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);
int cyScreen = ::GetSystemMetrics(SM_CYSCREEN);
int cxDlgFrame = ::GetSystemMetrics(SM_CXDLGFRAME);
int cyDlgFrame = ::GetSystemMetrics(SM_CYDLGFRAME);
int cxCaption = ::GetSystemMetrics(SM_CYCAPTION);
int cyMenu = ::GetSystemMetrics(SM_CYMENU);//系统菜单的宽度
int nWidth = m_wFrameHeight*2+ m_wFrameWidth*8 + 2*cxDlgFrame;//根据位图和系统参数
int nHeight = m_wFrameHeight*2+ m_wFrameWidth*8 + cxCaption + 2*cyDlgFrame + cyMenu;//确定界面的大下
MoveWindow((cxScreen-nWidth-230)/2, (cyScreen-nHeight)/2,nWidth+230, nHeight+2);
//确定窗口的位置和大小,默认状态是响应重画消息
TimeCount.Create(this,nWidth+ 20, 40 ,0,4);//时间和棋子计数控件(自定义)的创建,4代表4位数,0无效
TimeCount0.Create(this,nWidth+20, 120 ,0,4);
BCount.Create (this,nWidth+ 34, 230 ,0,2);
WCount.Create (this,nWidth+ 34 ,310 ,0,2);
// ShowNumber(1);static文本控件的位置和大小,以像素为单位,this的左上角为(0,0)
m_Time.MoveWindow(nWidth+18 ,20 ,60,20);
m_Time0.MoveWindow(nWidth+18 ,100 ,60,20);
m_Bnum.MoveWindow(nWidth+18 ,210 ,60,20);
m_Wnum.MoveWindow(nWidth+18 ,290 ,60,20);
m_ListInfo.MoveWindow(nWidth+95,22,110,410);//列表
m_Info.MoveWindow(nWidth+95,2,110,20);//m_Infostatic文本
m_IsGameStart=1;//游戏是否开始
//设置系统菜单
CMenu* sysmenu=GetSystemMenu(FALSE);
sysmenu->DeleteMenu(2,MF_BYPOSITION);
sysmenu->DeleteMenu(0,MF_BYPOSITION);
sysmenu->DeleteMenu(2,MF_BYPOSITION);
CString str;
str.LoadString(IDS_TITLE_CHINESE);//IDS_TITLE_CHINESE:“黑白棋”
SetWindowText(str);//设置标题
m_pMenu->DestroyMenu();
m_pMenu->LoadMenu(IDR_MENU_CHINESE);//载入主界面菜单
SetMenu(m_pMenu);
m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED);//提示无效
m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED);//悔棋无效
m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED);//查看可以下子的地方无效
m_pMenu->EnableMenuItem(IDM_SAVE,MF_GRAYED);//保存棋局无效
m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED);//导出走棋信息无效
m_pMenu->EnableMenuItem(IDM_REPLAY,MF_GRAYED);//重温棋局无效
if(g_bTopMost)//最前面,不移动,不改变大小
SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
else//不是最前面
SetWindowPos(&wndNoTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
m_wXNull = m_wFrameHeight+1;//9 //包括白线
m_wYNull = m_wFrameHeight+1;//10
m_Client.top = m_wYNull;//m_Client代表8*8棋盘
m_Client.left = m_wXNull;
m_Client.bottom =m_wYNull + NUM * m_wStoneHeight;
m_Client.right =m_wXNull + NUM * m_wStoneWidth;
int i,j;
for (i=0; i<NUM;++i)
for (j=0; j<NUM; j++)
kernel[i][j] = 0; //0代表无子
num_black=0;
num_white=0;
m_PassedTime=0;
m_PassedTime0=0;
m_TimerOn=0;
m_HintOnce=0;//0 for have not hinted yet,1 for have hinted
m_PeekOnce=0;
m_HintTime0=0;
m_HintTime1=0;
m_bGameOver=TRUE;
return TRUE; // return TRUE unless you set the focus to a control
}//end OnInitDialog
void CBWChessDlg::OnPaint() //游戏启动时作的一些准备工作
{
CPaintDC dc(this); // device context for painting
CDC * pdc=GetDC();
if (IsIconic())//如果窗口已最小化,画图标(意义不大)
{
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);//获取图标的大小,像素为单位
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);//获得画图区,并画图于窗口中间
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);//m_hIcon 代表图标
}
else//normal 大小
{
ShowNumber(1);//显示计数器控件
DrawFrame(&dc);//显示棋盘边框
BYTE t;
if(!m_IsGameStart)//没开始
{
for (int i=0; i<NUM; ++i)
for (int j=0; j<NUM; ++j)
{
t=(unsigned char)(kernel[i][j]-1);
if (kernel[i][j])//0 for none, 1 for white,2 for black,
PutStone(t, CPoint(j,i), &dc);//画棋盘 PutStone:画棋子
}
if(m_CurPt.x >=0)//m_CurPt.x/y 取0——7
{
int nX = m_CurPt.x*m_wStoneWidth + m_wXNull;//计算棋子的位置(nx,ny)
int nY = m_CurPt.y*m_wStoneHeight + m_wYNull;
int byColor= kernel[m_CurPt.y][m_CurPt.x]-1;//棋子的颜色 :白 黑
if (byColor == 0)//白
DrawBitmap(pdc,nX,nY,IDB_CURWHITE, SRCCOPY);
else if (byColor == 1)//黑
DrawBitmap(pdc,nX,nY,IDB_CURBLACK, SRCCOPY);
} //此处画棋子
}//end if(!m_IsGameStart)
if(m_HintOnce)//0 for have not hinted yet,1 for have hinted :m_HintOnce代表是否提示
{
COLORREF crColor = m_byColor ? RGB(255,255,255) : RGB(0,0,0);//确定颜色
CPen pen(PS_SOLID, 2, crColor);
CPen *pOldPen = dc.SelectObject(&pen); //画 提示符 “X”
dc.MoveTo(x1, y1);
dc.LineTo(x2, y1);
dc.LineTo(x2, y2);
dc.LineTo(x1, y2);
dc.LineTo(x1, y1);
dc.LineTo(x2, y2);
dc.MoveTo(x2, y1);
dc.LineTo(x1, y2);//x1 y1 x2 y2 的初值?????
dc.SelectObject(pOldPen);
}
if(m_PeekOnce)//代表是否查看可下的位置,画可下的位置
{
int px,py;
int xx1,yy1;
int length,hy;
if(m_byColor)//黑
length=wsp.isempty();
else//白
length=bsp.isempty();
if(length)
return;
do
{
if(m_byColor)//从栈里取可放子的格子
length=wsp.GetNextPos(&py,&px,&hy);//有效格子的个数
else
length=bsp.GetNextPos(&py,&px,&hy);
xx1 = px*m_wStoneWidth + m_wXNull;//-4 + m_cxGrid / 2;
yy1 = py*m_wStoneHeight + m_wYNull;//-4 + m_cyGrid / 2;
if(m_byColor)//显示可放子的格子(显示一个标志性的位图)
DrawBitmap(pdc,xx1,yy1,IDB_CANPLACE2, SRCCOPY);
else
DrawBitmap(pdc,xx1,yy1,IDB_CANPLACE1, SRCCOPY);
}while(length);
if(m_byColor)
wsp.CopyBackIndex ();
else
bsp.CopyBackIndex ();
}
Mutex1.Lock();//互斥,在“Globalvar0.h”里定义的变量
if(g_nIsDemo && g_nMutex)
{
g_nMutex=0;
m_Mutex.Unlock();//互斥,在“Globalvar0.h”里定义的变量
}
Mutex1.Unlock();
}
ReleaseDC(pdc);
}//end paint
HCURSOR CBWChessDlg::OnQueryDragIcon()//返回图标
{
return (HCURSOR) m_hIcon;//返回图标
}
void CBWChessDlg::OnLButtonDown(UINT nFlag, CPoint point)//左击
{
if(!ready)// P 操作!!!!!!!!
return;
CPoint pt;
if(!IsInPanel(point) || m_bGameOver || g_nIsDemo)
return;//无效 返回
//此处为非网络模式
if (g_nRunMode != MODE_NETWORK&&PointToStonePos(point, pt))
{
int nX = pt.x;
int nY = pt.y;
if (kernel[nY][nX]==0) //此处无子
{
if (g_nRunMode == MODE_WITH_COMPUTER)//模式是与计算机对弈
{
if ((g_bUserBlack && !m_byColor) ||
(!g_bUserBlack && m_byColor)) //数据正确
{
// User
m_byColor = !m_byColor; // 0-Black 1-White//设置当前棋手的颜色,因为初值为黑色棋手,
//但是m_byColor==0,代表白色,所以要先设成黑色
//undo
duplicate();//保存副本
//end undo
if(BtoW(nY,nX,m_byColor+1))//将棋盘上被夹住的子变色
{
m_HintOnce=0;
m_PeekOnce=0;
m_CurPt=pt;
AddStringToList(nY,nX,m_byColor);//将信息加入列表框
InvalidateRect(m_Client, FALSE);//刷新窗口
UpdateWindow();//显示窗口
PlaySounds(IDSOUND_PUTSTONE);
Ring(IsEnd(!m_byColor+1));//根据棋盘的状态处理善后工作
// -1 for both
//棋盘的状态: // 0 for the int have no position
//1 for the int have one position ,no use now
//return 2 for have more than one
//函数原型:int CBWChessDlg::IsEnd(int whogo);
//whogo :1代表黑色,2代表白色
// Computer
if (!m_bGameOver && !m_Skip)
{
do
{
m_byColor = !m_byColor; // 1-Black 0-White
int ptBest_x,ptBest_y;
//undo
duplicate();//保存副本
//end undo
Place(&ptBest_x,&ptBest_y,m_byColor+1);//计算机寻找最佳位置
//函数原型:void Place(int *x, int *y,int color,int nSkill)
//color: 1 白 2 黑
BtoW(ptBest_x,ptBest_y,m_byColor+1);//将棋盘上被夹住的子变色
CPoint pt;
pt.x = ptBest_y*m_wStoneWidth + m_wXNull+m_wStoneWidth/2;
pt.y = ptBest_x*m_wStoneHeight + m_wYNull+m_wStoneWidth/2;
m_CurPt.x=ptBest_y;
m_CurPt.y=ptBest_x;
ClientToScreen(&pt);
MoveCursor(pt.x, pt.y);//移动光标,此时m_byColor代表的是当前棋手的颜色
InvalidateRect(m_Client, FALSE);
UpdateWindow();//更新棋盘
AddStringToList(ptBest_x,ptBest_y,m_byColor);//将信息加入列表框
PlaySounds(IDSOUND_PUTSTONE);
Ring(IsEnd(!m_byColor+1));//作善后处理,包括“游戏结束或对手无子可走”
}while(m_Skip);//m_Skip==1表示对手无子可走,由计算机继续走
}
if(!m_bGameOver && g_bPeepOften)
OnCanplace();//继续搜索
}
else//没有夹住任何棋子,撤消已有的操作
{
int temp[NUM*NUM];
m_UndoPoint.pop(temp);
m_byColor=!m_byColor;
PlaySounds(IDSOUND_ERROR);
}
} // end if ((g_bUserBlack && !m_byColor) ||(!g_bUserBlack && m_byColor))
}// end 模式是与计算机对弈
else if (g_nRunMode == MODE_2PLAYER)// 人对人!! // Users
{
m_byColor = !m_byColor; // 1-Black 0-White,由当前棋手的ID取得当前棋手的颜色,
//颜色与ID正好相反,故取反
duplicate();
if(BtoW(nY,nX,m_byColor+1))//有棋子可变色
{
m_HintOnce=0;//不提示
m_PeekOnce=0;//不查看
m_CurPt=pt;
AddStringToList(nY,nX,m_byColor);
InvalidateRect(m_Client,FALSE);
UpdateWindow();
PlaySounds(IDSOUND_PUTSTONE);
Ring(IsEnd(!m_byColor+1));
if(!m_bGameOver && g_bPeepOften)
OnCanplace();
}
else//没有夹住任何棋子,撤消已有的操作
{
int temp[NUM*NUM];
m_UndoPoint.pop(temp);
m_byColor=!m_byColor;
PlaySounds(IDSOUND_ERROR);
}
}//end 人对人!!
else ;//此情况非法!!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -