/*
* Copyright (c) 2007,秦坤明
* 简要说明:不用太多说明,这个经典游戏想必各位肯定都玩过。
*
* 文件名称:Main.cpp
* 摘 要:
*/
#include<windows.h>
#define tDown 1
#define tPaint 2
#define tDownTime 500
#define tPaintTime 50
#define MAX_X 14
#define MAX_Y 24
#define MAX_CLASS 7
#define LEN 20
#define StartX -1 * LEN + 5
#define StartY -1 * LEN + 5
int Map[MAX_X][MAX_Y];
int CurrentBox[4][4];
int CurrentX, CurrentY;
int NextBox[4][4];
int Box[MAX_CLASS][4][4] = { /*MAX_C(7)种预定义的盒子*/
{
{0,0,0,0},
{1,1,1,1},
{0,0,0,0},
{0,0,0,0}
},
{
{0,0,0,0},
{0,1,0,0},
{1,1,1,0},
{0,0,0,0},
},
{
{0,0,0,0},
{1,1,0,0},
{0,1,1,0},
{0,0,0,0},
},
{
{0,0,0,0},
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
},
{
{0,1,1,0},
{0,0,1,0},
{0,0,1,0},
{0,0,0,0}
},
{
{0,1,1,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,0,0,0},
{0,1,1,0},
{0,1,1,0},
{0,0,0,0},
}
};
void InitMap() ;
int NewFall() ;
void BuildNextBox() ;
int Test(int x, int y, int box[4][4]) ;
int Drop() ;
void PutBox() ;
int Move(int Right) ;
void Clear() ;
int Rotate() ;
void RotateTest(int Box1[4][4], int Box2[4][4]) ;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Russion") ;
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 ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("俄罗斯方块单机版"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
(MAX_X + 3) * LEN, MAX_Y * LEN,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return (int)msg.wParam ;
}
void InitMap() //初始化地图,左右边和底边一行全"1",顶部为"0"
{
int x, y;
for(x = 0; x < MAX_X; x++)
{
for(y = 0; y < MAX_Y; y++)
{
if(x < 1 || x > MAX_X - 2 || y > MAX_Y - 2)
Map[x][y] = 1 ;
else
Map[x][y] = 0 ;
}
}
}
int NewFall() //根据下一个方格形状生成当前方格并设置其初始位置
{
int x, y ;
CurrentY = 0 ;
CurrentX = MAX_X / 2 - 2 ;
for(x = 0; x < 4; x++)
{
for(y = 0; y < 4; y++)
{
CurrentBox[x][y] = NextBox[x][y];
}
}
BuildNextBox();
return Test(CurrentX, CurrentY, CurrentBox);
}
void BuildNextBox() //构建下一个方格形状
{
int i, x, y ;
i = rand()%MAX_CLASS ;
for(x = 0; x < 4; x++)
{
for(y = 0; y < 4; y++)
{
NextBox[x][y] = Box[7][x][y] ;
}
}
}
int Test(int x, int y, int box[4][4]) //测试方格当前位置是否超越边界
{
int tmpx, tmpy ;
for(tmpx = 0; tmpx < 4; tmpx++)
{
for(tmpy = 0; tmpy < 4; tmpy++)
{
if(Map[tmpx + x][tmpy + y] && box[tmpx][tmpy])
{
return 0 ;
}
}
}
return 1 ;
}
int Drop() //下落一格
{
int NewY ;
NewY = CurrentY + 1 ;
if(Test(CurrentX, NewY, CurrentBox))
{
CurrentY = NewY ;
return 1 ;
}
return 0 ;
}
void PutBox() //方块落到底部后将其写入到地图中
{
int x, y ;
for(x = 0; x < 4; x++)
{
for(y = 0; y < 4; y++)
{
if(CurrentBox[x][y])
Map[CurrentX + x][CurrentY + y] = CurrentBox[x][y] ;
}
}
}
int Move(int Right) //左右移动
{
int x ;
if(Right)
x = CurrentX + 1;
else
x = CurrentX - 1;
if(Test(x, CurrentY, CurrentBox))
{
CurrentX = x ;
return 1 ;
}
return 0 ;
}
void Clear() //方块下落到底部后清除满行
{
int x, y ;
int DelX, DelY ;
int Full ;
for(y = 0; y < MAX_Y - 1; y++)
{
Full = 1 ;
for(x = 1; x < MAX_X - 1; x++)
{
if(!Map[x][y])
{
Full = 0 ;
break ;
}
}
if(Full)
{
for(DelY = y; DelY > 0; DelY--) //删除满行
for(DelX = 1; DelX < MAX_X - 1; DelX++)
Map[DelX][DelY] = Map[DelX][DelY - 1] ;
for(DelX = 1; DelX < MAX_X - 1; DelX++) //清除第一行
Map[DelX][0] = 0 ;
}
}
}
int Rotate() //旋转
{
int x, y ;
int TmpBox[4][4] ;
RotateTest(CurrentBox, TmpBox) ;
if(Test(CurrentX, CurrentY, TmpBox))
{
for(x = 0; x < 4; x++)
for(y = 0; y < 4; y++)
CurrentBox[x][y] = TmpBox[x][y] ;
return 1 ;
}
else
{
return 0 ;
}
}
void RotateTest(int Box1[4][4], int Box2[4][4]) //旋转测试
{
int x, y ;
for(x = 0; x < 4; x++)
for(y = 3; y >=0; y--)
Box2[y][x] = Box1[x][3 - y] ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc, hdcMem ;
int x, y ;
PAINTSTRUCT ps ;
HBITMAP hBitMap ;
HPEN hPen ;
HBRUSH hBrush ;
static int cxClient, cyClient ;
switch (message)
{
case WM_CREATE:
SetTimer(hwnd, tDown, tDownTime, NULL) ;
SetTimer(hwnd, tPaint, tPaintTime, NULL) ;
InitMap() ;
BuildNextBox() ;
NewFall() ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_TIMER:
switch(wParam)
{
case tDown:
MessageBeep (-1) ;
if(!Drop())
{
PutBox() ; //落到底后将现有box加入map中
Clear() ;
if(!NewFall())
{
PostMessage(hwnd, WM_CLOSE, NULL, NULL) ;
}
}
break ;
case tPaint:
InvalidateRect (hwnd, NULL, FALSE) ; //为TRUE擦除背景,FALSE不擦除
break ;
}
case WM_KEYDOWN:
switch(wParam)
{
case VK_LEFT:
MessageBeep (-1) ;
Move(0) ;
break ;
case VK_RIGHT:
MessageBeep (-1) ;
Move(1) ;
break ;
case VK_UP:
MessageBeep (-1) ;
Rotate() ;
break ;
case VK_DOWN:
MessageBeep (-1) ;
Drop() ;
break ;
case VK_SPACE:
while(1)
{
if(!Drop())
{
PutBox() ;
Clear() ;
if(!NewFall())
PostMessage(hwnd, WM_CLOSE, NULL, NULL) ;
break ;
}
}
}
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps) ;
hdcMem = CreateCompatibleDC(hdc) ; //利用内存画图实现双缓冲,避免屏幕闪烁
hBitMap = CreateCompatibleBitmap(hdc, cxClient, cyClient) ;
SelectObject(hdcMem, hBitMap) ;
Rectangle(hdcMem, StartX + LEN * 1 - 1, StartY + LEN * 1 - 1,
StartX + LEN * (MAX_X - 1) + 1, StartY + LEN * (MAX_Y - 1) + 1) ;
hPen = CreatePen(PS_SOLID, 1, RGB(240, 240, 240)) ;
SelectObject(hdcMem, hPen) ;
hBrush = CreateSolidBrush(RGB(250, 250, 250)) ;
SelectObject(hdcMem, hBrush) ;
for(x = 1; x < MAX_X - 1; x++) //画背景
{
for(y = 1; y < MAX_Y - 1; y++)
{
Rectangle(hdcMem, StartX + LEN * x, StartY + LEN * y,