这个程序是学Win32编程到GDI部分的产物,因为是纯粹用GDI写的,所以效率很一般,所幸这种棋类程序也不需要太多的图形性能. 程序分2部分,一个内核部分,一个图形界面部分. 对于五子棋来说,内核当然就要能正确的判断当前棋盘上的情况,要能知道一步棋走下去,是不是会产生输赢结果,图形接口则是提供完整的棋盘界面给用户交互.当然也担当着输入输出的任务.
下面这个是内核部分,我把他用dll库来实现,这样以后扩充别的会很方便.
//=================================================================================
//Name: Base.h
//Funcation: Base Type Define,CPU support,MyUnicode Support.
//Author: kakashi.R
//Last Update: 6.1.2005
//=================================================================================
#ifndef _BASE_H
#define _BASE_H
#define TRUE 1
#define FALSE 0
#define SUCCESS 1
#define FAILURE 0
#define ENABLE 1
#define DISABLE 0
#define HIGH 1
#define LOW 0
#define USED 1
#define UNUSE 0
#define NULL 0
#pragma message("")
#pragma message("This is A Header File Created by kakashir. :)")
#pragma message("")
#if (defined _IOSTREAM) //Incude iostream.h for I/O.
#pragma message("")
#pragma message("Macro _IOSTREAM actived Now.")
#pragma message("Now iostream.h included for I/O.")
#pragma message("")
#include <iostream.h>
#endif //#if (defined _IOSTREAM)
#if ( !(defined APIENTRY) && (defined _STDAPI) ) //__stdcall style support.
#pragma message("")
#pragma message("Macro _STDAPI actived Now.")
#pragma message("Funcations call style KeyWord APIENTRY Defined as __stdcall.")
#pragma message("")
#define APIENTRY __stdcall
#define CENTRY __cdecl
#define API APIENTRY
#define PASCAL API
#define CALLBACK PASCAL
#endif //#if ( !(defined APIENTRY) && (defined _STDAPI) )
#ifdef _I386 //Intel 80386 and later CPU support and typedefs.
#pragma message("")
#pragma message("Macro _I386 actived NOW.")
#pragma message("Data define Keywords defined for Intel 80386 and later Processer Family.")
#pragma message("")
#if !(defined _UNICODE)
typedef char CHAR;
typedef CHAR TCHAR;
#endif //#if !(defined _UNICODE )
typedef __int8 BYTE;
typedef __int16 WORD;
typedef __int32 DWORD;
typedef __int64 QWORD;
typedef float FLOAT;
typedef double DOUBLE;
typedef unsigned __int8 UBYTE;
typedef unsigned __int16 UWORD;
typedef unsigned __int32 UDWORD;
typedef unsigned __int64 UQWORD;
typedef void* LPVOID;
typedef WORD* LPWORD;
typedef BYTE* LPBYTE;
typedef DWORD* LPDWORD;
typedef QWORD* LPQWORD;
typedef FLOAT* LPFLOAT;
typedef DOUBLE* LPDOUBLE;
typedef UBYTE* LPUBYTE;
typedef UWORD* LPUWORD;
typedef UDWORD* LPUDWORD;
typedef UQWORD* LPUQWORD;
typedef bool BOOL;
typedef void VOID;
typedef union ___uint128 //128bit unsigned data support.
{
unsigned __int64 __128[2];
unsigned __int32 __32[4];
unsigned __int16 __16[8];
unsigned __int8 __8[16];
}uint128;
typedef union ___sint128 //128bit signed data support.
{
signed __int64 __128[2];
signed __int32 __32[4];
signed __int16 __16[8];
signed __int8 __8[16];
}sint128;
typedef UBYTE U8;
typedef short unsigned U16;
typedef long unsigned U32;
typedef UQWORD U64;
typedef uint128 U128;
typedef BYTE S8;
typedef short signed S16;
typedef long signed S32;
typedef QWORD S64;
typedef sint128 S128;
#endif //#ifdef _I386
#if (defined _UNICODE && defined _I386) // MyUNICODE support!! :)
#pragma message("")
#pragma message("Macro _UNICODE actived NOW.")
#pragma message("The Keyword CHAR(upcase) defined 16bit for support UNICODE now.")
#pragma message("Pleas use cout() to display UNICODE char or String.")
#pragma message("use __char to define Old ANSCII-Style Character :)")
#pragma message("")
typedef char __char;
typedef union ___wchar //Define MyUNICODE struct.
{
U16 Unicode16;
U8 Unicode8[2];
}__wchar;
typedef __wchar CHAR;
#include <UnicodeTable.h> //include MyUNICODE Table :)
#define __IOSTREAM
#include <iostream.h>
#if (defined _IOSTREAM)
void APIENTRY _cout(CHAR Word) //MyUnicode I/O Funcation for character Display
{
if(Word.Unicode8[1] == 0)
{
cout<<(__char)Word.Unicode8[0]<<flush;
}
else
{
if(Word.Unicode8[1] >=0 && Word.Unicode8[1] <= HIGH_WORD_MAX &&
Word.Unicode8[0] >=0 && Word.Unicode8[0] <= LOW_WORD_MAX)
{
_Buffer[0] = *(UnicodeTable[(Word.Unicode8[1]-1)] + (2*Word.Unicode8[0]) );
_Buffer[1] = *(UnicodeTable[(Word.Unicode8[1]-1)] + (2*Word.Unicode8[0])+1 );
_Buffer[2] = '/0';
cout<<_Buffer<<flush;
}
}
}
void APIENTRY _cout(CHAR* Word) //MyUnicode I/O Funcation for String display
{
U32 Length = sizeof(Word)/2;
U32 Tmp_a=0;
for(Tmp_a=0;Tmp_a<Length;Tmp_a++)
{
if((Word+Tmp_a)->Unicode8[1] == 0)
{
cout<<(__char)( (Word+Tmp_a)->Unicode8[0])<<flush;
}
else if ( ((Word+Tmp_a)->Unicode8[1]) >=0 && ((Word+Tmp_a)->Unicode8[1]) <= HIGH_WORD_MAX &&
((Word+Tmp_a)->Unicode8[0]) >=0 && ((Word+Tmp_a)->Unicode8[0]) <= LOW_WORD_MAX )
{
_Buffer[0] = *(UnicodeTable[ ( (Word+Tmp_a)->Unicode8[1] )-1 ] + 2*( (Word+Tmp_a)->Unicode8[0] ) );
_Buffer[1] = *(UnicodeTable[ ( (Word+Tmp_a)->Unicode8[1] )-1 ] + 2*( (Word+Tmp_a)->Unicode8[0] )+1);
_Buffer[2] = '/0';
cout<<_Buffer<<flush;
}
}
}
#define lpUnicode(var,value) ((var)->Unicode16) = value
#define Unicode(var,value) ((var).Unicode16) = value
#define cout(UnicodeString) _cout(UnicodeString)
#endif //#if (defined _IOSTREAM)
#endif //#if (define __UNICODE)
#endif //#ifndef _BASE_H
=ChesManDefine.h===============================================================================
#ifndef _CHESMAN_H
#define _CHESMAN_H
#define _I386
#define _STDCALL
#define _IOSTREAM
#include "./Header/Base.h"
#define MAX_X 20
#define MAX_Y 20
#define NO_CHESSMAN 0
#define WHITE_CHESSMAN 1
#define BLACK_CHESSMAN 2
#define BLACK_WIN 3
#define WHITE_WIN 4
#define NEXTONE 5
typedef struct _str_ChessManPos
{
DWORD X;
DWORD Y;
}str_ChessManPos;
VOID Replace();
DWORD CheckIsWin(__int8 *lpChess);
#endif //#ifndef _CHESMAN_H
================================================================================
#include "./Header/ChesManDefine.h"
str_ChessManPos str_WinPos[5]; //保存嬴方的棋路
DWORD gPosX,gPosY; //暂时存储当前棋路
BOOL IsLastCheckedBlack=FALSE; //上个棋子是否是黑棋
BOOL IsLastCheckedWhite=FALSE; // 上个棋子是否是白棋
BOOL IsCheckedBlack=FALSE; //当前棋子是否是黑棋
BOOL IsCheckedWhite=FALSE; //当前棋子是否是白棋
BYTE Counter=0;
DWORD DetectIsWin();
VOID RecordPos(DWORD _PosX,DWORD _PosY);
VOID RecordWinPos();
DWORD CheckIsWin(__int8 *lpChess)
{
WORD cPosX=1,cPosY=1,cPos=1,cPosEnd=0;
//Scan Part:
for(cPosY=1;cPosY<=MAX_Y;cPosY++) //Scan All rows. Swap two for,it'll scan all cols
{
for(cPosX=1;cPosX<=MAX_X;cPosX++)
{
if (lpChess[20*(cPosY-1)+(cPosX-1)] ==NO_CHESSMAN )
{
Counter=0;
IsLastCheckedBlack=FALSE;
IsLastCheckedWhite=FALSE;
continue;
}
if (lpChess[20*(cPosY-1)+(cPosX-1)] == BLACK_CHESSMAN )
{
IsCheckedBlack = TRUE;
IsCheckedWhite = FALSE;
RecordPos(cPosX,cPosY);
if(DetectIsWin()==BLACK_WIN){return BLACK_WIN;}
continue;
}
if (lpChess[20*(cPosY-1)+(cPosX-1)]== WHITE_CHESSMAN )
{
IsCheckedWhite = TRUE;
IsCheckedBlack = FALSE;
RecordPos(cPosX,cPosY);
if(DetectIsWin()==WHITE_WIN){return WHITE_WIN;}
continue;
}
}
Replace();
}
for(cPosX=1;cPosX<=MAX_Y;cPosX++) //Scan all cols
{
for(cPosY=1;cPosY<=MAX_X;cPosY++)
{
if (lpChess[20*(cPosY-1)+(cPosX-1)] ==NO_CHESSMAN )
{
Counter=0;
IsLastCheckedBlack=FALSE;
IsLastCheckedWhite=FALSE;
continue;
}
if (lpChess[20*(cPosY-1)+(cPosX-1)] == BLACK_CHESSMAN )
{
IsCheckedBlack = TRUE;
IsCheckedWhite = FALSE;
RecordPos(cPosX,cPosY);
if(DetectIsWin()==BLACK_WIN){return BLACK_WIN;}
continue;
}
if (lpChess[20*(cPosY-1)+(cPosX-1)]== WHITE_CHESSMAN )
{
IsCheckedWhite = TRUE;
IsCheckedBlack = FALSE;
RecordPos(cPosX,cPosY);
if(DetectIsWin()==WHITE_WIN){return WHITE_WIN;}
continue;
}
}
Replace();
}
for(cPos=1;cPos<=MAX_X;cPos++) //Scan Left Diagonal Line
{
if (lpChess[20*(cPos-1)+(cPos-1)] == NO_CHESSMAN )
{
Counter=0;
IsLastCheckedBlack=FALSE;
IsLastCheckedWhite=FALSE;
continue;
}
if (lpChess[20*(cPos-1)+(cPos-1)] == BLACK_CHESSMAN )
{
IsCheckedBlack = TRUE;
IsCheckedWhite = FALSE;
RecordPos(cPos,cPos);
if(DetectIsWin()==BLACK_WIN){return BLACK_WIN;}
continue;
}
if (lpChess[20*(cPos-1)+(cPos-1)]== WHITE_CHESSMAN )
{
IsCheckedWhite = TRUE;
IsCheckedBlack = FALSE;
RecordPos(cPos,cPos);
if(DetectIsWin()==WHITE_WIN){return WHITE_WIN;}
continue;
}
}
Replace();
for(cPos=1;cPos<=MAX_X;cPos++) //Scan Right Diagonal Line (Roatate the Matrix)
{
if (lpChess[20*(cPos-1)+(MAX_X-(cPos-1)-1)] == NO_CHESSMAN )
{
Counter=0;
IsLastCheckedBlack=FALSE;
IsLastCheckedWhite=FALSE;
continue;
}
if (lpChess[20*(cPos-1)+(MAX_X-(cPos-1)-1)] == BLACK_CHESSMAN )
{
IsCheckedBlack = TRUE;
IsCheckedWhite = FALSE;
RecordPos((MAX_X-(cPos-1)),cPos);
if(DetectIsWin()==BLACK_WIN){return BLACK_WIN;}
continue;
}
if (lpChess[20*(cPos-1)+(MAX_X-(cPos-1)-1)]== WHITE_CHESSMAN )
{
IsCheckedWhite = TRUE;
IsCheckedBlack = FALSE;
RecordPos((MAX_X-(cPos-1)),cPos);
if(DetectIsWin()==WHITE_WIN){return WHITE_WIN;}
continue;
}
}
Replace();
cPosX=0;
for(cPos=1;cPos<=MAX_X-1;cPos++) //Scan Left Diagnoal RightUp Parts
{
_asm push cPos;
cPosEnd = cPos;
for(cPos=1;cPos<=MAX_X-cPosEnd;cPos++)
{
if (lpChess[20*(cPos-1)+(cPos+cPosX)] == NO_CHESSMAN )
{
Counter=0;
IsLastCheckedBlack=FALSE;
IsLastCheckedWhite=FALSE;
continue;
}
if (lpChess[20*(cPos-1)+(cPos+cPosX)] == BLACK_CHESSMAN )
{
IsCheckedBlack = TRUE;
IsCheckedWhite = FALSE;
RecordPos((cPos+cPosX+1),cPos);
if(DetectIsWin()==BLACK_WIN){return BLACK_WIN;}
continue;
}
if (lpChess[20*(cPos-1)+(cPos+cPosX)] == WHITE_CHESSMAN )
{
IsCheckedWhite = TRUE;
IsCheckedBlack = FALSE;
RecordPos((cPos+cPosX+1),cPos);
if(DetectIsWin()==WHITE_WIN){return WHITE_WIN;}
continue;
}
}
Replace();
cPosX++;
_asm pop cPos;
}
Replace();
cPosX=0;
for(cPos=1;cPos<=MAX_X;cPos++) //Scan Left Diagnoal LeftDown Parts
{
_asm push cPos;
for(cPos;cPos<=MAX_X;cPos++)
{
if (lpChess[20*(cPos)+(cPosX)] == NO_CHESSMAN )
{
Counter=0;
IsLastCheckedBlack=FALSE;
IsLastCheckedWhite=FALSE;
cPosX++;
continue;
}
if (lpChess[20*(cPos)+(cPosX)] == BLACK_CHESSMAN )
{
IsCheckedBlack = TRUE;
IsCheckedWhite = FALSE;
RecordPos((cPosX+1),(cPos+1));
if(DetectIsWin()==BLACK_WIN){return BLACK_WIN;}
cPosX++;
continue;
}
if (lpChess[20*(cPos)+(cPosX)] == WHITE_CHESSMAN )
{
IsCheckedWhite = TRUE;
IsCheckedBlack = FALSE;
RecordPos((cPosX+1),(cPos+1));
if(DetectIsWin()==WHITE_WIN){return WHITE_WIN;}
cPosX++;
continue;
}
}
Replace();
cPosX=0;
_asm pop cPos;
}
Replace();
cPosX=0;
for(cPos=1;cPos<=MAX_X-1;cPos++) //Scan Right-Diagnoal RightDown Parts (Roatate the Matrix)
{
_asm push cPos;
cPosEnd = cPos;
for(cPos=1;cPos<=MAX_X-cPosEnd;cPos++)
{
if (lpChess[20*(cPos+cPosX)+MAX_X-cPos] == NO_CHESSMAN )
{
Counter=0;
IsLastCheckedBlack=FALSE;
IsLastCheckedWhite=FALSE;
continue;
}
if (lpChess[20*(cPos+cPosX)+MAX_X-cPos] == BLACK_CHESSMAN )
{
IsCheckedBlack = TRUE;
IsCheckedWhite = FALSE;
RecordPos((MAX_X-cPos+1),(cPos+cPosX+1));
if(DetectIsWin()==BLACK_WIN){return BLACK_WIN;}
continue;
}
if (lpChess[20*(cPos+cPosX)+MAX_X-cPos] == WHITE_CHESSMAN )
{
IsCheckedWhite = TRUE;
IsCheckedBlack = FALSE;
RecordPos((MAX_X-cPos+1),(cPos+cPosX+1));
if(DetectIsWin()==WHITE_WIN){return WHITE_WIN;}
continue;
}
}
Replace();
cPosX++;
_asm pop cPos;
}
Replace();
cPosX=0;
for(cPos=1;cPos<=MAX_X;cPos++) //Scan Right-Diagnoal LeftUp Parts (Roatate the Matrix)
{
_asm push cPos;
for(cPos;cPos<=MAX_X;cPos++)
{
if (lpChess[20*(cPosX)+(MAX_X-cPos-1)] == NO_CHESSMAN )
{
Counter=0;
IsLastCheckedBlack=FALSE;
IsLastCheckedWhite=FALSE;
cPosX++;
continue;
}
if (lpChess[20*(cPosX)+(MAX_X-cPos-1)] == BLACK_CHESSMAN )
{
IsCheckedBlack = TRUE;
IsCheckedWhite = FALSE;
RecordPos((MAX_X-cPos),(cPosX+1));
if(DetectIsWin()==BLACK_WIN){return BLACK_WIN;}
cPosX++;
continue;
}
if (lpChess[20*(cPosX)+(MAX_X-cPos-1)] == WHITE_CHESSMAN )
{
IsCheckedWhite = TRUE;
IsCheckedBlack = FALSE;
RecordPos((MAX_X-cPos),(cPosX+1));
if(DetectIsWin()==WHITE_WIN){return WHITE_WIN;}
cPosX++;
continue;
}
}
Replace();
cPosX=0;
_asm pop cPos;
}
Replace();
return FAILURE;
}
VOID Replace() //重置函数 当一行检测完时,用来重置记录变量
{
IsLastCheckedBlack=FALSE;
IsLastCheckedWhite=FALSE;
IsCheckedBlack=FALSE;
IsCheckedWhite=FALSE;
Counter=0;
}
VOID RecordPos(DWORD _PosX,DWORD _PosY) //记录当前棋路
{
gPosX=_PosX;
gPosY=_PosY;
}
VOID RecordWinPos() //记录胜利方的棋路
{
str_WinPos[Counter].X = gPosX;
str_WinPos[Counter].Y = gPosY;
}
DWORD DetectIsWin() //判断是否胜利
{
if ( (IsLastCheckedBlack==TRUE) && (IsCheckedBlack==TRUE) )
{
RecordWinPos();
Counter++;
}
if ( (IsLastCheckedWhite==TRUE) && (IsCheckedWhite==TRUE) )
{
RecordWinPos();
Counter++;
}
if ( (IsLastCheckedBlack==FALSE) && (IsCheckedBlack==TRUE))
{
Counter=0;
RecordWinPos();
IsLastCheckedBlack=TRUE;
IsLastCheckedWhite=FALSE;
Counter=1;
}
if ( (IsLastCheckedWhite==FALSE) && (IsCheckedWhite==TRUE))
{
Counter=0;
RecordWinPos();
IsLastCheckedWhite=TRUE;
IsLastCheckedBlack=FALSE;
Counter=1;
}
if (Counter>=5)
{
if(IsCheckedBlack)
{
Counter=0;
return BLACK_WIN;
}
if(IsCheckedWhite)
{
Counter=0;
return WHITE_WIN;
}
}
return NEXTONE;
}
这个是内核部分了,其实内核的思路很简单,我们知道,棋盘可以用2维数组来模拟,再这个内核中,我用了20*20大小的数组来模拟20行20列的棋盘.棋盘上的每个位置只会有3种状态:无棋子,黑色棋子,白色棋子.这样只要在每下一步后,检索整个数组就可以了。对于五子棋,当行,列,对角线的平行线集合上某个颜色的棋子连续达到5个时,就算赢.按这个算法.,可以写出内核.先扫描行,再是列,然后是对角线.注意对角线似乎是难一些的部分,其实只要写好一个方向的算法,然后把整个数组向右旋转90度就可以了。这点大家看看程序就明白了
测试了下,发现有BUG,当黑棋斜着下时,会报非法错误。仔细DEBUG后,是内联asm的问题。偶为了省事(其实就是懒),把循环体中的变量push保存了,按道理循环完毕后有对应的pop来恢复堆栈指针,但是在循环体中,在作条件检测,满足的话就会跳出这个函数,这样,堆栈指针就不会正常,而是有4字节的偏移量。导致在恢复esi时出错。这个错误在console下调试时不容易看出来,但是在做为dll时,就会明显出错。偶也灭改上面的代码,都说到这里了,有兴趣的朋友自己改改吧 :)