2048游戏破解程序(源码)

来源:互联网 发布:caffeine for mac 编辑:程序博客网 时间:2024/05/19 05:31

前两天一时兴起,用VS2008写了个“破解”2048游戏的程序,这里用引号是因为还没有完全破解,算法需要改进。由于又要开始忙了,不能再深入探究,所以把它放上来希望有更多的人一起研究。

首先肯定是要获取图像了,在这里我也没用摄像头来获取,因为并不是所有人都有摄像头,这个程序我们用屏幕捕捉就够用了。获取图像后就是要知道当前的数据了,一开始想着用字符识别的,后来仔细想想,这个程序可以不需要字符识别,通过判断区域颜色就可以了,若不放心可以做一下灰度直方图,提高稳定性。得到数据后就该分析如何移动了,这才是本文最关心的,我的算法思想是,计算移动的有效值,这个有效值不是单一的最大数,也不是单一的空格数最多,而是这两个数与其权值乘积的和,在递归调用时,随着深度的加深,对这些权值做一定的衰减处理。这个方法在一定程度上计算可以验证是正确的,但有些时候不太理想,特别在合成的数越大时越明显,可能我设置的参数不够好吧。我在程序中没有加入分布系数(数的分布,越密集权值应越大),也没有加入路径规划(而是用了递归,本来递归遍历可以不用路径规划的,但由于我加入了权系数,所以递归的作用没有完全表现出来)。好了就讲这么多了,希望有兴趣的一起交流。

源码下载



源码如下


源码中可能有很多地方是多余的,这可能是我在调试的时候尝试过的方法,不行后没有完全将其删除

// game2048Dlg.cpp : implementation file
//


#include "stdafx.h"
#include "game2048.h"
#include "game2048Dlg.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


const char* strmove[] = {"无","上","下","左","右"};
// CAboutDlg dialog used for App About


class CAboutDlg : public CDialog
{
public:
CAboutDlg();


// Dialog Data
enum { IDD = IDD_ABOUTBOX };


protected:
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support


// Implementation
protected:
DECLARE_MESSAGE_MAP()
};


CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}


void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()




// Cgame2048Dlg dialog








Cgame2048Dlg::Cgame2048Dlg(CWnd* pParent /*=NULL*/)
: CDialog(Cgame2048Dlg::IDD, pParent)
, m_pBackBitmap(NULL)
, startx(0)
, starty(0)
, endx(0)
, endy(0)
, maxnum(0)
, imgwidth(0)
, imgheight(0)
, pbitmap(NULL)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}


void Cgame2048Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(Cgame2048Dlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_BN_CLICKED(IDC_BUTTON1, &Cgame2048Dlg::OnBnClickedButton1)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_BUTTON2, &Cgame2048Dlg::OnBnClickedButton2)
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_BUTTON3, &Cgame2048Dlg::OnBnClickedButton3)
END_MESSAGE_MAP()




// Cgame2048Dlg message handlers


BOOL Cgame2048Dlg::OnInitDialog()
{
CDialog::OnInitDialog();


// Add "About..." menu item to system menu.


// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);


CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}


// Set the icon for this dialog.  The framework does this automatically
//  when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);// Set big icon
SetIcon(m_hIcon, FALSE);// Set small icon


// TODO: Add extra initialization here
m_strLog.Empty();

//startx = 490;
//starty = 170;
//endx = 990;//::GetSystemMetrics(SM_CXSCREEN); 
//endy = 670;//::GetSystemMetrics(SM_CYSCREEN);  
//imgwidth = endx - startx;
//imgheight = endy - starty;


rgb = NULL;
//rgb = new ARGB[imgwidth*imgheight];// 0xaabbggrr
ZeroMemory(prematrix,sizeof(int)*4*4);
int i = 0;
numcolor[i++] = Color(255,204,192,179).GetValue();//ARGB
numcolor[i++] = Color(255,238,228,218).GetValue();// 2
numcolor[i++] = Color(255,237,224,200).GetValue();// 4
numcolor[i++] = Color(255,242,177,121).GetValue();// 8
numcolor[i++] = Color(255,245,149,99).GetValue();// 16
numcolor[i++] = Color(255,246,124,95).GetValue();// 32
numcolor[i++] = Color(255,246,94,59).GetValue();// 64
numcolor[i++] = Color(255,237,207,114).GetValue();// 128
numcolor[i++] = Color(255,237,204,97).GetValue();// 256
numcolor[i++] = Color(255,237,200,80).GetValue();// 512
numcolor[i++] = Color(255,237,197,63).GetValue();// 1024
numcolor[i++] = Color(255,238,194,46).GetValue();// 2048
for (;i<17;i++)
{
numcolor[i] = 0;
}


return TRUE;  // return TRUE  unless you set the focus to a control
}


void Cgame2048Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}


// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.


void Cgame2048Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting


SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);


// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;


// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
Point pts[3];
CRect rect;
CDC *pdc = GetDlgItem(IDC_IMAGE)->GetDC();
Graphics graph(pdc->GetSafeHdc());
GetDlgItem(IDC_IMAGE)->GetClientRect(&rect);
Image image(_T("g2048.bmp"));
graph.DrawImage(&image,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top);// 显示图像


CDialog::OnPaint();
}
}


// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR Cgame2048Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}




void Cgame2048Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default




CDialog::OnMouseMove(nFlags, point);
}


void Cgame2048Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
// 鼠标框出目标区域


CDialog::OnLButtonDown(nFlags, point);
}


void Cgame2048Dlg::CaptureScreen2(int xStartPt, int yStartPt, int width, int height, int xToCopy, int yToCopy)
{
if (m_pBackBitmap != NULL)  
{  
delete m_pBackBitmap;  
m_pBackBitmap = NULL;  
}  
m_pBackBitmap = new CBitmap();  
CDC ScrDC,MemDC;  
ScrDC.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);  
MemDC.CreateCompatibleDC(&ScrDC);  
m_pBackBitmap->CreateCompatibleBitmap(&ScrDC,width,height);  
MemDC.SelectObject(m_pBackBitmap);   //开始拷贝  
MemDC.BitBlt(xStartPt, yStartPt, width, height,&ScrDC,xToCopy,yToCopy,SRCCOPY);  


ScrDC.DeleteDC();  
MemDC.DeleteDC();
}


void Cgame2048Dlg::CaptureScreen(void)
{
CDC ScrDC;
ScrDC.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);  
if (pbitmap != NULL)  
{   
::delete pbitmap;   
pbitmap = NULL;  
}   
pbitmap = ::new Bitmap((HBITMAP)::GetCurrentObject(ScrDC, OBJ_BITMAP),NULL);
ScrDC.DeleteDC();  
}




int Cgame2048Dlg::GetEndcoderClsid(const WCHAR * format, CLSID * pClsid)
{
UINT num = 0;
UINT size = 0;
ImageCodecInfo *pimagecodeinfo = NULL;
GetImageEncodersSize(&num,&size);
if (size == 0)
{
return -1;
}
pimagecodeinfo = (ImageCodecInfo*)(malloc(size));
if (pimagecodeinfo == NULL)
{
return -1;
}
GetImageEncoders(num,size,pimagecodeinfo);
for (UINT i = 0;i<num;++i)
{
if (wcscmp(pimagecodeinfo[i].MimeType,format)==0)
{
*pClsid = pimagecodeinfo[i].Clsid;
free(pimagecodeinfo);
return i;
}
}
free(pimagecodeinfo);
return -1;
}


void Cgame2048Dlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
imgwidth = endx - startx;
imgheight = endy - starty;


//SetWindowPos(&this->wndNoTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
SetWindowPos(&this->wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); 
#if 1
int i,j;


CaptureScreen();


int t1 = GetTickCount();
int scrnwidth,scrnheight;
scrnwidth = ::GetSystemMetrics(SM_CXSCREEN);
scrnheight = ::GetSystemMetrics(SM_CYSCREEN);


Color color;
Rect imgrect(0, 0, scrnwidth,scrnheight);
BitmapData* bitmapData = new BitmapData;
pbitmap->LockBits(&imgrect,ImageLockModeRead,PixelFormat32bppARGB,bitmapData);
UINT* pixels = (UINT*)bitmapData->Scan0;
ARGB* argb1 = new ARGB[scrnwidth*scrnheight];
int stride = bitmapData->Stride / 4;
//for (i=0;i<imgheight;i++)
//{
// for (j=0;j<imgwidth;j++)
// {
// rgb[i*imgwidth + j] = pixels[i * stride + j];
// }
//}
memcpy(argb1,pixels,sizeof(UINT)*scrnwidth*scrnheight);
pbitmap->UnlockBits(bitmapData);
delete bitmapData;




ARGB blockcolor = Color(255,187,173,160).GetValue();//ARGB
imgheight = 0;
imgwidth = 0;
for(i=0;i<scrnheight;i++)
{
int h=0,w=0;
for(j=0;j<scrnwidth;j++)
{
if(argb1[i*scrnwidth + j] == blockcolor)
{
w++;
if(w > imgwidth)
{
imgwidth = w;
starty = i-5;
}
}
else
w = 0;
}
}
for(i=0;i<scrnwidth;i++)
{
int h=0,w=0;
for(j=0;j<scrnheight;j++)
{
if(argb1[i + scrnwidth * j] == blockcolor)
{
h++;
if(h > imgheight)
{
imgheight = h;
startx = i-5;
}
}
else
h = 0;
}
}
delete[] argb1;


if(imgwidth < 400 || imgheight < 400)
{
MessageBox(_T("获取游戏区域错误"));
return;
}
endx = imgwidth + startx;
endy = imgheight + starty;
if(rgb != NULL)
delete[] rgb;
rgb = new ARGB[imgwidth*imgheight];


CString str;
str.Format(_T("耗时: %d"),GetTickCount() - t1);
//MessageBox(str);




//graph.DrawImage(pbitmap,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top);// 显示图像


#endif


//CaptureScreen(0, 0, ::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN), 0, 0);


int scrn_w = ::GetSystemMetrics(SM_CXSCREEN); 
int scrn_h = ::GetSystemMetrics(SM_CYSCREEN); 
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, startx*65536/scrn_w,starty*65536/scrn_h,0, 0); // 
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP,0,0,0,0);


CString strTime;
CTime CurrentTime=CTime::GetCurrentTime(); 
strTime = CurrentTime.Format(_T("%Y%m%d_%H%M%S 开始游戏\r\n"));
Logging(strTime);

SetTimer(MAIN_TIMER_ID,500,NULL);


}


bool Cgame2048Dlg::SaveBitmapToFile(CBitmap* bitmap, CString lpFileName)
{            
HBITMAP hBitmap;// 为刚才的屏幕位图句柄
HDC hDC; //设备描述表  
int iBits; //当前显示分辨率下每个像素所占字节数  
WORD wBitCount; //位图中每个像素所占字节数
DWORD dwPaletteSize = 0, //定义调色板大小
dwBmBitsSize,  //位图中像素字节大小   
dwDIBSize, //位图文件大小
dwWritten;  //写入文件字节数
BITMAP Bitmap; //位图属性结构  
BITMAPFILEHEADER bmfHdr; //位图文件头结构  
BITMAPINFOHEADER bi; //位图信息头结构    
LPBITMAPINFOHEADER lpbi; //指向位图信息头结构  
HANDLE fh, //定义文件
hDib, //分配内存句柄
hPal, //调色板句柄
hOldPal = NULL;


//计算位图文件每个像素所占字节数  
hBitmap = (HBITMAP)*bitmap;  
hDC = CreateDC(_T("DISPLAY"),NULL,NULL,NULL);  
iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);  
DeleteDC(hDC);


if (iBits <= 1)  
wBitCount = 1;
else if (iBits <= 4)  
wBitCount = 4;
else if (iBits <= 8)  
wBitCount = 8;
else if (iBits <= 24)  
wBitCount = 24;  
else if (iBits <= 32)
wBitCount = 32;


//计算调色板大小  
if (wBitCount <= 8)  
dwPaletteSize =(1 << wBitCount) * sizeof (RGBQUAD);


//设置位图信息头结构  
GetObject(hBitmap, sizeof (BITMAP), (LPSTR)&Bitmap);
bi.biSize = sizeof (BITMAPINFOHEADER);  
bi.biWidth = Bitmap.bmWidth;  
bi.biHeight = Bitmap.bmHeight;  
bi.biPlanes = 1;
bi.biBitCount =wBitCount;
bi.biCompression = BI_RGB;  
bi.biSizeImage = 0;  
bi.biXPelsPerMeter = 0;  
bi.biYPelsPerMeter = 0;  
bi.biClrUsed = 0;  
bi.biClrImportant = 0;  


dwBmBitsSize = ((Bitmap.bmWidth * wBitCount+31) / 32) * 4 * Bitmap.bmHeight;  


//为位图内容分配内存  
hDib = GlobalAlloc(GHND, dwBmBitsSize + dwPaletteSize + sizeof (BITMAPINFOHEADER));  
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);  
*lpbi = bi;


// 处理调色板   
hPal = GetStockObject(DEFAULT_PALETTE);  
if (hPal)  
{  
hDC = ::GetDC(NULL);
hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);
RealizePalette(hDC);
}  


// 获取该调色板下新的像素值  
GetDIBits(hDC, hBitmap,0, (UINT) Bitmap.bmHeight,
(LPSTR)lpbi + sizeof (BITMAPINFOHEADER)+ dwPaletteSize,
(LPBITMAPINFO)lpbi,DIB_RGB_COLORS);  


//恢复调色板
if (hOldPal)
{  
SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);  
RealizePalette(hDC);  
::ReleaseDC(NULL, hDC);
}  


//创建位图文件
fh = CreateFile(lpFileName, GENERIC_WRITE,
0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL |FILE_FLAG_SEQUENTIAL_SCAN, NULL);  


if (fh == INVALID_HANDLE_VALUE)
return FALSE;  


// 设置位图文件头  
bmfHdr.bfType =0x4D42;//"BM"  
dwDIBSize = sizeof (BITMAPFILEHEADER) 
+ sizeof (BITMAPINFOHEADER)  
+ dwPaletteSize+ dwBmBitsSize;  
bmfHdr.bfSize =dwDIBSize;
bmfHdr.bfReserved1 = 0;  
bmfHdr.bfReserved2 = 0;  
bmfHdr.bfOffBits = (DWORD)sizeof (BITMAPFILEHEADER) 
+ (DWORD)sizeof (BITMAPINFOHEADER)  
+ dwPaletteSize;


// 写入位图文件头  
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten,NULL);


// 写入位图文件其余内容  
WriteFile(fh, (LPSTR)lpbi, dwDIBSize,&dwWritten, NULL);


//清除  
GlobalUnlock(hDib);  
GlobalFree(hDib);  
CloseHandle(fh);  


return TRUE;
}  


// 返回:1、2 、3、4 对应 上下左右,返回0则表示无法移动
int Cgame2048Dlg::calc_move(int* num)
{
if (num == NULL)
return 0;


int mernum[4][4*4];// 四个方向合成后的数据
int i2p1[4][4*4];// 新增2 可能的位置
int empty = 0,maxnum = 0;
double mermax[4]={0};
int merempty[4]={0};
int movedir=0,defmov=0;// 小于0 表示不能移动
int i,j,k;


for(i=0;i<4*4;i++)
{
if(num[i] == 0)
empty++;
else if(maxnum < num[i])
maxnum = num[i];
}
for (i=0;i<4;i++)
{
memcpy(mernum[i],num,sizeof(int)*4*4);

if(1)//(maxnum < 9)
{
// 权值方法
mermax[i] = num_move(mernum[i],i+1,1);
}
else
{
num_move(mernum[i],i+1,1);
for (j=0;j<4*4;j++)
{
if(mernum[i][j] == 0)
merempty[i]++;
else if(mermax[i] < mernum[i][j])
mermax[i] = mernum[i][j];
}
if(memcmp(num,mernum[i],sizeof(int)*4*4)!=0)
defmov = i+1;
}
}




if(1)//(maxnum < 9)
{
double weight = -1;
for(i = 0;i<4;i++)
{
if(mermax[i] > weight)
{
movedir = i+1;
weight = mermax[i];
}
}
}
else
{
int* p = num; // 移动后的肯定要比移动前的优,不然算法是无效的,或已经无法再移动
for(i=0;i<4;i++)
{
if(MatrixCmp(mernum[i],p,4*4,maxnum)>0)// 应该是广义的最大值,除了值 的大小,还有值的合成度
{
movedir = i+1;
p = mernum[i];
}
}
}


if(movedir==0)
movedir = defmov;
return movedir;
}


int Cgame2048Dlg::get_dir_move(int* num, int dir)
{
int ret = 1;
switch(dir)
{
case 1:// up  有些时候,有0存在的时候也能移动
if( num[0]&&num[1]&&num[2]&&num[3])
return 1;
else
{
if((num[0] == 0)&&(num[1]||num[2]||num[3]))
ret = 0;
if((num[1] == 0)&&(num[0]||num[2]||num[3]))
ret = 0;
if((num[2] == 0)&&(num[1]||num[0]||num[3]))
ret = 0;
if((num[3] == 0)&&(num[1]||num[2]||num[0]))
ret = 0;
}
break;
case 2:// down
if( num[12]&&num[13]&&num[14]&&num[15])
return 1;
else
{
if((num[12] == 0)&&(num[13]||num[14]||num[15]))
ret = 0;
if((num[13] == 0)&&(num[12]||num[14]||num[15]))
ret = 0;
if((num[14] == 0)&&(num[12]||num[13]||num[15]))
ret = 0;
if((num[15] == 0)&&(num[12]||num[13]||num[14]))
ret = 0;
}
break;
case 3:// left
if( num[0]&&num[4]&&num[8]&&num[12])
return 1;
else
{
if((num[0] == 0)&&(num[4]||num[8]||num[12]))
ret = 0;
if((num[4] == 0)&&(num[0]||num[8]||num[12]))
ret = 0;
if((num[8] == 0)&&(num[0]||num[4]||num[12]))
ret = 0;
if((num[12] == 0)&&(num[0]||num[4]||num[8]))
ret = 0;
}
break;
case 4:// right
if(num[3]&&num[7]&&num[11]&&num[15])
return 1;
else
{
if((num[3] == 0)&&(num[7]||num[11]||num[15]))
ret = 0;
if((num[7] == 0)&&(num[3]||num[11]||num[15]))
ret = 0;
if((num[11] == 0)&&(num[3]||num[7]||num[15]))
ret = 0;
if((num[15] == 0)&&(num[3]||num[7]||num[11]))
ret = 0;
}
break;
default:
return 0;
break;
}
return ret;
}


double Cgame2048Dlg::num_move(int* num, int dir, int cmove)
{
int change = -1;
double Weight = 0;
if (dir <= 0 || dir > 4 || num == NULL)
return 0;
int i,j,index;
int emp = 0,tmax=0;


// 先矩阵变换,然后统一处理
matrixchange(num,dir);


// 统一按上移处理
for (i=0;i<4;i++)
{
index = 0;
for (j=1;j<4;j++)
{
if(tmax < num[j*4+i])
tmax = num[j*4+i];

if (num[j*4+i] != 0)
{
if (num[index*4+i] == 0)
{
num[index*4+i] = num[j*4+i];
num[j*4+i] = 0;
if(change == -1)
change = 0;
}
else if(num[index * 4+i] == num[j*4+i])
{
Weight+=num[index*4+i]*num[index*4+i]*num[index*4+i];//x^2 , x^3  ,x^4,  x^2*lg(cmove)或者多项式...
num[index*4+i]++;
index++;
num[j*4+i] = 0;
change++;
}
else
{
index++;
}
}
}
}
for(i=0;i<4*4;i++)
{
if(num[i] == 0)
{
emp++;
index=i;
}
}
if(emp==1)
{
num[index] = 1;// 补2 处理
}
// 在数据较大时应考虑路径规划,或调整相关系数
if(cmove > 0 && change >= 0&&cmove<6)// 因为组合移动6次足够了,不需要太多次
{
int mernum[4][4*4];// 四个方向合成后的数据
int tweight[4]={0};
cmove += 1;;// 防止死循环
// 四个方向继续移动
for(i=0;i<4;i++)
{
memcpy(mernum[i],num,sizeof(int)*4*4);
if(get_dir_move(mernum[i],i+1)) // 递归的时候应该考虑下2会出现的位置,也用相关数供稿计算
tweight[i] = num_move(mernum[i],i+1,cmove);
else
tweight[i] = num_move(mernum[i],i+1);
}
if(0)//(tmax >= 9)
{
int* tmar = mernum[0];
for(i=1;i<4;i++)
{
if(MatrixCmp(mernum[i],tmar,4*4,tmax)>0)
{
tmar = mernum[i];
}
}
memcpy(num,tmar,sizeof(int)*4*4);
}
else
{
double maxweight = 0;
for(i=0;i<4;i++)
{
if(maxweight < tweight[i])
maxweight = tweight[i];
}
maxweight = maxweight/(cmove*cmove);// x^2   x*lg(x)  ...
Weight += maxweight;
}
}
// 还原矩阵
switch (dir)
{
case 1:
break;
case 2:
matrixchange(num,2);
break;
case 3:
matrixchange(num,4);
break;
case 4:
matrixchange(num,3);
break;
}


if(change < 0)
return change;
else
return Weight;
}


void Cgame2048Dlg::matrixchange(int* num, int dir)
{
int i,j;
int temp[4*4];
memcpy(temp,num,sizeof(int)*4*4);
switch (dir)
{
case 1:// 上移
// 默认处理方法,不处理
break;
case 2:// 下移
for (i=0;i<4;i++)
{
for (j=0;j<4;j++)
num[i*4+j] = temp[(3-i)*4+3-j];
}
break;
case 3:// 左移
for (i=0;i<4;i++)
{
for (j=0;j<4;j++)
num[i*4+j] = temp[(3-j)*4+i];
}
break;
case 4:// 右移
for (i=0;i<4;i++)
{
for (j=0;j<4;j++)
num[i*4+j] = temp[j*4+3-i];
}
break;
}
}


void Cgame2048Dlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if(nIDEvent == MAIN_TIMER_ID)
{
KillTimer(MAIN_TIMER_ID);


int i,j;
int matrix[4*4];


CaptureScreen( );




Bitmap dispbitmap(imgwidth,imgheight,PixelFormat32bppARGB);
Rect imgrect(startx, starty, imgwidth, imgheight);
Rect dispimgrect(0, 0, imgwidth, imgheight);
BitmapData* bitmapData = new BitmapData;
BitmapData* dispbitmapData = new BitmapData;
pbitmap->LockBits(&imgrect,ImageLockModeRead,PixelFormat32bppARGB,bitmapData);
dispbitmap.LockBits(&dispimgrect,ImageLockModeWrite,PixelFormat32bppARGB,dispbitmapData);
UINT* pixels = (UINT*)bitmapData->Scan0;
UINT* disppixels = (UINT*)dispbitmapData->Scan0;
int stride = bitmapData->Stride / 4;
for (i=0;i<imgheight;i++)
{
for (j=0;j<imgwidth;j++)
{
rgb[i*imgwidth + j] = pixels[i * stride + j];
disppixels[i * stride + j] = pixels[i * stride + j];
}
}
pbitmap->UnlockBits(bitmapData);
dispbitmap.UnlockBits(dispbitmapData);
delete bitmapData;
delete dispbitmapData;


int w = 122;
int off = 30;
for (i=0;i<4;i++)
{
for (j=0;j<4;j++)
{
int k;
for (k=0;k<17;k++)
{
if(rgb[(i*w+ off)*imgwidth + j*w + off] == numcolor[k])
break;
}
if(k == 0)
{
matrix[i*4+j] = 0;
}
else if(k<17)
matrix[i*4+j] = k; // pow(2.0,1.0*k);
else if(maxnum < 17 && numcolor[maxnum]==0)//  合成较大的值,保存其颜色
{
numcolor[maxnum] = rgb[(i*w+ off)*imgwidth + j*w + off];
matrix[i*4+j] = maxnum;
}
else
{
// game over
//MessageBox(_T("识别出错"));
}
}
}




int movedir = calc_move(matrix);
CString log(_T("当前数据:\t"));
char strnum[200] = {0};
for (int i=0;i<4;i++)
{
if(i!=0)
sprintf(strnum,"%s\t\t",strnum);
for (int j=0;j<4;j++)
{
sprintf(strnum,"%s%4d ",strnum,matrix[i*4 + j]);
}
sprintf(strnum,"%s\r\n",strnum);
}
sprintf(strnum,"%s移动方向为:%s\r\n\r\n",strnum,strmove[movedir]);
log += strnum;
Logging(log);
switch (movedir)
{
case 1:
keybd_event(VK_UP,0,WM_KEYDOWN | WM_KEYUP,0);
break;
case 2:
keybd_event(VK_DOWN,0,WM_KEYDOWN | WM_KEYUP,0);
break;
case 3:
keybd_event(VK_LEFT,0,WM_KEYDOWN | WM_KEYUP,0);
break;
case 4:
keybd_event(VK_RIGHT,0,WM_KEYDOWN | WM_KEYUP,0);
break;
default :
break;
}

Point pts[3];
CRect rect;
CDC *pdc = GetDlgItem(IDC_IMAGE)->GetDC();
Graphics graph(pdc->GetSafeHdc());
GetDlgItem(IDC_IMAGE)->GetClientRect(&rect);
graph.DrawImage(&dispbitmap,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top);// 显示图像

if(movedir >=1&&movedir<=4)
{
maxnum = 0;
num_move(matrix,movedir);
memcpy(prematrix,matrix,sizeof(int)*4*4);
for(int i=0;i<4*4;i++)
{
if(maxnum < prematrix[i])
maxnum = prematrix[i];
}
SetTimer(MAIN_TIMER_ID,400,NULL);
}
else
{
CString str;
CaptureScreen2(0,0,imgwidth,imgheight,startx,starty);
SaveBitmapToFile(m_pBackBitmap,_T("g2048.bmp"));
str.Format(_T("g2048_%d.bmp"),maxnum);
SaveBitmapToFile(m_pBackBitmap,str);

str.Format(_T("maxnum is %d"),maxnum);
Logging(str);
Logging(_T("game over"));
MessageBox(_T("game over"));
WriteLogToFile();
SetWindowPos(&this->wndNoTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
}


}




CDialog::OnTimer(nIDEvent);
}


void Cgame2048Dlg::OnBnClickedButton2()
{
// TODO: Add your control notification handler code here
KillTimer(MAIN_TIMER_ID);
KillTimer(CAP_TIMER_ID);
Logging(_T("用户停止"));
WriteLogToFile();
SetWindowPos(&this->wndNoTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
}


void Cgame2048Dlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
Logging(_T("软件关闭"));
WriteLogToFile();
delete rgb;
CDialog::OnClose();
}


int Cgame2048Dlg::Logging(CString log)
{
if(m_strLog.GetLength()>20000)
WriteLogToFile( );


m_strLog += log + _T("\r\n");


return 0;
}


int Cgame2048Dlg::WriteLogToFile(void)
{
CString Filename,str;
CFile pfile;
Filename.Format(_T("log.txt"));
m_strLog = str + m_strLog;


if (!pfile.Open(Filename,CFile::modeWrite|CFile::modeRead|CFile::modeNoTruncate))
{
pfile.Open(Filename,CFile::modeWrite|CFile::modeRead|CFile::modeCreate|CFile::modeNoTruncate);
}


pfile.SeekToEnd();
#ifdef _UNICODE
USES_CONVERSION;
pfile.Write(W2CA(m_strLog),((CStringA)m_strLog).GetLength());
#else
pfile.Write(m_strLog,m_strLog.GetLength());
#endif
pfile.Close();
m_strLog.Empty();
return 0;
}




int Cgame2048Dlg::MatrixCmp(int* ma1, int* ma2, int n,int m)
{
int i;
int ret = 0;
int* tm1 = new int[n];
int* tm2 = new int[n];
int n1=0,n2=0;
memcpy(tm1,ma1,sizeof(int)*n);
memcpy(tm2,ma2,sizeof(int)*n);
SortInt(tm1,n);
SortInt(tm2,n);

// 移动后最大数和格子数都有可能不变,则再多考虑一步
// 或者移动后的整齐度,或者再多考虑一步能合成更大的数
// 或者多一步时消除的更多



// 优先处理
for(i = 0;i<n;i++)
{
if(tm1[i]!=0)
n1++;
if(tm2[i]!=0)
n2++;
}
//普通处理
//if(n1 == n2 || m >= 9)
if(n1 == n2 )
{
for(i = 0;i<n;i++)
{
// 综合判断
if(tm1[i] < tm2[i])
{
ret = -1;
break;
}
else if(tm1[i] > tm2[i])
{
ret = 1;
break;
}
}
}
else if(n1 < n2)
ret = 1;
else
ret = -1;
delete[] tm1;
delete[] tm2;
return ret;
}


void Cgame2048Dlg::SortInt(int* buf, int n)
{
int t;
for(int i=0;i<n;i++)
{
for(int j = i+1;j<n;j++)
{
if(buf[i] < buf[j])
{
t = buf[i];
buf[i] = buf[j];
buf[j] = t;
}
}
}
}




void Cgame2048Dlg::OnBnClickedButton3()
{
// TODO: Add your control notification handler code here
SetWindowPos(&this->wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); 
SetTimer(CAP_TIMER_ID,50,NULL);
}



由于是用了GDI+,所以在InitInstance( ) 函数中需要启动GDI+,即在该函数中加 

GdiplusStartup(&m_GdiplusToken,&m_GdiplusStartupInput,NULL);

在ExitInstance() 加

GdiplusShutdown(m_GdiplusToken);



0 0
原创粉丝点击