skyblue_LLKDlg.cpp
上传用户:hbrsgg1
上传日期:2014-05-08
资源大小:2826k
文件大小:12k
源码类别:

其他智力游戏

开发平台:

C/C++

  1. /*++
  2. Copyright (c) AFE(Active-Free-Elegance)
  3. Module Name:
  4.     skyblue_LLKDlg.cpp
  5. Abstract:
  6. LLK-Game's kernal-solving Dialog
  7. Author:
  8.     Weijian Luo (Arthur Luo)   15-Jun-2005
  9. E-mail: skybluehacker@yahoo.com.cn
  10. Revision History:      1.0
  11. --*/
  12. #include "stdafx.h"
  13. #include "skyblue_LLK.h"
  14. #include "skyblue_LLKDlg.h"
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20. /////////////////////////////////////////////////////////////////////////////
  21. // C_LLK_Dlg dialog
  22. #define BKCOLOR         RGB(128,128,128) //背景颜色
  23. #define FRONTWIDTH     (39+2)     //前面方块的宽度
  24. #define FRONTHEIGHT     (39+12)     //前面方块的高度
  25. #define BKWIDTH         46 //背景方块的宽度
  26. #define BKHEIGHT        56 //背景方块的高度
  27. #define ROWCOUNT        7 //行数
  28. #define COLCOUNT        12 //列数
  29. #define BLANK_STATE     -1                  //空方块(没有任何动物)
  30. /////////////////////////////////////////////////////////////////////////////
  31. // C_LLK_Dlg dialog
  32. C_LLK_Dlg::C_LLK_Dlg(CWnd* pParent /*=NULL*/)
  33. : CDialog(C_LLK_Dlg::IDD, pParent)
  34. {
  35. //{{AFX_DATA_INIT(C_LLK_Dlg)
  36. // NOTE: the ClassWizard will add member initialization here
  37. //}}AFX_DATA_INIT
  38. // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  39. m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  40. //记录方块置为无效状态
  41. m_nY1= BLANK_STATE;
  42. m_nX1= BLANK_STATE;
  43. //初始化行列数
  44. m_nRow=ROWCOUNT;
  45. m_nCol=COLCOUNT;
  46. //根据行列数动态分配内核数据数组空间
  47. m_map=new int[m_nRow*m_nCol];
  48. }
  49. C_LLK_Dlg::~C_LLK_Dlg()
  50. {
  51. //释放动态数组空间
  52. delete[] m_map;
  53. }
  54. void C_LLK_Dlg::DoDataExchange(CDataExchange* pDX)
  55. {
  56. CDialog::DoDataExchange(pDX);
  57. //{{AFX_DATA_MAP(C_LLK_Dlg)
  58. // NOTE: the ClassWizard will add DDX and DDV calls here
  59. //}}AFX_DATA_MAP
  60. }
  61. BEGIN_MESSAGE_MAP(C_LLK_Dlg, CDialog)
  62. //{{AFX_MSG_MAP(C_LLK_Dlg)
  63. ON_WM_PAINT()
  64. ON_WM_QUERYDRAGICON()
  65. ON_WM_LBUTTONDOWN()
  66. //}}AFX_MSG_MAP
  67. END_MESSAGE_MAP()
  68. /////////////////////////////////////////////////////////////////////////////
  69. // C_LLK_Dlg message handlers
  70. BOOL C_LLK_Dlg::OnInitDialog()
  71. {
  72. CDialog::OnInitDialog();
  73. // Set the icon for this dialog.  The framework does this automatically
  74. //  when the application's main window is not a dialog
  75. SetIcon(m_hIcon, TRUE); // Set big icon
  76. SetIcon(m_hIcon, FALSE); // Set small icon
  77. //获取程序框架的设备环境
  78. CDC *pWinDC = GetDC();
  79. //内存设备环境以及内存位图的创建,初始化,关联
  80. //3D方块边框图样内存位图
  81. m_mem3DBkDC.CreateCompatibleDC(pWinDC);
  82. m_mem3DBkBmp.LoadBitmap(IDB_BITMAP_3D_FRAMES);
  83. m_mem3DBkDC.SelectObject(&m_mem3DBkBmp);
  84. //动物图样内存位图
  85. m_memAnimalDC.CreateCompatibleDC(pWinDC);
  86. m_memAnimalBmp.LoadBitmap(IDB_BMP_ANIMAL);
  87. m_memAnimalDC.SelectObject(&m_memAnimalBmp);
  88. //整个游戏区域内存位图
  89. m_MemDC.CreateCompatibleDC(pWinDC);
  90. m_memBitmap.CreateCompatibleBitmap(pWinDC,
  91. m_nCol*FRONTWIDTH+5,
  92. m_nRow*FRONTHEIGHT+5);
  93. m_MemDC.SelectObject(&m_memBitmap);
  94. //开始一个新的游戏
  95. StartNewGame();
  96. //放在最桌面的前面显示
  97. HWND hWnd = ::AfxGetMainWnd()->m_hWnd;
  98. ::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
  99. return TRUE;  // return TRUE  unless you set the focus to a control
  100. }
  101. void C_LLK_Dlg::StartNewGame()
  102. {
  103. //初始化地图,将地图中所有方块区域位置置为空方块状态
  104. for(int iNum=0;iNum<(m_nCol*m_nRow);iNum++)
  105. {
  106. m_map[iNum] = BLANK_STATE;
  107. }
  108. //部下随机种子
  109. srand(time(NULL));
  110. //生成随机地图
  111. //将所有匹配成对的动物物种放进一个临时的地图中
  112. CDWordArray tmpMap;
  113. for(int i=0;i<(m_nCol*m_nRow)/4;i++)
  114. for(int j=0;j<4;j++)
  115. tmpMap.Add(i);
  116. //每次从上面的临时地图中取走(获取后并在临时地图删除)
  117. //一个动物放到地图的空方块上
  118. for(i=0;i<m_nRow*m_nCol;i++)
  119. {
  120. //随机挑选一个位置
  121. int nIndex=(int(rand()*0.1+rand()*0.01+rand()))%tmpMap.GetSize();
  122. //获取该选定物件放到地图的空方块
  123. m_map[i]=tmpMap.GetAt(nIndex);
  124. //在临时地图除去该动物
  125. tmpMap.RemoveAt(nIndex);
  126. }
  127. //更新显示
  128. Invalidate(TRUE);
  129. }
  130. //
  131. //  游戏区域的绘制
  132. //
  133. void C_LLK_Dlg::GameDraw(CDC * pDC)
  134. {
  135. //绘制背景颜色
  136. pDC->FillSolidRect(0,0,m_nCol*FRONTWIDTH+5,m_nRow*FRONTHEIGHT+5,BKCOLOR);
  137. for(int i=0;i<m_nRow;i++)
  138. {
  139. for(int j=0;j<m_nCol;j++)
  140. {
  141. if(m_map[i*m_nCol+j]==BLANK_STATE)
  142. {
  143. continue;
  144. }
  145. //绘制方块边框
  146. pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT,
  147. BKWIDTH,BKHEIGHT,
  148. &m_mem3DBkDC,
  149. 0,BKHEIGHT,
  150. SRCCOPY);
  151. //绘制方块
  152. //因为要使得效果透明,所以由图样的底色以及表面两部分构成
  153. pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT,
  154. FRONTWIDTH-2,FRONTHEIGHT-12,
  155. &m_memAnimalDC,
  156. FRONTWIDTH-2,m_map[i*m_nCol+j]*(FRONTHEIGHT-12),
  157. SRCAND);
  158. pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT,
  159. FRONTWIDTH-2,FRONTHEIGHT-12,
  160. &m_memAnimalDC,
  161. 0,m_map[i*m_nCol+j]*(FRONTHEIGHT-12),
  162. SRCPAINT);
  163. }
  164. }
  165. }
  166. // The system calls this to obtain the cursor to display while the user drags
  167. //  the minimized window.
  168. HCURSOR C_LLK_Dlg::OnQueryDragIcon()
  169. {
  170. return (HCURSOR) m_hIcon;
  171. }
  172. // If you add a minimize button to your dialog, you will need the code below
  173. //  to draw the icon.  For MFC applications using the document/view model,
  174. //  this is automatically done for you by the framework.
  175. void C_LLK_Dlg::OnPaint() 
  176. {
  177. CPaintDC dc(this); // device context for painting
  178. //先将整个游戏区域的图像绘制到内存位图
  179. GameDraw(&m_MemDC);
  180. //将内存位图中绘制好的图像一次性拷贝到屏幕
  181. dc.BitBlt(0,0,m_nCol*FRONTWIDTH,m_nCol*FRONTHEIGHT,&m_MemDC,0,0,SRCCOPY);
  182. }
  183. //
  184. // 鼠标左键消息处理
  185. //
  186. void C_LLK_Dlg::OnLButtonDown(UINT nFlags, CPoint point) 
  187. {
  188. //1.计算鼠标点击方块的的位置
  189. int x=point.x/FRONTWIDTH+(point.x%FRONTWIDTH?1:0)-1;
  190. int y=point.y/FRONTHEIGHT+(point.y%FRONTHEIGHT?1:0)-1;
  191. //2.在游戏区域内并且该区域还有该区域不是空的区域
  192. if(x<m_nCol&&y<m_nRow&&m_map[y*m_nCol+x]!= BLANK_STATE)
  193. {
  194. //3.假设尚未记录第一个方块
  195. if(m_nX1==BLANK_STATE)
  196. {
  197. //4.记录第一个方块的位置
  198. m_nX1=x;
  199. m_nY1=y;
  200. //获取程序框架的设备环境
  201. CDC *pWinDC = GetDC();
  202. //临时绘制点中的方块外框
  203. //只绘屏幕不载入内存位图
  204. CPen myPen;
  205. CPen *pOldPen;
  206. myPen.CreatePen(PS_SOLID, 4, RGB(255,0,0));
  207. pOldPen =  pWinDC->SelectObject(&myPen);
  208. //方块外框绘制,线条环绕绘制框架
  209. pWinDC->MoveTo(x*FRONTWIDTH,y*FRONTHEIGHT);
  210. pWinDC->LineTo(x*FRONTWIDTH,(y+1)*FRONTHEIGHT);
  211. pWinDC->LineTo((x+1)*FRONTWIDTH,(y+1)*FRONTHEIGHT);
  212. pWinDC->LineTo((x+1)*FRONTWIDTH,y*FRONTHEIGHT);
  213. pWinDC->LineTo(x*FRONTWIDTH,y*FRONTHEIGHT);
  214. //现场恢复
  215. pWinDC->SelectObject(pOldPen);
  216. }
  217. else
  218. //5.判断是否点击的方块非本身, 是否点击同一种动物
  219. if((m_nX1!=x||m_nY1!=y)&& 
  220.   m_map[m_nY1*m_nCol+m_nX1]==m_map[y*m_nCol+x]
  221. )
  222. {
  223. //6.检测是否可以消除
  224. if(IsLink(m_nX1,m_nY1,x,y))
  225. {
  226. //7.数据清理
  227. m_map[m_nY1*m_nCol+m_nX1]=BLANK_STATE;
  228. m_map[y*m_nCol+x]=BLANK_STATE;
  229. }
  230. }
  231. //8.清空记录方块的值
  232. m_nX1=BLANK_STATE;  
  233. m_nY1=BLANK_STATE;
  234. //通知重绘
  235. Invalidate(FALSE);
  236. }
  237. }
  238. //察看是否已经胜利
  239. if(IsWin())
  240. {
  241. MessageBox("恭喜您胜利闯关,即将开始新局");
  242. StartNewGame();
  243. }
  244. }
  245. //
  246. //X直接连通
  247. //
  248. BOOL C_LLK_Dlg::X1_Link_X2(int x, int y1,int y2)
  249. {
  250. //保证y1的值小于y2
  251. if(y1>y2)
  252. {
  253. //数据交换
  254. int n=y1;
  255. y1=y2;
  256. y2=n;
  257. }
  258. //直通 
  259. for(int i=y1+1;i<=y2;i++)
  260. {
  261. if(i==y2)
  262. return TRUE;
  263. if(m_map[i*m_nCol+x]!=BLANK_STATE)
  264. break;
  265. }
  266. //左通
  267. if(XThrough(x-1,y1,FALSE)&&XThrough(x-1,y2,FALSE))
  268. return TRUE;
  269. //右通
  270. if(XThrough(x+1,y1,TRUE)&&XThrough(x+1,y2,TRUE))
  271. return TRUE;
  272. return FALSE;
  273. }
  274. //
  275. //Y直接连通
  276. //
  277. BOOL C_LLK_Dlg::Y1_Link_Y2(int x1,int x2,int y)
  278. {
  279. if(x1>x2)
  280. {
  281. int x=x1;
  282. x1=x2;
  283. x2=x;
  284. }
  285. //直通
  286. for(int i=x1+1;i<=x2;i++)
  287. {
  288. if(i==x2)
  289. return TRUE;
  290. if(m_map[y*m_nCol+i]!=BLANK_STATE)
  291. break;
  292. }
  293. //上通
  294. if(YThrough(x1,y-1,FALSE)&&YThrough(x2,y-1,FALSE))
  295. return TRUE;
  296. //下通
  297. if(YThrough(x1,y+1,TRUE)&&YThrough(x2,y+1,TRUE))
  298. return TRUE;
  299. return FALSE;
  300. }
  301. //
  302. // 是否同一直线通
  303. //
  304. BOOL C_LLK_Dlg::LineX(int x,int y1,int y2)
  305. {
  306. if(y1>y2)
  307. {
  308. int y=y1;
  309. y1=y2;
  310. y2=y;
  311. }
  312. for(int y=y1;y<=y2;y++)
  313. {
  314. if(m_map[y*m_nCol+x]!=BLANK_STATE)
  315. return FALSE;
  316. if(y==y2)
  317. return TRUE;
  318. }
  319. return FALSE;
  320. }
  321. //
  322. // 是否同一直线通
  323. //
  324. BOOL C_LLK_Dlg::LineY(int x1,int x2,int y)
  325. {
  326. if(x1>x2)
  327. {
  328. int x=x1;
  329. x1=x2;
  330. x2=x;
  331. }
  332. for(int x=x1;x<=x2;x++)
  333. {
  334. if(m_map[y*m_nCol+x]!=BLANK_STATE)
  335. return FALSE;
  336. if(x==x2)
  337. return TRUE;
  338. }
  339. return FALSE;
  340. }
  341. //
  342. //  1直角接口连通
  343. //
  344. BOOL C_LLK_Dlg::OneCornerLink(int x1, int y1,int x2, int y2)
  345. {
  346. if(x1>x2)
  347. {
  348. int n=x1;
  349. x1=x2;
  350. x2=n;
  351. n=y1;
  352. y1=y2;
  353. y2=n;
  354. }
  355. if(y2<y1)
  356. {
  357. if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2+1))
  358. return TRUE;
  359. if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1-1))
  360. return TRUE;
  361. return FALSE;
  362. }
  363. else
  364. {
  365. if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2-1))
  366. return TRUE;
  367. if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1+1))
  368. return TRUE;
  369. return FALSE;
  370. }
  371. return FALSE;
  372. }
  373. //
  374. //  2直角接口连通
  375. //
  376. BOOL C_LLK_Dlg::TwoCornerLink(int x1, int y1, int x2, int y2)
  377. {
  378. if(x1>x2)
  379. {
  380. int n=x1;
  381. x1=x2;
  382. x2=n;
  383. n=y1;
  384. y1=y2;
  385. y2=n;
  386. }
  387. //右通
  388. if(XThrough(x1+1,y1,TRUE)&&XThrough(x2+1,y2,TRUE))
  389. return TRUE;
  390. //左通
  391. if(XThrough(x1-1,y1,FALSE)&&XThrough(x2-1,y2,FALSE))
  392. return TRUE;
  393. //上通
  394. if(YThrough(x1,y1-1,FALSE)&&YThrough(x2,y2-1,FALSE))
  395. return TRUE;
  396. //下通
  397. if(YThrough(x1,y1+1,TRUE)&&YThrough(x2,y2+1,TRUE))
  398. return TRUE;
  399. //右
  400. for(int x=x1+1;x<m_nCol;x++)
  401. {
  402. if(m_map[y1*m_nCol+x]>-1)
  403. break;
  404. if(OneCornerLink(x,y1,x2,y2))
  405. return TRUE;
  406. }
  407. //左
  408. for(x=x1-1;x>-1;x--)
  409. {
  410. if(m_map[y1*m_nCol+x]!=BLANK_STATE)
  411. break;
  412. if(OneCornerLink(x,y1,x2,y2))
  413. return TRUE;
  414. }
  415. //上
  416. for(int y=y1-1;y>-1;y--)
  417. {
  418. if(m_map[y*m_nCol+x1]!=BLANK_STATE)
  419. break;
  420. if(OneCornerLink(x1,y,x2,y2))
  421. return TRUE;
  422. }
  423. //下
  424. for(y=y1+1;y<m_nRow;y++)
  425. {
  426. if(m_map[y*m_nCol+x1]!=BLANK_STATE)
  427. break;
  428. if(OneCornerLink(x1,y,x2,y2))
  429. return TRUE;
  430. }
  431. return FALSE;
  432. }
  433. BOOL C_LLK_Dlg::XThrough(int x, int y, BOOL bAdd)
  434. {
  435. if(bAdd)
  436. {
  437. for(int i=x;i<m_nCol;i++)
  438. if(m_map[y*m_nCol+i]!=BLANK_STATE)
  439. return FALSE;
  440. }
  441. else
  442. {
  443. for(int i=0;i<=x;i++)
  444. if(m_map[y*m_nCol+i]!=BLANK_STATE)
  445. return FALSE;
  446. }
  447. return TRUE;
  448. }
  449. BOOL C_LLK_Dlg::YThrough(int x, int y,BOOL bAdd)
  450. {
  451. if(bAdd)
  452. {
  453. for(int i=y;i<m_nRow;i++)
  454. if(m_map[i*m_nCol+x]!=BLANK_STATE)
  455. return FALSE;
  456. }
  457. else
  458. {
  459. for(int i=0;i<=y;i++)
  460. if(m_map[i*m_nCol+x]!=BLANK_STATE)
  461. return FALSE;
  462. }
  463. return TRUE;
  464. }
  465. //
  466. //  判断选中的两个方块是否可以消除
  467. //
  468. BOOL C_LLK_Dlg::IsLink(int x1, int y1, int x2, int y2)
  469. {
  470. //X直连方式
  471. if(x1==x2)
  472. {
  473. if(X1_Link_X2(x1,y1,y2))
  474. return TRUE;
  475. }
  476. //Y直连方式
  477. else if(y1==y2)
  478. {
  479. if(Y1_Link_Y2(x1,x2,y1))
  480. return TRUE;
  481. }
  482. //一个转弯直角的联通方式
  483. if(OneCornerLink(x1,y1,x2,y2))
  484. {
  485. return TRUE;
  486. }
  487. //两个转弯直角的联通方式
  488. else if(TwoCornerLink(x1,y1,x2,y2))
  489. {
  490. return TRUE;
  491. }
  492. return FALSE;
  493. }
  494. //
  495. //  截获键盘消息 F2 (用于新游戏开始)
  496. //
  497. BOOL C_LLK_Dlg::PreTranslateMessage(MSG* pMsg) 
  498. {
  499. if(pMsg->message==WM_KEYDOWN)
  500. {
  501. if(pMsg->wParam==VK_F2)
  502. {
  503. StartNewGame();
  504. }
  505. }
  506. return CDialog::PreTranslateMessage(pMsg);
  507. }
  508. //
  509. //   检测是否已经赢得了游戏
  510. //
  511. BOOL C_LLK_Dlg::IsWin(void)
  512. {
  513. //检测所有是否尚有非未被消除的方块
  514. // (非BLANK_STATE状态)
  515. for(int i=0;i<m_nRow*m_nCol;i++)
  516. {
  517. if(m_map[i] != BLANK_STATE)
  518. {
  519. return FALSE;
  520. }
  521. }
  522. return TRUE;
  523. }