Commit 9569a7ed authored by Hubert Denkmair's avatar Hubert Denkmair

track food

parent ca602b9c
......@@ -15,6 +15,7 @@ add_executable(
main.cpp
RelayServer.h RelayServer.cpp
TcpProtocol.h TcpProtocol.cpp
SpatialMap.h
)
target_link_libraries(
......
#pragma once
#include <array>
#include <vector>
#include <functional>
#include <Eigen/Geometry>
typedef double real_t;
typedef Eigen::Matrix<real_t, 2, 1> Vector2D;
template <class T> class SpatialMapRegion;
template <class T, size_t TILES_X, size_t TILES_Y> class SpatialMap
{
public:
typedef std::vector<T> TileVector;
typedef SpatialMapRegion<SpatialMap<T,TILES_X,TILES_Y>> Region;
friend class SpatialMapRegion<SpatialMap<T,TILES_X,TILES_Y>>;
public:
SpatialMap(size_t fieldSizeX, size_t fieldSizeY, size_t reserveCount)
: m_fieldSizeX(fieldSizeX)
, m_fieldSizeY(fieldSizeY)
, m_tileSizeX(fieldSizeX/TILES_X)
, m_tileSizeY(fieldSizeY/TILES_Y)
, m_fullRegion(*this, 0, 0, TILES_X-1, TILES_Y-1)
{
for (auto &v: m_tiles)
{
v.reserve(reserveCount);
}
}
void clear()
{
for (auto &v: m_tiles)
{
v.clear();
}
}
size_t size() const
{
size_t retval = 0;
for (auto &tile: m_tiles)
{
retval += tile.size();
}
return retval;
}
void addElement(const T& element)
{
getTileVectorForPosition(element.pos()).push_back(element);
}
void erase_if(std::function<bool(const T&)> predicate)
{
for (auto &tile: m_tiles)
{
tile.erase(std::remove_if(tile.begin(), tile.end(), predicate), tile.end());
}
}
Region getRegion(const Vector2D& center, real_t radius)
{
const Vector2D topLeft = center - Vector2D { radius, radius };
const Vector2D bottomRight = center + Vector2D { radius, radius };
return {
*this,
static_cast<int>(topLeft.x() / m_tileSizeX),
static_cast<int>(topLeft.y() / m_tileSizeY),
static_cast<int>(bottomRight.x() / m_tileSizeX),
static_cast<int>(bottomRight.y() / m_tileSizeY)
};
}
typename Region::Iterator begin()
{
return m_fullRegion.begin();
}
typename Region::Iterator end()
{
return m_fullRegion.end();
}
private:
size_t m_fieldSizeX, m_fieldSizeY;
real_t m_tileSizeX, m_tileSizeY;
Region m_fullRegion;
std::array<TileVector, TILES_X*TILES_Y> m_tiles;
TileVector& getTileVector(int tileX, int tileY)
{
return m_tiles[wrap<TILES_Y>(tileY)*TILES_X + wrap<TILES_X>(tileX)];
}
TileVector& getTileVectorNoWrap(int tileX, int tileY)
{
return m_tiles[tileY*TILES_X +tileX];
}
TileVector& getTileVectorForPosition(const Vector2D& pos)
{
size_t tileX = wrap<TILES_X>(pos.x() / m_tileSizeX);
size_t tileY = wrap<TILES_Y>(pos.y() / m_tileSizeY);
return m_tiles[tileY*TILES_X + tileX];
}
template <size_t SIZE> static size_t wrap(int unwrapped)
{
int result = (unwrapped % SIZE);
if (result<0) { result += SIZE; }
return static_cast<size_t>(result);
}
static bool needsWrapX(int unwrapped)
{
return (unwrapped<0) || (unwrapped>=TILES_X);
}
static bool needsWrapY(int unwrapped)
{
return (unwrapped<0) || (unwrapped>=TILES_Y);
}
};
template <class T> class SpatialMapRegion
{
public:
class Iterator
{
public:
Iterator(SpatialMapRegion* region, bool atEnd)
: m_region(region)
, m_needsWrap(region->m_needsWrap)
, m_atEnd(atEnd)
{
if (m_atEnd)
{
moveToEnd();
}
else
{
m_tileX = m_region->m_x1;
m_tileY = m_region->m_y1;
skipEmptyTiles();
}
}
Iterator& operator++()
{
if (m_atEnd) { return *this; }
if (++m_positionInTile >= getCurrentTile().size())
{
m_positionInTile = 0;
m_tileX++;
skipEmptyTiles();
}
return *this;
}
bool operator!=(const Iterator& other)
{
if (m_atEnd)
{
return (other.m_region != m_region) || (!other.m_atEnd);
}
return (other.m_region != m_region)
|| (other.m_atEnd!=m_atEnd)
|| (other.m_tileX != m_tileX)
|| (other.m_tileY != m_tileY)
|| (other.m_positionInTile != m_positionInTile);
}
auto& operator*()
{
return getCurrentTile()[m_positionInTile];
}
private:
SpatialMapRegion* m_region;
const bool m_needsWrap = true;
bool m_atEnd = false;
int m_tileX = 0;
int m_tileY = 0;
size_t m_positionInTile = 0;
void skipEmptyTiles()
{
while (m_tileY <= m_region->m_y2)
{
while (m_tileX <= m_region->m_x2)
{
if (getCurrentTile().size()>0)
{
return;
}
m_tileX++;
}
m_tileX = m_region->m_x1;
m_tileY++;
}
moveToEnd();
}
void moveToEnd()
{
m_atEnd = true;
m_tileX = 0;
m_tileY = 0;
m_positionInTile = 0;
}
typename T::TileVector& getCurrentTile()
{
return m_needsWrap
? m_region->m_map.getTileVector(m_tileX, m_tileY)
: m_region->m_map.getTileVectorNoWrap(m_tileX, m_tileY);
}
};
SpatialMapRegion(T& map, int x1, int y1, int x2, int y2)
: m_map(map), m_x1(x1), m_y1(y1), m_x2(x2), m_y2(y2)
, m_needsWrap(map.needsWrapX(x1) || map.needsWrapX(x2) || map.needsWrapY(y1) || map.needsWrapY(y2))
{
}
Iterator begin()
{
return Iterator(this, false);
}
Iterator end()
{
return Iterator(this, true);
}
private:
T& m_map;
const int m_x1, m_y1, m_x2, m_y2;
const bool m_needsWrap;
};
......@@ -65,32 +65,84 @@ void TcpProtocol::OnMessageReceived(std::vector<char> &data)
{
case 0x00:
if (arr.size<5) { return; }
std::cerr << "size_x " << arr.ptr[2].via.f64 << " size_y " << arr.ptr[3].via.f64 << " decrate " << arr.ptr[4].via.f64 << std::endl;
OnWorldInfoReceived(arr.ptr[2].via.f64, arr.ptr[3].via.f64, arr.ptr[4].via.f64);
break;
case 0x01:
std::cerr << "world update" << std::endl;
break;
case 0x10:
std::cerr << "tick" << std::endl;
break;
case 0x20:
std::cerr << "bot spawn" << std::endl;
break;
case 0x21:
std::cerr << "bot kill" << std::endl;
break;
case 0x22:
std::cerr << "bot move" << std::endl;
break;
case 0x30:
std::cerr << "food spawn" << std::endl;
if (arr.size<3) { return; }
for (auto& item: arr.ptr[2].via.array)
{
auto &fi = item.via.array;
if (fi.size < 3) { continue; }
OnFoodSpawnReceived({
static_cast<guid_t>(fi.ptr[0].via.i64), // guid
{fi.ptr[1].via.f64, fi.ptr[2].via.f64}, // position
fi.ptr[3].via.f64 // value
});
}
break;
case 0x31:
std::cerr << "food consume" << std::endl;
if (arr.size<3) { return; }
for (auto& item: arr.ptr[2].via.array)
{
auto &fi = item.via.array;
if (fi.size < 2) { continue; }
OnFoodConsumedReceived(
static_cast<guid_t>(fi.ptr[0].via.i64), // food guid
static_cast<guid_t>(fi.ptr[1].via.i64) // bot guid
);
}
break;
case 0x32:
std::cerr << "food decay" << std::endl;
if (arr.size<3) { return; }
for (auto& item: arr.ptr[2].via.array)
{
OnFoodDecayedReceived(static_cast<guid_t>(item.via.u64));
}
break;
}
}
void TcpProtocol::OnWorldInfoReceived(real_t size_x, real_t size_y, real_t decay_rate)
{
_food = std::make_unique<FoodMap>(size_x, size_y, 1000);
_foodDecayRate = decay_rate;
}
void TcpProtocol::OnFoodSpawnReceived(const TcpProtocol::Food &food)
{
if (_food == nullptr) { return; }
_food->addElement(food);
}
void TcpProtocol::OnFoodConsumedReceived(guid_t food_id, guid_t bot_id)
{
_food->erase_if([food_id](const Food& food) { return food.guid == food_id; });
}
void TcpProtocol::OnFoodDecayedReceived(guid_t food_id)
{
_food->erase_if([food_id](const Food& food) { return food.guid == food_id; });
}
......@@ -4,7 +4,10 @@
#include <functional>
#include <deque>
#include <vector>
#include <memory>
#include "SpatialMap.h"
typedef std::uint64_t guid_t;
class TcpProtocol
{
public:
......@@ -13,9 +16,31 @@ class TcpProtocol
bool Read(int socket);
private:
static constexpr const size_t SPATIAL_MAP_TILES_X = 128;
static constexpr const size_t SPATIAL_MAP_TILES_Y = 128;
static constexpr const size_t SPATIAL_MAP_RESERVE_COUNT = 10;
struct Food
{
guid_t guid;
Vector2D position;
real_t value;
const Vector2D& pos() const { return position; }
};
typedef SpatialMap<Food, SPATIAL_MAP_TILES_X, SPATIAL_MAP_TILES_Y> FoodMap;
size_t _awaitedSize = 0;
std::deque<char> _buf;
MessageReceivedCallback _messageReceivedCallback;
std::unique_ptr<FoodMap> _food;
real_t _foodDecayRate = 0;
void OnMessageReceived(std::vector<char>& data);
void OnWorldInfoReceived(real_t size_x, real_t size_y, real_t decay_rate);
void OnFoodSpawnReceived(const Food& food);
void OnFoodConsumedReceived(guid_t food_id, guid_t bot_id);
void OnFoodDecayedReceived(guid_t food_id);
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment