Commit dcbcdba3 authored by Thomas Kolb's avatar Thomas Kolb
Browse files

Merge remote-tracking branch 'origin/dev' into snakes_permanently_loose_mass

parents f7a4ad3f f3caa3c1
Subproject commit 68698de3be438fda96af49d79c60a0b8c9efdd6f
Subproject commit 01bed4031046231c1636991672e3e3d75b258e63
......@@ -123,3 +123,13 @@ real_t Bot::getSightRadius() const
{
return 50.0f + 15.0f * getSnake()->getSegmentRadius();
}
uint32_t Bot::getFace()
{
return m_lua_bot->getFace();
}
uint32_t Bot::getDogTag()
{
return m_lua_bot->getDogTag();
}
......@@ -93,5 +93,9 @@ class Bot : public IdentifyableObject
std::vector<uint32_t> getColors();
real_t getSightRadius() const;
uint32_t getFace();
uint32_t getDogTag();
};
......@@ -45,24 +45,6 @@ void MysqlDatabase::Connect(std::string host, std::string username, std::string
_saveBotVersionErrorMessageStmt = makePreparedStatement(
"UPDATE core_snakeversion SET server_error_message=? WHERE id=?"
);
_setupLiveStatsStmt = makePreparedStatement(
"REPLACE INTO core_livestats "
" (user_id) "
"VALUES"
" (?)"
);
_updateLiveStatsStmt = makePreparedStatement(
"UPDATE core_livestats "
"SET last_update_frame=?, mass=?, natural_food_consumed=?, carrison_food_consumed=?, hunted_food_consumed=? "
"WHERE user_id=?"
);
_removeLiveStatsStmt = makePreparedStatement(
"DELETE FROM core_livestats "
"WHERE user_id=?"
);
}
std::unique_ptr<BotScript> MysqlDatabase::GetBotData(int bot_id)
......@@ -143,31 +125,6 @@ void MysqlDatabase::DisableBotVersion(long version_id, std::string errorMessage)
}
}
void MysqlDatabase::SetupLiveStats(long user_id)
{
_setupLiveStatsStmt->setInt64(1, user_id);
_setupLiveStatsStmt->execute();
}
void MysqlDatabase::UpdateLiveStats(long user_id, long current_frame, double mass,
double natural_food_consumed, double carrison_food_consumed,
double hunted_food_consumed)
{
_updateLiveStatsStmt->setInt64(1, current_frame);
_updateLiveStatsStmt->setDouble(2, mass);
_updateLiveStatsStmt->setDouble(3, natural_food_consumed);
_updateLiveStatsStmt->setDouble(4, carrison_food_consumed);
_updateLiveStatsStmt->setDouble(5, hunted_food_consumed);
_updateLiveStatsStmt->setInt64(6, user_id);
_updateLiveStatsStmt->execute();
}
void MysqlDatabase::RemoveLiveStats(long user_id)
{
_removeLiveStatsStmt->setInt64(1, user_id);
_removeLiveStatsStmt->execute();
}
std::unique_ptr<sql::PreparedStatement> MysqlDatabase::makePreparedStatement(std::string sql)
{
return std::unique_ptr<sql::PreparedStatement>(
......
......@@ -47,12 +47,6 @@ namespace db
virtual void SetCommandCompleted(long commandId, bool result, std::string resultMsg) = 0;
virtual void ReportBotKilled(long victim_id, long version_id, long start_frame, long end_frame, long killer_id, double final_mass, double natural_food_consumed, double carrison_food_consumed, double hunted_food_consumed) = 0;
virtual void DisableBotVersion(long version_id, std::string errorMessage) = 0;
virtual void SetupLiveStats(long user_id) = 0;
virtual void UpdateLiveStats(long user_id, long current_frame, double mass,
double natural_food_consumed, double carrison_food_consumed,
double hunted_food_consumed) = 0;
virtual void RemoveLiveStats(long user_id) = 0;
};
class MysqlDatabase : public IDatabase
......@@ -66,12 +60,6 @@ namespace db
void ReportBotKilled(long victim_id, long version_id, long start_frame, long end_frame, long killer_id, double final_mass, double natural_food_consumed, double carrison_food_consumed, double hunted_food_consumed) override;
void DisableBotVersion(long version_id, std::string errorMessage) override;
void SetupLiveStats(long user_id) override;
void UpdateLiveStats(long user_id, long current_frame, double mass,
double natural_food_consumed, double carrison_food_consumed,
double hunted_food_consumed) override;
void RemoveLiveStats(long user_id) override;
private:
enum {
IDX_BOTSCRIPT_BOT_ID = 1,
......@@ -90,9 +78,6 @@ namespace db
std::unique_ptr<sql::PreparedStatement> _reportBotKilledStmt;
std::unique_ptr<sql::PreparedStatement> _disableBotVersionStmt;
std::unique_ptr<sql::PreparedStatement> _saveBotVersionErrorMessageStmt;
std::unique_ptr<sql::PreparedStatement> _setupLiveStatsStmt;
std::unique_ptr<sql::PreparedStatement> _updateLiveStatsStmt;
std::unique_ptr<sql::PreparedStatement> _removeLiveStatsStmt;
std::unique_ptr<sql::PreparedStatement> makePreparedStatement(std::string sql);
};
}
......@@ -188,10 +188,16 @@ void Field::moveAllBots(void)
std::shared_ptr<Bot> killer = job->killer;
if (killer)
{
// collision detected, convert the colliding bot to food
killBot(victim, killer);
if (killer) {
// size check on killer
double killerMass = killer->getSnake()->getMass();
double victimMass = victim->getSnake()->getMass();
if(killerMass > (victimMass * config::KILLER_MIN_MASS_RATIO)) {
// collision detected and killer is large enough
// -> convert the colliding bot to food
killBot(victim, killer);
}
} else {
// no collision, bot still alive
m_updateTracker->botMoved(victim, steps);
......@@ -262,15 +268,14 @@ std::shared_ptr<Bot> Field::getBotByDatabaseId(int id)
void Field::createDynamicFood(real_t totalValue, const Vector2D &center, real_t radius,
const std::shared_ptr<Bot> &hunter)
{
// create at least 1 food item
std::size_t count = 1 + totalValue / config::FOOD_SIZE_MEAN;
real_t remainingValue = totalValue;
for(std::size_t i = 0; i < count; i++) {
while(remainingValue > 0) {
real_t value;
if(totalValue >= config::FOOD_SIZE_MEAN) {
if(remainingValue > config::FOOD_SIZE_MEAN) {
value = (*m_foodSizeDistribution)(*m_rndGen);
} else {
value = totalValue;
value = remainingValue;
}
real_t rndRadius = radius * (*m_simple0To1Distribution)(*m_rndGen);
......@@ -284,6 +289,8 @@ void Field::createDynamicFood(real_t totalValue, const Vector2D &center, real_t
Food food {false, pos, value, hunter};
m_updateTracker->foodSpawned(food);
m_foodMap.addElement(food);
remainingValue -= value;
}
}
......
......@@ -59,10 +59,6 @@ Game::Game()
victim->getConsumedFoodHuntedBySelf()
);
m_database->RemoveLiveStats(
victim->getDatabaseId()
);
createBot(victim->getDatabaseId());
}
);
......@@ -78,6 +74,8 @@ bool Game::OnConnectionEstablished(TcpSocket &socket)
initTracker.worldState(*m_field);
socket.Write(initTracker.serialize());
socket.SetWriteBlocking(false);
return true;
}
......@@ -113,11 +111,6 @@ bool Game::OnTimerInterval()
m_streamStatsUpdateCounter = 0;
}
if(++m_dbStatsUpdateCounter >= DB_STATS_UPDATE_INTERVAL) {
updateStatsInDB();
m_dbStatsUpdateCounter = 0;
}
m_field->processLog();
m_field->tick();
......@@ -220,18 +213,6 @@ void Game::queryDB()
}
}
void Game::updateStatsInDB(void)
{
for(auto &b: m_field->getBots()) {
m_database->UpdateLiveStats(b->getDatabaseId(),
m_field->getCurrentFrame(),
b->getSnake()->getMass(),
b->getConsumedNaturalFood(),
b->getConsumedFoodHuntedByOthers(),
b->getConsumedFoodHuntedBySelf());
}
}
void Game::createBot(int bot_id)
{
auto data = m_database->GetBotData(bot_id);
......@@ -246,7 +227,5 @@ void Game::createBot(int bot_id)
{
m_database->DisableBotVersion(newBot->getDatabaseVersionId(), initErrorMessage);
// TODO save error message, maybe lock version in inactive state
} else {
m_database->SetupLiveStats(newBot->getDatabaseId());
}
}
......@@ -20,11 +20,9 @@ class Game
std::unique_ptr<db::IDatabase> m_database;
int m_dbQueryCounter = 0;
int m_streamStatsUpdateCounter = 0;
int m_dbStatsUpdateCounter = 0;
bool connectDB();
void queryDB();
void updateStatsInDB();
void createBot(int bot_id);
public:
......
......@@ -24,6 +24,7 @@ namespace MsgPackProtocol
MESSAGE_TYPE_BOT_MOVE = 0x22,
MESSAGE_TYPE_BOT_LOG = 0x23,
MESSAGE_TYPE_BOT_STATS = 0x24,
MESSAGE_TYPE_BOT_MOVE_HEAD = 0x25,
MESSAGE_TYPE_FOOD_SPAWN = 0x30,
MESSAGE_TYPE_FOOD_CONSUME = 0x31,
......@@ -39,6 +40,11 @@ namespace MsgPackProtocol
double world_size_x = 0;
double world_size_y = 0;
double food_decay_per_frame = 0;
double snake_distance_per_step = 0;
double snake_segment_distance_factor = 0;
double snake_segment_distance_exponent = 0;
double snake_pull_factor = 0;
};
struct PlayerInfoMessage
......@@ -75,6 +81,20 @@ namespace MsgPackProtocol
std::vector<BotMoveItem> items;
};
struct BotMoveHeadItem
{
guid_t bot_id;
double mass;
// one head position for each step moved in this frame, in temporal order
std::vector< Vector2D > new_head_positions;
};
struct BotMoveHeadMessage
{
std::vector<BotMoveHeadItem> items;
};
struct BotKillMessage
{
guid_t killer_id;
......@@ -108,6 +128,7 @@ namespace MsgPackProtocol
double natural_food_consumed;
double carrison_food_consumed;
double hunted_food_consumed;
double mass;
};
struct BotStatsMessage
......@@ -135,12 +156,16 @@ namespace msgpack {
{
template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, MsgPackProtocol::GameInfoMessage const& v) const
{
o.pack_array(5);
o.pack_array(9);
o.pack(MsgPackProtocol::PROTOCOL_VERSION);
o.pack(static_cast<int>(MsgPackProtocol::MESSAGE_TYPE_GAME_INFO));
o.pack(v.world_size_x);
o.pack(v.world_size_y);
o.pack(v.food_decay_per_frame);
o.pack(v.snake_distance_per_step);
o.pack(v.snake_segment_distance_factor);
o.pack(v.snake_segment_distance_exponent);
o.pack(v.snake_pull_factor);
return o;
}
};
......@@ -219,6 +244,30 @@ namespace msgpack {
}
};
template <> struct pack<MsgPackProtocol::BotMoveHeadMessage>
{
template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, MsgPackProtocol::BotMoveHeadMessage const& v) const
{
o.pack_array(3);
o.pack(MsgPackProtocol::PROTOCOL_VERSION);
o.pack(static_cast<int>(MsgPackProtocol::MESSAGE_TYPE_BOT_MOVE_HEAD));
o.pack(v.items);
return o;
}
};
template <> struct pack<MsgPackProtocol::BotMoveHeadItem>
{
template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, MsgPackProtocol::BotMoveHeadItem const& v) const
{
o.pack_array(3);
o.pack(v.bot_id);
o.pack(v.mass);
o.pack(v.new_head_positions);
return o;
}
};
template <> struct pack<MsgPackProtocol::BotKillMessage>
{
template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, MsgPackProtocol::BotKillMessage const& v) const
......@@ -295,11 +344,12 @@ namespace msgpack {
{
template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, MsgPackProtocol::BotStatsItem const& v) const
{
o.pack_array(4);
o.pack_array(5);
o.pack(v.bot_id);
o.pack(v.natural_food_consumed);
o.pack(v.carrison_food_consumed);
o.pack(v.hunted_food_consumed);
o.pack(v.mass);
return o;
}
};
......@@ -316,6 +366,18 @@ namespace msgpack {
}
};
template <> struct pack<Vector2D>
{
template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, Vector2D const& v) const
{
o.pack_array(2);
o.pack(v.x());
o.pack(v.y());
return o;
}
};
template<>
struct convert<Snake::Segment> {
msgpack::object const& operator()(msgpack::object const& o, Snake::Segment& v) const {
......@@ -342,17 +404,20 @@ namespace msgpack {
}
};
template <> struct pack< std::shared_ptr<Bot> >
template <> struct pack< std::shared_ptr<Bot>>
{
template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, std::shared_ptr<Bot> const& v) const
{
o.pack_array(6);
o.pack_array(9);
o.pack(v->getGUID());
o.pack(v->getName());
o.pack(v->getDatabaseVersionId());
o.pack(v->getFace());
o.pack(v->getDogTag());
o.pack(v->getColors());
o.pack(v->getSnake()->getMass());
o.pack(v->getSnake()->getSegmentRadius());
o.pack(v->getSnake()->getSegments());
o.pack(v->getColors());
o.pack(v->getDatabaseVersionId());
return o;
}
};
......
......@@ -75,6 +75,7 @@ void MsgPackUpdateTracker::botKilled(
void MsgPackUpdateTracker::botMoved(const std::shared_ptr<Bot> &bot, std::size_t steps)
{
// Fill BotMoveMessage
MsgPackProtocol::BotMoveItem item;
const Snake::SegmentList &segments = bot->getSnake()->getSegments();
......@@ -85,6 +86,15 @@ void MsgPackUpdateTracker::botMoved(const std::shared_ptr<Bot> &bot, std::size_t
item.current_length = segments.size();
m_botMoveMessage->items.push_back(item);
// Fill BotMoveHeadMessage
MsgPackProtocol::BotMoveHeadItem headItem;
headItem.bot_id = bot->getGUID();
headItem.mass = bot->getSnake()->getMass();
headItem.new_head_positions = bot->getSnake()->getHeadPositionsDuringLastMove();
m_botMoveHeadMessage->items.push_back(headItem);
}
void MsgPackUpdateTracker::botLogMessage(uint64_t viewerKey, const std::string& message)
......@@ -96,10 +106,15 @@ void MsgPackUpdateTracker::gameInfo(void)
{
MsgPackProtocol::GameInfoMessage msg;
msg.world_size_x = config::FIELD_SIZE_X;
msg.world_size_y = config::FIELD_SIZE_Y;
msg.world_size_x = config::FIELD_SIZE_X;
msg.world_size_y = config::FIELD_SIZE_Y;
msg.food_decay_per_frame = config::FOOD_DECAY_STEP;
msg.snake_distance_per_step = config::SNAKE_DISTANCE_PER_STEP;
msg.snake_segment_distance_factor = config::SNAKE_SEGMENT_DISTANCE_FACTOR;
msg.snake_segment_distance_exponent = config::SNAKE_SEGMENT_DISTANCE_EXPONENT;
msg.snake_pull_factor = config::SNAKE_PULL_FACTOR;
msgpack::sbuffer buf;
msgpack::pack(buf, msg);
appendMessage(buf);
......@@ -139,6 +154,7 @@ void MsgPackUpdateTracker::botStats(const std::shared_ptr<Bot> &bot)
item.natural_food_consumed = bot->getConsumedNaturalFood();
item.carrison_food_consumed = bot->getConsumedFoodHuntedByOthers();
item.hunted_food_consumed = bot->getConsumedFoodHuntedBySelf();
item.mass = bot->getSnake()->getMass();
m_botStatsMessage->items.push_back(item);
}
......@@ -173,6 +189,13 @@ std::string MsgPackUpdateTracker::serialize(void)
appendMessage(buf);
}
// moved bots (compressed version)
if(!m_botMoveHeadMessage->items.empty()) {
msgpack::sbuffer buf;
msgpack::pack(buf, m_botMoveHeadMessage);
appendMessage(buf);
}
// bot statistics
if(!m_botStatsMessage->items.empty()) {
msgpack::sbuffer buf;
......@@ -198,6 +221,7 @@ void MsgPackUpdateTracker::reset(void)
m_foodSpawnMessage = std::make_unique<MsgPackProtocol::FoodSpawnMessage>();
m_foodDecayMessage = std::make_unique<MsgPackProtocol::FoodDecayMessage>();
m_botMoveMessage = std::make_unique<MsgPackProtocol::BotMoveMessage>();
m_botMoveHeadMessage = std::make_unique<MsgPackProtocol::BotMoveHeadMessage>();
m_botStatsMessage = std::make_unique<MsgPackProtocol::BotStatsMessage>();
m_botLogMessage = std::make_unique<MsgPackProtocol::BotLogMessage>();
......
......@@ -21,6 +21,7 @@ class MsgPackUpdateTracker : public UpdateTracker
std::unique_ptr<MsgPackProtocol::FoodSpawnMessage> m_foodSpawnMessage;
std::unique_ptr<MsgPackProtocol::FoodDecayMessage> m_foodDecayMessage;
std::unique_ptr<MsgPackProtocol::BotMoveMessage> m_botMoveMessage;
std::unique_ptr<MsgPackProtocol::BotMoveHeadMessage> m_botMoveHeadMessage;
std::unique_ptr<MsgPackProtocol::BotStatsMessage> m_botStatsMessage;
std::unique_ptr<MsgPackProtocol::BotLogMessage> m_botLogMessage;
......
......@@ -53,7 +53,8 @@ void Snake::ensureSizeMatchesMass(void)
}
// update segment radius
m_segmentRadius = std::sqrt(m_mass) / 2;
m_segmentRadius = std::pow((20*m_mass+100), 0.3) - 3.9810717055349722;
// 100**0.3 --------^
}
real_t Snake::maxRotationPerStep(void)
......@@ -105,6 +106,8 @@ std::size_t Snake::move(real_t targetAngle, bool boost)
steps = config::SNAKE_BOOST_STEPS;
}
m_headPositionsDuringLastMove.clear();
// create new segments at head
for(std::size_t i = 0; i < steps; i++) {
// calculate new segment offset
......@@ -116,6 +119,8 @@ std::size_t Snake::move(real_t targetAngle, bool boost)
headSegment.setPos(headSegment.pos() + movementVector2D);
m_headPositionsDuringLastMove.push_back(headSegment.pos());
m_movedSinceLastSpawn += config::SNAKE_DISTANCE_PER_STEP;
// create new segments, if necessary
......@@ -205,7 +210,12 @@ void Snake::dropFood(real_t value)
Vector2D dropOffset = (m_segments.end() - 1)->pos() - (m_segments.end() - 2)->pos();
Vector2D dropPos = (m_segments.end() - 1)->pos() + dropOffset.normalized() * 5;
m_field->createDynamicFood(value * config::SNAKE_CONVERSION_FACTOR, dropPos, m_segmentRadius, nullptr);
m_foodToDrop += value * config::SNAKE_CONVERSION_FACTOR;
if(m_foodToDrop >= config::FOOD_SIZE_MEAN) {
m_field->createDynamicFood(m_foodToDrop, dropPos, m_segmentRadius, nullptr);
m_foodToDrop = 0;
}
m_mass -= value;
if(m_mass < 1e-6) {
......
......@@ -28,6 +28,7 @@ class Snake
};
typedef std::deque< Segment > SegmentList;
typedef std::vector< Vector2D > PositionList;
private:
/*!
......@@ -35,6 +36,8 @@ class Snake
*/
SegmentList m_segments;
PositionList m_headPositionsDuringLastMove;
Field *m_field;
real_t m_mass; //!< Mass (length) of the snake
......@@ -48,6 +51,7 @@ class Snake
real_t m_boostedLastMove = false; //!< Track if the snake boosted during the last move
real_t m_foodToDrop = 0;
public:
/*!
* Construct a unit snake (1 segment at 0/0, heading 0°).
......@@ -129,4 +133,8 @@ class Snake
bool boostedLastMove(void) const { return m_boostedLastMove; }
/*!
* Get a list of head positions that were used during the last call to move().
*/
const PositionList& getHeadPositionsDuringLastMove(void) const { return m_headPositionsDuringLastMove; };
};
......@@ -46,7 +46,7 @@ namespace config {
static const real_t SNAKE_CONSUME_RANGE = 2.0;
// Part of Snake's mass to drop in every frame the boost is on.
static const real_t SNAKE_BOOST_LOSS_FACTOR = 1e-3;
static const real_t SNAKE_BOOST_LOSS_FACTOR = 5e-3;
// Snakes continuously loose mass. This parameter adjust the part of mass
// lost every movement (==frame). The mass is not dropped, but simply lost.
......@@ -64,6 +64,12 @@ namespace config {
// Food decay value per frame
static const real_t FOOD_DECAY_STEP = 0.002;
// Minimum mass ratio required that a bot can kill another bot. This prevents
// that very small/newly spawned snakes can kill large snakes.
// Example: 0.01 means that the killer has to have at least 1% of the victims
// mass to be successful.
static const real_t KILLER_MIN_MASS_RATIO = 0.001;
// Lua memory pool configuration
static const std::size_t LUA_MEM_POOL_SIZE_BYTES = 10 * 1024*1024;
static const std::size_t LUA_MEM_POOL_BLOCK_SIZE_BYTES = 256;
......
......@@ -14,6 +14,8 @@ class LuaBot
bool init(std::string &initErrorMessage);
bool step(float &next_heading, bool &boost);
std::vector<uint32_t> getColors() { return m_self.colors; }
uint32_t getFace() { return m_self.getFace(); }
uint32_t getDogTag() { return m_self.getDogTag(); }
private:
Bot& m_bot;
......
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as pp
mass = np.arange(0, 500e3, 100)
radius1 = np.sqrt(mass)/2
radius2 = (20*mass+100)**0.3 - 100**0.3
#radius2 = 30*(np.log2((mass+10000)/100) - np.log2(100))
pp.plot(mass, radius1, 'r')
pp.plot(mass, radius2, 'g')
pp.show()
Supports Markdown
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