以下代码可以直接复制到vs中运行
// LLK_Console.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <time.h>
#include <string>
using namespace std;
typedef enum
{
ntUnknown = -1,
ntEmpty,
nt1,
nt2,
nt3,
nt4,
nt5,
nt6,
nt7,
nt8,
nt9,
nt10,
nt11,
nt12,
nt13,
nt14,
nt15,
nt16,
nt17,
nt18,
nt19,
nt20,
nt21
} eNodeType;
//从1~m个数字中随机取出n个不相同的数字
void Random_m_n(int m, int n, int *arry)
{
//重置时间算子,用于产生随机数
srand((int)time(0));
int * data_m = new int[m];
//生成1~m个数字,存入数组中
for(int i = 0;i < m; i++)
{
data_m[i] = i+1;
}
while (n--)
{
//产生范围0~m-1内的一个随机数
int i = rand() % m;
//拷贝到目标数组中
arry[n] = data_m[i];
//把当前位置的数字替换成其他不重复数字
--m;
data_m[i] = data_m[m];
}
delete[] data_m;
}
class MapNode
{
private:
int row;
int column;
eNodeType nodeType;
MapNode* pairNode;
public:
MapNode(int row, int column, eNodeType nodeType)
{
this->nodeType = nodeType;
this->row = row;
this->column = column;
}
void SetPairNode(MapNode* pNode)
{
pairNode = pNode;
}
MapNode* GetPairNode()
{
return pairNode;
}
static MapNode* GenEmptyNode()
{
return new MapNode(0, 0, ntEmpty);
}
eNodeType GetNodeType()
{
return nodeType;
}
void SetNodeTypeEmpty()
{
nodeType = ntEmpty;
}
int GetRow()
{
return row;
}
int GetColumn()
{
return column;
}
void SetRow(int nRow)
{
row = nRow;
}
void SetColumn(int nColumn)
{
column = nColumn;
}
};
class NodeContainer
{
public:
void InitNodeContainer(int rows, int columns, vector<MapNode*>& vectNodes)
{
// Need add 2 side-rows and 2 side-columns
m_totalRows = rows + 2;
m_totalColumns = columns + 2;
//Next, Init nodes
/*
1. Generate numbers from 0 to rows * columns - 1 and put it into a array
2. Use numbers in the array as index to get node in vectNodes and put it into m_vectorNodes
*/
int* aRandomNums = new int[rows * columns];
Random_m_n(rows * columns, rows * columns, aRandomNums);
int insideNodeCounter = 0;
for (int i = 0; i < rows + 2; ++i)
{
for (int j = 0; j < columns + 2; ++j)
{
if (i == 0 || j == 0 || i == rows + 1 || j == columns + 1)
{
MapNode* emptyNode = MapNode::GenEmptyNode();
emptyNode->SetRow(i);
emptyNode->SetColumn(j);
m_vectNodes.push_back(emptyNode);
}
else
{
MapNode* pNode = vectNodes[aRandomNums[insideNodeCounter] - 1];
m_originalNodeMatrix.push_back(pNode);
pNode->SetRow(i);
pNode->SetColumn(j);
if (pNode->GetNodeType() != ntEmpty)
{
FindAndSetPairNode(pNode);
}
m_vectNodes.push_back(pNode);
++insideNodeCounter;
}
}
}
delete[] aRandomNums;
}
int GetTotalRows() { return m_totalRows;}
int GetTotalColumns() { return m_totalColumns;}
MapNode* GetNodeAtIndexOf(int row, int colum)
{
return m_vectNodes[row * m_totalColumns + colum];
}
void printMap()
{
for (int i = 0; i < m_totalRows; ++i)
{
for ( int j = 0; j < m_totalColumns; ++j)
{
cout<< m_vectNodes[i * m_totalColumns + j]->GetNodeType() << '\t';
}
cout<<endl;
}
}
bool LinkWithStraightLine(MapNode* node1, MapNode* node2)
{
if (node1->GetRow() == node2->GetRow())
{
int leftNodeIndex = min(node1->GetColumn(), node2->GetColumn());
int rightNodeIndex = max(node1->GetColumn(), node2->GetColumn());
for (int i = leftNodeIndex + 1; i < rightNodeIndex; ++i)
{
if (GetNodeAtIndexOf(node1->GetRow(), i)->GetNodeType() != ntEmpty)
{
return false;
}
}
return true;
}
else if (node1->GetColumn() == node2->GetColumn())
{
int upNodeIndex = min(node1->GetRow(), node2->GetRow());
int downNodeIndex = max(node1->GetRow(), node2->GetRow());
for (int i = upNodeIndex + 1; i < downNodeIndex; ++i)
{
if (GetNodeAtIndexOf(i, node1->GetColumn())->GetNodeType() != ntEmpty)
{
return false;
}
}
return true;
}
else
{
return false;
}
}
bool LinkWithOneCorner(MapNode* node1, MapNode* node2)
{
MapNode* conerNode = NULL;
if ((conerNode = GetNodeAtIndexOf(node1->GetRow(), node2->GetColumn()))->GetNodeType() == ntEmpty)
{
if (LinkWithStraightLine(node1, conerNode) && LinkWithStraightLine(node2, conerNode) )
{
return true;
}
}
if ((conerNode = GetNodeAtIndexOf(node2->GetRow(), node1->GetColumn()))->GetNodeType() == ntEmpty)
{
if (LinkWithStraightLine(node1, conerNode) && LinkWithStraightLine(node2, conerNode))
{
return true;
}
}
return false;
}
bool LinkWithTwoCorner(MapNode* node1, MapNode* node2)
{
//Find all the nodes those are in the same rows or colums to check if one of them can link with node 2 through one corner
//in the same row
MapNode* nodeHolder = NULL;
for (int i = node1->GetColumn() + 1; i < GetTotalColumns(); ++i)
{
if (( nodeHolder = GetNodeAtIndexOf(node1->GetRow(), i))->GetNodeType() == ntEmpty)
{
if (LinkWithOneCorner(nodeHolder, node2))
{
return true;
}
}
else
{
break;
}
}
for (int i = node1->GetColumn() - 1; i > -1; --i)
{
if (( nodeHolder = GetNodeAtIndexOf(node1->GetRow(), i))->GetNodeType() == ntEmpty)
{
if (LinkWithOneCorner(nodeHolder, node2))
{
return true;
}
}
else
{
break;
}
}
//in the same column
for (int i = node1->GetRow() + 1; i < GetTotalRows(); ++i)
{
if ((nodeHolder = GetNodeAtIndexOf(i, node1->GetColumn()))->GetNodeType() == ntEmpty)
{
if (LinkWithOneCorner(nodeHolder, node2))
{
return true;
}
}
else
{
break;
}
}
for (int i = node1->GetRow() - 1; i > -1; ++i)
{
if ((nodeHolder = GetNodeAtIndexOf(i, node1->GetColumn()))->GetNodeType() == ntEmpty)
{
if (LinkWithOneCorner(nodeHolder, node2))
{
return true;
}
}
else
{
break;
}
}
return false;
}
bool CanBeLinked(MapNode* node1, MapNode* node2)
{
if (node1->GetNodeType() == node2->GetNodeType())
{
return LinkWithStraightLine(node1, node2) || LinkWithOneCorner(node1, node2) || LinkWithTwoCorner(node1, node2);
}
else
{
cout<<"Not even the same type...wow!"<<endl;
return false;
}
}
bool CanBeLinked(int row1, int column1, int row2, int column2)
{
MapNode* node1 = GetNodeAtIndexOf(row1, column1);
MapNode* node2 = GetNodeAtIndexOf(row2, column2);
if (node1->GetNodeType() == ntEmpty || node2->GetNodeType() == ntEmpty)
{
cout<<"Empty node, u r kidding me ?!"<<endl;
return false;
}
if (node1->GetNodeType() == node2->GetNodeType())
{
return LinkWithStraightLine(node1, node2) || LinkWithOneCorner(node1, node2) || LinkWithTwoCorner(node1, node2);
}
else
{
cout<<"Not even the same type...wow!"<<endl;
return false;
}
}
bool Hint()
{
for (vector<MapNode*>::iterator iNode = m_vectNodes.begin(); iNode != m_vectNodes.end(); ++iNode )
{
MapNode* pNode = (*iNode);
if (pNode->GetNodeType() != ntEmpty)
{
if (CanBeLinked(pNode, pNode->GetPairNode()))
{
pNode->SetNodeTypeEmpty();
pNode->GetPairNode()->SetNodeTypeEmpty();
return true;
}
}
}
return false;
}
bool HintWithoutSettingLinkedNodeEmpty()
{
for (vector<MapNode*>::iterator iNode = m_vectNodes.begin(); iNode != m_vectNodes.end(); ++iNode )
{
MapNode* pNode = (*iNode);
if (pNode->GetNodeType() != ntEmpty)
{
if (CanBeLinked(pNode, pNode->GetPairNode()))
{
return true;
}
}
}
return false;
}
void ReArrangeMap()
{
while(1)
{
if (ReArrangeNodes())
{
return;
}
}
}
private:
bool ReArrangeNodes()
{
ReInitNodeContainer();
return HintWithoutSettingLinkedNodeEmpty();
}
void ReInitNodeContainer()
{
int rows = m_totalRows - 2;
int columns = m_totalColumns - 2;
m_vectNodes.clear();
int* aRandomNums = new int[rows * columns];
Random_m_n(rows * columns, rows * columns, aRandomNums);
int insideNodeCounter = 0;
for (int i = 0; i < rows + 2; ++i)
{
for (int j = 0; j < columns + 2; ++j)
{
if (i == 0 || j == 0 || i == rows + 1 || j == columns + 1)
{
MapNode* emptyNode = MapNode::GenEmptyNode();
emptyNode->SetRow(i);
emptyNode->SetColumn(j);
m_vectNodes.push_back(emptyNode);
}
else
{
MapNode* pNode = m_originalNodeMatrix[aRandomNums[insideNodeCounter] - 1];
pNode->SetRow(i);
pNode->SetColumn(j);
if (pNode->GetNodeType() != ntEmpty)
{
FindAndSetPairNode(pNode);
}
m_vectNodes.push_back(pNode);
++insideNodeCounter;
}
}
}
delete[] aRandomNums;
}
void FindAndSetPairNode(MapNode* pNode)
{
eNodeType nt = pNode->GetNodeType();
for (vector<MapNode*>::iterator iNode = m_vectNodes.begin(); iNode != m_vectNodes.end(); ++iNode)
{
if ( (*iNode)->GetNodeType() == nt)
{
pNode->SetPairNode(*iNode);
(*iNode)->SetPairNode(pNode);
break;
}
}
}
private:
int m_totalRows;
int m_totalColumns;
vector<MapNode*> m_vectNodes;
vector<MapNode*> m_originalNodeMatrix;
};
#define ROWS 6
#define COLUMNS 6
int _tmain(int argc, _TCHAR* argv[])
{
/*
1. Init nodes: nodes number(including empty number): rows*columns, put them into a array, random numbers from 0 to rows*columns - 1, then sequencely put them onto the map
*/
#define NODE_TYPE_NUMS (ROWS*COLUMNS/2)
std::vector<MapNode*> vectNodes;
for (int i = 0; i < ROWS; ++i)
{
for ( int j = 0; j < COLUMNS; ++j)
{
MapNode* pNode = new MapNode(0, 0, (eNodeType)((i*COLUMNS + j) / 2));
vectNodes.push_back(pNode);
}
}
NodeContainer* gNodeContainer = new NodeContainer;
gNodeContainer->InitNodeContainer(ROWS, COLUMNS, vectNodes);
gNodeContainer->printMap();
while(1)
{
string strYN;
cout<<"Do you want to hint? y/n"<<endl;
cin>>strYN;
if (strYN == "y" || strYN == "Y")
{
if (gNodeContainer->Hint())
{
cout<<"hit success"<<endl;
gNodeContainer->printMap();
}
else
{
cout<<"No two same node can be link, you should rearrange the whole map ... -_-|||"<<endl;
cout<<"Do you want to rearrange the map? y/n"<<endl;
strYN.clear();
cin>>strYN;
if (strYN == "y" || strYN == "Y")
{
gNodeContainer->ReArrangeMap();
gNodeContainer->printMap();
}
}
}
else
{
break;
}
}
while(1)
{
int row1,column1,row2,column2;
cout<<"Input first node's node row and column"<<endl;
cin>>row1;
cin>>column1;
cout<<"Input second node's node row and column"<<endl;
cin>>row2;
cin>>column2;
if (gNodeContainer->CanBeLinked(row1, column1, row2, column2))
{
cout<<"Link success!!! >_<"<<endl;
gNodeContainer->GetNodeAtIndexOf(row1, column1)->SetNodeTypeEmpty();
gNodeContainer->GetNodeAtIndexOf(row2, column2)->SetNodeTypeEmpty();
gNodeContainer->printMap();
}
else
{
cout<<"Can't be linked ... -_-"<<endl;
string strYN;
cout<<"Do you want to hint? y/n"<<endl;
cin>>strYN;
if (strYN == "y" || strYN == "Y")
{
if (gNodeContainer->Hint())
{
cout<<"hit success"<<endl;
gNodeContainer->printMap();
}
else
{
cout<<"No two same node can be link, you should rearrange your map ... -_-|||"<<endl;
}
}
}
}
return 0;
}
这里整理一下思路:
1. 初始化布局:顺序的建立一个数组,把nodetype按两个两个顺序插入此数组a1(这里数组泛指一种数据结构,我使用的是vector),然后生成n个0 ~ n - 1的随机数(n=行*列),依次的使用索引的方式在a1上取得node,然后顺序的插入另一个地图布局中(其实也是一个数组结构)。特别需要注意的是因为边界问题,地图布局的格子的行和列都要比实际可点击的节点多2 。
2. 连通算法(至多两个拐点表示相连):
1)广度优先:两个节点node1和node2,将能和node1直接相连的节点加入集合S,然后再将能和S集合中节点直接相连的节点加入S(去重复),最后再将能和S集合中节点直接相连的节点加入S(去重复),如果node2在S集合中,则表示两者相连。
2)分类算法:(此程序采用)首先判断两个节点是否可以直接相连,如果否,则两个节点是否可以通过一个拐角相连(两个节点是一个正方形的对角线),如果还是否,则判断两个节点是否可以通过两个拐角相连。
3. 关于hint()提示:遍历图中所有非空的节点,然后检查是否和他配对的节点可相连。 在初始化的时候就把每两个相同的节点建立关联,虽然这样使得初始化会多执行一些代码,但因为hint()这个需要在每次玩家消除一对以后检查地图是否有解,一开始建立了关联,则可以提高效率。
4. 地图布局是否有解:此思路可以参考以下几条,是网上找到的比较容易理解而且实现起来也比较简单的一种思路,这种方法是保证玩家的下一步一定有可相连的节点来保证游戏的进行,如果没有,则程序重新随机生成布局直至满足至少有一对可相连为止
1)随机生成布局
2)使用hint()来判断是否至少有一对相同节点能相互相连,如果没有任何一对可以相连,则回到第1)步
3)此地图布局有解(是指至少有一对可相连)