#include
#include
#include
#include
#define tDown 1 //方块下落定时器的标识(编号)
#define tPaint 2 //重绘定时器的标识(编号)
#define tDownTime 500 //方块下落一行位置的时间间隔
#define tPaintTime 50 //窗口重绘的时间间隔
#define ROW 24 //地图的行数目(第23行不用)
#define COL 14 //地图的列数目(第0列和第13列不用)
#define MAX_CLASS 7 //方块形状数目
#define LEN 20 //每个方格大小为20×20像素
#define StartY -1 * LEN + 5 //-15,绘制俄罗斯方块地图时的边界起始位置
#define StartX -1 * LEN + 5 //-15
int iDeleteRows = 0; //总共清除的行
int iTotalNum = 0; //总得分
char WindowTxt[100] = "俄罗斯方块游戏 自动求解已关闭"; //窗口标题
char s1[] = "关闭", s2[] = "启动"; //用于启动/关闭自动求解功能时显示不同的标题
bool bAuto; //是否自动求解的标志
bool Pause; //是否暂停的标志
int Map[ROW][COL]; //俄罗斯方块的地图(被占据的方格为1,否则为0)
int CurrentBox[4][4]; //当前落下的方块
int CurrentY, CurrentX; //当前落下方块的当前位置(指左上角位置)
int NextBox[4][4]; //下一个将落下的方块
int Box[MAX_CLASS][4][4] = //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 y, int x, int box[4][4] ); //测试在(y,x)位置是否能放置方块box,能放置返回1,否则返回0
int Drop( ); //定时时间到,当前方块下降一行位置
void PutBox( ); //放置当前方块
int Move( int Right ); //(通过方向键)移动方块,参数right为1表示向右移动,为0表示向左移动
void Clear( ); //清除满足条件的行
int Rotate( ); //测试旋转是否可行,如果可行则旋转当前方块
int RotateTest( int Box1[4][4], int Box2[4][4] ); //旋转当前方块
int count1( int y, int x, int box[4][4] ); //新增函数
int BestStartX( ); //新增函数
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, WindowTxt,
WS_OVERLAPPED | WS_SYSMENU | WS_BORDER,
CW_USEDEFAULT, CW_USEDEFAULT,
(COL + 4) * LEN, //窗口宽度:(14+4)×20=360像素
ROW * LEN, //窗口高度:24×20=480像素(包括标题栏部分)
NULL, NULL, hInstance, NULL );
ShowWindow( hwnd, iCmdShow );
UpdateWindow( hwnd );
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return msg.wParam;
}
//初始化地图(将第0列和第13列、第23行设置为1(被占据),其他位置设置为0)
void InitMap( )
{
int y, x;
for( y = 0; y < ROW; y++ )
{
for( x = 0; x < COL; x++ )
{
//第0列、第13列、第23行设置为1(被占据)
if( x < 1 || x > COL - 2 || y > ROW - 2 )
Map[y][x] = 1;
else Map[y][x] = 0;
}
}
}
//计算在(y,x)位置(左上角位置)上放置方块box后空出的方格数
int count1( int y, int x, int box[4][4] )
{
if( !Test(y,x,box) ) return 100; //不能在(y,x)位置放置box,返回∞
if( Test(y+1,x,box) ) return 100; //如果box还能下降,也返回∞
int tmpy, tmpx;
int c = 0; //空出的方格数
for( tmpx = 0; tmpx < 4; tmpx++ ) //考虑第0~3列
{
for( tmpy = 3; tmpy >= 0; tmpy-- )
{
if( box[tmpy][tmpx] ) break;
}tmpy++;
if( tmpy>0 )
{
for( ; tmpy<4; tmpy++ )
{
if( tmpy+y<0 || tmpy+y>=ROW || tmpx+x<0 || tmpx+x>=COL ) continue;
if(!Map[tmpy+y][tmpx+x]) c++; //空出的方格
}
}
}
return c;
}
//当启动自动求解功能时,求下一个方块的最佳下降位置
//策略1为:放置后,空出的方格数最少,为MinC1,此时能达到最高位置为MaxY1,该位置为BestX1;
//策略2为:放置后,能下降的位置最高,为MaxY2,此时空出的方格数为MinC2,该位置为BestX2;
//必有MaxY1<=MaxY2, MinC1>=MinC2
//取二者的折衷,策略为:优先采取策略1,但如果MinC2==MinC1或MaxY2>=MaxY1+2,则取策略2
int BestStartX( )
{
int X, Y, tmpx, tmpy; //循环变量
int BestX = 0, MaxY = 0, MinC = 100;//最终所求的最佳下降位置
int BestX1, MaxY1, MinC1; //策略1:MinC:最佳位置处放置方块时,空出的空格最少,BestX:最佳下降位置,MaxY:能下降到的位置
int BestX2, MaxY2, MinC2; //策略2:最佳位置为能下降的位置最高
int c; //以上策略求最值时用到的辅助变量
int tBox1[4][4], tBox2[4][4]; //tBox2为实现旋转时用到的临时变量
int Rotates = 0, Rotates1 = 0, Rotates2 = 0;//找到最佳位置后,当前方块需要旋转的次数
int Last1, Last2; //Last1为下一个方块未旋转时最下一个方格所在的行,Last2为旋转后最下一个方格所在的行
memcpy(tBox1, NextBox, sizeof(tBox1)); memcpy(tBox2, NextBox, sizeof(tBox1));
for( tmpy=3; tmpy>=0; tmpy-- ) //统计tBox1中最下一个方格所在的行
{
for( tmpx=0; tmpx<4; tmpx++ ) if(tBox1[tmpy][tmpx]) break;
if(tmpx<4) break;
}
Last1 = tmpy;
BestX1 = 0, MaxY1 = 0, MinC1 = 100; BestX2 = 0, MaxY2 = 0, MinC2 = 100;
//枚举从第0~COL-4列下落
for( X=0; X<=COL-4; X++ )
{
for( Y=0; Y<=ROW-1; Y++ )
if( !Test( Y, X, tBox1 ) ) break;
Y--;
c = count1(Y,X,tBox1);
if( cMaxY1 )
MinC1 = c, BestX1 = X, MaxY1 = Y+Last1;
if( Y+Last1>MaxY2 || Y+Last1==MaxY2 && cMaxY1 )
MinC1 = c, BestX1 = X, MaxY1 = Y+Last2, Rotates1 = 1;
if( Y+Last2>MaxY2 || Y+Last2==MaxY2 && cMaxY1 )
MinC1 = c, BestX1 = X, MaxY1 = Y+Last2, Rotates1 = 2;
if( Y+Last2>MaxY2 || Y+Last2==MaxY2 && cMaxY1 )
MinC1 = c, BestX1 = X, MaxY1 = Y+Last2, Rotates1 = 3;
if( Y+Last2>MaxY2 || Y+Last2==MaxY2 && c=MaxY1+2 )
MinC = MinC2, BestX = BestX2, MaxY = MaxY2, Rotates = Rotates2;
if( Rotates>0 )
{
for( int i=0; i 0; DelY-- )
{
for( DelX = 1; DelX < COL - 1; DelX++ )
Map[DelY][DelX] = Map[DelY-1][DelX];
}
for( DelX = 1; DelX < COL - 1; DelX++ ) //第0行置为0
Map[0][DelX] = 0;
}
}
}
int Rotate( ) //测试旋转是否可行,如果可行则旋转当前方块
{
int y, x;
int TmpBox[4][4];
RotateTest( CurrentBox, TmpBox );
if( Test( CurrentY, CurrentX, TmpBox ) )
{
for( y = 0; y < 4; y++ )
{
for( x = 0; x < 4; x++ )
CurrentBox[y][x] = TmpBox[y][x];
}
return 1;
}
else return 0;
}
/*
0000 0000 0000 //旋转规律是:Box3[y][x] = Box1[y][3-x] -> 方块绕竖直方向对称变换
0100-> 0010-> 0010 //Box2[x][y] = Box3[y][x] -> 沿着主对角线对称变换(相当于矩阵转置)
1110 0111 0110
0000 0000 0010 */
int RotateTest( int Box1[4][4], int Box2[4][4] ) //旋转当前方块
{ //新增返回值为:旋转后的Box2中最下一个方格所在的行
int y, x;
for( y = 0; y < 4; y++ )
{
for( x = 3; x >=0; x-- )
Box2[x][y] = Box1[y][3 - x];
}
for( y=3; y>=0; y-- ) //统计Box2中最下一个方格所在的行
{
for( x=0; x<4; x++ )
{
if(Box2[y][x]) break;
}
if(x<4) break;
}
return y;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT Message, //窗口处理函数
WPARAM wParam, LPARAM lParam )
{
HDC hdc, hdcMem;
int y, x;
PAINTSTRUCT ps;
HBITMAP hBitMap;
HPEN hPen;
HBRUSH hBrush;
static int cxClient, cyClient; //窗口客户区宽度和高度
char str[20]; //用于显示得分的变量
switch( Message )
{
case WM_CREATE:
SetTimer( hwnd, tDown, tDownTime, NULL ); //开启两个定时器
SetTimer( hwnd, tPaint, tPaintTime, NULL );
srand( (unsigned)time( NULL ) );
bAuto = false;
Pause = false;
InitMap( );
BuildNextBox( ); //先随机产生一个方块
NewFall( ); //方块落下并随机产生下一个方块
sprintf( str, " 得分:%d", iTotalNum ); strcat( WindowTxt, str );
SetWindowText(hwnd,WindowTxt);
return 0;
case WM_SIZE:
cxClient = LOWORD( lParam ); //取得窗口客户区宽度和高度
cyClient = HIWORD( lParam );
return 0;
case WM_TIMER:
switch( wParam )
{
case tDown: //下降定时器
if( !Drop( ) ) //如果不能下降则放置当前方块
{
PutBox( );
MessageBeep( -1 );
Clear( ); //清除
//刷新得分
sprintf( str, "%d", iTotalNum ); WindowTxt[36] = 0;
strcat( WindowTxt, str ); SetWindowText(hwnd,WindowTxt);
if( !NewFall( ) ) //如果新的方块不能落下,则程序结束
{
KillTimer(hwnd, tDown );
KillTimer(hwnd, tPaint );
//PostMessage( hwnd, WM_CLOSE, NULL, NULL );
}
}
break;
case tPaint: //重绘定时器
InvalidateRect(hwnd, NULL, FALSE); //强制重绘窗口工作区
break;
}
case WM_KEYDOWN:
switch( wParam )
{
case VK_LEFT: //"向左"方向键
if(bAuto) break;
Move(0); break;
case VK_RIGHT: //"向右"方向键
if(bAuto) break;
Move(1); break;
case VK_UP: //"向上"方向键:旋转
if(bAuto) break;
Rotate( ); break;
case VK_DOWN: //"向下"方向键:当前方块下移一行位置
if(bAuto) break;
MessageBeep( -1 ); Drop( ); break;
case VK_return: //回车键:暂停
Pause = !Pause;
if( Pause ) //暂停、自动求解时也可以暂停
KillTimer( hwnd, tDown );
else //启动
{
if(bAuto) SetTimer( hwnd, tDown, tDownTime/5, NULL );
else SetTimer( hwnd, tDown, tDownTime, NULL );
}
break;
case VK_SPACE:
if(bAuto) break;
while( 1 ) //使用永真循环,使得当前方块一直下降到不能下降为止
{
if( !Drop( ) )
{
PutBox( ); Clear( );
sprintf( str, "%d", iTotalNum ); WindowTxt[36] = 0;
strcat( WindowTxt, str ); SetWindowText(hwnd,WindowTxt);
if( !NewFall( ) ) //如果新的方块不能落下,则程序结束
{
KillTimer(hwnd, tDown );
KillTimer(hwnd, tPaint );
//PostMessage( hwnd, WM_CLOSE, NULL, NULL );
}
break;
}
}
break;
case VK_F1:
bAuto = !bAuto;
if(bAuto) //自动求解
{
KillTimer(hwnd, tDown );
SetTimer( hwnd, tDown, tDownTime/5, NULL );
memcpy( WindowTxt+25, s2, strlen(s2) ); //修改标题
}
else
{
KillTimer(hwnd, tDown );
SetTimer( hwnd, tDown, tDownTime, NULL );
memcpy( WindowTxt+25, s1, strlen(s1) ); //修改标题
}
SetWindowText(hwnd,WindowTxt);
break;
}
case WM_PAINT: //重绘窗口工作区
hdc = BeginPaint( hwnd, &ps );
hdcMem = CreateCompatibleDC( hdc );
hBitMap = CreateCompatibleBitmap( hdc, cxClient, cyClient );
SelectObject( hdcMem, hBitMap );
//画地图最外面的矩形(4, 4, 246, 446)
Rectangle( hdcMem, StartX + LEN * 1 - 1,StartY + LEN * 1 - 1,
StartX + LEN * (COL - 1) + 1, StartY + LEN * (ROW - 1) + 1 );
hPen = CreatePen( PS_SOLID, 1, RGB(180, 180, 180) );
SelectObject( hdcMem, hPen );
hBrush = CreateSolidBrush( RGB(250, 250, 250) );
SelectObject( hdcMem, hBrush );
for( y = 1; y < ROW - 1; y++ ) //画地图中的每一格
{
for( x = 1; x < COL - 1; x++ )
{
Rectangle( hdcMem, StartX + LEN * x, StartY + LEN * y,
StartX + LEN * (x + 1), StartY + LEN * (y + 1) );
}
}
DeleteObject( hPen );
DeleteObject( hBrush );
hPen = CreatePen( PS_SOLID, 1, RGB(180, 180, 180) );
SelectObject( hdcMem, hPen );
hBrush = CreateSolidBrush( RGB(255, 100, 100) );
SelectObject(hdcMem, hBrush);
for( y = 1; y < ROW - 1; y++ ) //画出地图中每个被占据的方格
{
for( x = 1; x < COL - 1; x++ )
{
if( Map[y][x] )
{
Rectangle( hdcMem, StartX + LEN * x, StartY + LEN * y,
StartX +LEN * (x + 1), StartY + LEN * (y + 1) );
}
}
}
for( y = 0; y < 4; y++ ) //画当前方块
{
for( x = 0; x < 4; x++ )
{
if( CurrentBox[y][x] )
{
if( y + CurrentY > 0 )
{
Rectangle( hdcMem, (x + CurrentX) * LEN + StartX,
(y + CurrentY) * LEN +StartY,
(x + CurrentX + 1) * LEN + StartX,
(y + CurrentY + 1) * LEN + StartY );
}
}
}
}
for( y = 0; y < 4; y++ )//在窗口右边区域画下一个方块
{
for( x = 0; x < 4; x++ )
{
if( NextBox[y][x] )
{
Rectangle( hdcMem, (x + COL) * LEN + StartX,
(y + 2) * LEN + StartY,
(x+ COL + 1) * LEN + StartX, (y + 3) * LEN + StartY );
}
}
}
DeleteObject( hPen );
DeleteObject( hBrush );
DeleteObject( hBitMap );
BitBlt( hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY );
DeleteDC( hdcMem );
EndPaint( hwnd, &ps );
return 0;
case WM_DESTROY:
KillTimer(hwnd, tDown );
KillTimer(hwnd, tPaint );
PostQuitMessage( 0 );
return 0;
}//end of switch( message )
return DefWindowProc( hwnd, message, wParam, lParam );
}
本文档为【VC 6.0 MFC 俄罗斯方块 自动求解 代码 源程序】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。