2、多线程(程序辅助)
最初,我们的程序中没有给计算机的“思考”另外开辟新的线程。而仅仅是简单地按照如下顺序编写代码: 用户走棋 —〉计算机思考并走棋 按这种方式编写的程序似乎毫无问题,程序运行一切正常。 然而,在我们给程序加入计时功能(后面将会在讲到其实现)后,程序出现了异常:对用户方的计时功能完全正确,而对电脑方的计时功能却根本不起作用!后来,经指导老师点拨,我们找到了问题的所在以及相应的解决方案——由于程序在进行搜索时会占用大量的CPU时间,因而阻塞了位于同一线程内的计时器,使之无法正常工作。解决方案就是另外开一个线程,让搜索与计时器分处两个线程。 启动一个新的线程的方法非常简单,只需调用API函数AfxBeginThread即可,函数原型: CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );[ 该函数原型的描述摘自Visual Studio .NET MSDN 版权所有 1987-2002 Microsoft Corporation] 该函数启动一个新的线程并返回一个指向该新线程对象的指针,然后新的线程与启动该新线程的线程同时运行。该函数的第一个参数AFX_THREADPROC pfnThreadProc指定了线程函数。线程函数的内容即为新线程所要执行的内容,线程函数执行完毕,新线程结束(自动销毁)。 线程函数必须被定义为全局函数,其返回值类型必须是UINT,必须有一个LPVOID类型的参数。我们可以把调用引擎部分的搜索函数的代码以及完成走棋动作的代码放入我们所定义的思考线程内,如下: UINT ThinkingThread(LPVOID pParam) { //计算机思考并走棋 } 然后,我们只要将原先调搜索函数并完成走棋的代码代之以调用AfxBeginThread来启动新线程即可。这样一来,我们就实现了程序的多线程,计算机方的计时器不能正常工作的问题也就随之解决了。
3、计时器(程序辅助)
我们要给程序添加计时功能(分别记录下棋双方的“思考时间”),可以使用SetTimer函数、KillTimer函数以及OnTimer函数,SetTimer函数可写成如下: SetTimer(1,1000,NULL); 其中第一个参数指明了计时器的ID(可以在同一个程序中建立多个计时器,用计时器ID来区别它们)。第二个参数给出了产生WM_TIMER消息的时间间隔,单位是毫秒。 当不想再继续使用该计时器时,可以通过调用函数KillTimer(计时器ID)来销毁计时器。如销毁上面所设的计时器可以写作如下: KillTimer(1); OnTimer函数是WM_TIMER消息的消息响应函数,通俗地讲即每过SetTimer函数中指定的时间间隔,程序就调用一次OnTimer函数。它只有一个参数,即计时器的ID——当一个程序中有多个计时器时,OnTimer函数可以通过识别不同的计时器ID号来完成不同的操作。 这样要给程序增加对双方下棋时间的计时功能,可以按如下流程编写程序: 0 - 棋局正式开始,红方先行; 1 - SetTimer(1,1000,NULL); 2 - 红方思考; 3 - 红方走棋; 4 - KillTimer(1); 5 - SetTimer(2,1000,NULL); 6 - 黑方思考; 7 - 黑方走棋; 8 - KillTimer(2); 9 - 跳转至1,重复走棋过程 OnTimer函数则按如下编写代码: OnTimer(计时器ID) { if 计时器ID == 1 then 红方计时+1; if 计时器ID == 2 then 黑方计时+1; } 当然,上面的流程及伪码仅仅说明编写象棋计时器大体思想,实际情况要比这复杂的多。在我们的实际的程序中还涉及了线程间的通信(因为我们把计算机方的思考和走棋的过程放在了另一个线程之内),时间的刷新显示,分、秒、时的进位换算等等。而且为了提高计时精度,我们还将SetTimer函数的第二个参数设为了100,即每0.1秒做一次计时(有时
首页 上一页 2 3 4 5 6 7 下一页 尾页 5/7/7