草庐IT

Visual C++实现连连看游戏项目实战三:核心算法设计与实现(附源码和资源 可用于大作业)

showswoller 2023-04-17 原文

需要源码和资源请点赞关注收藏后评论区留言私信~~~

一、主对话框类的设计

连连看的主对话框类,主要负责显示游戏界面,等级,时间显示以及快捷键调用等等。主要有以下几个处理模块

1:主菜单处理模块

2:连接提示处理模块

3:换盘处理模块

4:初始化棋盘数据模块

5:游戏信息化处理模块

主对话框类声明代码如下

其中包含连接提示,显示棋盘,显示数据,换盘,初始化游戏以及棋盘数据函数等

// llkDlg.h : header file
//

#if !defined(AFX_LLKDLG_H__BCB1D0A0_D08E_42B3_B138_E0F4345D7AAC__INCLUDED_)
#define AFX_LLKDLG_H__BCB1D0A0_D08E_42B3_B138_E0F4345D7AAC__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/
// CLlkDlg dialog

#include "LineStatic.h"
#include "ChessMan.h"

class CLlkDlg : public CDialog
{
// Construction
public:
	void RefreshMap();
	void Exchange(int map[MAXX][MAXY]);
	void CallHint();
	void CallExchange();
	void ShowMap(int map[MAXX][MAXY]);
	void InitMap(int map[MAXX][MAXY]);
	void ShowMsg(CRgn * rgn);
	void Start(int nlevel);
	void PlayBackMusic(BOOL bflag);
	void isHighLevel();
	CLlkDlg(CWnd* pParent = NULL);	// standard constructor

	CChessMan * m_p;		//棋子指针
	int map[MAXX][MAXY];	//棋盘数组
	BOOL	m_bStart;		//游戏开始状态
	int		m_nLevel;		//当前等级限制
	int		m_timePoint;	//时间限制
	CRgn	m_MsgRgn;		//信息区范围
	CPtrArray m_cmGroup;	//棋子数组
	int		m_hintNum;		//提示次数限制
	int		m_exchangeNum;	//换盘次数限制
	int     m_nHighLevel;	//最高等级

// Dialog Data
	//{{AFX_DATA(CLlkDlg)
	enum { IDD = IDD_LLK_DIALOG };
	CStatic	m_method;
	CLineStatic	m_line;
	CStatic	m_bkPic;
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CLlkDlg)
	public:
	virtual BOOL PreTranslateMessage(MSG* pMsg);
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	HICON m_hIcon;

	CMenu m_main_menu;

	int m_hintP2;			//第2个转折点
	int m_hintP1;			//第1个转折点

	// Generated message map functions
	//{{AFX_MSG(CLlkDlg)
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	afx_msg void OnAbout();
	afx_msg void OnExitGame();
	afx_msg void OnHelp();
	afx_msg void OnHeroList();
	afx_msg void OnPlayMusic();
	afx_msg void OnStartGame();
	afx_msg void OnTimer(UINT nIDEvent);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_LLKDLG_H__BCB1D0A0_D08E_42B3_B138_E0F4345D7AAC__INCLUDED_)

主对话框类实现如下,其中包含基本的初始化对话框函数,游戏开始处理函数以及背景音乐播放功能函数等等

// llkDlg.cpp : implementation file
//

#include "stdafx.h"
#include "llk.h"
#include "llkDlg.h"

#include "HeroDlg.h"
#include "HelpDlg.h"

#include <mmsystem.h>


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define IDC_BLOCK 2000 
/
// CAboutDlg dialog used for App About

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

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

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

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

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/
// CLlkDlg dialog

CLlkDlg::CLlkDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CLlkDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CLlkDlg)
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CLlkDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CLlkDlg)
	DDX_Control(pDX, IDC_METHOD, m_method);
	DDX_Control(pDX, IDC_LINE, m_line);
	DDX_Control(pDX, IDC_BKPIC, m_bkPic);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CLlkDlg, CDialog)
	//{{AFX_MSG_MAP(CLlkDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_COMMAND(IDR_ABOUT, OnAbout)
	ON_COMMAND(IDR_EXIT_GAME, OnExitGame)
	ON_COMMAND(IDR_HELP, OnHelp)
	ON_COMMAND(IDR_HERO_LIST, OnHeroList)
	ON_COMMAND(IDR_PLAY_MUSIC, OnPlayMusic)
	ON_COMMAND(IDR_START_GAME, OnStartGame)
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/
// CLlkDlg message handlers

BOOL CLlkDlg::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);
		}
	}


	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	m_main_menu.LoadMenu(IDR_MAIN_MENU);
	
	SetMenu(&m_main_menu);

	m_nLevel = 1;

	SetWindowPos(NULL, 100, 100, 800, 600, SWP_SHOWWINDOW|SWP_NOZORDER);
	m_method.SetWindowPos(NULL, 300, 500, 200, 25, SWP_SHOWWINDOW|SWP_NOZORDER);
	m_bkPic.SetWindowPos(NULL, 130, 70, 480, 280, SWP_SHOWWINDOW|SWP_NOZORDER);
	m_line.SetWindowPos(NULL, 90, 30, 560, 360, SWP_SHOWWINDOW|SWP_NOZORDER);
	
	m_MsgRgn.CreateRectRgn(150, 20, 550, 40);
	
	m_bStart = false;
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

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

void CLlkDlg::OnPaint() 
{
	CDialog::OnPaint();
}

HCURSOR CLlkDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CLlkDlg::OnAbout() 
{
	CAboutDlg dlg;
	dlg.DoModal();
}

void CLlkDlg::OnExitGame() 
{
	CDialog::OnCancel();
}

void CLlkDlg::OnHelp() 
{
	CHelpDlg dlg;
	dlg.DoModal();
}

void CLlkDlg::OnHeroList() 
{
	CHeroDlg dlg;
	dlg.DoModal();
}

void CLlkDlg::OnPlayMusic() 
{
	
	//判断播放音乐菜单当前状态
	BOOL bCheck = (BOOL)m_main_menu.GetMenuState(IDR_PLAY_MUSIC, MF_CHECKED);
	
	if(m_bStart)
	{							//游戏如果开始才允许播放音乐
		if(bCheck)
		{
			m_main_menu.CheckMenuItem(IDR_PLAY_MUSIC,
				MF_BYCOMMAND | MF_UNCHECKED);
		}
		else
		{
			m_main_menu.CheckMenuItem(IDR_PLAY_MUSIC, 
				MF_BYCOMMAND | MF_CHECKED);
		}
		
		PlayBackMusic(!bCheck);		//调用播放背景音乐功能函数
	}
}

void CLlkDlg::OnStartGame() 
{
	char pszTmp[128] = {0};

	m_hintNum = 3;
	m_exchangeNum = 3;
	m_line.m_lineNum = 0;

	m_method.SetWindowText("开 始 游 戏!");

	Start(1);

	GetPrivateProfileString("HERO", "level", "1", 
			pszTmp, 127, ".\\setup.ini");
	m_nHighLevel = atoi(pszTmp);
}
//
//播放背景音乐
//
void CLlkDlg::PlayBackMusic(BOOL bflag)
{
	//指定文件并播放
	if(bflag)
	{								//播放音乐
		sndPlaySound("music.wav",SND_ASYNC); 
	}
	else
	{								//停止播放
		sndPlaySound(NULL,SND_PURGE); 
	}
}
//
//游戏开始
//
void CLlkDlg::Start(int level)
{
	CString str;

	m_nLevel = level;
	
	m_timePoint = 130 - level * 10;	//设置每个等级的限制时间
	
	//随机设置背景图片
	srand((unsigned int)time(NULL));
	str.Format("res\\b%d.bmp", m_nLevel);
	m_bkPic.ModifyStyle(0,SS_BITMAP|SS_CENTERIMAGE);    
	HBITMAP m_bkBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(), str, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE); 
	m_bkPic.SetBitmap(m_bkBmp);
	
	InitMap(map);

	ShowMap(map);

	m_p = NULL;
	CRgn rgn;
	rgn.CreateRectRgn(420, 0, 560, 160);
	m_MsgRgn.CopyRgn(&rgn);

	ShowMsg(&m_MsgRgn);

	//设置计时器
	KillTimer(1);
	SetTimer(1, 1000, NULL);
	m_bStart = true;
}
//
//信息显示
//
void CLlkDlg::ShowMsg(CRgn *rgn)
{
	CClientDC *pDC = (CClientDC *)GetDC();	

//	int nOldDC = pDC->SaveDC();
	
	CFont font; 

	CString str;
	//设置字体
	if(0==font.CreatePointFont(150,"Comic Sans MS"))
	{
		AfxMessageBox("Can't Create Font");
	}
	pDC->SelectObject(&font);
	//设置字体颜色及其背景颜色
	pDC->SetTextColor(RGB(39,244,10));
	pDC->SetBkColor(RGB(0,0,0));
    //输出数字
	str.Format("游戏等级: %d",m_nLevel);
	pDC->TextOut(650,420,str);

	str.Format("剩余时间: %03d", m_timePoint);
	pDC->TextOut(650, 450, str);

	str.Format("提示次数: %d",m_hintNum);	
	pDC->TextOut(650,480,str);
	
	str.Format("换盘次数: %d", m_exchangeNum);
	pDC->TextOut(650, 510, str);

	
}
//
//初始化棋盘数组
//
void CLlkDlg::InitMap(int map[][MAXY])
{
	int i, j;
	int x, y;
	
	//初始化边界
	for(i=0; i<MAXX; i++)
	{
		for(j=0; j<MAXY; j++)
		{
			if((i==0) || (i==MAXX-1) || (j==0) || (j==MAXY-1))
			{
				map[i][j] = -1;
			}
			else
			{
				map[i][j] = 0;
			}
		}
	}
	srand((unsigned int)time(NULL));//随机数种子
	
	//初始化地图
	for(i=0; i<SAME; i++)
	{
		for(j=1; j<=TYPENUM; j++)
		{
			x = rand()%MAXX;
			y = rand()%MAXY;
			if(map[x][y])
			{
				j--;
			}
			else
			{
				map[x][y] = j;
			}
		}
	}
}
//
//转换棋盘数组的中数据为棋子并显示出来
//
void CLlkDlg::ShowMap(int map[][MAXY])
{
	this->Invalidate();
	int i, j;
	POINT p;
	CString str;
	
	//清除原有按钮
	for(i=0; i<m_cmGroup.GetSize(); i++)
		delete (CChessMan *)m_cmGroup.GetAt(i);
	
	m_cmGroup.RemoveAll();
	for(i=1; i<MAXX-1; i++)
	{
		for(j=1; j<MAXY-1; j++)
		{
			p.x = i;
			p.y = j;
			m_cmGroup.Add(new CChessMan(map[i][j], p));
		}
	}
	for(i=0; i<(MAXX-2)*(MAXY-2); i++)
	{
		CChessMan *btn = (CChessMan *)m_cmGroup.GetAt(i);
		
		btn->Create(str, WS_CHILD|BS_BITMAP, //注意属性!!!
			CRect(130+(i%(MAXY-2))*40, 70+(i/(MAXY-2))*40, 170+(i%(MAXY-2))*40, 110+(i/(MAXY-2))*40), this, IDC_BLOCK+i);
		if(btn->m_id)//如果为0则不显示
		{
			str.Format("res\\%d.bmp", btn->m_id);
			HBITMAP m_fkBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(), str, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE);
			if(m_fkBmp == NULL) 
			{
				if(MessageBox("缺少图片资源!", "错误", MB_ICONERROR|MB_OK) == IDOK)
				{
					CDialog::OnCancel();
					return;
				}
			}	
			btn->SetBitmap(m_fkBmp);
			btn->ShowWindow(SW_SHOW);
		}
		else
		{
			btn->ShowWindow(SW_HIDE);
		}
	}
}
//
//换盘接口成员函数
//
void CLlkDlg::CallExchange()
{
	if(m_exchangeNum)
	{
		do
		Exchange(map);
		while(!CChessMan::Hint(map));//至少有一个可消去
		ShowMap(map);
		m_exchangeNum--;
	}
}
//
//提示连接接口成员函数
//
void CLlkDlg::CallHint()
{
	if(m_hintNum)
	{
		if(CChessMan::Hint(map, &m_hintP1, &m_hintP2))
		{
			CChessMan *temp;
			temp = (CChessMan *)m_cmGroup.GetAt(m_hintP1);
			temp->SetButtonStyle(BS_DEFPUSHBUTTON);
			temp = (CChessMan *)m_cmGroup.GetAt(m_hintP2);
			temp->SetButtonStyle(BS_DEFPUSHBUTTON);
			m_hintNum--;
		}
	}
}
//
//换盘函数
//
void CLlkDlg::Exchange(int map[][MAXY])
{
	int i, j;
	int k = 0;
	int temp[(MAXX-2)*(MAXY-2)+1] = {0};//比格子数多一个,防止数组越界!!!
	for(i=1; i<MAXX-1; i++)
	{
		for(j=1; j<MAXY-1; j++)
		{
			if(map[i][j])
			{
				temp[k++] = map[i][j];
				map[i][j] = 0;
			}
		}
	}
	srand((unsigned int)time(NULL));
	k = 0;
	while(temp[k])
	{
		i = rand()%MAXX;
		j = rand()%MAXY;
		if(map[i][j])
			k--;
		else
			map[i][j] = temp[k];
		k++;
	}
}
//
//更新棋盘数组
//
void CLlkDlg::RefreshMap()
{
	CRgn resultRgn;
	resultRgn.CreateRectRgn(90,30,690,430);
	CRgn tmpRgn;
	tmpRgn.CreateRectRgn(0,0,0,0);
	for(int i=0; i<MAXX; i++)
	{
		for(int j=0; j<MAXY; j++)
		{
			CRect rect;
			CRgn srcRgn;
			
			if(map[i][j]==-1 || map[i][j]==0)
			{
				rect.top = 30 + i*40;
				rect.bottom = 70 + i*40;
				rect.left = 90 + j*40;
				rect.right = 130 + j*40;
				
				srcRgn.CreateRectRgnIndirect(&rect);
				//把消去的区域加进来(覆盖原有区域),以便刷新
				resultRgn.CombineRgn(&srcRgn,&tmpRgn,RGN_OR);
				tmpRgn.CopyRgn(&resultRgn);
			}
		}
	}
	//只刷新被消去的区域,防止界面闪烁
	this->InvalidateRgn(&resultRgn);
}
//
//定时器
//
void CLlkDlg::OnTimer(UINT nIDEvent) 
{
	m_timePoint -= 1;
	if(m_timePoint <= 0)
	{
		KillTimer(1);
		
		int nRet = MessageBox("限 制 时 间 到!", "闯 关 失 败", MB_YESNO|MB_ICONINFORMATION);
		
		if(IDYES == nRet)
		{
			OnStartGame();
		}
		else
		{
			isHighLevel();
			CDialog::OnCancel();
		}
		return;
	}
	
	InvalidateRgn(&m_MsgRgn);

	ShowMsg(&m_MsgRgn);
}
//
//截获用户消息
//
BOOL CLlkDlg::PreTranslateMessage(MSG* pMsg) 
{
	//键盘按下消息
	if(pMsg->message==WM_KEYDOWN)
	{
		switch((int)pMsg->wParam)
		{
		case VK_F5:			//快捷键F5
			CallHint();
			m_line.m_lineNum = 0;
			RefreshMap();
			m_line.Invalidate();
			break;
		case VK_F6:			//快捷键F6
			CallExchange();			
			m_line.m_lineNum = 0;
			RefreshMap();
			m_line.Invalidate();
			break;
		default:
			break;
		}
	}
	return CDialog::PreTranslateMessage(pMsg);
}

void CLlkDlg::isHighLevel()
{
	if(m_nHighLevel<m_nLevel)
	{
		CHeroDlg dlg;
		dlg.m_level = m_nLevel;
		dlg.SetWriteFlg(TRUE);
		dlg.DoModal();
	}
}

二、棋子类的设计

棋子类包含如下几个功能函数

1:游戏胜负判断处理

2:游戏升级处理

3:查找处理

4:提示处理

棋子类声明如下,包含两个构造函数,查找接口函数,判断棋子为空函数以及鼠标左键响应函数,代码如下

#if !defined(AFX_CHESSMAN_H__EB414A5E_D02A_4F89_ACE0_2187863ECEAD__INCLUDED_)
#define AFX_CHESSMAN_H__EB414A5E_D02A_4F89_ACE0_2187863ECEAD__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// ChessMan.h : header file
//

/
// CChessMan window
class CChessMan : public CButton
{
	// Construction
public:
	CChessMan();
	CChessMan(int id, POINT pos);
	
public:
	static BOOL FindTwoCorner(int map[][MAXY], POINT p1, POINT p2, POINT  *cross1, POINT *cross2);
	static BOOL FindCorner(int map[][MAXY], POINT p1, POINT p2, POINT *cross1);
	static BOOL Hint(int map[][MAXY], int* a1, int *a2);
	static BOOL Hint(int map[MAXX][MAXY]);
	static BOOL FindLine(int map[][MAXY], POINT p1, POINT p2);
	BOOL IsEmpty(int map[][MAXY]);
	BOOL Find(int map[MAXX][MAXY], POINT p1, POINT p2);
	BOOL Find(int map[MAXX][MAXY], POINT p1, POINT p2, POINT cross1, POINT cross2);
	static BOOL FindTwoCorner(int map[MAXX][MAXY], POINT p1, POINT p2);
	static BOOL FindCorner(int map[MAXX][MAXY], POINT p1, POINT p2);
	POINT m_pos;
	int m_id;
	virtual ~CChessMan();
	
	// Generated message map functions
protected:
	//{{AFX_MSG(CChessMan)
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	//}}AFX_MSG
	
	DECLARE_MESSAGE_MAP()
};

/

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_LLKBUTTON_H__EB414A5E_D02A_4F89_ACE0_2187863ECEAD__INCLUDED_)


棋子类实现函数如下,包含基本的构造函数,析构函数,鼠标左键响应函数等等

// CChessMan.cpp : implementation file
//

#include "stdafx.h"
#include "llk.h"
#include "ChessMan.h"
#include "LlkDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CChessMan
CChessMan::CChessMan()
{
}

CChessMan::CChessMan(int id, POINT pos)
{
	m_id = id;
	m_pos = pos;
}

CChessMan::~CChessMan()
{
}


BEGIN_MESSAGE_MAP(CChessMan, CButton)
	//{{AFX_MSG_MAP(CChessMan)
	ON_WM_LBUTTONDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/
// CChessMan message handlers

BOOL CChessMan::FindLine(int map[][MAXY], POINT p1, POINT p2)
{
	int max, min;
	int i;

	if(p1.x == p2.x)
	{
		max = (p1.y>p2.y)?p1.y:p2.y;
		min = (p1.y<p2.y)?p1.y:p2.y;
		if(max == min+1)
		{
			return TRUE;//相邻的两个格子
		}
		for(i=min+1; i<max; i++)
		{
			if((map[p1.x][i]!=0) && (map[p1.x][i]!=-1))
			{
				return FALSE;
			}
		}
		return TRUE;
	}

	if(p1.y == p2.y)
	{
		max = (p1.x>p2.x)?p1.x:p2.x;
		min = (p1.x<p2.x)?p1.x:p2.x;
		if(max == min+1)
		{
			return TRUE;//相邻的两个格子
		}
		for(i=min+1; i<max; i++)
		{
			if((map[i][p1.y]!=0) && (map[i][p1.y]!=-1))
			{
				return FALSE;
			}
		}
		return TRUE;
	}

	return FALSE;
}

BOOL CChessMan::FindCorner(int map[][MAXY], POINT p1, POINT p2)
{
	int maxx, maxy, minx, miny;
	POINT tempPoint = {0};

	//测试矩形格子
	maxx = (p1.x>p2.x)?p1.x:p2.x;
	maxy = (p1.y>p2.y)?p1.y:p2.y;
	minx = (p1.x<p2.x)?p1.x:p2.x;
	miny = (p1.y<p2.y)?p1.y:p2.y;

	if(map[minx][maxy] == 0)
	{
		tempPoint.x = minx;
		tempPoint.y = maxy;
		if((FindLine(map, p1, tempPoint)) 
			&&(FindLine(map, tempPoint, p2)))
		{
			return TRUE;
		}
	}
	
	if(map[maxx][miny] == 0)
	{
		tempPoint.x = maxx;
		tempPoint.y = miny;
		if((FindLine(map, p1, tempPoint))
			&& (FindLine(map, tempPoint, p2)))
		{
			return TRUE;
		}
	}

	if(map[minx][miny] == 0)
	{
		tempPoint.x = minx;
		tempPoint.y = miny;
		if((FindLine(map, p1, tempPoint)) 
			&& (FindLine(map, tempPoint, p2)))
		{
			return TRUE;
		}
	}
	
	if(map[maxx][maxy] == 0)
	{
		tempPoint.x = maxx;
		tempPoint.y = maxy;
		if((FindLine(map, p1, tempPoint)) 
			&& (FindLine(map, tempPoint, p2)))
		{
			return TRUE;
		}
	}

	return FALSE;
}

BOOL CChessMan::FindCorner(int map[][MAXY], POINT p1, POINT p2, POINT *cross1)
{
	int maxx, maxy, minx, miny;
	POINT tempPoint = {0};

	//测试矩形格子
	maxx = (p1.x>p2.x)?p1.x:p2.x;
	maxy = (p1.y>p2.y)?p1.y:p2.y;
	minx = (p1.x<p2.x)?p1.x:p2.x;
	miny = (p1.y<p2.y)?p1.y:p2.y;

	if(map[minx][maxy] == 0)
	{
		tempPoint.x = minx;
		tempPoint.y = maxy;
		if((FindLine(map, p1, tempPoint)) 
			&& (FindLine(map, tempPoint, p2)))
		{
			cross1->x = tempPoint.x;
			cross1->y = tempPoint.y;
			return TRUE;
		}
	}
	
	if(map[maxx][miny] == 0)
	{
		tempPoint.x = maxx;
		tempPoint.y = miny;
		if((FindLine(map, p1, tempPoint)) 
			&& (FindLine(map, tempPoint, p2)))
		{
			cross1->x = tempPoint.x;
			cross1->y = tempPoint.y;
			return TRUE;
		}
	}

	if(map[minx][miny] == 0)
	{
		tempPoint.x = minx;
		tempPoint.y = miny;
		if((FindLine(map, p1, tempPoint)) 
			&& (FindLine(map, tempPoint, p2)))
		{
			cross1->x = tempPoint.x;
			cross1->y = tempPoint.y;
			return TRUE;
		}
	}
	
	if(map[maxx][maxy] == 0)
	{
		tempPoint.x = maxx;
		tempPoint.y = maxy;
		if((FindLine(map, p1, tempPoint)) 
			&& (FindLine(map, tempPoint, p2)))
		{
			cross1->x = tempPoint.x;
			cross1->y = tempPoint.y;
			return TRUE;
		}
	}

	return FALSE;
}

BOOL CChessMan::FindTwoCorner(int map[][MAXY], POINT p1, POINT p2)
{
	int i;
	POINT tempPoint = {0};
	//纵向
	for(i=0; i<MAXY; i++)
	{
		if(i == p1.y)
		{
			continue;
		}
		tempPoint.x = p1.x;
		tempPoint.y = i;
		if((map[tempPoint.x][tempPoint.y]==0) 
			|| (map[tempPoint.x][tempPoint.y]==-1))
		{
			if(FindLine(map, tempPoint, p1))
			{
				tempPoint.x = p2.x;
				if((map[tempPoint.x][tempPoint.y]==0) 
					|| (map[tempPoint.x][tempPoint.y]==-1))
				{
					if(FindLine(map, tempPoint, p2))
					{
						return TRUE;
					}
				}
			}
		}
	}

	//横向
	for(i=0; i<MAXX; i++)
	{
		if(i == p1.x)
			continue;
		tempPoint.x = i;
		tempPoint.y = p1.y;
		if((map[tempPoint.x][tempPoint.y]==0) 
			|| (map[tempPoint.x][tempPoint.y]==-1))
		{
			if(FindLine(map, tempPoint, p1))
			{
				tempPoint.y = p2.y;
				if((map[tempPoint.x][tempPoint.y]==0) 
					|| (map[tempPoint.x][tempPoint.y]==-1))
				{
					if(FindLine(map, tempPoint, p2))
					{
						return TRUE;
					}
				}
			}
		}
	}

	return FALSE;
}

BOOL CChessMan::FindTwoCorner(int map[][MAXY], POINT p1, POINT p2, POINT *cross1, POINT *cross2)
{
	int i;
	POINT tempPoint1 = {0};
	POINT tempPoint2 = {0};
	//横向
	for(i=0; i<MAXY; i++)
	{
		if(i == p1.y)
			continue;
		tempPoint1.x = p1.x;
		tempPoint1.y = i;
		if((map[tempPoint1.x][tempPoint1.y]==0) 
			|| (map[tempPoint1.x][tempPoint1.y]==-1))
		{
			if(FindLine(map, tempPoint1, p1))
			{
				tempPoint2.x = p2.x;
				tempPoint2.y = i;
				if((map[tempPoint2.x][tempPoint2.y]==0) 
					|| (map[tempPoint2.x][tempPoint2.y]==-1))
				{
					if(FindLine(map, tempPoint2, p2))
					{	//判断两个转折点是否连通!!!
						if(FindLine(map, tempPoint1, tempPoint2))
						{
							cross1->x = p1.x;
							cross1->y = i;
							cross2->x = p2.x;
							cross2->y = i;
							return TRUE;
						}	
					}
				}
			}
		}
	}

	//纵向
	for(i=0; i<MAXX; i++)
	{
		if(i == p1.x)
			continue;
		tempPoint1.x = i;
		tempPoint1.y = p1.y;
		if((map[tempPoint1.x][tempPoint1.y]==0) 
			|| (map[tempPoint1.x][tempPoint1.y]==-1))
		{
			if(FindLine(map, tempPoint1, p1))
			{
				tempPoint2.x = i;
				tempPoint2.y = p2.y;
				if((map[tempPoint2.x][tempPoint2.y]==0) 
					|| (map[tempPoint2.x][tempPoint2.y]==-1))
				{
					if(FindLine(map, tempPoint2, p2))
					{//判断两个转折点是否连通!!!
						if(FindLine(map, tempPoint1, tempPoint2))
						{
							cross1->x = i;
							cross1->y = p1.y;
							cross2->x = i;
							cross2->y = p2.y;
							return TRUE;
						}
					}
				}
			}
		}
	}

	return FALSE;
}

BOOL CChessMan::Find(int map[MAXX][MAXY], POINT p1, POINT p2)
{
	CLlkDlg *parent = (CLlkDlg *)GetParent();
	CString str;
	if(FindLine(map, p1, p2))
	{
		str.Format("直线:(%d,%d)->(%d,%d)\n", 
			p1.x, p1.y, p2.x, p2.y);
		parent->m_method.SetWindowText(str);
		return TRUE;
	}
	if(FindCorner(map, p1, p2))
	{
		str.Format("一拐角:(%d,%d)->(%d,%d)\n", 
			p1.x, p1.y, p2.x, p2.y);
		parent->m_method.SetWindowText(str);
		return TRUE;
	}
	if(FindTwoCorner(map, p1, p2))
	{
		str.Format("两拐角:(%d,%d)->(%d,%d)\n", 
			p1.x, p1.y, p2.x, p2.y);
		parent->m_method.SetWindowText(str);
		return TRUE;
	}

	return FALSE;
}

BOOL CChessMan::Find(int map[][MAXY], 
					 POINT p1, POINT p2, 
					 POINT cross1, POINT cross2)
{
	CLlkDlg *parent = (CLlkDlg *)GetParent();
	parent->m_line.m_src1 = p1;
	parent->m_line.m_src2 = p2;

	CString str;
	if(FindLine(map, p1, p2))
	{
		str.Format("直线:(%d,%d)->(%d,%d)\n", 
			p1.x, p1.y, p2.x, p2.y);
		parent->m_method.SetWindowText(str);
		parent->m_line.m_lineNum = 1;
		return TRUE;
	}
	if(FindCorner(map, p1, p2, &(parent->m_line.m_crossP1)))
	{
		str.Format("一拐角:(%d,%d)->(%d,%d)\n", 
			p1.x, p1.y, p2.x, p2.y);
		parent->m_method.SetWindowText(str);
		parent->m_line.m_lineNum = 2;
		return TRUE;
	}
	if(FindTwoCorner(map, p1, p2, &(parent->m_line.m_crossP1), 
		&(parent->m_line.m_crossP2)))
	{
		str.Format("两拐角:(%d,%d)->(%d,%d)\n", 
			p1.x, p1.y, p2.x, p2.y);
		parent->m_method.SetWindowText(str);
		parent->m_line.m_lineNum = 3;
		return TRUE;
	}

	return FALSE;
}

BOOL CChessMan::IsEmpty(int map[][MAXY])
{
 	int i, j;
 	int sum = 0;
 
 	for(i=1; i<MAXX-1; i++)
 		for(j=1; j<MAXY-1; j++)
 			sum += map[i][j];
 	if(sum)
 		return FALSE;
 	else
 		return TRUE;
}


BOOL CChessMan::Hint(int map[][MAXY])
{
	int x1, y1, x2, y2;
	POINT p1 = {0};
	POINT p2 = {0};

	for(x1=1; x1<MAXX-1; x1++)
	{
		for(y1=1; y1<MAXY-1; y1++)
		{
			for(x2=1; x2<MAXX-1; x2++)
			{
				for(y2=1; y2<MAXY-1; y2++)
				{
					p1.x = x1;
					p1.y = y1;
					p2.x = x2;
					p2.y = y2;
					if((map[x1][y1]==0) || (map[x2][y2]==0))
					{//空白格子
						continue;
					}
					if(map[x1][y1] != map[x2][y2])
					{//不相等
						continue;
					}		
					if((x1==x2) && (y1==y2))
					{//同一个点
						continue;
					}
					if(FindLine(map, p1, p2))
					{
						return TRUE;
					}
					if(FindCorner(map, p1, p2))
					{
						return TRUE;
					}
					if(FindTwoCorner(map, p1, p2))
					{
						return TRUE;
					}
				}
			}
		}
	}
	return FALSE;
}

BOOL CChessMan::Hint(int map[][MAXY], int *a1, int *a2)
{
	int x1, y1, x2, y2;
	POINT p1 = {0};
	POINT p2 = {0};

	for(x1=1; x1<MAXX-1; x1++)
	{
		for(y1=1; y1<MAXY-1; y1++)
		{
			for(x2=1; x2<MAXX-1; x2++)
			{
				for(y2=1; y2<MAXY-1; y2++)
				{
					p1.x = x1;
					p1.y = y1;
					p2.x = x2;
					p2.y = y2;
					if((map[x1][y1]==0) || (map[x2][y2]==0))
					{//空白格子
						continue;
					}
					if(map[x1][y1] != map[x2][y2])
					{//不相等
						continue;
					}
					if((x1==x2) && (y1==y2))
					{//同一个点
						continue;
					}
					if(FindLine(map, p1, p2))
					{
						*a1 = (x1-1) * (MAXY-2) + y1 - 1;
						*a2 = (x2-1) * (MAXY-2) + y2 - 1;
						return TRUE;
					}
					if(FindCorner(map, p1, p2))
					{
						*a1 = (x1-1) * (MAXY-2) + y1 - 1;
						*a2 = (x2-1) * (MAXY-2) + y2 - 1;
						return TRUE;
					}
					if(FindTwoCorner(map, p1, p2))
					{
						*a1 = (x1-1) * (MAXY-2) + y1 - 1;
						*a2 = (x2-1) * (MAXY-2) + y2 - 1;
						return TRUE;
					}
				}
			}
		}
	}
	return FALSE;
}

void CChessMan::OnLButtonDown(UINT nFlags, CPoint point) //用此事件可以加快响应速度(不用Clicked事件)
{
	SetButtonStyle(BS_DEFPUSHBUTTON);//显示黑边框
	CLlkDlg *parent = (CLlkDlg *)GetParent();

	if((parent->m_p==NULL) || (parent->m_p->m_id!=m_id)
		|| ((parent->m_p->m_pos.x==m_pos.x)
		&&(parent->m_p->m_pos.y==m_pos.y)))
	{
		parent->m_p = this;
		if(parent->m_line.m_lineNum != 0)
		{
			parent->m_line.m_lineNum = 0;
			parent->RefreshMap();
			parent->m_line.Invalidate();
		}
	}
	else 
	{
		if(Find(parent->map, parent->m_p->m_pos, 
			m_pos, parent->m_line.m_crossP1, 
			parent->m_line.m_crossP2))
		{
			//消去
			parent->map[parent->m_p->m_pos.x][parent->m_p->m_pos.y] = 0;
			parent->map[m_pos.x][m_pos.y] = 0;
			//不能用delete!!!否则重新开始时无法清除原有按钮
			parent->m_p->ShowWindow(SW_HIDE);
			this->ShowWindow(SW_HIDE);
			
			parent->RefreshMap();
			parent->m_line.Invalidate();

			parent->m_p = NULL;
			parent->m_timePoint += 3;//增加时间点
			//画时间条
			parent->InvalidateRgn(&(parent->m_MsgRgn));

			if(IsEmpty(parent->map))//是否消完
			{
				int ret = MessageBox("过关拉!要挑战下一关吗?", 
					"恭喜你!", MB_ICONINFORMATION|MB_OKCANCEL);
				if(ret == IDOK)
				{
					parent->Start(++(parent->m_nLevel));
				}
				else
				{
					for(int i=0; i<(MAXX-2)*(MAXY-2); i++)
					{
						delete (CChessMan *)parent->m_cmGroup.GetAt(i);
					}

					parent->isHighLevel();	//结束游戏时,调用等级判断函数

					parent->DestroyWindow();
					
				}
			}

			if(!Hint(parent->map))//是否无处可消
			{
				parent->m_exchangeNum++;
				parent->CallExchange();
				parent->m_method.SetWindowText("无可用消除!自动切换!");
			}
		}
		else
		{
			parent->m_p = this;
		}
	}	

}

实现效果如下 

 

 

 创作不易 觉得有帮助请点赞关注收藏~~~

有关Visual C++实现连连看游戏项目实战三:核心算法设计与实现(附源码和资源 可用于大作业)的更多相关文章

  1. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  2. ruby-on-rails - 如何使辅助方法在 Rails 集成测试中可用? - 2

    我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel

  3. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  4. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  5. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  6. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  7. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  8. ruby - Arrays Sets 和 SortedSets 在 Ruby 中是如何实现的 - 2

    通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复

  9. ruby - "public/protected/private"方法是如何实现的,我该如何模拟它? - 2

    在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定

  10. ruby - 我需要从 facebook 游戏中抓取数据——使用 ruby - 2

    修改(澄清问题)我已经花了几天时间试图弄清楚如何从Facebook游戏中抓取特定信息;但是,我遇到了一堵又一堵砖墙。据我所知,主要问题如下。我可以使用Chrome的检查元素工具手动查找我需要的html-它似乎位于iframe中。但是,当我尝试抓取该iframe时,它​​是空的(属性除外):如果我使用浏览器的“查看页面源代码”工具,这与我看到的输出相同。我不明白为什么我看不到iframe中的数据。答案不是它是由AJAX之后添加的。(我知道这既是因为“查看页面源代码”可以读取Ajax添加的数据,也是因为我有b/c我一直等到我可以看到数据页面之后才抓取它,但它仍然不存在)。发生这种情况是因为

随机推荐