// gobang.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#include "math.h"
#define MAX_LOADSTRING 100
//全局变量:
HINSTANCE hInst;
HBITMAP chess[2];
HDC hdc,mdc,bufdc;
HWND hWnd;
DWORD tPre,tNow;
int board[10][10];
bool ptab[10][10][192];
bool ctab[10][10][192];
int win[2][192];
int num[2];
bool turn,over;
int winner;
//TCHAR szTitle[MAX_LOADSTRING];
//TCHAR szWindowClass[MAX_LOADSTRING];
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
//函数声明
void MyPaint(HDC hdc);
void InitGame();
void ComTurn();
//****WIN MIAN*************************************
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance);
//
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
//
while( msg.message!=WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
tNow = GetTickCount();
if(tNow-tPre >= 100)
MyPaint(hdc);
}
}
return msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_GOBANG);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_GOBANG;
wcex.lpszClassName = "canvas";//窗口名称
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HBITMAP tile,bmp;
int rowNum,colNum;
int i,x,y;
hInst = hInstance;
hWnd = CreateWindow("canvas",
"五子棋人机对弈" ,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
0,
CW_USEDEFAULT,
0,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd)
{
return FALSE;
}
MoveWindow(hWnd,10,10,480,520,true);
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
hdc = GetDC(hWnd);
mdc = CreateCompatibleDC(hdc);
bufdc = CreateCompatibleDC(hdc);
bmp = CreateCompatibleBitmap(hdc,450,450);
SelectObject(mdc,bmp);
tile = (HBITMAP)LoadImage(NULL,"tile.bmp",IMAGE_BITMAP,45,45,LR_LOADFROMFILE);
chess[0] = (HBITMAP)LoadImage(NULL,"chess0.bmp",IMAGE_BITMAP,38,38,LR_LOADFROMFILE);
chess[1] = (HBITMAP)LoadImage(NULL,"chess1.bmp",IMAGE_BITMAP,38,38,LR_LOADFROMFILE);
//地图拼接
for (i=0;i<100;i++)
{
rowNum = i / 10;
colNum = i % 10;
x = colNum * 45;
y = rowNum * 45;
SelectObject(bufdc,tile);
BitBlt(mdc,x,y,45,45,bufdc,0,0,SRCCOPY);
}
InitGame();
MyPaint(hdc);
return TRUE;
}
//*******棋局初始函数*********************************
void InitGame()
{
int i,j,k;
int count=0;
over = false;
num[0] = num[1] = 0;
//设定玩家与计算机在各个获胜组合中的棋子数
for(i=0;i<192;i++)
{
win[0][i] = 0;
win[1][i] = 0;
}
//初始化棋盘状态
for(i=0;i<10;i++)
for(j=0;j<10;j++)
board[i][j] = 2;
//设定水平方向的获胜组合
for(i=0;i<10;i++)
for(j=0;j<6;j++)
{
for(k=0;k<5;k++)
{
ptab[i][j+k][count] = true;
ctab[i][j+k][count] = true;
}
count++;
}
//设定垂直方向的获胜组合
for(i=0;i<10;i++)
for(j=0;j<6;j++)
{
for(k=0;k<5;k++)
{
ptab[j+k][i][count] = true;
ctab[j+k][i][count] = true;
}
count++;
}
//设定正对角线方向的获胜组合
for(i=0;i<6;i++)
for(j=0;j<6;j++)
{
for(k=0;k<5;k++)
{
ptab[j+k][i+k][count] = true;
ctab[j+k][i+k][count] = true;
}
count++;
}
//设定反对角线上的获胜组合
for(i=0;i<6;i++)
for(j=9;j>=4;j--)
{
for(k=0;k<5;k++)
{
ptab[j-k][i+k][count] = true;
ctab[j-k][i+k][count] = true;
}
count++;
}
//随机数决定由那一方先下
srand(GetTickCount());
if(rand()%2 == 0)
turn = true;
else
turn = false;
}
//*******计算机下棋函数*******************************
void ComTurn()
{
int grades[2][10][10];
int m,n,i,max=0;
int u,v;
for(m=0;m<10;m++)
for(n=0;n<10;n++)
{
grades[0][m][n] = 0;
grades[1][m][n] = 0;
if(board[m][n] == 2)
{
for(i=0;i<192;i++)
{
//计算玩家在空位置上的获胜分数
if(ptab[m][n][i] && win[0][i] != 7)
{
switch(win[0][i])
{
case 0:
grades[0][m][n]+=1;
break;
case 1:
grades[0][m][n]+=200;
break;
case 2:
grades[0][m][n]+=400;
break;
case 3:
grades[0][m][n]+=2000;
break;
case 4:
grades[0][m][n]+=10000;
break;
}
}
//计算计算机在空位置上的获胜分数
if(ctab[m][n][i] && win[1][i] != 7)
{
switch(win[1][i])
{
case 0:
grades[1][m][n]+=1;
break;
case 1:
grades[1][m][n]+=220;
break;
case 2:
grades[1][m][n]+=420;
break;
case 3:
grades[1][m][n]+=2100;
break;
case 4:
grades[1][m][n]+=20000;
break;
}
}
}
if(max == 0)
{
u = m;
v = n;
}
if(grades[0][m][n] > max)
{
max = grades[0][m][n];
u = m;
v = n;
}
else if(grades[0][m][n] == max)
{
if(grades[1][m][n] > grades[1][u][v])
{
u = m;
v = n;
}
}
if(grades[1][m][n] > max)
{
max = grades[1][m][n];
u = m;
v = n;
}
else if(grades[1][m][n] == max)
{
if(grades[0][m][n] > grades[0][u][v])
{
u = m;
v = n;
}
}
}
}
board[u][v] = 1; //设定为计算机的棋子数
num[1]++;
if(num[0] == 50 && num[1] == 50)
{
winner = 2; //平手
over = true;
}
else
for(i=0;i<192;i++)
{
if(ctab[u][v][i])
{
win[1][i]++;
ptab[u][v][i] = false;
win[0][i] = 7;
if(win[1][i] == 5)
{
winner = 1;
over = true;
}
}
}
turn = true; //换由玩家下
}
void MyPaint(HDC hdc)
{
int m,n;
char *str;
if(over)
{
switch(winner)
{
case 0:
str = "您赢了! 按下[F1]键可重新开始..";
break;
case 1:
str = "计算机赢了! 按下[F1]键可重新开始..";
break;
case 2:
str = "平局! 按下[F1]键可重新开始..";
break;
}
TextOut(hdc,10,470,str,strlen(str));
}
else if(!turn) //计算机下棋
{
str = "计算机思考中... ";
TextOut(hdc,10,470,str,strlen(str));
ComTurn();
}
else
{
str = "该您下了... ";
TextOut(hdc,10,470,str,strlen(str));
}
for(m=0;m<10;m++)
for(n=0;n<10;n++)
{
if(board[m][n] == 0) //贴上玩家棋子
{
SelectObject(bufdc,chess[0]);
BitBlt(mdc,m*45+3,n*45+3,38,38,bufdc,0,0,SRCCOPY);
}
else if(board[m][n] == 1) //贴上计算机棋子
{
SelectObject(bufdc,chess[1]);
BitBlt(mdc,m*45+3,n*45+3,38,38,bufdc,0,0,SRCCOPY);
}
else //贴上空格
{
SelectObject(bufdc,chess[1]);
BitBlt(mdc,m*45+3,n*45+3,38,38,bufdc,0,0,WHITENESS);
}
}
BitBlt(hdc,10,10,450,450,mdc,0,0,SRCCOPY);
tPre = GetTickCount();
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int x,y,m,n,i;
switch (message)
{
case WM_KEYDOWN: //按下按键消息
switch (wParam)
{
case VK_ESCAPE: //按下ESC键
PostQuitMessage( 0 );
break;
case VK_F1: //按下F1键
InitGame();
break;
}
case WM_LBUTTONDOWN: //单击鼠标左键消息
if(!over)
if(turn)
{
x = LOWORD(lParam); //取得鼠标X坐标
y = HIWORD(lParam); //取得鼠标Y坐标
if(x> 10 && x < 460 && y> 10 && y < 460)
{
m = (int)floor((x-10)/45);
n = (int)floor((y-10)/45);
if(board[m][n] == 2)
{
board[m][n] = 0; //设定为玩家下的棋子
num[0]++;
if(num[0] == 50 && num[1] == 50)
{
winner = 2; //判断平局
over = true;
}
else
for(i=0;i<192;i++)
{
if(ptab[m][n][i])
{
win[0][i]++;
ctab[m][n][i] = false;
win[1][i] = 7;
if(win[0][i] == 5)
{
winner = 0;
over = true;
}
}
}
turn = false; //换由计算机下
}
}
}
break;
case WM_DESTROY: //窗口结束消息
DeleteDC(mdc);
DeleteDC(bufdc);
DeleteObject(chess[0]);
DeleteObject(chess[1]);
ReleaseDC(hWnd,hdc);
PostQuitMessage(0);
break;
default: //其他消息
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}