isohex10_4.cpp

来自「一個遊戲教程」· C++ 代码 · 共 1,096 行 · 第 1/2 页

CPP
1,096
字号
/*****************************************************************************
IsoHex10_4.cpp
Ernest S. Pazera
27JUN2000
Start a WIN32 Application Workspace, add in this file
Needs ddraw.lib,  and dxguid.lib
Needs GDICanvas.h/cpp
Needs DDFuncs.h/cpp
Needs tileset.h/cpp
*****************************************************************************/

//////////////////////////////////////////////////////////////////////////////
//INCLUDES
//////////////////////////////////////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN  

#include <windows.h>   
#include "GDICanvas.h"
#include "ddraw.h"
#include "DDFuncs.h"
#include "mmsystem.h"
#include "TileSet.h"

//////////////////////////////////////////////////////////////////////////////
//DEFINES
//////////////////////////////////////////////////////////////////////////////
//name for our window class
#define WINDOWCLASS "ISOHEX10"
//title of the application
#define WINDOWTITLE "IsoHex 10-4: Reversi"

const int PLAYERONE=0;//black player
const int PLAYERTWO=1;//white player
const int PIECEEMPTY=-1;//empty square
const int PIECEBLACK=0;//black piece
const int PIECEWHITE=1;//white piece
const int PIECETRANSIT=2;//animated flip

//game states
const int GS_NONE=-1;
const int GS_WAITFORINPUT=0;
const int GS_NEWGAME=1;
const int GS_NEXTPLAYER=2;
const int GS_FLIP=3;

//directions
const int DIR_NORTH=0;
const int DIR_NORTHEAST=1;
const int DIR_EAST=2;
const int DIR_SOUTHEAST=3;
const int DIR_SOUTH=4;
const int DIR_SOUTHWEST=5;
const int DIR_WEST=6;
const int DIR_NORTHWEST=7;
const int DIR_COUNT=8;

//ai levels
const int AI_HUMAN=0;
const int AI_RANDOM=1;
const int AI_GREEDY=2;
const int AI_MISER=3;
const int AI_COUNT=4;

//////////////////////////////////////////////////////////////////////////////
//PROTOTYPES
//////////////////////////////////////////////////////////////////////////////
bool Prog_Init();//game data initalizer
void Prog_Loop();//main game loop
void Prog_Done();//game clean up
//save/restore board to backup board
void SaveBoard();
void RestoreBoard();
//game manipulation
void SetUpBoard();
void ShowBoard();
//move
void ScanForMoves(int plyr);
bool AnyValidMoves(int plyr);
bool ValidMove(int plyr,int x,int y);
bool ValidRun(int plyr,int x,int y,int dir);
//move x and y in direction
int DeltaX(int dir);
int DeltaY(int dir);
//make a move
void MakeMove(int plyr,int x, int y);
void FinishMove(int plyr);
//ai move functions
void MakeRandomMove(int plyr);
void MakeGreedyMove(int plyr);
void MakeMiserMove(int plyr);
//score evaulation
int GetScore(int plyr);
void ShowScores();
//last move
void SetLastMove(int x, int y);
//show players
void ShowPlayers();

//////////////////////////////////////////////////////////////////////////////
//GLOBALS
//////////////////////////////////////////////////////////////////////////////
HINSTANCE hInstMain=NULL;//main application handle
HWND hWndMain=NULL;//handle to our main window
//IDirectDraw7 Pointer
LPDIRECTDRAW7 lpdd=NULL;
//surfaces
LPDIRECTDRAWSURFACE7 lpddsMain=NULL;
LPDIRECTDRAWSURFACE7 lpddsBack=NULL;
//tileset
CTileSet tsReversi;

//tile information structure
struct REVERSITILE
{
	int iTileNum;//base tile number for square
	bool bHilite;//hilited, or not hilited
	int iPiece;//piece occupying square
	bool bLastMove;//last move made
};

//the board
REVERSITILE Board[8][8];
//backup board
REVERSITILE BackUpBoard[8][8];
//current player
int iPlayer=0;
//counter for animated "flipping" of pieces
int iAnimation=0;
//ai level for the players
int iAILevel[2];

//gamestate
int iGameState=GS_NONE;

//////////////////////////////////////////////////////////////////////////////
//WINDOWPROC
//////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	//which message did we get?
	switch(uMsg)
	{
	case WM_LBUTTONUP:
		{
			//grab mouse position
			POINT ptMouse;
			ptMouse.x=LOWORD(lParam);
			ptMouse.y=HIWORD(lParam);

			//test rectangle
			RECT rcTest;
			//get tile width and height
			int iTileWidth=tsReversi.GetTileList()[0].rcSrc.right-tsReversi.GetTileList()[0].rcSrc.left;
			int iTileHeight=tsReversi.GetTileList()[0].rcSrc.bottom-tsReversi.GetTileList()[0].rcSrc.top;

			//calc board rect
			SetRect(&rcTest,(400-iTileWidth*4),(300-iTileHeight*4),(400+iTileWidth*4),(300+iTileHeight*4));
			//point on board?
			if(PtInRect(&rcTest,ptMouse))
			{
				//if we are waiting for input and the ai is "human", check for inside the board
				if((iGameState==GS_WAITFORINPUT) && (iAILevel[iPlayer]==AI_HUMAN))
				{
					//find board position
					int BoardX=(ptMouse.x-rcTest.left)/iTileWidth;
					int BoardY=(ptMouse.y-rcTest.top)/iTileHeight;

					//check for a valid square
					if(ValidMove(iPlayer,BoardX,BoardY))
					{
					//make the move
						MakeMove(iPlayer,BoardX,BoardY);
						SetLastMove(BoardX,BoardY);
						iGameState=GS_FLIP;
					}
				}
				//if a game is over, start a new game by clicking on the board
				if(iGameState==GS_NONE)
				{
					iGameState=GS_NEWGAME;
				}
			}
			//check for the AI indicators
			//player one
			SetRect(&rcTest,0,600-iTileHeight,iTileWidth,600);
			//check for mouse in rect
			if(PtInRect(&rcTest,ptMouse))
			{
				iAILevel[PLAYERONE]++;
				iAILevel[PLAYERONE]%=AI_COUNT;
			}
			//player two
			SetRect(&rcTest,iTileWidth,600-iTileHeight,iTileWidth*2,600);
			//check for mouse in rect
			if(PtInRect(&rcTest,ptMouse))
			{
				iAILevel[PLAYERTWO]++;
				iAILevel[PLAYERTWO]%=AI_COUNT;
			}
		}break;
	case WM_KEYDOWN:
		{
			//check for escape key
			if(wParam==VK_ESCAPE)
			{
				DestroyWindow(hWndMain);
			}

			//check for F2(new game)
			if(wParam==VK_F2)
			{
				iGameState=GS_NEWGAME;
			}

			return(0);//handled message
		}break;
	case WM_DESTROY://the window is being destroyed
		{

			//tell the application we are quitting
			PostQuitMessage(0);

			//handled message, so return 0
			return(0);

		}break;
	case WM_PAINT://the window needs repainting
		{
			//a variable needed for painting information
			PAINTSTRUCT ps;
			
			//start painting
			HDC hdc=BeginPaint(hwnd,&ps);

			/////////////////////////////
			//painting code would go here
			/////////////////////////////

			//end painting
			EndPaint(hwnd,&ps);
						
			//handled message, so return 0
			return(0);
		}break;
	}

	//pass along any other message to default message handler
	return(DefWindowProc(hwnd,uMsg,wParam,lParam));
}


//////////////////////////////////////////////////////////////////////////////
//WINMAIN
//////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
	//assign instance to global variable
	hInstMain=hInstance;

	//create window class
	WNDCLASSEX wcx;

	//set the size of the structure
	wcx.cbSize=sizeof(WNDCLASSEX);

	//class style
	wcx.style=CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

	//window procedure
	wcx.lpfnWndProc=TheWindowProc;

	//class extra
	wcx.cbClsExtra=0;

	//window extra
	wcx.cbWndExtra=0;

	//application handle
	wcx.hInstance=hInstMain;

	//icon
	wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);

	//cursor
	wcx.hCursor=LoadCursor(NULL,IDC_ARROW);

	//background color
	wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);

	//menu
	wcx.lpszMenuName=NULL;

	//class name
	wcx.lpszClassName=WINDOWCLASS;

	//small icon
	wcx.hIconSm=NULL;

	//register the window class, return 0 if not successful
	if(!RegisterClassEx(&wcx)) return(0);

	//create main window
	hWndMain=CreateWindowEx(0,WINDOWCLASS,WINDOWTITLE, WS_POPUP | WS_VISIBLE,0,0,320,240,NULL,NULL,hInstMain,NULL);

	//error check
	if(!hWndMain) return(0);

	//if program initialization failed, then return with 0
	if(!Prog_Init()) return(0);

	//message structure
	MSG msg;

	//message pump
	for(;;)	
	{
		//look for a message
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			//there is a message

			//check that we arent quitting
			if(msg.message==WM_QUIT) break;
			
			//translate message
			TranslateMessage(&msg);

			//dispatch message
			DispatchMessage(&msg);
		}

		//run main game loop
		Prog_Loop();
	}
	
	//clean up program data
	Prog_Done();

	//return the wparam from the WM_QUIT message
	return(msg.wParam);
}

//////////////////////////////////////////////////////////////////////////////
//INITIALIZATION
//////////////////////////////////////////////////////////////////////////////
bool Prog_Init()
{
	//seed random number generator
	srand((int)GetTickCount());

	//create directdraw interface
	lpdd=LPDD_Create(hWndMain,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);

	//set display mode(800x600x16)
	lpdd->SetDisplayMode(800,600,16,0,0);

	//create primary surface
	lpddsMain=LPDDS_CreatePrimary(lpdd,1);

	//get back buffer
	lpddsBack=LPDDS_GetSecondary(lpddsMain);

	//load in the tileset
	tsReversi.Load(lpdd,"IsoHex10_4.bmp");

	//clear the board
	SetUpBoard();
	//set game state
	iGameState=GS_NONE;

	//set initial AI levels
	iAILevel[0]=AI_HUMAN;
	iAILevel[1]=AI_RANDOM;

	return(true);//return success
}

//////////////////////////////////////////////////////////////////////////////
//CLEANUP
//////////////////////////////////////////////////////////////////////////////
void Prog_Done()
{	
	//release primary
	LPDDS_Release(&lpddsMain);

	//release ddraw
	LPDD_Release(&lpdd);
}

//////////////////////////////////////////////////////////////////////////////
//MAIN GAME LOOP
//////////////////////////////////////////////////////////////////////////////
void Prog_Loop()
{
	//clear out back buffer
	DDBLTFX ddbltfx;
	DDBLTFX_ColorFill(&ddbltfx,0);
	lpddsBack->Blt(NULL,NULL,NULL,DDBLT_WAIT | DDBLT_COLORFILL,&ddbltfx);

	switch(iGameState)
	{
		case GS_WAITFORINPUT:
			{
				//make move appropriate to the AI
				switch(iAILevel[iPlayer])
				{
				case AI_RANDOM:
					{
						MakeRandomMove(iPlayer);
					}break;
				case AI_GREEDY:
					{
						MakeGreedyMove(iPlayer);
					}break;
				case AI_MISER:
					{
						MakeMiserMove(iPlayer);
					}break;
				}
			}break;
		case GS_NEWGAME:
			{
				//clear the board
				SetUpBoard();

				//set player
				iPlayer=PLAYERTWO;

				//change gamestate
				iGameState=GS_NEXTPLAYER;
			}break;
		case GS_NEXTPLAYER:
			{
				//scan for moves
				ScanForMoves(iPlayer);

				//if no more valid moves, game over
				if((!AnyValidMoves(PLAYERTWO))  && (!AnyValidMoves(PLAYERONE)))
				{
					iGameState=GS_NONE;
				}
				else
				{
					//find if opponent has any moves
					if(AnyValidMoves(1-iPlayer))
					{
						iPlayer=1-iPlayer;
					}

					//scan for moves by current player
					ScanForMoves(iPlayer);

					//get next move
					iGameState=GS_WAITFORINPUT;
				}
			}break;
		case GS_FLIP:
			{
				switch(iPlayer)
				{
				case PLAYERTWO:
					{
						if(iAnimation==0)
						{
							FinishMove(iPlayer);
							iGameState=GS_NEXTPLAYER;
						}
						else
						{
							iAnimation--;
						}
					}break;
				case PLAYERONE:
					{
						if(iAnimation==14)
						{
							FinishMove(iPlayer);
							iGameState=GS_NEXTPLAYER;
						}
						else
						{
							iAnimation++;
						}
					}break;
				}
			}break;
	}
	
	//show the board
	ShowBoard();

	//show the scores
	ShowScores();

	//show players
	ShowPlayers();

	//flip
	lpddsMain->Flip(NULL,DDFLIP_WAIT);
}

void SaveBoard()
{
	//loop through board squares
	for(int x=0;x<8;x++)
	{
		for(int y=0;y<8;y++)
		{
			//save square to backup
			BackUpBoard[x][y]=Board[x][y];
		}
	}
}

void RestoreBoard()
{
	//loop through board squares
	for(int x=0;x<8;x++)
	{
		for(int y=0;y<8;y++)
		{
			//restore from backup
			Board[x][y]=BackUpBoard[x][y];
		}
	}
}

void SetUpBoard()
{
	//loop through board squares
	for(int x=0;x<8;x++)
	{
		for(int y=0;y<8;y++)
		{
			//setup board square
			Board[x][y].bHilite=false;
			Board[x][y].iTileNum=0;
			Board[x][y].iPiece=PIECEEMPTY;
			Board[x][y].bLastMove=false;
		}
	}

	//place initial pieces
	Board[3][3].iPiece=PIECEWHITE;
	Board[4][4].iPiece=PIECEWHITE;
	Board[3][4].iPiece=PIECEBLACK;
	Board[4][3].iPiece=PIECEBLACK;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?