PPC的C/C++和人工智能学习笔记
每一篇学习笔记,都只是为了更好地掌握和理解

C++语言基础(14-1)_练习:连连看小游戏

C++类和对象基本学完了,尝试着写个小游戏:连连看。

用的是easyx的图形库。

 

连线的算法没有采用最常见的A*寻路、深度搜索寻路、广度搜索寻路,而是自己凭感觉弄的,不是太规范。

 

连连看游戏中,加了个自动游戏功能,毕竟玩起来确实挺累的。

 

做了4个类:地图类、附加地图类、元素类、管理类。

main.cpp 主程序

//main.cpp
/*连连看*/
#include <graphics.h>
#include <iostream>
#include <assert.h>
#include "LLKElem.h"
#include "LLKMap.h"
#include "LLKMapAdd.h"
#include "LLKManage.h"
using namespace std;

#define MAP_WIDTH 560 //地图宽
#define MAP_HEIHT 480 //地图高
#define ADD_WIDTH 80 //游戏说明宽度80
#define ELEM_WIDTH 40 //元素宽
#define ELEM_HEIGHT 40 //元素高
#define ELEM_NUMS 15 //最多28(准备了28个图片) //总共的元素个数

void InitElems(LLKElem **Elem,int nums,IMAGE* pbg); //初始化 连连看元素小图像
void DeleteElems(LLKElem **Elem, int nums); //删除 对象内存

int main() 
{
 int rows = MAP_HEIHT / ELEM_HEIGHT;
 int cols = MAP_WIDTH / ELEM_WIDTH;
 IMAGE bg, imgAuto; //背景图,右边的自动按钮
 loadimage(&bg, "image/bg.jpg"); //背景图片
 loadimage(&imgAuto, "image/auto.jpg"); //自动按钮

 LLKElem *Elem[ELEM_NUMS]; //准备给每个元素创建一个实例
 InitElems(Elem, ELEM_NUMS,&bg); //初始化元素实例,关联图像数据

 LLKMapAdd add(MAP_WIDTH, MAP_HEIHT, ADD_WIDTH,&bg,&imgAuto); //右边的附加图片 对象
 LLKMap map(rows,cols, ELEM_NUMS, ELEM_HEIGHT, ELEM_WIDTH,Elem,&bg); //地图 对象
 map.CreateMap(); //创建地图
 map.InitMap(); //初始化地图

 //initgraph(MAP_WIDTH + ADD_WIDTH, MAP_HEIHT, SHOWCONSOLE);
 initgraph(MAP_WIDTH + ADD_WIDTH, MAP_HEIHT);
 add.ShowAdd(); //显示右边的图片
 map.ShowMap(); //显示地图
 LLKManage man(Elem,&map); //管理类 对象

 MOUSEMSG m;
 while (1)
 {
 while (MouseHit()) { //处理鼠标 [这里用while以后,鼠标的点击响应速度正常了]
 m = GetMouseMsg();
 if (m.uMsg == WM_LBUTTONDOWN) {//鼠标左键
 if (m.x < MAP_WIDTH && !man.GetAutoFlag())
 {
 int c_col = m.x / ELEM_WIDTH;
 int c_row = m.y / ELEM_HEIGHT;
 man.SetSelect(c_row, c_col);
 man.SetSelectShow();
 if (man.GetRow2() > -1 && man.GetRow1() > -1) //要判断是否可以删除
 {
 if (man.CanDelete()) //能删除
 {
 man.DeleteLineSHow();
 Sleep(200);
 //man.DeleteTwoElemShow();
 man.DeleteTwoElem();
 map.ShowMap();
 man.ClearSelect();
 }
 else //不能删除
 {
 man.ClearSelectShow();
 man.ClearSelect();
 }
 }
 }
 //这里要加上自动的那个
 if (m.x > MAP_WIDTH) //没精确判断
 {
 bool flag = man.GetAutoFlag();
 man.SetAutoFlag(!flag);
 //man.CalcEC();
 }
 }
 else if (m.uMsg == WM_RBUTTONDOWN && !man.GetAutoFlag()) { //鼠标右键
 man.ClearSelectShow();
 man.ClearSelect();
 }
 }
 Sleep(15);
 if (man.GetAutoFlag()) //自动运行
 {
 //printf("auto...");
 man.ClearSelectShow();
 man.ClearSelect();
 if (!man.AutoSelect()) //自动选择2个点
 {
 printf("没有找到合适的2个点!!!\n");
 outtextxy(200, 100, "没有找到点可以消除,任意键结束。");
 getchar();
 return 0;
 }
 man.SetSelectShow(); //显示选择动画
 Sleep(100);
 man.DeleteLineSHow();
 Sleep(400);
 //man.DeleteTwoElemShow();
 man.DeleteTwoElem();
 map.ShowMap();
 }
 }//end while(1)
 map.DeleteMap();
 closegraph();
 DeleteElems(Elem, ELEM_NUMS); //销毁元素对象
 return 0;
}

void InitElems(LLKElem **Elem, int nums, IMAGE* pbg) //初始化 连连看元素小图像
{
 for (int i = 0; i < nums; ++i)
 {
 char id = static_cast<char>(i);
 string fname;
 fname = "image/";
 char tmp[30] = { 0 };
 sprintf_s(tmp, "%d", i + 1);
 fname = fname + tmp;
 fname = fname + ".jpg";
 cout << fname.c_str() << endl;
 Elem[i] = new LLKElem(id, ELEM_WIDTH, ELEM_HEIGHT, fname,pbg);
 assert(Elem[i] != NULL);
 }
}

void DeleteElems(LLKElem **Elem, int nums) //删除 对象内存
{
 for (int i = 0; i < nums; ++i)
 {
 if (Elem[i] != NULL)
 delete Elem[i];
 Elem[i] = NULL;
 }
}

LLKMap地图类 LLKMap.h

//LLKMap.h
//连连看地图类

#pragma once
#ifndef _LLKMAP_H
#define _LLKMAP_H
#include <graphics.h>
#include <assert.h>
#include <time.h>
#include <stdio.h>
#include "LLKElem.h"

#define MAP_BLANK 0
class LLKMap
{
public:
 LLKMap(int rows,int cols,int elemNums, int elemRows,int elemCols,
 LLKElem **ppElem, IMAGE *pbg);
 ~LLKMap();
 void CreateMap(); //创建地图的内存
 void DeleteMap(); //删除地图的内存
 void InitMap(); //给出地图数据
 void ShowMap() const; //显示地图
 void SetMapData(int row, int col, char data); //设置地图数据
 int GetMapRows() const { return m_rows; }
 int GetMapCols() const { return m_cols; }
 int GetElemRows() const { return m_elemRows; }
 int GetElemCols() const { return m_elemCols; }
 int GetElemNums() const { return m_elemNums; }
 const char GetMapData(int row, int col) const { return m_ppMap[row][col]; }
 const char** GetMapPP() const { return (const char**)m_ppMap; } //获取地图数据 (比较方便)
private:
 int m_cols, m_rows; //游戏区域的逻辑尺寸
 int m_elemRows,m_elemCols;
 int m_elemNums; //总共有几个唯一的元素,初始化给出
 char** m_ppMap;
 IMAGE *m_pbg; //背景图片指针,传进来
 LLKElem **m_ppElem; //元素对象指针,传进来
};

#endif

LLKMap地图类 LLKMap.cpp

//LLKMap.cpp
#include "LLKMap.h"



LLKMap::LLKMap(int rows, int cols, int elemNums, int elemRows, int elemCols, 
 LLKElem **ppElem, IMAGE *pbg)
 :m_rows(rows),m_cols(cols),m_elemNums(elemNums), m_elemRows(elemRows),
 m_elemCols(elemCols), m_ppElem(ppElem),m_pbg(pbg)
{
}


LLKMap::~LLKMap()
{
}

void LLKMap::CreateMap() //创建地图的内存
{
 m_ppMap = new char*[m_rows];
 assert(m_ppMap != NULL);
 for (int i = 0; i < m_rows; ++i)
 {
 m_ppMap[i] = new char[m_cols];
 assert(m_ppMap[i] != NULL);
 memset((void*)m_ppMap[i], 0, m_cols); //清0
 }
}

void LLKMap::DeleteMap() //删除地图的内存
{
 for (int i = 0; i < m_rows; ++i)
 {
 if (m_ppMap[i] != NULL)
 {
 delete[] m_ppMap[i];
 m_ppMap[i] = NULL;
 }
 }
 delete[] m_ppMap;
}

void LLKMap::InitMap() //给出地图数据
{
 int len = m_rows*m_cols; //总长度
 printf("%d %d %d %d\n", m_rows, m_cols, len, m_elemNums);
 int half_len = len / 2; //一半长度
 //因为要考虑地图边缘空白的关系,创建1个半长的一维数组存放数据,用来打乱
 char *ptmp = new char[half_len];
 assert(ptmp != NULL);
 memset((void*)ptmp, 0, half_len); //清0
 int index_ptmp = 0; //计数ptmp指针
 srand((unsigned int)time(NULL));
 for (int i = 0; i < half_len; ++i) //随机赋值
 {
 char t = MAP_BLANK;
 if (i / m_cols == 0 || i / m_cols == m_rows - 1 || i%m_cols == 0 || i%m_cols == m_cols - 1)
 {
 m_ppMap[i / m_cols][i%m_cols] = MAP_BLANK;
 }
 else
 {
 t = rand() % m_elemNums + 1;
 m_ppMap[i / m_cols][i%m_cols] = t;
 ptmp[index_ptmp++] = t;
 }
 m_ppMap[(len - 1 - i) / m_cols][(len - 1 - i) % m_cols] = t; //后半部分 反向相同
 }

 //打乱ptmp
 for (int i = 0; i < index_ptmp; ++i)
 {
 int j = rand() % index_ptmp;
 char tmp = ptmp[i];
 ptmp[i] = ptmp[j];
 ptmp[j] = tmp;
 }
 //把乱序的ptmp写到 map的上半部分
 for (int i = 0; i < half_len; ++i) //上半部分重新打乱
 {
 if (m_ppMap[i / m_cols][i%m_cols] != MAP_BLANK)
 {
 m_ppMap[i / m_cols][i%m_cols] = ptmp[--index_ptmp];
 }
 }
 //printf("-=-=-=-=index_ptmp=%d\n", index_ptmp);
 ////显示个数,看看问题:
 //int ttt[29] = { 0 };
 //for (int r = 0; r < m_rows; r++) {
 // for (int c = 0; c < m_cols; c++) {
 // ttt[m_ppMap[r]]++;
 // }
 //}
 //printf("2==========================\n");
 //for (int i = 0; i < 29; i++) {
 // if (ttt[i] % 2 == 1)
 // printf("error! ");
 // printf("%d\n", ttt[i]);
 //}
 //printf("2==========================\n");

 delete[] ptmp;
}

void LLKMap::ShowMap() const //显示地图
{
 BeginBatchDraw();
 putimage(0, 0, m_cols*m_elemCols, m_rows*m_elemRows, m_pbg, 0, 0);
 for (int row = 0; row < m_rows; ++row) 
 {
 for (int col = 0; col < m_cols; ++col)
 {
 int id = m_ppMap[row][col];
 if (id > 0 && id <= m_elemNums)
 m_ppElem[id - 1]->SHowElem(row, col);
 }
 }
 FlushBatchDraw();
 EndBatchDraw();
}

void LLKMap::SetMapData(int row, int col, char data) //设置地图数据
{
 assert(row > 0 && row < m_rows - 1 && col>0 && col < m_cols - 1 && data >= 0 && data <= m_elemNums);
 m_ppMap[row][col] = data;
}


LLKElem类 LLKElem.h

//LLKElem.h
//LLKElem类 头文件
//连连看元素的id和图片数据
#pragma once
#ifndef _LLKELEM_H
#define _LLKELEM_H
#include <graphics.h>
#include <iostream>
using std::string;

class LLKElem
{
public:
 LLKElem(char id,int width,int height,string& filename, IMAGE* pbg); //构造函数
 ~LLKElem();
 void SHowElem(int row,int col) const; //在x,y的地方显示元素
 void UnShowElem(int row, int col) const; //用了静态,删除显示
 void SelectElem(int row, int col) const; //鼠标点击 元素的显示
private:
 char m_elemId; //ID号
 IMAGE m_elemImg; //对应的图片
 int m_width, m_height; //元素图片的宽和高
 string m_fileName; //元素图片的路径和文件名
 IMAGE* m_pbg; //背景图片,外面传入
};

#endif

LLKElem类 LLKElem.cpp

//LLKElem.cpp
#include "LLKElem.h"

LLKElem::LLKElem(char id, int width, int height, string& filename,IMAGE* pbg) //构造函数
{
 m_elemId = id;
 m_width = width;
 m_height = height;
 m_fileName = filename;
 m_pbg = pbg;
 loadimage(&m_elemImg, m_fileName.c_str(), width, height, false);
}

LLKElem::~LLKElem()
{
}

void LLKElem::SHowElem(int row, int col) const //在x,y的地方显示元素
{
 putimage(col*m_width, row*m_height, &m_elemImg);
}

void LLKElem::UnShowElem(int row, int col) const //删除显示
{
 putimage(col*m_width, row*m_height, m_width, m_height, m_pbg, col*m_width, row*m_height );
}

void LLKElem::SelectElem(int row, int col) const //鼠标点击 元素的显示
{
 setlinecolor(RGB(255, 0, 0));
 setlinestyle(PS_SOLID, 2);
 rectangle(col*m_width+2, row*m_height+2, (col + 1)*m_width-4,(row + 1)*m_height-4 );
}

LLKManage管理类 LLKManage.h

//LLKManage.h
//连连看管理类 
#pragma once
#ifndef _LLKMANAGE_H
#define _LLKMANAGE_H
#include "LLKElem.h"
#include "LLKMap.h"
#include <assert.h>
#include <vector>
using namespace std;
class LLKManage
{
public:
 LLKManage(LLKElem **ppElem,LLKMap* pmap);
 ~LLKManage();
 bool GetSelectFlag() const { return m_selectflag; }
 void SetSelectFlag(bool flag) { m_selectflag = flag; }
 int GetRow1() const { return m_row1; }
 int GetCol1() const { return m_col1; }
 int GetRow2() const { return m_row2; }
 int GetCol2() const { return m_col2; }
 void SetRow1(int row) { m_row1 = row; }
 void SetCol1(int col) { m_col1 = col; }
 void SetRow2(int row) { m_row2 = row; }
 void SetCol2(int col) { m_col2 = col; }
 void ClearSelectShow() const; //清除选择的显示
 void ClearSelect(); //清除选择
 void SetSelect(int row,int col); //设置选择
 void SetSelectShow() const; //显示选择
 void SetDLine(int num = 0, int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0,
 int x3 = 0, int y3 = 0, int x4 = 0, int y4 = 0);
 bool GetAutoFlag() const { return m_autoflag; }
 void SetAutoFlag(bool flag) { m_autoflag = flag; }
 void MinData(int& a, int& b); //保证小的在前
 void ExchangeData(int& a, int& b); //总是交换
 bool Link_p2p(int row1, int col1, int row2, int col2); //同一条线上的情况,是否连通
 bool Link_one(); //一条线
 bool Link_two_1_left(int row1,int col1,int row2,int col2); //二条线 上面的点在左边(left通道)
 bool Link_two_1_right(int row1, int col1, int row2, int col2); //二条线 上面的点在左边(right通道)
 bool Link_two_2_left(int row1, int col1, int row2, int col2); //二条线 下面的点在左边(left通道)
 bool Link_two_2_right(int row1, int col1, int row2, int col2); //二条线 下面的点在左边(right通道)
 void GetXspace(int row,int col,int& left, int& right); //获取横向平行线的 左右位置
 void GetYspace(int row,int col,int& top, int& bottom); //获取横向平行线的 上下位置
 bool Link_three_2X(); //三条线,横向2条
 bool Link_three_2Y(); //三条线,竖向2条
 bool CanDelete(); //是否可以消除
 void DeleteTwoElem(); //删除2个元素
 void DeleteTwoElemShow() const; //删除2个元素的显示
 void DeleteLineSHow() const; //显示删除线
 void InitEC(); //重置 m_ec 
 void CalcEC(); //计算重新填满 m_ec
 bool AutoSelect();//自动选择可以消除的2个点
private:
 int m_row1, m_col1; //选中的第1个 逻辑坐标
 int m_row2, m_col2; //选择的第2个
 bool m_selectflag; //选中状态:true表示当前已经有1个选中了,false表示没有选中
 LLKElem **m_ppElem; //元素对象指针,传进来
 LLKMap* m_pmap; //连连看地图指针,传进来
 int m_DLine[9]; //删除的路线图,[0]表示点的个数,[1][2] [3][4] [5][6] [7][8]分别表示4个点
 bool m_autoflag; //自动运行标志
 vector <vector<int> > m_ec;
};

#endif

LLKManage管理类 LLKManage.cpp

//LLKManage.cpp
#include "LLKManage.h"

LLKManage::LLKManage(LLKElem **ppElem,LLKMap* pmap)
{
 m_row1 = -1;
 m_col1 = -1;
 m_row2 = -1;
 m_col2 = -1;
 m_selectflag = false; 
 m_ppElem = ppElem;
 m_pmap = pmap;
 m_DLine[0] = 0;
 m_autoflag = false;
 m_ec.resize(pmap->GetElemNums());
}

LLKManage::~LLKManage()
{
}

void LLKManage::ClearSelectShow() const //清除选择的显示
{
 if (m_row1 > -1)
 {
 int val = m_pmap->GetMapData(m_row1,m_col1);
 m_ppElem[val - 1]->SHowElem(m_row1,m_col1);
 }
 if (m_row2 > -1)
 {
 int val = m_pmap->GetMapData(m_row2, m_col2);
 m_ppElem[val - 1]->SHowElem(m_row2, m_col2);
 }
}
void LLKManage::ClearSelect() //清除选择
{
 m_row1 = -1;
 m_col1 = -1;
 m_row2 = -1;
 m_col2 = -1;
 m_selectflag = false;
}

void LLKManage::SetSelect(int row,int col) //设置选择
{
 if (m_pmap->GetMapData(row, col) == 0) //点的不是元素 不行
 return;
 if (!m_selectflag) //没有选择
 {
 ClearSelectShow();
 ClearSelect();
 m_row1 = row;
 m_col1 = col;
 m_selectflag = true;
 }
 else //已经选择了1个了
 {
 if (m_row1 == row&&m_col1 == col) //还是点在第一个上不行
 return;
 m_row2 = row;
 m_col2 = col;
 m_selectflag = false;
 }
}
void LLKManage::SetSelectShow() const //显示选择
{
 if (m_row1 > -1)
 m_ppElem[0]->SelectElem(m_row1,m_col1);
 //Sleep(1000);
 if (m_row2 > -1)
 m_ppElem[0]->SelectElem(m_row2, m_col2);
}
void LLKManage::SetDLine(int num,int x1,int y1,int x2, int y2,int x3,int y3,int x4,int y4)
{
 m_DLine[0] = num;
 m_DLine[1] = x1;
 m_DLine[2] = y1;
 m_DLine[3] = x2;
 m_DLine[4] = y2;
 m_DLine[5] = x3;
 m_DLine[6] = y3;
 m_DLine[7] = x4;
 m_DLine[8] = y4;
}
void LLKManage::MinData(int& a, int& b) //小的在前
{
 if (a > b)
 {
 int tmp = a;
 a = b;
 b = tmp;
 }
}

void LLKManage::ExchangeData(int& a, int& b) //总是交换
{
 int tmp = a;
 a = b;
 b = tmp;
}

bool LLKManage::Link_p2p(int row1, int col1, int row2, int col2) //同一条线上的情况,是否连通
{ //必须保证 小的在前,大的在后
 assert(row1 >= 0 && row1 < m_pmap->GetMapRows() && col1 >= 0 && col1 < m_pmap->GetMapCols());
 assert(row2 >= 0 && row2<m_pmap->GetMapRows() && col2 >= 0 && col2<m_pmap->GetMapCols());
 //assert(row1 <= row2&&col1 <= col2);
 char** pmap = const_cast<char**>(m_pmap->GetMapPP());
 if (row1 == row2) //横线
 {
 bool res = true;
 for (int i = col1; i <= col2; ++i)
 {
 if (pmap[row1][i] != 0)
 {
 res = false;
 break;
 }
 }
 return res;
 }
 else if(col1 == col2) //竖线
 {
 bool res = true;
 for (int i = row1; i <= row2; ++i)
 {
 if (pmap[i][col1] != 0)
 {
 res = false;
 break;
 }
 }
 return res;
 }
}

bool LLKManage::Link_one() //一条线
{
 if (m_row1 == m_row2) //横线
 {
 //if (col1 + 1 == col2) return true;
 return Link_p2p(m_row1, m_col1 + 1, m_row2, m_col2 - 1);
 }
 else if(m_col1 == m_col2) //竖线
 {
 //if (row1 + 1 == row2) return true;
 return Link_p2p(m_row1 + 1, m_col1, m_row2 - 1, m_col2);
 }
 return false;
}

bool LLKManage::Link_two_1_left(int row1, int col1, int row2, int col2) 
{ //二条线 上面的点在左边(left通道)
 if (Link_p2p(row2, col1, row2, col2 ) &&
 Link_p2p(row1 , col1, row2, col1))
 return true;
 return false;
}
bool LLKManage::Link_two_1_right(int row1, int col1, int row2, int col2)
{ //二条线 上面的点在左边(right通道)
 if (Link_p2p(row1, col1, row1, col2) &&
 Link_p2p(row1, col2, row2, col2))
 return true;
 return false;
}
bool LLKManage::Link_two_2_left(int row1, int col1, int row2, int col2)
{ //二条线 下面的点在左边(left通道)
 if (Link_p2p(row1, col2, row1, col1) &&
 Link_p2p(row1, col2, row2, col2))
 return true;
 return false;
}
bool LLKManage::Link_two_2_right(int row1, int col1, int row2, int col2)
{ //二条线 下面的点在左边(right通道)
 if (Link_p2p(row2, col2, row2, col1) &&
 Link_p2p(row1, col1, row2, col1))
 return true;
 return false;
}

void LLKManage::GetXspace(int row, int col, int& left, int& right)//获取横向平行线的 左右位置
{ 
 char** pmap = const_cast<char**>(m_pmap->GetMapPP());
 int t = col-1;
 while (t >= 0 && pmap[row][t] == 0)
 t--;
 left = t + 1;
 t = col + 1;
 while (t < m_pmap->GetMapCols() && pmap[row][t] == 0)
 t++;
 right = t - 1;
}
void LLKManage::GetYspace(int row, int col, int& top, int& bottom) //获取横向平行线的 上下位置
{
 char** pmap = const_cast<char**>(m_pmap->GetMapPP());
 int t = row - 1;
 while (t >= 0 && pmap[t][col] == 0)
 t--;
 top = t + 1;
 t = row + 1;
 while (t < m_pmap->GetMapRows() && pmap[t][col] == 0)
 t++;
 bottom = t - 1;
}
bool LLKManage::Link_three_2X() //三条线,横向2条
{
 int left1, right1, left2, right2, left, right;
 GetXspace(m_row1, m_col1, left1, right1);
 printf("2x点1:%d %d\n", left1, right1);
 GetXspace(m_row2, m_col2, left2, right2);
 printf("2x点2:%d %d\n", left2, right2);
 if (right1<left2 || left1>right2) return false;
 if (left1 <= left2&&right1 >= right2){left = left2; right = right2; }
 else if (left1 >= left2&&right1 <= right2) { left = left1; right = right1;}
 else if (right1 >= left2 && left1<=left2) { left = left2; right = right1; }
 else if (right2 >= left1&&right1>=right2) { left = left1; right = right2; }
 for (int i = left; i <= right; ++i)
 {
 if (Link_p2p(m_row1, i, m_row2, i))
 {
 printf("--->2x: %d %d %d\n", left, right, i);
 SetDLine(4, m_row1, m_col1, m_row1, i, m_row2, i, m_row2, m_col2);
 return true;
 }
 }
 return false;
}
bool LLKManage::Link_three_2Y() //三条线,竖向2条
{
 int top1, bottom1, top2, bottom2, top, bottom;
 GetYspace(m_row1, m_col1, top1, bottom1);
 printf("2y点1:%d %d\n", top1, bottom1);
 GetYspace(m_row2, m_col2, top2, bottom2);
 printf("2y点2:%d %d\n", top2, bottom2);
 if (bottom1<top2 || top1>bottom2) return false;
 if (top1 <= top2&&bottom1 >= bottom2) { top = top2; bottom = bottom2; }
 else if (top1 >= top2&&bottom1 <= bottom2) { top = top1; bottom = bottom1; }
 else if (bottom1 >= top2 && top1 <= top2) { top = top2; bottom = bottom1; }
 else if (bottom2 >= top1&&bottom1 >= bottom2) { top = top1; bottom = bottom2; }
 for (int i = top; i <= bottom; ++i)
 {
 if (Link_p2p(i, m_col1, i, m_col2))
 {
 printf("--->2y: %d %d %d\n", top, bottom, i);
 SetDLine(4, m_row1, m_col1, i, m_col1, i, m_col2, m_row2, m_col2);
 return true;
 }
 
 }
 return false;
}
bool LLKManage::CanDelete() //是否可以消除
{
 if (m_pmap->GetMapData(m_row1,m_col1) != m_pmap->GetMapData(m_row2, m_col2))
 return false; //元素不同,直接返回了。
 //1.同行或者同列
 if (m_row1 == m_row2 || m_col1 == m_col2)
 {
 MinData(m_row1, m_row2);
 MinData(m_col1, m_col2); //这种情况,可以直接交换原数据
 if (Link_one())
 {
 SetDLine(2, m_row1, m_col1, m_row2, m_col2);
 return true;
 }
 }
 //2.不同行也不同列:2根线的尝试?(只有2个方向,共4根线的判断)
 if (m_row1 > m_row2)
 {
 ExchangeData(m_row1, m_row2);
 ExchangeData(m_col1, m_col2); //保证行号小的在前面
 }
 if (m_col1 < m_col2) //上面的点 在左边
 {
 if (Link_two_1_left(m_row1 + 1, m_col1, m_row2, m_col2 - 1))
 {
 SetDLine(3, m_row1, m_col1, m_row2, m_col1, m_row2, m_col2);
 return true;
 }
 if (Link_two_1_right(m_row1, m_col1 + 1, m_row2 - 1, m_col2))
 {
 SetDLine(3, m_row1, m_col1, m_row1, m_col2, m_row2, m_col2);
 return true;
 }
 }
 else //上面的点 在右边
 {
 if (Link_two_2_left(m_row1, m_col1 - 1, m_row2 - 1, m_col2))
 {
 SetDLine(3, m_row1, m_col1, m_row1, m_col2, m_row2, m_col2);
 return true;
 }
 if (Link_two_2_right(m_row1 + 1, m_col1, m_row2, m_col2 + 1))
 {
 SetDLine(3, m_row1, m_col1, m_row2, m_col1, m_row2, m_col2);
 return true;
 }
 }
 //3.需要3根线的情况:
 //此处 点1肯定在上面了,两点分别做横向平行线
 if (Link_three_2X())
 return true;
 //假如col1>col2 交换,保证点1在左边
 if (m_col1 > m_col2)
 {
 ExchangeData(m_row1, m_row2);
 ExchangeData(m_col1, m_col2); //保证列号小的在前面
 }
 if (Link_three_2Y())
 return true;
 return false;
}

void LLKManage::DeleteTwoElem() //删除2个元素
{
 m_pmap->SetMapData(m_row1, m_col1, MAP_BLANK);
 m_pmap->SetMapData(m_row2, m_col2, MAP_BLANK);
 ClearSelect(); //2个点坐标清空
 m_DLine[0] = 0;
}
void LLKManage::DeleteTwoElemShow() const //删除2个元素的显示
{
 m_ppElem[0]->UnShowElem(m_row1, m_col1);
 m_ppElem[0]->UnShowElem(m_row2, m_col2);
}

void LLKManage::DeleteLineSHow() const //显示删除线
{
 srand((unsigned int)time(NULL));
 setlinecolor(RGB(rand() % 240 + 15, rand() % 240 + 15, rand() % 240 + 15));
 //setlinecolor(RGB(255, 0, 0));
 setlinestyle(PS_SOLID, 4);
 for (int i = 0; i < m_DLine[0] - 1; i++) {
 int x1 = m_DLine[i * 2 + 2] * m_pmap->GetElemCols()+ m_pmap->GetElemCols()/2;
 int y1 = m_DLine[i * 2 + 1] * m_pmap->GetElemRows()+ m_pmap->GetElemRows()/2;
 int x2 = m_DLine[i * 2 + 4] * m_pmap->GetElemCols()+ m_pmap->GetElemCols()/2;
 int y2 = m_DLine[i * 2 + 3] * m_pmap->GetElemRows()+ m_pmap->GetElemRows()/2;
 line(x1, y1,x2,y2);
 }
}

/////下面关于自动删除的
void LLKManage::InitEC() //重置 m_ec 
{
 for (int i = 0; i < m_ec.size(); ++i) {
 m_ec[i].clear();
 m_ec[i].push_back(0);
 }
}
void LLKManage::CalcEC() //计算重新填满 m_ec
{
 InitEC(); //重置m_ec
 int rows = m_pmap->GetMapRows();
 int cols = m_pmap->GetMapCols();
 for (int row = 0; row < rows; ++row) 
 {
 for (int col = 0; col < cols; ++col)
 {
 int t = m_pmap->GetMapData(row, col);
 if (t > 0)
 {
 m_ec[t - 1][0]++;
 m_ec[t - 1].push_back(row);
 m_ec[t - 1].push_back(col);
 }
 }
 }
 for (int i = 0; i < m_ec.size(); ++i) {
 for (int j = 0; j < m_ec[i].size(); ++j) {
 printf("%d ", m_ec[i][j]);
 }
 printf("\n");
 }
}

bool LLKManage::AutoSelect()//自动选择可以消除的2个点
{
 CalcEC(); //重新计算每个元素的分布情况
 for (int i = 0; i < m_ec.size(); ++i) //28个元素遍历
 {
 for (int j = 0; j < m_ec[i][0]; ++j) //第1个存放的是 个数
 {
 for (int k = j + 1; k < m_ec[i][0]; ++k)
 {
 m_row1 = m_ec[i][j * 2 + 1];
 m_col1 = m_ec[i][j * 2 + 2];
 m_row2 = m_ec[i][k * 2 + 1];
 m_col2 = m_ec[i][k * 2 + 2];
 if (CanDelete())
 return true;
 }
 }
 }
 return false;
}

LLKMapAdd附加地图类 LLKMapAdd.h

//LLKMapAdd.h
//连连看 右边的显示区域,用来提示信息等
#pragma once
#ifndef _LLKMAPADD_H
#define _LLKMAPADD_H
#include <graphics.h>

class LLKMapAdd
{
public:
 LLKMapAdd(int mapWidth,int mapHeight,int addWidth, IMAGE *pbg, IMAGE *pAuto);
 ~LLKMapAdd();
 void ShowAdd();//显示右边的图片
private:
 int m_mapWidth; //左边游戏地图宽度
 int m_mapHeight; //游戏地图高度
 int m_addWidth; //右边增加的部分宽度
 IMAGE *m_pbg; //背景图片指针,传入
 IMAGE *m_pAuto; //按钮图片,自动运行
};

#endif

LLKMapAdd附加地图类 LLKMapAdd.cpp

//LLKMapAdd.cpp
#include "LLKMapAdd.h"

LLKMapAdd::LLKMapAdd(int mapWidth, int mapHeight,
 int addWidth, IMAGE *pbg, IMAGE *pAuto):
 m_mapWidth(mapWidth),m_mapHeight(mapHeight),m_addWidth(addWidth),
 m_pbg(pbg),m_pAuto(pAuto)
{
}

LLKMapAdd::~LLKMapAdd()
{
}

void LLKMapAdd::ShowAdd()//显示右边的图片
{
 putimage(m_mapWidth, 0, m_addWidth, m_mapHeight, m_pbg, m_mapWidth, 0);
 int w = m_pAuto->getwidth();
 int h = m_pAuto->getheight();
 int dst_w = m_mapWidth + (m_addWidth - w) / 2;
 int dst_h = (m_mapHeight - h) / 2;
 putimage(dst_w, dst_h, m_pAuto);
}

(2017-04-04 www.vsppc.com)

学习笔记未经允许不得转载:PPC的C/C++和人工智能学习笔记 » C++语言基础(14-1)_练习:连连看小游戏

分享到:更多 ()

评论 78

评论前必须登录!