//
#include "stdafx.h"
#include <stdio.h>
#include <Winsock2.h>
#pragma comment (lib, "ws2_32")
#include <thread>
#include "tinyxml.h"
#include <string>
#include <vector>
#include <iostream>
#define UDP
class DataStruct
{
public:
int startx;
int starty;
int endx;
int endy;
};
class CCPoint
{
public:
CCPoint(){};
CCPoint(float x, float y) : x(x), y(y)
{
}
int x;
int y;
};
struct CCSize
{
int width;
int height;
};
struct MapXML
{
std::string m_data;
CCSize m_size;
};
class PathSprite
{
public:
PathSprite():m_parent(NULL),
m_child(NULL),
m_costToSource(0),
m_FValue(0),
m_startX(0),
m_startY(0),
m_endX(0),
m_endY(0)
{
};
public:
PathSprite* m_parent;//父节点
PathSprite* m_child;//子节点
float m_costToSource;//到起始点的距离
int m_x;//地图坐标
int m_y;
float m_FValue;
int m_startX;//开始点
int m_startY;
int m_endX;//结束点
int m_endY;
};
class PathSearchInfo
{
public:
PathSearchInfo(CCSize size, std::vector< std::vector<PathSprite*>> inspectArray):m_mapSize(size),m_inspectArray(inspectArray){};
~PathSearchInfo(){};
CCSize m_mapSize;
std::vector< std::vector<PathSprite*>> m_inspectArray;
std::vector<CCPoint> m_pathList;//路径列表
std::vector<PathSprite*> m_haveInspectList;//检测过的列表
std::vector<PathSprite*> m_openList;//开放列表(里面存放相邻节点)
std::function<void(const char* , int , int)> sendData;
void calculatePath(int startX, int startY, int endX, int endY)//计算路径
{
clearPath();
#ifndef NOMAL_SEARCH_PATH
//得到开始点的节点
PathSprite* _endNode= m_inspectArray[startX][startY];
//得到结束点的节点
PathSprite* _startNode = m_inspectArray[endX][endY];
//因为是开始点 把到起始点的距离设为0, F值也为0
_startNode->m_costToSource = 0;
_startNode->m_FValue = 0;
//把已经检测过的点从检测列表中删除
m_inspectArray[endX][endY] = NULL;
//把该点放入已经检测过点的列表中
m_haveInspectList.push_back(_startNode);
//然后加入开放列表
m_openList.push_back(_startNode);
PathSprite* _node = NULL;
while (true)
{
//得到离起始点最近的点(如果是第一次执行, 得到的是起点)
_node = getMinPathFormOpenList();
if (!_node)
{
//不到路径
break;
}
//把计算过的点从开放列表中删除
removeObjFromOpenList( _node);
int _x = _node->m_x;
int _y = _node->m_y;
//
if (_x ==startX && _y == startY)
{
break;
}
//检测8个方向的相邻节点是否可以放入开放列表中
PathSprite* _adjacent = NULL;
_adjacent = getObjFromInspectArray( _x +1, _y);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x , _y -1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x -1, _y);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x , _y+1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x + 1, _y + 1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x +1, _y-1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x -1, _y - 1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x -1, _y+1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
}
while (_node)
{
//把路径点加入到路径列表中
m_pathList.push_back(CCPoint(_node->m_x, _node->m_y) );
_node = _node->m_parent;
}
#else
//得到开始点的节点
PathSprite* _startNode = m_inspectArray[startX][startY];
//得到结束点的节点
PathSprite* _endNode = m_inspectArray[endX][endY];
//因为是开始点 把到起始点的距离设为0, F值也为0
_startNode->m_costToSource = 0;
_startNode->m_FValue = 0;
//把已经检测过的点从检测列表中删除
m_inspectArray[startX][startY] = NULL;
//把该点放入已经检测过点的列表中
m_haveInspectList.push_back(_startNode);
//然后加入开放列表
m_openList.push_back(_startNode);
PathSprite* _node = NULL;
while (true)
{
//得到离起始点最近的点(如果是第一次执行, 得到的是起点)
_node = getMinPathFormOpenList();
if (!_node)
{
break;
}
//把计算过的点从开放列表中删除
removeObjFromOpenList( _node);
int _x = _node->m_x;
int _y = _node->m_y;
//
if (_x ==endX && _y == endY)
{
break;
}
//检测8个方向的相邻节点是否可以放入开放列表中
PathSprite* _adjacent = NULL;
_adjacent = getObjFromInspectArray( _x +1, _y);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x , _y -1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x -1, _y);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x , _y+1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x + 1, _y + 1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x +1, _y-1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x -1, _y - 1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
_adjacent = getObjFromInspectArray( _x -1, _y+1);
inspectTheAdjacentNodes(_node, _adjacent, _endNode);
}
while (_node)
{
//把路径点加入到路径列表中
m_pathList.insert(m_pathList.begin(),CCPoint(_node->m_x, _node->m_y) );
_node = _node->m_parent;
}
#endif
CCPoint _pArray[200];
for (int i = 0 ; i < m_pathList.size(); i ++)
{
_pArray[i] = m_pathList[i];
}
sendData((const char*)&_pArray, sizeof(CCPoint)*m_pathList.size(), NULL);
}
PathSprite* getMinPathFormOpenList()
{
if (m_openList.size()>0) {
PathSprite* _sp =* m_openList.begin();
for ( std::vector<PathSprite*>::iterator iter = m_openList.begin(); iter != m_openList.end(); iter++)
{
if ((*iter)->m_FValue < _sp->m_FValue)
{
_sp = *iter;
}
}
return _sp;
}
else
{
return NULL;
}
}
bool removeObjFromOpenList( PathSprite* sprite )
{
if (!sprite) {
return false;
}
for ( std::vector<PathSprite*>::iterator iter = m_openList.begin(); iter != m_openList.end(); iter++)
{
if (*iter == sprite)
{
m_openList.erase(iter);
return true;
}
}
return false;
}
PathSprite* getObjFromInspectArray( int x, int y )
{
if (x >=0 && y >=0 && x < m_mapSize.width && y < m_mapSize.height) {
return m_inspectArray[x][y];
}
return NULL;
}
void PathSearchInfo::inspectTheAdjacentNodes( PathSprite* node, PathSprite* adjacent, PathSprite* endNode )
{
if (adjacent)
{
float _x = abs(endNode->m_x - adjacent->m_x);
float _y = abs(endNode->m_y - adjacent->m_y);
float F , G, H1, H2, H3;
adjacent->m_costToSource = node->m_costToSource + calculateTwoObjDistance(node, adjacent);//获得累计的路程
G = adjacent->m_costToSource;
//三种算法, 感觉H2不错
H1 = _x + _y;
H2 = hypot(_x, _y);
H3 = max(_x, _y);
#if 1 //A*算法 = Dijkstra算法 + 最佳优先搜索
F = G + H1;
#endif
#if 0//Dijkstra算法
F = G;
#endif
#if 0//最佳优先搜索
F = H2;
#endif
adjacent->m_FValue = F;
adjacent->m_parent = node;//设置父节点
m_haveInspectList.push_back(adjacent);
node->m_child = adjacent;//设置子节点
PathSearchInfo::m_inspectArray[adjacent->m_x][adjacent->m_y] = NULL;//把检测过的点从检测列表中删除
PathSearchInfo::m_openList.push_back(adjacent);//加入开放列表
}
}
float PathSearchInfo::calculateTwoObjDistance( PathSprite* obj1, PathSprite* obj2 )
{
float _x = abs(obj2->m_x - obj1->m_x);
float _y = abs(obj2->m_y - obj1->m_y);
return _x + _y;
}
void PathSearchInfo::clearPath( )
{
resetInspectArray();
//把移除了障碍物的地图放入检测列表中
m_openList.clear();
m_pathList.clear();
m_haveInspectList.clear();
}
void PathSearchInfo::resetInspectArray()
{
for (std::vector<PathSprite*>::iterator iter = m_haveInspectList.begin(); iter != m_haveInspectList.end(); iter++)
{
(*iter)->m_costToSource = 0;
(*iter)->m_FValue = 0;
(*iter)->m_parent = NULL;
(*iter)->m_child = NULL;
m_inspectArray[(*iter)->m_x][(*iter)->m_y] = (*iter);
}
}
};
void getMapdataFromXML(MapXML& data)
{
std::string wirtePath = "mapData.xml";
TiXmlDocument* myDocument = new TiXmlDocument(wirtePath.c_str());
myDocument->LoadFile();
TiXmlElement* MapDataElement = myDocument->RootElement(); // MapData
std::string _strwidth = MapDataElement->Attribute("width"); //获得student的name属性
std::string _strheight = MapDataElement->Attribute("height"); //获得student的name属性
data.m_size.width =std::atoi( _strwidth.c_str() );
data.m_size.height =std::atoi( _strheight.c_str() );
TiXmlElement* dataElement = MapDataElement->FirstChildElement();
data.m_data = dataElement->GetText();
delete myDocument;
}
class createMapData
{
public:
MapXML m_mapXml;
std::vector< std::vector<PathSprite*>> m_inspectArray;
createMapData(std::string mapPath)
{
getMapdataFromXML(mapPath);
std::string & _str = m_mapXml.m_data;
int _width = m_mapXml.m_size.width;
int _height = m_mapXml.m_size.height;
int index = 0;
for (int j = 0; j < _width; j++) {
std::vector<PathSprite*> _pathSprite;
m_inspectArray.push_back(_pathSprite);
for (int i = 0; i < _height; i++) {
index = j * _height + i;
if (_str[index]=='1') {
PathSprite* _pathSprite = new PathSprite();
_pathSprite->m_x = j;
_pathSprite->m_y =i;
m_inspectArray[j].push_back(_pathSprite); //把地图中所有的点一一对应放入检测列表中
}
else
{
m_inspectArray[j].push_back(NULL);
}
}
}
}
void getMapdataFromXML(std::string mapPath)
{
std::string wirtePath = mapPath;//"mapData.xml";
TiXmlDocument* myDocument = new TiXmlDocument(wirtePath.c_str());
myDocument->LoadFile();
TiXmlElement* MapDataElement = myDocument->RootElement(); // MapData
std::string _strwidth = MapDataElement->Attribute("width"); //获得student的name属性
std::string _strheight = MapDataElement->Attribute("height"); //获得student的name属性
m_mapXml.m_size.width =std::atoi( _strwidth.c_str() );
m_mapXml.m_size.height =std::atoi( _strheight.c_str() );
TiXmlElement* dataElement = MapDataElement->FirstChildElement();
// CCLOG("%s",dataElement->GetText());
m_mapXml.m_data = dataElement->GetText();
delete myDocument;
}
};
class ServerSocate
{
public:
SOCKET sockConn;
std::function<void(int,int,int,int)> calculatePath;
struct sockaddr_in from;
int fromlen ;
ServerSocate()
{
fromlen =sizeof(from);
}
void startServer()
{
#if 0
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,1),&wsaData)) //调用Windows Sockets DLL
{
printf("Winsock无法初始化!\n");
WSACleanup();
return;
}
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
//2:绑定套接字到一个IP地址和一个端口上(bind());
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
//3:将套接字设置为监听模式等待连接请求(listen());
listen(sockSrv,5);
//4:请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR);
sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
#endif
#if 1
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,1),&wsaData)) //调用Windows Sockets DLL
{
printf("Winsock无法初始化!\n");
WSACleanup();
return;
}
printf("服务器开始创建SOCKET。\n");
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(6000); ///监听端口
local.sin_addr.s_addr=INADDR_ANY; ///本机
sockConn=socket(AF_INET,SOCK_DGRAM,0);
bind(sockConn,(struct sockaddr*)&local,sizeof(local));
#endif
//多线程
std::function<void(SOCKET &)> _recv = std::bind(&ServerSocate::recvFunction, this, std::placeholders::_1);
std::thread recvThread(_recv,sockConn);
recvThread.detach();
while(1)
{
}
}
#if 0
void sendFuction(SOCKET &sockConn)
{
while (true)
{
}
}
#endif
void sendData(const char* buf, int len, int flags)
{
sendto(sockConn, buf, len, flags,(struct sockaddr*)&from,fromlen);
}
void recvFunction(SOCKET& sockClient)
{
while (true)
{
char buffer[2048]="\0";
printf("waiting for message from others-------------\n");
if (recvfrom(sockClient,buffer,sizeof(buffer),0,(struct sockaddr*)&from,&fromlen)!=SOCKET_ERROR)
{
DataStruct *_data = (DataStruct *)buffer;
printf("%s\n",inet_ntoa(from.sin_addr));
printf("%d\n",_data->startx);
printf("%d\n",_data->starty);
printf("%d\n",_data->endx);
printf("%d\n",_data->endy);
calculatePath(_data->startx,_data->starty,_data->endx,_data->endy);
}
}
}
};
void main()
{
createMapData* MapData = new createMapData("mapData.xml");
PathSearchInfo* _pathSearch = new PathSearchInfo(MapData->m_mapXml.m_size,MapData->m_inspectArray);
ServerSocate* _server = new ServerSocate;
_pathSearch->sendData = std::bind(&ServerSocate::sendData, _server, std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
_server->calculatePath = std::bind(&PathSearchInfo::calculatePath, _pathSearch, std::placeholders::_1,std::placeholders::_2,std::placeholders::_3, std::placeholders::_4);
_server->startServer();
}