本篇继续上篇的未完部分。上篇介绍到了软件的实现,介绍完了大部分逻辑控制的实现,本篇继续介绍后续内容的编码。
(9)重写光标设置函数
在尚未开始评测或者评测过程中一局结束(新局尚未开始)时,鼠标是不允许点击棋盘区域的,或者说鼠标点击是没有反应的,而仅当该被测者(人)落子时才允许鼠标点击棋盘区域进行落子。为通过明显的光标提醒用户,这里重写光标设置函数,在该被测者落子时将棋盘区域内的鼠标光标设置为手状,否则设置为禁止光标。
在testDlg.h文件中添加以下代码来重写光标设置函数:
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
如下图所示:
然后在testDlg.cpp文件中添加如下的实现代码:
BOOL CtestDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
CPoint pos;
GetCursorPos(&pos); //在整个屏幕上的坐标
CRect rc;
GetDlgItem(IDC_BOARD)->GetWindowRect(&rc); //在整个屏幕上的坐标
if (rc.PtInRect(pos))
{
if (m_bStarted && m_bHumanPlay)
{
SetCursor(LoadCursor(NULL, IDC_HAND)); //设置成手状
}
else
{
SetCursor(LoadCursor(NULL, IDC_NO)); //设置成禁用
}
return TRUE;
}
return CDialogEx::OnSetCursor(pWnd, nHitTest, message);
}
该代码操作的仅是棋盘区域内的鼠标光标,当鼠标在棋盘区域外时不受影响。
在函数定义和实现均添加之后,在BEGIN_MESSAGE_MAP部分添加如下代码来将捕获鼠标设置消息并绑定到刚刚定义的事件响应函数上:
ON_WM_SETCURSOR()
如下图所示:
至此,可以运行程序查看效果。
(10)重写鼠标单击事件
在尚未开始评测时用鼠标点击棋盘区域是不允许落子的,可提示先“开始评测”;在评测过程中一局结束(新局尚未开始)时,鼠标点击棋盘区域也是不允许落子的,可提示用户先“开始新游戏”;而仅当该被测者(人)落子时才允许鼠标点击棋盘区域进行落子。虽然前面已经通过鼠标光标进行了提醒,但为了明确操作的意义和要求,在某些操作下还是需要添加提示信息明确给出提醒。
在testDlg.h文件中添加以下代码来重写鼠标单击事件:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
如下图所示:
然后在testDlg.cpp文件中添加如下的实现代码:
void CtestDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect rect;
m_objBoard.GetClientRect(&rect);
if (rect.PtInRect(point))
{
if (!m_bStarted)
{
if (m_nNumLeft == m_nNumTotal)
MessageBox(_T("请先点击开始评测按钮"), _T("温馨提示"), MB_OK | MB_ICONHAND);
else
MessageBox(_T("请先点击开始新游戏按钮"), _T("温馨提示"), MB_OK | MB_ICONHAND);
}
else if (m_bHumanPlay)
{
if (SetPieceWithGUI(&m_objBoard, point.x, point.y))
{
m_bHumanPlay = false;
if (IsGameOver())
{
ShowGameOver();
}
else
{
if (!SetPieceByAIAndShow(&m_objBoard))
{
AfxMessageBox(_T("积分不足或网络问题,请确保网络畅通且积分充足(若是积分不足,充值后可继续本次对局)"));
}
else
{
m_bHumanPlay = true;
if (IsGameOver())
{
ShowGameOver();
}
}
}
}
}
}
CDialogEx::OnLButtonDown(nFlags, point);
}
该代码操作的仅是棋盘区域内的鼠标单击事件,当鼠标在棋盘区域外点击时不受影响。另外,本例中将人落子和机器落子放在一起操作的,即被测者(人)落子后,若游戏未结束,则立即调用SetPieceByAIAndShow()函数来让机器落子,若需要将这两次落子拆分开来,可自行尝试,例如:使用定时器等等。
在函数定义和实现均添加之后,在BEGIN_MESSAGE_MAP部分添加如下代码来将鼠标单击事件绑定到刚刚定义的事件响应函数上:
ON_WM_LBUTTONDOWN()
如下图所示:
最后,在鼠标单击事件操作中使用了一个辅助函数ShowGameOver(),其用于在一局对弈结束时做相应的变量设置、界面刷新、结果提示等,后续将进行介绍。
(11)一局对弈结束的辅助函数
在testDlg.h文件中添加如下代码来定义这些辅助函数:
void ShowResult(); //显示评估结果
void ShowWin(); //显示胜负
void ShowGameOver(); //显示游戏结束
结果如下图所示:
其中,ShowGameOver()函数在每局对弈结束时调用,用于显示游戏结束信息,并在全部评测结束时显示评测结果;ShowWin()函数仅显示本次对弈的输赢;ShowResult()函数则用于显示整个等级评测的结果。具体实现代码如下所示:
void CtestDlg::ShowResult()
{
switch (m_nNumWin)
{
case 0:
case 1:
case 2:
MessageBox(_T("不合格!建议去更低一级评估"), _T("评估结束"), MB_OK | MB_ICONINFORMATION);
m_nDepth = (m_nCurSel + 1) * 2 - 2;
break;
case 3:
case 4:
case 5:
MessageBox(_T("不合格!"), _T("评估结束"), MB_OK | MB_ICONINFORMATION);
m_nDepth = (m_nCurSel + 1) * 2 - 1;
break;
case 6:
MessageBox(_T("合格!"), _T("评估结束"), MB_OK | MB_ICONINFORMATION);
m_nDepth = (m_nCurSel + 1) * 2;
break;
case 7:
case 8:
MessageBox(_T("良好!"), _T("评估结束"), MB_OK | MB_ICONINFORMATION);
m_nDepth = (m_nCurSel + 1) * 2 + 1;
break;
case 9:
case 10:
MessageBox(_T("优秀!建议去更高一级评估"), _T("评估结束"), MB_OK | MB_ICONINFORMATION);
m_nDepth = (m_nCurSel + 1) * 2 + 2;
break;
}
}
void CtestDlg::ShowWin()
{
switch (GetWinner())
{
case 1:
MessageBox(_T("很遗憾,您输了"), _T("温馨提示"), MB_OK | MB_ICONINFORMATION);
break;
case -1:
m_nNumWin++;
MessageBox(_T("恭喜,您赢了"), _T("温馨提示"), MB_OK | MB_ICONINFORMATION);
break;
default: //0
AfxMessageBox(_T("平局"));
break;
}
}
void CtestDlg::ShowGameOver()
{
m_bStarted = false; //本次对弈结束
m_nNumLeft--; //本次对弈已结束,剩余局数减一
ShowWin(); //显示本局的输赢,并重新计算获胜局数
char strTemp[10] = { 0 };
sprintf(strTemp, "%d", m_nNumLeft);
SetDlgItemText(IDC_NUM_LEFT, CA2CT(strTemp)); //更新剩余局数
sprintf(strTemp, "%d/%d", m_nNumWin, m_nNumTotal);
SetDlgItemText(IDC_RATIO, CA2CT(strTemp)); //更新胜率
if (m_nNumLeft <= 0)
{
ShowResult(); //评估思维深度并显示结果
sprintf(strTemp, "%d 层", m_nDepth);
SetDlgItemText(IDC_DEPTH, CA2CT(strTemp)); //更新思维深度
GetDlgItem(IDC_BTN_START)->EnableWindow(true); //启用开始评测
}
}
从实现代码可以看出,ShowGameOver()函数先设置游戏结束标识并更新剩余局数变量,然后调用ShowWin()函数来显示本次对弈的结果及更新获胜局数,之后更新剩余局数、胜率的显示信息,最后判断本次评测是否已经结束,若评测已结束,则调用ShowResult()函数来评估思维深度并显示结果,同时更新思维深度的界面信息及启用“开始评测”按钮以便重新评测。注:此处的代码中对思维深度的评估仅用的是简单的对应关系,且未计算专注度值,这些评测算法可由各使用机构根据自己的研究成果进行实现替换,也可以使用其他研究人员的成果进行替换。
到此为止,整个的案例编码已经完成,可以进行测试使用了。其中的一些细节,如果觉得有需要,可以根据自己的考虑进行修改完善,例如:默认的焦点设置、使用定时器、添加落子声音等。
后续将进行简单的测试,详细内容请继续关注下一篇