1)添加键盘响应,通过键盘控制标框位置并安放棋子;
2)修改了消息框,不在是单次游玩;
3)代码:
#include<Windows.h>
#include<windowsx.h>
#include<strsafe.h>
//回调函数,windows自己调用
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int End();
void DrawBox(HDC hdc, int x, int y);
void Return();
//窗口初始宽高,宽高比
#define w_h 1.28
int hight = 600;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("MyWindows");
HWND hWnd; //句柄
MSG msg; //消息
WNDCLASS wndClass; //窗口类
//设置窗口类的各项数据
wndClass.style = CS_HREDRAW | CS_VREDRAW; //调整窗口大小时是否重绘
wndClass.lpfnWndProc = WndProc; //回调函数
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance; //实例句柄
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //图标
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); //光标
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szAppName;
//注册该窗口类
if (!RegisterClass(&wndClass))
{
MessageBox(NULL, TEXT("这个程序需要在windowsNT才能执行!"), szAppName, MB_ICONERROR);
return 0;
}
//设置窗口具体特征(分化)
hWnd = CreateWindow(szAppName, TEXT("五子棋"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, (int)(hight*w_h), hight,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
//消息循环,windows核心
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg); //调用窗口过程函数(回调函数)
}
return msg.wParam;
}
//棋盘范围
RECT chess;
//棋盘点
typedef struct CHESS
{
LONG x;
LONG y;
int c; //颜色
}Chess[15][15];
Chess ptChess;
//棋子宽度
LONG pieceWidth;
//棋子颜色\胜手
#define UNKNOW 0
#define BLACK 1
#define WHITE 2
//平局
#define LEVEL 3
//棋子
typedef struct PIECE
{
int i;
int j;
int color;
}Piece[255];
Piece pieces;
int ip = 0;
//当前手的棋子颜色
int nowColor = BLACK;
void Reverse()
{
switch (nowColor)
{
case WHITE:
nowColor = BLACK;
break;
case BLACK:
nowColor = WHITE;
break;
}
}
//控制台
RECT contralRect;
//标框,标识棋盘点位,响应键盘鼠标
struct BOX
{
int i, j;
}box;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static int cxClient, cyClient;
static HBRUSH hOldBrush, hBlackBrush, hWhiteBrush;
static HPEN hOldPen, hRedPen;
POINT ptClick;
TCHAR szBuffer[30] = TEXT("%s棋赢了!\n是否开始下一局?"), szDest[30];
int i, j;
switch (message)
{
case WM_CREATE:
//创建画刷,画笔
hBlackBrush = CreateSolidBrush(RGB(0, 0, 0));
hWhiteBrush = CreateSolidBrush(RGB(255, 255, 255));
hRedPen = CreatePen(PS_ALTERNATE, 2, RGB(255, 0, 0));
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
//获取棋子宽度
pieceWidth = min(cxClient, cyClient) / 18;
//获取棋盘点
for (int i = 0; i < 15; ++i)
{
for (int j = 0; j < 15; ++j)
{
ptChess[i][j].x = pieceWidth*(i + 2);
ptChess[i][j].y = pieceWidth*(j + 2);
}
}
//棋盘范围
SetRect(&chess, pieceWidth, pieceWidth, pieceWidth * 17, pieceWidth * 17);
//获取控制板
contralRect.left = pieceWidth * 18;
contralRect.bottom = cyClient - pieceWidth * 2;
contralRect.right = cxClient-pieceWidth*2;
contralRect.top = pieceWidth * 2;
//获取标框
box.i = 7;
box.j = 7;
return 0;
case WM_LBUTTONDOWN:
if (wParam != 0) //消息来自鼠标
{ //获取单击位置
ptClick.x = GET_X_LPARAM(lParam);
ptClick.y = GET_Y_LPARAM(lParam);
//计算棋子安放位置
i = (ptClick.x + pieceWidth / 2) / pieceWidth - 2;
j = (ptClick.y + pieceWidth / 2) / pieceWidth - 2;
}
else //消息来自键盘
{
i = box.i;
j = box.j;
}
//判断棋子安放位置是否合理
if (i < 0 || i>14 || j < 0 || j>14 || ptChess[i][j].c != UNKNOW)
{
return 0;
}
//载入棋子队列
pieces[ip].i = i;
pieces[ip].j = j;
pieces[ip].color = nowColor;
ptChess[i][j].c = nowColor;
Reverse();
ip++;
if (wParam != 0)
{
//标框移动
box.i = i;
box.j = j;
}
//重绘
InvalidateRect(hWnd, &chess, TRUE);
return 0;
case WM_RBUTTONDOWN:
if (ip == 0)
{
return 0;
}
ip--;
i = pieces[ip].i;
j = pieces[ip].j;
//值回溯
ptChess[i][j].c = UNKNOW;
pieces[ip].i = 0;
pieces[ip].j = 0;
pieces[ip].color = UNKNOW;
//当前手颜色回复
Reverse();
//标框复位
if (ip == 0)
{
box.i = 7;
box.j = 7;
}
else
{
box.i = pieces[ip - 1].i;
box.j = pieces[ip - 1].j;
}
//重绘
InvalidateRect(hWnd, &chess, TRUE);
return 0;
case WM_KEYDOWN:
switch (wParam)
{
case VK_UP: box.j--; break;
case VK_DOWN: box.j++; break;
case VK_LEFT: box.i--; break;
case VK_RIGHT: box.i++; break;
case VK_RETURN:
case VK_SPACE:
SendMessage(hWnd, WM_LBUTTONDOWN, 0, 0);
break;
case VK_DELETE:
SendMessage(hWnd, WM_RBUTTONDOWN, 0, 0);
break;
}
box.i = (box.i + 15) % 15;
box.j = (box.j + 15) % 15;
InvalidateRect(hWnd, &chess, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
//绘制棋盘
for (int i = 0; i < 15; ++i)
{
MoveToEx(hdc, ptChess[i][0].x, ptChess[i][0].y, NULL);
LineTo(hdc, ptChess[i][14].x, ptChess[i][14].y);
}
for (int j = 0; j < 15; ++j)
{
MoveToEx(hdc, ptChess[0][j].x, ptChess[0][j].y, NULL);
LineTo(hdc, ptChess[14][j].x, ptChess[14][j].y);
}
//绘制控制板
FrameRect(hdc, &contralRect, hBlackBrush);
//绘制标框
hOldPen = SelectObject(hdc, hRedPen);
i = ptChess[box.i][box.j].x;
j = ptChess[box.i][box.j].y;
DrawBox(hdc,i,j);
SelectObject(hdc, hOldPen);
//绘制棋子
hOldBrush = SelectObject(hdc, hBlackBrush);
for (int i = 0, j = 0, k = 0; k < ip; ++k)
{
if (pieces[k].color == UNKNOW)
continue;
if (pieces[k].color == BLACK)
SelectObject(hdc, hBlackBrush);
if (pieces[k].color == WHITE)
SelectObject(hdc, hWhiteBrush);
int i = pieces[k].i, j = pieces[k].j;
Ellipse(hdc, ptChess[i][j].x - pieceWidth / 2, ptChess[i][j].y - pieceWidth / 2, ptChess[i][j].x + pieceWidth / 2, ptChess[i][j].y + pieceWidth / 2);
}
SelectObject(hdc, hOldBrush);
//判断五子连珠
switch (End())
{
case WHITE:
SendMessage(hWnd, WM_CLOSE, WHITE, 0);
break;
case BLACK:
SendMessage(hWnd, WM_CLOSE, BLACK, 0);
break;
}
//判断棋盘占满
if (ip == 255)
{
SendMessage(hWnd, WM_CLOSE, LEVEL, 0);
}
EndPaint(hWnd, &ps);
return 0;
case WM_CLOSE:
switch (wParam)
{
case WHITE:
StringCchPrintf(szDest, 30, szBuffer, TEXT("白"));
if (MessageBox(hWnd, szDest, TEXT("GameOver"), MB_YESNO) == IDNO)
DestroyWindow(hWnd);
else
{
Return();
InvalidateRect(hWnd, &chess, TRUE);
}
break;
case BLACK:
StringCchPrintf(szDest, 30, szBuffer, TEXT("黑"));
if (MessageBox(hWnd, szDest, TEXT("GameOver"), MB_YESNO) == IDNO)
DestroyWindow(hWnd);
else
{
Return();
InvalidateRect(hWnd, &chess, TRUE);
}
break;
case LEVEL:
StringCchPrintf(szDest, 30, TEXT("平局!"));
if (MessageBox(hWnd, szDest, TEXT("GameOver"), MB_YESNO) == IDNO)
DestroyWindow(hWnd);
else
{
Return();
InvalidateRect(hWnd, &chess, TRUE);
}
break;
default:
StringCchPrintf(szDest, 30, TEXT("对局尚未结束,是否离开游戏?"));
if (MessageBox(hWnd, szDest, TEXT("End"), MB_YESNO) == IDYES)
DestroyWindow(hWnd);
break;
}
return 0;
case WM_DESTROY:
DeleteObject(hWhiteBrush);
DeleteObject(hBlackBrush);
DeleteObject(hRedPen);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
//判断五子连珠
int End()
{
int current = ip - 1;
if (current < 8)
{
return UNKNOW;
}
int iTarget, i, j, x, y, color;
i = pieces[current].i;
j = pieces[current].j;
color = pieces[current].color;
//判断横向
x = max(i - 4, 0);
y = j;
iTarget = 0;
for (; x <= min(i + 4, 14); ++x)
{
if (ptChess[x][y].c == color)
{
++iTarget;
if (iTarget == 5)
{
return color;
}
}
else iTarget = 0;
}
//判断纵向
x = i;
y = max(j - 4, 0);
iTarget = 0;
for (; y <= min(j + 4, 14); ++y)
{
if (ptChess[x][y].c == color)
{
++iTarget;
if (iTarget == 5)
{
return color;
}
}
else iTarget = 0;
}
//判断斜向
x = i - 4;
y = j + 4;
//越界
if (x < 0 || y>14)
{
int temp = max(0 - x, y - 14);
x += temp;
y -= temp;
}
iTarget = 0;
for (; ( y >= max(j - 4, 0)) && (x <= min(14, i + 4)); ++x, --y)
{
if (ptChess[x][y].c == color)
{
++iTarget;
if (iTarget == 5)
{
return color;
}
}
else iTarget = 0;
}
x = i - 4;
y = j - 4;
if (x < 0 || y < 0)
{
int temp = max(0 - x, 0 - y);
x += temp;
y += temp;
}
iTarget = 0;
for (; (y <= min(j + 4, 14)) && (x <= min(14, i + 4)); ++x, ++y)
{
if (ptChess[x][y].c == color)
{
++iTarget;
if (iTarget == 5)
{
return color;
}
}
else iTarget = 0;
}
return UNKNOW;
}
//绘制标框
void DrawBox(HDC hdc,int x,int y)
{ //左上角
MoveToEx(hdc, x - pieceWidth / 2, y - pieceWidth / 2, NULL);
LineTo(hdc, x - pieceWidth / 4, y - pieceWidth / 2);
MoveToEx(hdc, x - pieceWidth / 2, y - pieceWidth / 2, NULL);
LineTo(hdc, x - pieceWidth / 2, y - pieceWidth / 4);
//右上角
MoveToEx(hdc, x + pieceWidth / 2, y - pieceWidth / 2, NULL);
LineTo(hdc, x + pieceWidth / 4, y - pieceWidth / 2);
MoveToEx(hdc, x + pieceWidth / 2, y - pieceWidth / 2, NULL);
LineTo(hdc, x + pieceWidth / 2, y - pieceWidth / 4);
//左下角
MoveToEx(hdc, x - pieceWidth / 2, y + pieceWidth / 2, NULL);
LineTo(hdc, x - pieceWidth / 4, y + pieceWidth / 2);
MoveToEx(hdc, x - pieceWidth / 2, y + pieceWidth / 2, NULL);
LineTo(hdc, x - pieceWidth / 2, y + pieceWidth / 4);
//右下角
MoveToEx(hdc, x + pieceWidth / 2, y + pieceWidth / 2, NULL);
LineTo(hdc, x + pieceWidth / 4, y + pieceWidth / 2);
MoveToEx(hdc, x + pieceWidth / 2, y + pieceWidth / 2, NULL);
LineTo(hdc, x + pieceWidth / 2, y + pieceWidth / 4);
}
//棋盘回复函数
void Return()
{
int i, j;
for (i = 0; i < 15; ++i)
{
for (j = 0; j < 15; ++j)
{
ptChess[i][j].c = UNKNOW;
pieces[i * 15 + j].i = 0;
pieces[i * 15 + j].j = 0;
pieces[i * 15 + j].color = UNKNOW;
}
}
ip = 0;
box.i = 7;
box.j = 7;
nowColor = BLACK;
}