C++ロシアブロック(windows API)


                        ,                 ,               ,                          ,               ,             ,          ,                  ,          。              ,           ,    ,          。    code::block  +  MinGW ,  CB  IDE          ,          VC          ,             ,                           。    windows API  , windows       ,       ,      。
#include <windows.h>
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
#define CellWidth 20
#define  MAP_WIDTH  12
#define  MAP_HEIGHT  18
#define  ID_TIMER 1
class map_floor;
class Block;
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/*  Make the class name into a global variable  */
char szClassName[ ] = "CodeBlocksWindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS|CS_HREDRAW | CS_VREDRAW;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);//COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                 /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Code::Blocks Template Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           CW_USEDEFAULT,                 /* The programs width */
           CW_USEDEFAULT,                 /* and height in pixels */
           NULL,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}

enum{e_LINE,e_CORNER,e_STAIR,e_TANCK,e_TIAN};
const int TOTAL_BLOCK_STYLE = 5;//     4 
class Block
{
	public:
            Block(int x = 100, int y = 100);
            Block(const Block & rh)//      ,      ,        
            {
                this->m_style  = rh.m_style;
                this->m_direct = rh.m_direct;
                for(int i = 0 ; i < 4 ; i ++)
                    this->m_block[i] = rh.m_block[i];
            }
            Block & operator = (const Block& rh)//  = ,       
            {
                this->m_style  = rh.m_style;
                this->m_direct = rh.m_direct;
                for(int i = 0 ; i < 4 ; i ++)
                    this->m_block[i] = rh.m_block[i];
                return *this;
            }
            ~Block(){}
    int     create_block(int x = 100 , int y = 100);
    //            
    int     show_block(HDC hdc,const POINT& GameLeftTop);
    //         ,         
    int     show_next_block(HDC hdc);
    //  ,        ,       ,          ,        
    int     rotate();
    //      
    int     random_block();

    //            
    int     get_block_height(){ return m_block[1].y;}
    int     move_down(const RECT& GameClient);
    int     move_left(const RECT& GameClient);
    int     move_right(const RECT& GameClient);
    int     move_up(const RECT& GameClient);
    int     move_to(int x , int y);
    //           
//    int     check_block(const map_floor& map, const RECT& GameClent);
    int     check_block(const map_floor& map, const POINT& LeftTopScrCdnt);
    int     print_to_map(map_floor& map , const POINT& LeftTopScrCdnt);
	private:
    int     m_style;//       ,          
    int     m_direct;//     ,  m_style     
  POINT     m_block[4];//   1        ,            ,             
};
class map_floor
{
	public:
		map_floor()
		{
		    ZeroMemory(m_block_bar,sizeof(int )*12*18);
		}
		~map_floor(){}
    void show_block_bar(HDC hdc , const POINT& LeftTopScrCdnt)
    {
        for(int i = 0 ; i < MAP_HEIGHT ; ++ i)
        {
            for(int j = 0 ; j < MAP_WIDTH ; ++ j)
            {
                if(m_block_bar[i][j])
                {
                    Rectangle(hdc,LeftTopScrCdnt.x + j*CellWidth , LeftTopScrCdnt.y + i*CellWidth,
                                  LeftTopScrCdnt.x + (j+1)*CellWidth , LeftTopScrCdnt.y + (i+1)*CellWidth);
                }
            }
        }

    }
    friend  class Block;
	protected:

	private:

    int         m_block_bar[MAP_HEIGHT][MAP_WIDTH];//      , 18*12       


};

Block::Block(int x , int y)
{
//    ZeroMemory(m_block_bar,sizeof(int )*12*18);
    srand( (unsigned)time( NULL ) );//      ,      
//    POINT pt = {100,100};
    create_block(x,y);
}
int Block::random_block()
{
    m_style = rand()%TOTAL_BLOCK_STYLE;
//    m_style = e_CORNER; //    
//    m_style = e_LINE; //    
    if(m_style == e_STAIR || m_style == e_TANCK)
        m_direct = rand()%4;
    else if(m_style == e_LINE)
        m_direct = rand()%2;
    else if(m_style == e_CORNER)
        m_direct = rand()%8;
    else if(m_style == e_TIAN)
        m_direct = 0;
    m_direct = 1;

}
int   Block::check_block(const map_floor& map, const POINT& LeftTopScrCdnt)
{
    int x , y ; //x , y            ,    (0,0)
    for(int i = 0 ; i < 4 ; i ++)
    {
        x = (m_block[i].x - LeftTopScrCdnt.x)/CellWidth;
        y = (m_block[i].y - LeftTopScrCdnt.y)/CellWidth;
        if(x < 0 || x >= MAP_WIDTH || y >= MAP_HEIGHT)//    y < 0    
        return 0;
        if(y < 0) continue;
        if(map.m_block_bar[y][x])
        return 0;
    }
    return 1;
}
int Block::move_down(const RECT& GameClient)//  ,        
{
    int i;
//    for (i = 0 ; i < 4 ; i ++ )
//    {
//    	if(m_block[i].y == GameClient.bottom - CellWidth)
//    	return 0;
//    }
    for (i = 0; i < 4 ;i ++ )
    {
    	m_block[i].y += CellWidth;
    }
    return 1;
}
int Block::move_up(const RECT& GameClient)
{
    move_to(m_block[1].x,m_block[1].y - CellWidth);
    return 1;
}
int Block::move_left(const RECT& GameClient)
{
    move_to(m_block[1].x - CellWidth,m_block[1].y);
    return 1;
}
int Block::move_right(const RECT& GameClient)
{
    move_to(m_block[1].x + CellWidth , m_block[1].y);
    return 1;
}
int Block::create_block(int x , int y)
{
    m_block[1].x = x;
    m_block[1].y = y;
    random_block();
    rotate();
    return 1;
}
int Block::move_to(int x , int y)
{
    int Vx = x - m_block[1].x;
    int Vy = y - m_block[1].y;
    for(int i = 0 ; i < 4 ; i ++)
    {
        m_block[i].x += Vx;
        m_block[i].y += Vy;
    }
}
int Block::print_to_map(map_floor& map , const POINT& LeftTopScrCdnt)
{
    int x , y;
    int i , j;
    for(i = 0 ; i < 4 ; i ++ )
    {
        x = (m_block[i].x - LeftTopScrCdnt.x)/CellWidth;
        y = (m_block[i].y - LeftTopScrCdnt.y)/CellWidth;
        if(x<0 || x >= MAP_WIDTH || y <0 || y >= MAP_HEIGHT)//     ,    ,        
            return 0;
        map.m_block_bar[y][x]  = 1 ;
        for(j = 0 ; j < MAP_WIDTH ; j ++)
        {
            if(map.m_block_bar[y][j] != 1)
                break;
        }
        if(MAP_WIDTH == j)
        {
            for(j = 0 ; j < MAP_WIDTH ; j ++)
            {
                map.m_block_bar[y][j] = 5;//  5       
            }
        }

    }
    int idx;
    for(i = 0 ; i < MAP_WIDTH ; i ++)
    {
        for(idx = j = MAP_HEIGHT - 1  ; j >= 0 ; j --)
        {
            if(map.m_block_bar[j][i] != 5)
            {
                map.m_block_bar[idx--][i] = map.m_block_bar[j][i];
            }
        }
        while(idx >= 0)
        {
            map.m_block_bar[idx--][i] = 0;
        }
    }
    return 1;
}

//              ,      【     】     ,       
//      block【4】  ,  3       block【1】  ,          
//  ,      7 ,          ,               ,   :
//
//e_LINE                 ,        ,               ,  
//                 m_direct  ,       
//
//e_TANCK               ,     ,  m_direct 4             
//                   ,                      ,           ,
//                           。
//
//e_STAIR                      ,           ,         
//                      ,      m_direct      ,      e_STAIR_BACK e_STAIR_FRONT
//                      ,                     block【0】 block【1】     
//                  ,    block【2】 block【3】,block【2】  block【1】     ,x   block【1】
//                  ,block【3】.y   block【1】    ,       
//
//e_CORNER                      ,       ,       e_CORNER_FRONT , e_CORNER_BACK
//                  ,          ,                     ,  block【3】    
//                  m_direct       

int Block::rotate()
{
		    switch (m_style)
		    {
		    	case e_LINE:
		    	{
		    	    switch(m_direct)
		    	    {
		    	        case 0://      
		    	        {
                            for(int i = 0 ; i < 4 ; i ++)
                                {
                                    m_block[i].x = m_block[1].x;
                                    m_block[i].y = m_block[1].y + (1-i)*CellWidth;
                                }
		    	            m_direct = 1;
		    	        }
		    	        	break;
                        case 1://      
                        {
                            for(int i = 0 ; i < 4 ; i ++)
                            {
                                    m_block[i].y = m_block[1].y;
                                    m_block[i].x = m_block[1].x + (1-i)*CellWidth;
                            }
                            m_direct = 0;
                        }
                        	break;
		    	    }
		    	}
		    		break;
                //          ,               ,           ,
                //m_direct% == 0          
                case e_STAIR:
                {
                    int flag;
                    flag = m_direct < 2 ? 1 : -1;
                    m_block[0].x = m_block[1].x + flag*CellWidth;
                    m_block[0].y = m_block[1].y;
                    m_block[2].x = m_block[1].x;
                    m_block[3].y = m_block[1].y + CellWidth;
                    if(m_direct%2 == 0)
                    {
                        m_block[2].y = m_block[1].y - CellWidth;
                        m_block[3].x = m_block[1].x + flag*CellWidth;
                        m_direct++;
                    }
                    else
                   {
                        m_block[2].y = m_block[1].y + CellWidth;
                        m_block[3].x = m_block[1].x - flag*CellWidth;
                        if(m_direct < 2) m_direct = 0;
                        else             m_direct = 2;
                    }
                }
                	break;
                //    ,           ,      ,       ,
                //    m_direct%4           ,   ,       
                //     ,  block【3】       ,             
                case e_CORNER:
                {
                    switch (m_direct%4)
                    {
                    	case 0:
                    	{
                    	    m_block[0].x = m_block[1].x+CellWidth;
                    	    m_block[0].y =  m_block[2].y = m_block[1].y;
                    	    m_block[2].x = m_block[1].x-CellWidth;
                    	    m_block[3].x = m_block[1].x-CellWidth;
                    	    if(m_direct>=4)  m_block[3].y = m_block[1].y-CellWidth;
                            else             m_block[3].y = m_block[1].y+CellWidth;
                    	    m_direct ++;
                    	}
                    		break;
                    	case 1:
                    	{
                    	    m_block[0].x = m_block[2].x = m_block[1].x;
                    	    m_block[0].y = m_block[1].y+CellWidth;
                    	    m_block[2].y = m_block[1].y-CellWidth;
                    	    if(m_direct>=4)     m_block[3].x = m_block[1].x+CellWidth;
                    	    else             m_block[3].x = m_block[1].x-CellWidth;
                    	    m_block[3].y = m_block[1].y-CellWidth;
                    	    m_direct ++;
                    	}
                            break;
                    	case 2:
                    	{
                            m_block[0].x = m_block[1].x-CellWidth;
                    	    m_block[0].y = m_block[2].y = m_block[1].y;
                    	    m_block[2].x = m_block[1].x+CellWidth;
                    	    m_block[3].x = m_block[1].x+CellWidth;
                    	    if (m_direct>=4)    m_block[3].y = m_block[1].y+CellWidth;
                    	    else             m_block[3].y = m_block[1].y-CellWidth;

                    	    m_direct ++;
                    	}
                            break;
                    	case 3:
                    	{
                            m_block[0].x = m_block[2].x = m_block[1].x;
                    	    m_block[0].y = m_block[1].y-CellWidth;
                    	    m_block[2].y = m_block[1].y+CellWidth;
                    	    if(m_direct>=4)   {  m_block[3].x = m_block[1].x-CellWidth;  m_direct = 4;}
                            else              {  m_block[3].x = m_block[1].x+CellWidth;  m_direct = 0;}
                    	    m_block[3].y = m_block[1].y+CellWidth;
                    	}
                            break;
                    	default:
                    		break;
                    }

                }
                	break;
                case e_TANCK://     ,           ,     
                {
                    switch (m_direct%2)
                    {
                    	case 0:
                    	{
                    	    m_block[0].x = m_block[2].x = m_block[1].x;
                    	    m_block[0].y = m_block[1].y - CellWidth;
                    	    m_block[2].y = m_block[1].y + CellWidth;
                    	    int flag = m_direct == 0 ? 1 : -1;
                    	    m_block[3].x = m_block[1].x + flag*CellWidth;
                    	    m_block[3].y = m_block[1].y;
                    	    m_direct++;
                    	}
                    		break;
                        case 1:
                        {
                            m_block[0].y = m_block[2].y = m_block[1].y;
                            m_block[0].x = m_block[1].x - CellWidth;
                    	    m_block[2].x = m_block[1].x + CellWidth;
                    	    m_block[3].x = m_block[1].x;
                    	    int flag = m_direct == 3 ? -1:1;
                    	    m_block[3].y = m_block[1].y + flag*CellWidth;
                    	    if(m_direct == 3)  m_direct = 0;
                    	    else m_direct++;

                        }
                        	break;
                    	default:
                    		break;
                    }

                }
                	break;
                case e_TIAN:
                {
                    m_block[0].y = m_block[1].y;
                    m_block[0].x = m_block[1].x + CellWidth;
                    m_block[2].x = m_block[1].x;
                    m_block[2].y = m_block[1].y + CellWidth;
                    m_block[3].x = m_block[1].x + CellWidth;
                    m_block[3].y = m_block[1].y + CellWidth;
                }
                	break;

		    	default:
		    		break;
		    }

                return 0;
}
int Block::show_block(HDC hdc,const POINT& GameLeftTop)
{
    for (int i = 0 ; i < 4  ; i ++ )
    {
        if(m_block[i].y >= GameLeftTop.y)
            Rectangle(hdc,m_block[i].x,m_block[i].y,m_block[i].
                      x+CellWidth,m_block[i].y+CellWidth);
        if(i==0)//    ,         
        {MoveToEx(hdc,m_block[i].x,m_block[i].y,NULL);
        LineTo(hdc,m_block[i].x+CellWidth,m_block[i].y+CellWidth);}

    }
    return 1;
}
int Block::show_next_block(HDC hdc)
{
     for (int i = 0 ; i < 4  ; i ++ )
    {

        Rectangle(hdc,m_block[i].x,m_block[i].y,m_block[i].
                      x+CellWidth,m_block[i].y+CellWidth);
    }
    return 1;
}
Block block , next_block , try_block;
map_floor map;int d = 0;
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     HDC         hdc ;
     PAINTSTRUCT ps ;
     //     
     static RECT GameClient;
     //        CellWidth = 20       12        18    
     const int   Width = 240  ,Height = 360;
     static POINT  LeftTopScrCdnt;//         

     switch (message)
     {
     case WM_CREATE:
          SetTimer(hwnd,ID_TIMER,500,NULL);
          return 0 ;
     case WM_SIZE:
          GetClientRect(hwnd,&GameClient);
          LeftTopScrCdnt.x = (GameClient.right-GameClient.left)/2 - Width/2;
          LeftTopScrCdnt.y = GameClient.top + 50;
          GameClient.left   = LeftTopScrCdnt.x;
          GameClient.top    = LeftTopScrCdnt.y;
          GameClient.right  = LeftTopScrCdnt.x + Width;
          GameClient.bottom = LeftTopScrCdnt.y + Height;
          //            
          next_block.create_block(GameClient.right+2*CellWidth,(GameClient.bottom+GameClient.top)/2-3*CellWidth);
          block.move_to((GameClient.right+GameClient.left)/2,GameClient.top-CellWidth);

    	  break;
     case WM_TIMER:
          block.move_down(GameClient);
          if(!block.check_block(map,LeftTopScrCdnt))//       ,           ,           
          {
              block.move_up(GameClient);
              if(!block.check_block(map,LeftTopScrCdnt) ||
                  block.get_block_height() <= LeftTopScrCdnt.y )//        
                 {
                     KillTimer(hwnd,ID_TIMER);
                     d = 4;
                 }
              block.print_to_map(map,LeftTopScrCdnt);
              SendMessage(hwnd,WM_KEYDOWN,VK_ESCAPE,0);
          }
		  InvalidateRect(hwnd,NULL,true);
          break;
     case WM_PAINT:
          hdc = BeginPaint (hwnd, &ps) ;
		  MoveToEx(hdc,LeftTopScrCdnt.x,LeftTopScrCdnt.y,NULL);
          Rectangle(hdc,GameClient.left,GameClient.top,GameClient.right,GameClient.bottom);//     
          SelectObject(hdc,GetStockObject(BLACK_BRUSH));
          map.show_block_bar(hdc,LeftTopScrCdnt);
		  block.show_block(hdc,LeftTopScrCdnt);
		  next_block.show_next_block(hdc);
          EndPaint (hwnd, &ps);
          break;
     case WM_KEYDOWN:
          InvalidateRect(hwnd,NULL,true);
          switch (wParam)
          {
          	case VK_SPACE:
          	{
          	    try_block = block;
          	    try_block.rotate();
          	    if(try_block.check_block(map ,LeftTopScrCdnt))
                    block = try_block;
          		break;
          	}
            case VK_LEFT:
            {
                block.move_left(GameClient);
                if(!block.check_block(map ,LeftTopScrCdnt))
                    block.move_right(GameClient);
            }
            	break;
            case VK_RIGHT:
            {
                block.move_right(GameClient);
                if (!block.check_block(map ,LeftTopScrCdnt))
                	block.move_left(GameClient);
            }
            	break;
            case VK_DOWN:
            {
//                block.move_down(GameClient);
                  SendMessage(hwnd,WM_TIMER,0,0);
            }
            	break;

            case VK_ESCAPE://   ,         
            {
                block = next_block;
                next_block.create_block(GameClient.right+2*CellWidth,(GameClient.bottom+GameClient.top)/2-3*CellWidth);
                block.move_to((GameClient.right+GameClient.left)/2,GameClient.top-CellWidth);
            }
                break;
          	default:
          		break;
          }
          break;
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}