软件工程周总结
本周完成了数据结构第二节阶段大作业--连连看
摘 要
该系统的功能是以菜单方式工作,进入系统时首先进入菜单选择界面,用户通过鼠标点击来选择:
基本模式——进入基本游戏界面
休闲模式——进入休闲游戏界面
关卡模式——进入关卡游戏界面
进入游戏界面后有菜单栏,可以通过鼠标进行选择:
开始游戏功能——显示出连连看地图,游戏开始;
暂停游戏功能——游戏暂停,倒计时暂停,再次点击游戏开始;
提示功能——显示出能够可以进行相连的一对,进行提示;
重排功能——连连看地图重新排列。
在各项基本功能之下我们可以看到各种小的模块来满足用户的各种需求,达到快速方便的效果。
程序在设计的过程中遇到的问题已及时更正,但由于编者的能力和水平有限,连连看系统和文档不免出现一些不期待的错误,望文档读者谅解,并欢迎及时提醒和改正,在此表示谢意。
关键词:数据结构; 连连看
第1章 引言
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率的算法。数据结构往往同高效的检索算法和索引技术有关。
本次课程设计,是利用图来实现连连看。
本文档从概要设计,详细设计,参考源程序代码以及显示程序运行的截屏等方面详尽的介绍了软件开发过程。
第2章 系统功能需求分析
2.1 问题描述:
利用图,实现下面的功能:
1)生成连连看的地图
2)消除能够匹配的两个顶点
3)对能够进行匹配的两个点进行提示功能
2.2 需求分析
1) 用图表实现生成连连看地图的基本功能,可以实现地图的生成,地图的显示。
2) 图使程序设计的数据存储更方便简洁。
3) 通过图实现的连连看的消除更加方便。
第3章 概要设计
3.1 抽象数据类型(ADT)
ADT CGraph
{ #define MAX_VERTEX_NUM 160 //顶点数
typedef int Vertices[MAX_VERTEX_NUM];
typedef bool** AdjMatrix;
基本操作:
(1) int AddVertex(int info);
初始条件:图G已存在
操作结果:添加点
(2) void AddArc(int vIndex1, int vIndex2);
初始条件:图G已存在
操作结果:添加边
(3) int GetVertex(int vIndex);
初始条件:图G已存在
操作结果:获得顶点信息
(4) bool GetArc(int vIndex1, int vIndex2);
初始条件:图G已存在
操作结果:更新顶点信息
(5) int GetVertexN();
初始条件:图G已存在
操作结果:获得顶点个数
(6) void ResetCGraph();
初始条件:图G已存在
操作结果:重置图信息
(7) void InitGraph();
操作结果:初始化图
}
3.2 存储结构
struct Information
{
Vertices m_Vertics;//顶点数组
AdjMatrix m_AdjMatrix;//关系矩阵
int m_nVertexN;//顶点个数
int m_nArcnum;//边个数};
3.3 系统流程图
第4章 详细设计
该程序设计用 InitGrap()函数初始化邻接矩阵,InitMap()函数生成游戏地图,IsLink()函数来判断两个点是否连接,ClearLog()函数来消除两个相同且连接的图案, UpdateArc()函数更新边, SearchaPath()函数判断v1,v2是否连通,
Hint()函数用来进行提示提示,通过ReArrangeLog(&)函数进行重排。
4.1 重要程序段1
void CGraph::InitGraph()//初始化邻接矩阵
{
for (int i = 0; i < MAX_VERTEX_NUM;i++)
{
//初始化顶点
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
m_Vertics[i] = -1;
}
//初始化边
m_AdjMatrix = new bool* [MAX_VERTEX_NUM];
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
m_AdjMatrix[i] = new bool[MAX_VERTEX_NUM];
for (int j = 0; j < MAX_VERTEX_NUM; j++)
{
m_AdjMatrix[i][j] = false;
}
/*if (m_nVertexN >= MAX_VERTEX_NUM)return 0;
m_Vertics[m_nVertexN++] = info;
return 1;*/
}
}
}
4.2 重要程序段2
void CGameLogic::InitMap(CGraph& g)//游戏地图初始化
{
g.ResetCGraph();
//随机生成地图
int TempMap[MAX_VERTEX_NUM];
//多少花色
for (int i = 0; i < MAX_PIC_NUM; i++)
{
for (int j = 0; j < REPEART_NUM; j++)
{
TempMap[i * REPEART_NUM + j] = i;
}
}
//设置种子
srand((int)time(NULL));
//随机任意交换两个数字
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
int vIndex1 = rand() % MAX_VERTEX_NUM;
int vIndex2 = rand() % MAX_VERTEX_NUM;
//交换两个数值
int ntemp = TempMap[vIndex1];
TempMap[vIndex1] = TempMap[vIndex2];
TempMap[vIndex2] = ntemp;
}
//添加点
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
//添加点
g.AddVertex(TempMap[i]);
}
for (int i = 0; i <MAX_ROW; i++) //添加边
{
//g.GetVertex(vIndex1)==g.GetVertex(vIndex2)&& g.GetVertex(vIndex1) !=BLANK&&SearchaPath(g,vIndex1, vIndex2)==true
for (int j = 0; j <MAX_COL; j++)
{
UpdateArc(g, i, j);
}
}
}
4.3 重要程序段3
bool CGameLogic::IsLink(CGraph&g, Vertex v1, Vertex v2)//是否可以连接
{
int vIndex1 = v1.row * MAX_COL + v1.col;
int vIndex2 = v2.row * MAX_COL + v2.col;
PushVertex(vIndex1);//
if (g.GetVertex(vIndex1)==g.GetVertex(vIndex2)&& g.GetVertex(vIndex1) !=BLANK&&SearchaPath(g,vIndex1, vIndex2)==true)
{
return true;
}
PopVertex();
return false;
}
4.4 重要程序段4
void CGameLogic::ClearLog(CGraph& g, Vertex v1, Vertex v2)//消除
{
/*anMap[v1.row][v1.col] = BLANK;
anMap[v2.row][v2.col] = BLANK;*/
int vIndex1 = v1.row * MAX_COL + v1.col;
int vIndex2 = v2.row * MAX_COL + v2.col;
//更新顶点
g.UpdateVertex(vIndex1, BLANK);
g.UpdateVertex(vIndex2,BLANK);
UpdateArc(g,v1.row,v1.col);
UpdateArc(g, v2.row, v2.col);
CStudioFile::WriteString(g);
}
4.5 重要程序段5
//更新边
void CGameLogic::UpdateArc(CGraph& g, int row, int col)
{
//看左右顶点是否有边 vIndex2在vIndex1的
int vIndex1 = row * MAX_COL + col;//获取索引
if (col > 0)//左
{
int vIndex2 = vIndex1 - 1;//找第二个点的索引号
int v1info = g.GetVertex(vIndex1);
int v2info = g.GetVertex(vIndex2);
if (v1info==v2info||v1info==BLANK||v2info==BLANK)
{
g.AddArc(vIndex1,vIndex2);
}
}
if (col < MAX_COL-1)//右
{
int vIndex2 = vIndex1 + 1;//找第二个点的索引号
int v1info = g.GetVertex(vIndex1);
int v2info = g.GetVertex(vIndex2);
if (v1info == v2info || v1info == BLANK || v2info == BLANK)
{
g.AddArc(vIndex1, vIndex2);
}
}
if (row > 0)//上
{
int vIndex2 = vIndex1 - MAX_COL;//找第二个点的索引号
int v1info = g.GetVertex(vIndex1);
int v2info = g.GetVertex(vIndex2);
if (v1info == v2info || v1info == BLANK || v2info == BLANK)
{
g.AddArc(vIndex1, vIndex2);
}
}
if (row < MAX_ROW-1)//下
{
int vIndex2 = vIndex1 + MAX_COL;//找第二个点的索引号
int v1info = g.GetVertex(vIndex1);
int v2info = g.GetVertex(vIndex2);
if (v1info == v2info || v1info == BLANK || v2info == BLANK)
{
g.AddArc(vIndex1, vIndex2);
}
}
}
4.6重要程序段6
//深度优先
bool CGameLogic::SearchaPath(CGraph& g, int v1, int v2)//判断v1,v2是否连通
{
int vexNum = g.GetVertexN();//顶点个数
int pathCount = 0;
for (int i = 0; i < vexNum; i++)
{
if (g.GetArc(v1, i) && !IsExsit(i))
{
bool p = false;
//压入当前点
PushVertex(i);
//当中间点不是v2时,继续寻找下一个相邻且连通的顶点
if (i != v2)
{
//当中间顶点不为空时,表示该条路径不通
if (g.GetVertex(i) != BLANK)
{
PopVertex();
continue;
}
if (SearchaPath(g, i, v2))
{
return true;
}
}
else
{
if (CornerCount() > 2)
{
PopVertex();
return false;
}
return true;
}
PopVertex();
}
}
return false;
}
4.7重要程序段7
void CGameControl::Hint(Vertex path[],int &nVernum,Vertex& ver1,Vertex& ver2)
{
int vernum = m_graph.GetVertexN();
for (int i = 0; i < vernum; i++)
{
for (int j = 0; j < vernum; j++)
{
if (m_graph.GetVertex(i) != BLANK && m_graph.GetVertex(j) != BLANK)
{
Vertex v1,v2;
v1.row = i / MAX_COL; v1.col = i - i / MAX_COL * MAX_COL;
v2.row = j / MAX_COL; v2.col = j - j / MAX_COL * MAX_COL;
if (m_gameLogic.IsLink(m_graph, v1, v2))
{
nVernum = m_gameLogic.GetVexPath(path);
ver1 = v1;
ver2 = v2;
return;
}
}
}
}
}
4.8重要程序段8
void CGameLogic::ReArrangeLog(CGraph& g)
{
//设置种子
srand((int)time(NULL));
//随机任意交换两个数字
for (int i = 0; i < 100; i++)
{
int vIndex1 = rand() % MAX_VERTEX_NUM;
int vIndex2 = rand() % MAX_VERTEX_NUM;
//交换两个数值
int ntemp =g.GetVertex(vIndex1);
g.UpdateVertex( vIndex1, g.GetVertex(vIndex2));
g.UpdateVertex( vIndex2, ntemp);
}
//更新边
for (int i = 0; i < MAX_ROW; i++)
{
for (int j = 0; j < MAX_COL; j++)
{
UpdateArc(g, i, j);
}
}
}
第5章 调试分析
调试程序分析是课程设计必不可少的环节,调试分析可以在程序运行之后发现原来没有出现的问题,以及做进一步的更正,是程序达到预期的目的。
1、 问题一:画框的位置是通过坐标计算的
现象:点击鼠标后,画出的框不是一位置
原因:画框的位置计算错了
2、 问题二:生成地图时图标需要打乱顺序
现象:生成地图时一排一排全相同
原因:没有对其打乱顺序
第6章 运行结果
1、进入首页,如图1所示
图1 系统首页界面
2、进入基本模式界面,如图2所示
图2 基本模式界面
3、首先“开始游戏”,此时游戏开始,运行结果如图3所示。
图3 开始游戏
4、选择“暂停游戏”,游戏暂停,倒计时暂停,运行结果如图4所示。
图4 暂停游戏
5、选择“提示”,可看见提示消除内容,如图5所示
图5提示
6、选择“重排”,可以看到游戏地图重新排列,如图6所示
图6 重排
7、选择两个可以消除图案,可看见图案消除,如图7所示
图7 消除图案
8、时间结束,图片仍没有消除,游戏失败,如图8所示。
图8 游戏失败
第七章 总结与展望
- 本次小学期课设我第一次使用C++来编写大程序,深入认识了最优路径、查找二叉排序树、jmu-ds-实现KMP等。由于是第一次使用,所以显得尤为生疏,一回生二回熟嘛,下一次一定可以做得更好。
2.该系统的功能是以菜单方式工作,进入系统时首先进入菜单选择界面,用户通过鼠标点击来选择:
基本模式——进入基本游戏界面
休闲模式——进入休闲游戏界面
关卡模式——进入关卡游戏界面
进入游戏界面后有菜单栏,可以通过鼠标进行选择:
开始游戏功能——显示出连连看地图,游戏开始;
暂停游戏功能——游戏暂停,倒计时暂停,再次点击游戏开始;
提示功能——显示出能够可以进行相连的一对,进行提示;
重排功能——连连看地图重新排列。
在各项基本功能之下我们可以看到各种小的模块来满足用户的各种需求,达到快速方便的效果。
3.这个系统的不足之处在于没有实现真人对抗模式,初用C++还无法实现此功能,希望通过之后的学习,我能把他做出来
附录
CGameControl.h:
#pragma once
#include"global.h"
#include"CGameLogic.h"
#include"CGraph.h"
//游戏控制类,调用相应的方法
class CGameControl
{
public:
CGameControl() {}
~CGameControl() {}
void StartGame();//创建开始游戏
int GetElement(int row, int col);//获得某行某列的图片编号
void SetFirstPoint(int row, int col);//设置第一个点
void SetSecPoint(int row, int col);//设置第一个点
bool Link(Vertex path[], int &nVexnum);
void Clear();
bool IsWin();
void Hint(Vertex path[], int& nVernum, Vertex& ver1, Vertex& ver2);//提示
void ReArrange();
public:
CGraph m_graph;//游戏地图
Vertex m_ptSelFirst;//第一个点
Vertex m_ptSelSec;//第二个点
CGameLogic m_gameLogic;
};
CGameControl.cpp:
#include "pch.h"
#include "CGameControl.h"
#include"CGameLogic.h"
#include"CGraph.h"
#include"CStudioFile.h"
//同一协调功能
void CGameControl::StartGame() //开始游戏
{
CGameLogic gameLogic;
gameLogic.InitMap(m_graph);
}
int CGameControl::GetElement(int row, int col)//获得某行某列的图片编号函数
{
return m_graph.GetVertex(row*MAX_COL+col);
}
//nVexnum=m_gameLogic.GetVexPath(path);//消子判断 返回路径顶点
void CGameControl::SetFirstPoint(int row, int col)//获得第一个点的行号列号
{
m_ptSelFirst.col = col;
m_ptSelFirst.row = row;
}
void CGameControl::SetSecPoint(int row, int col)//获得第二个点的行号列号
{
m_ptSelSec.col = col;
m_ptSelSec.row = row;
}
bool CGameControl::Link(Vertex path[], int& nVexnum)//消子判断
{
bool b = m_gameLogic.IsLink(m_graph, m_ptSelFirst, m_ptSelSec);
nVexnum=m_gameLogic.GetVexPath(path);//返回路径顶点
return b;
}
void CGameControl::Clear()
{
m_gameLogic.ClearLog(m_graph, m_ptSelFirst, m_ptSelSec);
}
bool CGameControl::IsWin()
{
if (m_gameLogic.IsBlank(m_graph))
{
return true;
}
return false;
}
void CGameControl::Hint(Vertex path[],int &nVernum,Vertex& ver1,Vertex& ver2)
{
int vernum = m_graph.GetVertexN();
for (int i = 0; i < vernum; i++)
{
for (int j = 0; j < vernum; j++)
{
if (m_graph.GetVertex(i) != BLANK && m_graph.GetVertex(j) != BLANK)
{
Vertex v1,v2;
v1.row = i / MAX_COL; v1.col = i - i / MAX_COL * MAX_COL;
v2.row = j / MAX_COL; v2.col = j - j / MAX_COL * MAX_COL;
if (m_gameLogic.IsLink(m_graph, v1, v2))
{
nVernum = m_gameLogic.GetVexPath(path);
ver1 = v1;
ver2 = v2;
return;
}
}
}
}
}
void CGameControl::ReArrange()
{
m_gameLogic.ReArrangeLog(m_graph);
}
CGameDlg.h:
#pragma once
#include"global.h"
#include"CGameControl.h"
//显示游戏界面,进行交互
// CGameDlg 对话框
class CGameDlg : public CDialogEx
{
DECLARE_DYNAMIC(CGameDlg)
public:
CGameDlg(CWnd* pParent = nullptr); // 标准构造函数
virtual ~CGameDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_GAME_DIALOG };
#endif
protected:
HICON m_hIcon;//系统图标
CDC m_dcMem;//内存dc
CDC m_dcBG;//背景dc
CDC m_dcHelp1;
CDC m_dcElement;//元素内存dc
CDC m_dcMask;
CPoint m_ptGameTop;
CSize m_sizeElem;
CRect m_rtGameRect;//游戏区域
bool m_bFirstPoint;//是否是第一个点
CGameControl m_gameContorl;//一个游戏界面对应一个控制
bool m_bPlaying;
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
void InitBackground();
void InitElement();
/*void initMap();*/
void UpWindow();
void UpdateMap();
void DrawTipFrame(int ,int);
/*bool IsLink();*/
void DrawTipLine(Vertex &v1, Vertex &v2);
public:
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg void OnClickedBtnStart();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnClickedBtnHint();
afx_msg void OnClickedBtnRearrange();
CProgressCtrl m_GameProgress;
afx_msg void OnTimer(UINT_PTR nIDEvent);
void DrawGameTime();
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
afx_msg void OnClickedBtnStop();
afx_msg void OnClickedBtnBasicSetting();
afx_msg void OnClickedBtnBasicHelp();
};
CGameDlg.cpp:
// CGameDlg.cpp: 实现文件,显示游戏界面
// CGameDlg 消息处理程序
#include<CString>
#include "pch.h"
#include "LLK1.h"
#include "CGameDlg.h"
#include "afxdialogex.h"
#include"global.h"
#include"CHelpDlg.h"
// CGameDlg 对话框
IMPLEMENT_DYNAMIC(CGameDlg, CDialogEx)
CGameDlg::CGameDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_GAME_DIALOG, pParent)
{
//加载系统图标
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
//初始化游戏更新区域
m_ptGameTop.x = MAP_LEFT;
m_ptGameTop.y = MAP_TOP;
m_sizeElem.cx = PIC_WIDTH;
m_sizeElem.cy = PIC_HEIGHT;
m_rtGameRect.top = m_ptGameTop.y;
m_rtGameRect.left = m_ptGameTop.x;
m_rtGameRect.right = m_rtGameRect.left + m_sizeElem.cx * MAX_COL;
m_rtGameRect.bottom = m_rtGameRect.top + m_sizeElem.cy * MAX_ROW ;
m_bFirstPoint = true;
m_bPlaying = false;
}
CGameDlg::~CGameDlg()
{
}
void CGameDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_GAME_TIME, m_GameProgress);
}
BEGIN_MESSAGE_MAP(CGameDlg, CDialogEx)
ON_WM_PAINT()
ON_BN_CLICKED(IDC_BTN_START, &CGameDlg::OnClickedBtnStart)
ON_WM_LBUTTONUP()
ON_BN_CLICKED(IDC_BTN_HINT, &CGameDlg::OnClickedBtnHint)
ON_BN_CLICKED(IDC_BTN_REARRANGE, &CGameDlg::OnClickedBtnRearrange)
ON_WM_TIMER()
ON_WM_CTLCOLOR()
ON_BN_CLICKED(IDC_BTN_STOP, &CGameDlg::OnClickedBtnStop)
ON_BN_CLICKED(IDC_BTN_BASIC_SETTING, &CGameDlg::OnClickedBtnBasicSetting)
ON_BN_CLICKED(IDC_BTN_BASIC_HELP, &CGameDlg::OnClickedBtnBasicHelp)
END_MESSAGE_MAP()
void CGameDlg::InitBackground() {//加载游戏背景
CClientDC dc(this);
HANDLE bmp=::LoadImageW(NULL, _T("theme\\picture\\IDB_BASIC_BG.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_dcBG.CreateCompatibleDC(&dc);
m_dcBG.SelectObject(bmp);
m_dcMem.CreateCompatibleDC(&dc);
CBitmap bmpMem;
bmpMem.CreateCompatibleBitmap(&dc,800,600);
m_dcMem.SelectObject(&bmpMem);
//绘制背景到内存DC中
m_dcMem.BitBlt(0, 0, 800, 600, &m_dcBG, 0, 0, SRCCOPY);
UpdateWindow();
}
void CGameDlg::UpWindow() {//更新窗口
CRect rtWin;
CRect rtClient;
this->GetWindowRect(rtWin);
this->GetClientRect(rtClient);
int nSpanWidth = rtWin.Width() - rtClient.Width();
int nSpanHeight = rtWin.Height() - rtClient.Height();
MoveWindow(0, 0, 800 + nSpanWidth, 600 + nSpanHeight);
CenterWindow();
}
BOOL CGameDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化
InitBackground();
InitElement();
this->GetDlgItem(IDC_BTN_STOP)->EnableWindow(FALSE);
this->GetDlgItem(IDC_BTN_REARRANGE)->EnableWindow(FALSE);
this->GetDlgItem(IDC_BTN_HINT)->EnableWindow(FALSE);
SetDlgItemText(IDC_TIMER,_T( "300"));
return TRUE; // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}
void CGameDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CDialogEx::OnPaint()
dc.BitBlt(0, 0, 800, 600, &m_dcMem, 0, 0, SRCCOPY);
}
void CGameDlg::InitElement() {
HANDLE bmp = ::LoadImageW(NULL, _T("theme\\picture\\element.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
CClientDC dc(this);
m_dcElement.CreateCompatibleDC(&dc);
m_dcElement.SelectObject(bmp);
HANDLE bmpMask = ::LoadImageW(NULL, _T("theme\\picture\\mask.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_dcMask.CreateCompatibleDC(&dc);
m_dcMask.SelectObject(bmpMask);
}
void CGameDlg::OnClickedBtnStart()//开始游戏
{
//初始化游戏地图
m_gameContorl.StartGame();
m_bPlaying = true;
this->GetDlgItem(IDC_BTN_START)->EnableWindow(FALSE);
this->GetDlgItem(IDC_BTN_STOP)->EnableWindow(TRUE);
this->GetDlgItem(IDC_BTN_REARRANGE)->EnableWindow(TRUE);
this->GetDlgItem(IDC_BTN_HINT)->EnableWindow(TRUE);
m_GameProgress.SetRange(0, 300);
m_GameProgress.SetStep(-1);
m_GameProgress.SetPos(300);
this->SetTimer(PLAY_TIMER_ID, 1000, NULL);
DrawGameTime();
//更新界面
UpdateMap();
//更新窗口
InvalidateRect(m_rtGameRect, FALSE);
}
void CGameDlg::UpdateMap() {//更新游戏地图
//计算图片的顶点与图片大小
int nLeft = m_ptGameTop.x;
int nTop = m_ptGameTop.y;
int nElemW = m_sizeElem.cx;
int nElemH = m_sizeElem.cy;
m_dcMem.BitBlt(m_rtGameRect.left, m_rtGameRect.top, m_rtGameRect.Width(), m_rtGameRect.Height(), &m_dcBG, m_rtGameRect.left, m_rtGameRect.top, SRCCOPY);//将背景图片绘制上去
//m_dcMem.BitBlt(nLeft + j * nElemW, nTop + i * nElemW, nElemW, nElemH, &m_dcElement, 0, m_anMap[i][j] * nElemH, SRCCOPY);SRCPAINT SRCAND
//循环绘制图片
for (int i = 0; i < MAX_ROW; i++) {
for (int j = 0; j < MAX_COL; j++) {
int info = m_gameContorl.GetElement(i,j);
//m_dcMem.BitBlt(nLeft + j * nElemW, nTop + i * nElemW, nElemW, nElemH, &m_dcElement, 0, m_anMap[i][j] * nElemH, SRCCOPY);
m_dcMem.BitBlt(nLeft + j * nElemW, nTop + i * nElemW, nElemW, nElemH, &m_dcMask, 0, info * nElemH, SRCPAINT);
m_dcMem.BitBlt(nLeft + j * nElemW, nTop + i * nElemW, nElemW, nElemH, &m_dcElement, 0, info * nElemH, SRCAND);
}
}
}
//鼠标点击事件
void CGameDlg::OnLButtonUp(UINT nFlags, CPoint point)//点击处理的代码
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (point.x < m_ptGameTop.x || point.y < m_ptGameTop.y || m_bPlaying == FALSE)
{
return CDialogEx::OnLButtonUp(nFlags, point);
}
int nRow = (point.y - m_ptGameTop.y) / m_sizeElem.cy;
int nCol = (point.x - m_ptGameTop.x) / m_sizeElem.cx;
if (nRow > MAX_ROW-1 || nCol > MAX_COL-1)
{
return CDialogEx::OnLButtonUp(nFlags, point);
/*for (int i = 0; i < nVexnum - 1; i++)
DrawTipLine(aPath[i], aPath[i + 1]);
m_gameContorl.Clear();
UpdateMap();*/
}
if (m_bFirstPoint)
{
//绘制提示框
DrawTipFrame(nRow, nCol);
m_gameContorl.SetFirstPoint(nRow, nCol);
m_bFirstPoint = !m_bFirstPoint;
}
else//第二个点
{
//判断是否是相同图片
if (nRow != m_gameContorl.m_ptSelFirst.row || nCol != m_gameContorl.m_ptSelFirst.col)
{
DrawTipFrame(nRow, nCol);
m_gameContorl.SetSecPoint(nRow, nCol);
Vertex aPath[MAX_VERTEX_NUM];
int nVexnum = 0;
if (m_gameContorl.Link(aPath,nVexnum))
{
for(int i=0;i<nVexnum-1;i++)
DrawTipLine(aPath[i], aPath[i+1]);
m_gameContorl.Clear();
UpdateMap();
}
Sleep(200);//延迟
InvalidateRect(m_rtGameRect, FALSE);
m_bFirstPoint = !m_bFirstPoint;
if (m_gameContorl.IsWin())
{
MessageBox(_T(" 基本模式获胜!"),_T("欢乐连连看--基本模式"));
this->GetDlgItem(IDC_BTN_START)->EnableWindow(TRUE);
this->GetDlgItem(IDC_BTN_STOP)->EnableWindow(FALSE);
this->GetDlgItem(IDC_BTN_REARRANGE)->EnableWindow(FALSE);
this->GetDlgItem(IDC_BTN_HINT)->EnableWindow(FALSE);
m_bPlaying = FALSE;
}
}
}
}
//绘画图片提示框
void CGameDlg::DrawTipFrame(int nRow, int nCol)
{
CClientDC dc(this);
CBrush brush(RGB(233, 43, 43));
CRect rtTipFrame;
rtTipFrame.left = m_ptGameTop.x + nCol * m_sizeElem.cx;
rtTipFrame.top = m_ptGameTop.y + nRow * m_sizeElem.cx;
rtTipFrame.right = rtTipFrame.left + m_sizeElem.cx;
rtTipFrame.bottom = rtTipFrame.top + m_sizeElem.cy;
dc.FrameRect(rtTipFrame,&brush);
}
//绘制提示线
void CGameDlg::DrawTipLine(Vertex &v1,Vertex &v2)
{
CClientDC dc(this);
CPen penLine(PS_SOLID, 2, RGB(0, 255, 0));
CPen* pOldPen = dc.SelectObject(&penLine);
dc.MoveTo(m_ptGameTop.x + v1.col * m_sizeElem.cx + m_sizeElem.cx / 2, m_ptGameTop.y + v1.row * m_sizeElem.cy + m_sizeElem.cy / 2);
dc.LineTo(m_ptGameTop.x + v2.col * m_sizeElem.cx + m_sizeElem.cx / 2, m_ptGameTop.y + v2.row * m_sizeElem.cy + m_sizeElem.cy / 2);
dc.SelectObject(pOldPen);
}
void CGameDlg::OnClickedBtnHint()
{
Vertex aPath[MAX_VERTEX_NUM],v1,v2;
int nVexnum = 0;
m_gameContorl.Hint(aPath, nVexnum,v1,v2);
DrawTipFrame(v1.row, v1.col);
DrawTipFrame(v2.row, v2.col);
for (int i = 0; i < nVexnum - 1; i++)
DrawTipLine(aPath[i], aPath[i + 1]);
Sleep(800);
InvalidateRect(m_rtGameRect, FALSE);
}
void CGameDlg::OnClickedBtnRearrange()
{
if (m_bPlaying == true)
{
//重排
m_gameContorl.ReArrange();
//更新游戏地图
UpdateMap();
//重绘界面
InvalidateRect(m_rtGameRect, FALSE);
}
}
void CGameDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (nIDEvent == PLAY_TIMER_ID && m_bPlaying)
{
m_GameProgress.StepIt();
}
DrawGameTime();
if (m_GameProgress.GetPos() == 0)
{
this->GetDlgItem(IDC_BTN_START)->EnableWindow(TRUE);
this->GetDlgItem(IDC_BTN_STOP)->EnableWindow(FALSE);
this->GetDlgItem(IDC_BTN_REARRANGE)->EnableWindow(FALSE);
this->GetDlgItem(IDC_BTN_HINT)->EnableWindow(FALSE);
m_bPlaying = FALSE;
this->KillTimer(PLAY_TIMER_ID);
m_gameContorl.m_graph.ResetCGraph();
UpdateMap();
InvalidateRect(m_rtGameRect, FALSE);
MessageBox(_T(" 很遗憾,基本模式失败!请重新开始!"), _T("欢乐连连看--基本模式"));
}
CDialogEx::OnTimer(nIDEvent);
}
void CGameDlg::DrawGameTime()
{
// TODO: 在此处添加实现代码.
int time = m_GameProgress.GetPos();
char num1, num2, num3;
num1 = time / 100 + '0';
num2 = time / 10 - (num1-'0' )* 10 + '0';
num3 = time - (num2 - '0') * 10 - (num1 - '0') * 100 + '0';
CString nums1(num1), nums2(num2), nums3(num3);
CString strText(nums1 + num2 + num3);
int x = 600;
int y = 430;
SetDlgItemText(IDC_TIMER, strText);
CDialogEx::OnPaint();
}
HBRUSH CGameDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: 在此更改 DC 的任何特性
if (pWnd->GetDlgCtrlID() == IDC_TIMER)
{
CFont font;
font.CreatePointFont(200,_T("Arial"));
pDC->SelectObject(&font);
pDC->SetTextColor(RGB(0,0,0));
pDC->SetBkColor(RGB(255,255,255));
}
return hbr;
// TODO: 如果默认的不是所需画笔,则返回另一个画笔
return hbr;
}
void CGameDlg::OnClickedBtnStop()
{
// TODO: 在此添加控件通知处理程序代码
if (m_bPlaying == false)
{
//更新游戏地图
UpdateMap();
//重绘界面
InvalidateRect(m_rtGameRect, FALSE);
this->GetDlgItem(IDC_BTN_REARRANGE)->EnableWindow(TRUE);
this->GetDlgItem(IDC_BTN_HINT)->EnableWindow(TRUE);
}
if (m_bPlaying == true)
{
this->GetDlgItem(IDC_BTN_REARRANGE)->EnableWindow(FALSE);
this->GetDlgItem(IDC_BTN_HINT)->EnableWindow(FALSE);
}
m_bPlaying = !m_bPlaying;
}
void CGameDlg::OnClickedBtnBasicSetting()
{
// TODO: 在此添加控件通知处理程序代码
}
void CGameDlg::OnClickedBtnBasicHelp()
{
CHelpDlg helpdlg;
helpdlg.SetGameMode(1);
helpdlg.DoModal();
}
CGameLogic.h:
#pragma once
#include"global.h"
#include"CGraph.h"
class CGameLogic
{
public:
CGameLogic()
{
nVertexNum = 0;
m_nCorner = 0;
}
~CGameLogic(){}
void InitMap(CGraph& g);//生成游戏地图
bool IsLink(CGraph& g, Vertex v1, Vertex v2);
bool SearchaPath(CGraph& g, int v1, int v2);//判断v1,v2是否连通
bool IsExsit(int nVi);//判断nvi是否保存到连通数组m_anPath中
void ClearLog(CGraph& g, Vertex v1, Vertex v2);
int GetVexPath(Vertex path[]);//获取路径
void UpdateArc(CGraph& g, int row, int col);//更新边
bool IsBlank(CGraph& g);
void ReArrangeLog(CGraph& g);
protected:
//Vertex m_avPath[4];//保存需要消除图片过程中需要记录的点
int nVertexNum;//用来记录栈中的元素的数目
int m_anPath[MAX_VERTEX_NUM];//保存连通路径的顶点索引
int m_nCorner;//记录拐点数
bool IsCorner(int i,int j,int k);//连续三个顶点是否构成一个拐点
int CornerCount();
//void AddVertex(Vertex v);//向路径中添加一个顶点
//void DeleteVertex();//向路径中删除一个顶点
void PushVertex(int v);//
void PopVertex();
};
CGameLogic.cpp:
#include "pch.h"
#include "CGameLogic.h"
#include"CGraph.h"
#include"CStudioFile.h"
//根据不同的数据结构,完成判断,逻辑规则
//srand((int)time(NULL));
void CGameLogic::InitMap(CGraph& g)//游戏地图初始化
{
g.ResetCGraph();
//随机生成地图
int TempMap[MAX_VERTEX_NUM];
//多少花色
for (int i = 0; i < MAX_PIC_NUM; i++)
{
for (int j = 0; j < REPEART_NUM; j++)
{
TempMap[i * REPEART_NUM + j] = i;
}
}
//设置种子
srand((int)time(NULL));
//随机任意交换两个数字
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
int vIndex1 = rand() % MAX_VERTEX_NUM;
int vIndex2 = rand() % MAX_VERTEX_NUM;
//交换两个数值
int ntemp = TempMap[vIndex1];
TempMap[vIndex1] = TempMap[vIndex2];
TempMap[vIndex2] = ntemp;
}
//添加点
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
//添加点
g.AddVertex(TempMap[i]);
}
for (int i = 0; i <MAX_ROW; i++) //添加边
{
//g.GetVertex(vIndex1)==g.GetVertex(vIndex2)&& g.GetVertex(vIndex1) !=BLANK&&SearchaPath(g,vIndex1, vIndex2)==true
for (int j = 0; j <MAX_COL; j++)
{
UpdateArc(g, i, j);
}
}
}
bool CGameLogic::IsLink(CGraph&g, Vertex v1, Vertex v2)//是否可以连接
{
int vIndex1 = v1.row * MAX_COL + v1.col;
int vIndex2 = v2.row * MAX_COL + v2.col;
PushVertex(vIndex1);//
if (g.GetVertex(vIndex1)==g.GetVertex(vIndex2)&& g.GetVertex(vIndex1) !=BLANK&&SearchaPath(g,vIndex1, vIndex2)==true)
{
return true;
}
PopVertex();
return false;
}
void CGameLogic::ClearLog(CGraph& g, Vertex v1, Vertex v2)//消除
{
/*anMap[v1.row][v1.col] = BLANK;
anMap[v2.row][v2.col] = BLANK;*/
int vIndex1 = v1.row * MAX_COL + v1.col;
int vIndex2 = v2.row * MAX_COL + v2.col;
//更新顶点
g.UpdateVertex(vIndex1, BLANK);
g.UpdateVertex(vIndex2,BLANK);
UpdateArc(g,v1.row,v1.col);
UpdateArc(g, v2.row, v2.col);
CStudioFile::WriteString(g);
}
void CGameLogic::PushVertex(int v)
{
m_anPath[nVertexNum++] = v;
}
void CGameLogic::PopVertex()
{
nVertexNum--;
}
int CGameLogic::GetVexPath(Vertex path[])
{
for (int i = 0; i < nVertexNum; i++)
{
Vertex v1;
v1.row = m_anPath[i] / MAX_COL;
v1.col = m_anPath[i] - m_anPath[i] / MAX_COL * MAX_COL;
path[i] = v1;
}
int n = nVertexNum;
nVertexNum = 0;
m_nCorner = 0;
//int vIndex1 = row * MAX_COL + col;
return n;
}
//更新边
void CGameLogic::UpdateArc(CGraph& g, int row, int col)
{
//看左右顶点是否有边 vIndex2在vIndex1的
int vIndex1 = row * MAX_COL + col;//获取索引
if (col > 0)//左
{
int vIndex2 = vIndex1 - 1;//找第二个点的索引号
int v1info = g.GetVertex(vIndex1);
int v2info = g.GetVertex(vIndex2);
if (v1info==v2info||v1info==BLANK||v2info==BLANK)
{
g.AddArc(vIndex1,vIndex2);
}
}
if (col < MAX_COL-1)//右
{
int vIndex2 = vIndex1 + 1;//找第二个点的索引号
int v1info = g.GetVertex(vIndex1);
int v2info = g.GetVertex(vIndex2);
if (v1info == v2info || v1info == BLANK || v2info == BLANK)
{
g.AddArc(vIndex1, vIndex2);
}
}
if (row > 0)//上
{
int vIndex2 = vIndex1 - MAX_COL;//找第二个点的索引号
int v1info = g.GetVertex(vIndex1);
int v2info = g.GetVertex(vIndex2);
if (v1info == v2info || v1info == BLANK || v2info == BLANK)
{
g.AddArc(vIndex1, vIndex2);
}
}
if (row < MAX_ROW-1)//下
{
int vIndex2 = vIndex1 + MAX_COL;//找第二个点的索引号
int v1info = g.GetVertex(vIndex1);
int v2info = g.GetVertex(vIndex2);
if (v1info == v2info || v1info == BLANK || v2info == BLANK)
{
g.AddArc(vIndex1, vIndex2);
}
}
}
//深度优先
bool CGameLogic::SearchaPath(CGraph& g, int v1, int v2)//判断v1,v2是否连通
{
int vexNum = g.GetVertexN();//顶点个数
int pathCount = 0;
for (int i = 0; i < vexNum; i++)
{
if (g.GetArc(v1, i) && !IsExsit(i))
{
bool p = false;
//压入当前点
PushVertex(i);
//当中间点不是v2时,继续寻找下一个相邻且连通的顶点
if (i != v2)
{
//当中间顶点不为空时,表示该条路径不通
if (g.GetVertex(i) != BLANK)
{
PopVertex();
continue;
}
if (SearchaPath(g, i, v2))
{
return true;
}
}
else
{
if (CornerCount() > 2)
{
PopVertex();
return false;
}
return true;
}
PopVertex();
}
}
return false;
}
bool CGameLogic::IsExsit(int nVi)
{
for (int i = 0; i < nVertexNum; i++)
{
if (m_anPath[i] == nVi)
return true;
}
return false;
}
bool CGameLogic::IsCorner(int i,int j,int k)//i+2==j+1==k
{
if (nVertexNum >= 3)
{
if ((m_anPath[i] + m_anPath[k]) / 2 == m_anPath[j])
{
return false;
}
else
{
return true;
}
}
return false;
}
int CGameLogic::CornerCount()
{
m_nCorner = 0;
if (nVertexNum >= 3)
{
for (int i = 0; i <= nVertexNum - 3; i++)
if (IsCorner(i, i + 1, i + 2))
m_nCorner++;
return m_nCorner;
}
return 0;
}
bool CGameLogic::IsBlank(CGraph&g)
{
int vernum = g.GetVertexN();
for (int i = 0; i < vernum; i++)
{
if (g.GetVertex(i) != BLANK)
{
return false;
}
}
return true;
}
void CGameLogic::ReArrangeLog(CGraph& g)
{
//设置种子
srand((int)time(NULL));
//随机任意交换两个数字
for (int i = 0; i < 100; i++)
{
int vIndex1 = rand() % MAX_VERTEX_NUM;
int vIndex2 = rand() % MAX_VERTEX_NUM;
//交换两个数值
int ntemp =g.GetVertex(vIndex1);
g.UpdateVertex( vIndex1, g.GetVertex(vIndex2));
g.UpdateVertex( vIndex2, ntemp);
}
//更新边
for (int i = 0; i < MAX_ROW; i++)
{
for (int j = 0; j < MAX_COL; j++)
{
UpdateArc(g, i, j);
}
}
}
CGraph.h:
#pragma once
#include"global.h"
//图的数据结构
class CGraph
{
public:
typedef int Vertices[MAX_VERTEX_NUM];//顶点数据类型
//两图片相同代表有边,用邻接矩阵表示边的相互关系
typedef bool** AdjMatrix;//边数据类型typedef bool AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
CGraph();
~CGraph();
int AddVertex(int info);//添加点
void AddArc(int vIndex1, int vIndex2);//添加边
int GetVertex(int vIndex);//获得顶点信息
bool GetArc(int vIndex1, int vIndex2);//获得边信息
void UpdateVertex(int vIndex,int info);//更新顶点信息
int GetVertexN();//获得顶点个数
void ResetCGraph();//重置图信息
void InitGraph();//初始化图
protected:
Vertices m_Vertics;//顶点数组
AdjMatrix m_AdjMatrix;//关系矩阵
int m_nVertexN;//顶点个数
int m_nArcnum;//边个数
};
CGraph.cpp:
#include "pch.h"
#include "CGraph.h"
CGraph::CGraph()
{
m_nArcnum = 0;
m_nVertexN = 0;
InitGraph();
}
CGraph::~CGraph()
{
m_nArcnum = m_nVertexN = 0;
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
delete[] m_AdjMatrix[i];
}
delete[] m_AdjMatrix;
}
void CGraph::InitGraph()//初始化邻接矩阵
{
for (int i = 0; i < MAX_VERTEX_NUM;i++)
{
//初始化顶点
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
m_Vertics[i] = -1;
}
//初始化边
m_AdjMatrix = new bool* [MAX_VERTEX_NUM];
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
m_AdjMatrix[i] = new bool[MAX_VERTEX_NUM];
for (int j = 0; j < MAX_VERTEX_NUM; j++)
{
m_AdjMatrix[i][j] = false;
}
/*if (m_nVertexN >= MAX_VERTEX_NUM)return 0;
m_Vertics[m_nVertexN++] = info;
return 1;*/
}
}
}
int CGraph::AddVertex(int info)
{
if (m_nVertexN >= MAX_VERTEX_NUM)
return 0;
m_Vertics[m_nVertexN] = info;
m_nVertexN++;
return 1;
}
void CGraph::AddArc(int vIndex1, int vIndex2)
{
m_AdjMatrix[vIndex1][vIndex2] = true;
m_AdjMatrix[vIndex2][vIndex1] = true;
m_nArcnum++;
}
int CGraph::GetVertex(int vIndex)
{
return m_Vertics[vIndex];
}
bool CGraph::GetArc(int vIndex1, int vIndex2)
{
return m_AdjMatrix[vIndex1][vIndex2];
}
void CGraph::UpdateVertex(int vIndex,int info)
{
m_Vertics[vIndex] = info;
}
int CGraph::GetVertexN()
{
return m_nVertexN;
}
void CGraph::ResetCGraph()
{
m_nArcnum = 0;
m_nVertexN = 0;
InitGraph();
}
CHelpDlg.h:
#pragma once
// CHelpDlg 对话框
class CHelpDlg : public CDialogEx
{
DECLARE_DYNAMIC(CHelpDlg)
public:
CHelpDlg(CWnd* pParent = nullptr); // 标准构造函数
virtual ~CHelpDlg();
virtual BOOL OnInitDialog();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_HELP_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
DECLARE_MESSAGE_MAP()
HICON m_hIcon;
CDC m_dcMem;//内存DC
CDC m_dcHelp;//帮助图片DC
CRect m_rtHelp;//帮助图片显示区域
int gameModel; //帮助框标识
public:
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
void UpdateHelp(int nPos);
afx_msg void OnPaint();
int SetGameMode(int mode);
};
CHelpDlg.cpp:
// CHelpDlg.cpp: 实现文件
//
#include "pch.h"
#include "LLK1.h"
#include "CHelpDlg.h"
#include "afxdialogex.h"
#include"Resource.h"
// CHelpDlg 对话框
IMPLEMENT_DYNAMIC(CHelpDlg, CDialogEx)
CHelpDlg::CHelpDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_HELP_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
CHelpDlg::~CHelpDlg()
{
}
void CHelpDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CHelpDlg, CDialogEx)
ON_WM_VSCROLL()
ON_WM_PAINT()
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
BOOL CHelpDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
HANDLE hBmpHelp;
if (gameModel == 1)//基本模式
{
hBmpHelp = ::LoadImage(NULL, _T("theme\\picture\\HelpInfo.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
else if (gameModel == 2)//休闲模式
{
hBmpHelp = ::LoadImage(NULL, _T("theme\\picture\\HelpInfo.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
else if (gameModel == 3)//关卡模式
{
hBmpHelp = ::LoadImage(NULL, _T("theme\\picture\\HelpInfo.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
else//主页面的帮助按钮
{
hBmpHelp = ::LoadImage(NULL, _T("theme\\picture\\HelpInfo.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
CClientDC dc(this);
//加载BMP图片资源
//创建与视频内容兼容的内存DC
m_dcHelp.CreateCompatibleDC(&dc);
//将位图资源选入DC
m_dcHelp.SelectObject(hBmpHelp);
//创建内存DC大小
CRect rtClient;
this->GetWindowRect(&rtClient);
m_dcMem.CreateCompatibleDC(&dc);
CBitmap bmpMem;
bmpMem.CreateCompatibleBitmap(&dc, rtClient.Width(), rtClient.Height());
m_dcMem.SelectObject(&bmpMem);
//绘制白色背景
m_dcMem.BitBlt(0, 0, rtClient.Width(), rtClient.Height(), NULL, 0, 0, WHITENESS);
CRect rtWin;
CRect rtClient1;
this->GetWindowRect(rtWin);
this->GetClientRect(rtClient1);
int nSpanWidth = rtWin.Width() - rtClient1.Width();
int nSpanHeight = rtWin.Height() - rtClient1.Height();
MoveWindow(0, 0, 600 + nSpanWidth, 390 + nSpanHeight);
CenterWindow();
//绘制帮助信息显示区域
this->GetDlgItem(IDC_PIC_STATIC)->GetWindowRect(&m_rtHelp);
this->ScreenToClient(&m_rtHelp);
//绘制帮助信息
UpdateHelp(0);
//设置滚动条范围
CBitmap bmpHelp;
bmpHelp.Attach(hBmpHelp);
BITMAP bmpInfo;
bmpHelp.GetBitmap(&bmpInfo);
//设置滚动条的范围
((CScrollBar*)this->GetDlgItem(IDC_SCROLLBAR1))->SetScrollRange(0, bmpInfo.bmHeight);
return TRUE; // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}
// CHelpDlg 消息处理程序
void CHelpDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
int pos = pScrollBar->GetScrollPos();
int nMinPos;
int nMaxPos;
pScrollBar->GetScrollRange(&nMinPos, &nMaxPos); //得到滚动条的范围
switch (nSBCode)
{
case SB_LINEUP: //点击向上按钮
pos -= 1;
break;
case SB_LINEDOWN: //点击向下按钮
pos += 1;
break;
case SB_PAGEUP: //向上翻页
pos -= 10;
break;
case SB_PAGEDOWN: //向下翻页
pos += 10;
break;
case SB_TOP: //顶部
pos = nMinPos;
break;
case SB_BOTTOM: //底部
pos = nMaxPos;
break;
case SB_THUMBPOSITION: //点击在滑块上
pos = nPos;
break;
default:
break;
}
//设置滚动条当前点的值
pScrollBar->SetScrollPos(pos, TRUE);
//更新帮助信息
UpdateHelp(pos);
CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar);
}
//
//
//
void CHelpDlg::UpdateHelp(int nPos)
{
//将重绘区绘制成白色
m_dcMem.BitBlt(m_rtHelp.left, m_rtHelp.top, m_rtHelp.Width(), m_rtHelp.Height(), NULL, 0, 0, WHITENESS);
//绘制当前点的帮助信息
m_dcMem.BitBlt(m_rtHelp.left, m_rtHelp.top, m_rtHelp.Width(), m_rtHelp.Height(), &m_dcHelp, 0, nPos, SRCCOPY);
//更新界面
InvalidateRect(m_rtHelp, FALSE);
}
void CHelpDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CDialogEx::OnPaint()
//CRect rect;
//GetClientRect(rect);
//dc.FillSolidRect(rect, RGB(255, 255, 255)); //设置为白色背景
//绘制背景到内存DC中
//m_dcMem.BitBlt(0, 0, m_rtHelp.Width(), m_rtHelp.Height(), &m_dcHelp, 0, 0, SRCCOPY);
//绘制背景图片
dc.BitBlt(0, 0, m_rtHelp.Width(), m_rtHelp.Height(), &m_dcMem, 0, 0, SRCCOPY);
CDialogEx::OnPaint();
}
int CHelpDlg::SetGameMode(int mode)
{
// TODO: 在此处添加实现代码.
gameModel = mode;
return 0;
}
CStudioFile.h:
#pragma once
#include"CGraph.h"
class CStudioFile
{
public:
static void WriteString(CGraph &g);
};
CStudioFile.cpp:
#include "pch.h"
#include "CStudioFile.h"
#include<iostream>
#include<fstream>
using namespace std;
void CStudioFile::WriteString(CGraph& g)
{
ofstream fout("TestData\\TestData.txt");
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
fout << g.GetVertex(i);
}
fout << endl;
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
for (int j = 0; j < MAX_VERTEX_NUM; j++)
{
fout << g.GetArc(i,j);
}
fout << endl;
}
fout.close();
}
global.h:
#pragma once
typedef struct tagVertex//
{
int row;//行号
int col;//列号
int info;//选中信息
}Vertex;
#define BLANK -1
#define MAX_ROW 10 //游戏地图行数
#define MAX_COL 16 //游戏地图列数
#define MAX_VERTEX_NUM 160 //顶点数
#define MAX_PIC_NUM 16 //图片花色
#define REPEART_NUM 10 //每个花色图片的个数
#define MAP_TOP 50 //游戏地图左上角纵坐标
#define MAP_LEFT 8 //游戏地图左上角横坐标
#define PIC_WIDTH 40 //游戏图片宽度
#define PIC_HEIGHT 40 //游戏图片高度
#define PLAY_TIMER_ID 1
LLK1.h:
// LLK1.h: PROJECT_NAME 应用程序的主头文件
//
#pragma once
#ifndef __AFXWIN_H__
#error "在包含此文件之前包含 'pch.h' 以生成 PCH"
#endif
#include "resource.h" // 主符号
// CLLK1App:
// 有关此类的实现,请参阅 LLK1.cpp
//
class CLLK1App : public CWinApp
{
public:
CLLK1App();
// 重写
public:
virtual BOOL InitInstance();
// 实现
DECLARE_MESSAGE_MAP()
};
extern CLLK1App theApp;
LLK1.cpp:
// LLK1.cpp: 定义应用程序的类行为。
//
#include "pch.h"
#include "framework.h"
#include "LLK1.h"
#include "LLK1Dlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CLLK1App
BEGIN_MESSAGE_MAP(CLLK1App, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
// CLLK1App 构造
CLLK1App::CLLK1App()
{
// 支持重新启动管理器
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
// TODO: 在此处添加构造代码,
// 将所有重要的初始化放置在 InitInstance 中
}
// 唯一的 CLLK1App 对象
CLLK1App theApp;
// CLLK1App 初始化
BOOL CLLK1App::InitInstance()
{
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControlsEx()。 否则,将无法创建窗口。
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// 将它设置为包括所有要在应用程序中使用的
// 公共控件类。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinApp::InitInstance();
AfxEnableControlContainer();
// 创建 shell 管理器,以防对话框包含
// 任何 shell 树视图控件或 shell 列表视图控件。
CShellManager *pShellManager = new CShellManager;
// 激活“Windows Native”视觉管理器,以便在 MFC 控件中启用主题
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
// 标准初始化
// 如果未使用这些功能并希望减小
// 最终可执行文件的大小,则应移除下列
// 不需要的特定初始化例程
// 更改用于存储设置的注册表项
// TODO: 应适当修改该字符串,
// 例如修改为公司或组织名
SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
CLLK1Dlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: 在此放置处理何时用
// “确定”来关闭对话框的代码
}
else if (nResponse == IDCANCEL)
{
// TODO: 在此放置处理何时用
// “取消”来关闭对话框的代码
}
else if (nResponse == -1)
{
TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n");
TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
}
// 删除上面创建的 shell 管理器。
if (pShellManager != nullptr)
{
delete pShellManager;
}
#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
ControlBarCleanUp();
#endif
// 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
// 而不是启动应用程序的消息泵。
return FALSE;
}
LLK1Dlg.h:
// LLK1Dlg.h: 头文件
//
#pragma once
// CLLK1Dlg 对话框
class CLLK1Dlg : public CDialogEx
{
// 构造
public:
CLLK1Dlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_LLK1_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
CDC m_dcMem;
void InitBackground();
public:
afx_msg void OnBnClickedButton2();
afx_msg void OnClickedBtnBasic();
};
LLK1Dlg.cpp:
// LLK1Dlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "LLK1.h"
#include "LLK1Dlg.h"
#include "afxdialogex.h"
#include"CGameDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CLLK1Dlg 对话框
CLLK1Dlg::CLLK1Dlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_LLK1_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CLLK1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CLLK1Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_BASIC, &CLLK1Dlg::OnClickedBtnBasic)
END_MESSAGE_MAP()
// CLLK1Dlg 消息处理程序
BOOL CLLK1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
InitBackground();
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CLLK1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CLLK1Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
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;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CPaintDC dc(this);
dc.BitBlt(0, 0, 800, 600, &m_dcMem,0,0,SRCCOPY);
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CLLK1Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CLLK1Dlg::InitBackground() {
CBitmap bmpMain;
bmpMain.LoadBitmapW(IDB_MAIN_BG);
CClientDC dc(this);
m_dcMem.CreateCompatibleDC(&dc);
m_dcMem.SelectObject(bmpMain);
CRect rtWin;
CRect rtClient;
this->GetWindowRect(rtWin);
this->GetClientRect(rtClient);
int nSpanWidth = rtWin.Width() - rtClient.Width();
int nSpanHeight = rtWin.Height() - rtClient.Height();
MoveWindow(0, 0, 800 + nSpanWidth, 600 + nSpanHeight);
CenterWindow();
}
void CLLK1Dlg::OnClickedBtnBasic()
{
// TODO: 在此添加控件通知处理程序代码
this->ShowWindow(SW_HIDE);
CGameDlg dlg;
dlg.DoModal();
this->ShowWindow(SW_SHOW);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)