这里编译时没开XP支持,所以不兼容XP。XP用户可以用Visual Studio 2010自己编译一下。
引用
评论
// OOXX.cpp : Defines the entry point for the console application.
//
//#include "stdafx.h"
#define UNICODE 1
#include <windows.h>
#include <windowsx.h> // HANDLE_MSG
HWND hMainWnd;
int data[3][3] = { 0 };
int status = 1;
RECT rects[3][3] = {
0, 0, 100, 100,
100, 0, 200, 100,
200, 0, 300, 100,
0, 100, 100, 200,
100, 100, 200, 200,
200, 100, 300, 200,
0, 200, 100, 300,
100, 200, 200, 300,
200, 200, 300, 300,
};
void DrawHash(HDC hdc, RECT firstrc) // 绘制边线
{
int width = firstrc.right - firstrc.left;
int height = firstrc.bottom - firstrc.top;
MoveToEx(hdc, firstrc.left, firstrc.bottom, NULL);
LineTo(hdc, firstrc.left + 3 * width, firstrc.bottom);
MoveToEx(hdc, firstrc.left, firstrc.bottom + height, NULL);
LineTo(hdc, firstrc.left + 3 * width, firstrc.bottom + height);
MoveToEx(hdc, firstrc.right, firstrc.top, NULL);
LineTo(hdc, firstrc.right, firstrc.top + 3 * height);
MoveToEx(hdc, firstrc.right + width, firstrc.top, NULL);
LineTo(hdc, firstrc.right + width, firstrc.top + 3 * height);
}
void DrawO(HDC hdc, RECT rc) // 绘制O
{
Ellipse(hdc, rc.left + 10, rc.top + 10, rc.right - 10, rc.bottom - 10);
}
void DrawX(HDC hdc, RECT rc) // 绘制X
{
MoveToEx(hdc, rc.left, rc.top, NULL);
LineTo(hdc, rc.right, rc.bottom);
MoveToEx(hdc, rc.right, rc.top, NULL);
LineTo(hdc, rc.left, rc.bottom);
}
void MainWnd_OnPaint(HWND hwnd)
{
// WM_PAINT界面重绘消息
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps); // 开始重绘
DrawHash(hdc, rects[0][0]); // 绘制边线
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++) // 绘制棋子
{
if (data[j][k] == 1)
DrawO(hdc, rects[j][k]);
else if (data[j][k] == 2)
DrawX(hdc, rects[j][k]);
}
}
EndPaint(hwnd, &ps); // 结束重绘
}
void DropOX(HWND hwnd, int j, int k) // 落子
{
if (data[j][k] == 0) // 如果这个位置没有棋子
{
data[j][k] = status; // 落子
if (status == 1)
status = 2; // 换对手
else
status = 1;
InvalidateRect(hwnd, NULL, FALSE); // 绘制棋子
}
}
void WinGame(HWND hwnd, int winner) // 显示胜负并重新开局
{
switch (winner)
{
case 0:
MessageBox(hwnd, L"No one won the game.", L"Result", MB_OK);
break;
case 1:
MessageBox(hwnd, L"'O' won the game.", L"Result", MB_OK);
break;
case 2:
MessageBox(hwnd, L"'X' won the game.", L"Result", MB_OK);
break;
}
memset(data, 0, sizeof data); // 重新开局
InvalidateRect(hwnd, NULL, TRUE); // 重新绘制界面
}
void DetectWinner(HWND hwnd) // 检测是否有胜出
{
if (data[0][0] != 0
&& data[0][0] == data[1][1]
&& data[1][1] == data[2][2])
return WinGame(hwnd, data[0][0]); // 正对角线
if (data[0][2] != 0
&& data[0][2] == data[1][1]
&& data[1][1] == data[2][0])
return WinGame(hwnd, data[0][2]); // 反对角线
for (int j = 0; j < 3; j++)
{
if (data[0][j] != 0
&& data[0][j] == data[1][j]
&& data[1][j] == data[2][j])
return WinGame(hwnd, data[0][j]); // 横向
if (data[j][0] != 0
&& data[j][0] == data[j][1]
&& data[j][1] == data[j][2])
return WinGame(hwnd, data[j][0]); // 纵向
}
int zeros = 0;
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++) // 计数空位
if (data[j][k] == 0)
zeros++;
if (zeros == 0) // 如果全部下满
{
int ones = 0, twos = 0;
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++) // 计数两种棋子
{
if (data[j][k] == 1)
ones++;
else if (data[j][k] == 2)
twos++;
}
if (ones > twos)
return WinGame(hwnd, 1); // 圈多于叉
else if (twos > ones)
return WinGame(hwnd, 2); // 叉多余圈
else
return WinGame(hwnd, 0); // 相等(实际不可能出现)
}
}
void MainWnd_OnLButtonDown(HWND hwnd, BOOL dblclk, int x, int y, UINT vkey)
{
// WM_LBUTTONDOWN鼠标按下消息
POINT pt = { x, y };
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
if (PtInRect(&rects[j][k], pt)) // 如果在落子区域按下
{
DropOX(hwnd, j, k); // 落子
DetectWinner(hwnd); // 检测是否有胜出
}
}
}
}
BOOL MainWnd_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
// WM_CREATE窗口创建消息
RECT rcwindow, rcclient;
GetWindowRect(hwnd, &rcwindow);
GetClientRect(hwnd, &rcclient);
rcwindow.right += 300 - (rcclient.right - rcclient.left);
rcwindow.bottom += 300 - (rcclient.bottom - rcclient.top);
MoveWindow(hwnd, rcwindow.left, rcwindow.top,
rcwindow.right - rcwindow.left,
rcwindow.bottom - rcwindow.top, FALSE); // 保证客户区为300x300
return TRUE;
}
void MainWnd_OnDestroy(HWND hwnd)
{
// WM_DESTROY窗口销毁消息
PostQuitMessage(0);
}
LRESULT CALLBACK MainWnd_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// WndProc窗口消息处理函数
switch (message)
{
HANDLE_MSG(hwnd, WM_CREATE, MainWnd_OnCreate);
HANDLE_MSG(hwnd, WM_DESTROY, MainWnd_OnDestroy);
HANDLE_MSG(hwnd, WM_PAINT, MainWnd_OnPaint);
HANDLE_MSG(hwnd, WM_LBUTTONDOWN, MainWnd_OnLButtonDown);
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR lpszCmdLine, int nCmdShow)
{
// wWinMain入口点
WNDCLASSEX wc = {
sizeof wc,
CS_HREDRAW | CS_VREDRAW, // 窗口显示方式
MainWnd_WndProc, // 窗口消息处理函数
0, 0, // 类附加数据、窗口附加数据
NULL, // 模块句柄(EXE模块可NULL)
LoadIcon(NULL, IDI_APPLICATION), // 图标
LoadCursor(NULL, IDC_ARROW), // 鼠标指针
(HBRUSH)GetStockObject(WHITE_BRUSH), // 背景画刷
NULL, // 菜单
L"MyOOXXClass", // 窗口类名
LoadIcon(NULL, IDI_APPLICATION) // 小图标
};
RegisterClassEx(&wc); // 注册窗口类
hMainWnd = CreateWindowEx( // 创建窗口
WS_EX_OVERLAPPEDWINDOW, // 扩展风格
L"MyOOXXClass", L"OOXX", // 窗口类,窗口标题
WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, // 基本风格
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, // 四角坐标
NULL, NULL, NULL, NULL); // 父窗口,菜单或序号,模块句柄,附加信息
ShowWindow(hMainWnd, nCmdShow); // 显示窗口
UpdateWindow(hMainWnd); // 刷新窗口
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) // 获取消息(同时分发高优先级消息)
{
TranslateMessage(&msg); // 翻译键盘消息
DispatchMessage(&msg); // 分发消息
}
return (int)msg.wParam; // 收到WM_QUIT,GetMessage返回FALSE退出
}</windowsx.h></windows.h>