Commit c384c788 authored by Hubert Denkmair's avatar Hubert Denkmair
Browse files

Merge branch 'feature/boost_drops_mass' into 'dev'

Feature/boost drops mass

See merge request GPN18Programmierspiel/gameserver!16
parents ea527b5d 20ad4bc9
......@@ -37,7 +37,15 @@ BotThreadPool::BotThreadPool(std::size_t num_threads)
}
if(currentJob) {
currentJob->steps = currentJob->bot->move();
switch(currentJob->jobType) {
case Move:
currentJob->steps = currentJob->bot->move();
break;
case CollisionCheck:
currentJob->killer = currentJob->bot->checkCollision();
break;
}
std::lock_guard<std::mutex> processedQueueGuard(m_processedQueueMutex);
m_processedJobs.push(std::move(currentJob));
......
......@@ -16,12 +16,26 @@ class Bot;
class BotThreadPool
{
public:
enum JobType {
Move,
CollisionCheck
};
struct Job {
JobType jobType;
// inputs
std::shared_ptr<Bot> bot;
// output
// for jobType == Move
std::size_t steps;
// for jobType == CollisionCheck
std::shared_ptr<Bot> killer;
Job(JobType type, const std::shared_ptr<Bot> myBot)
: jobType(type), bot(myBot)
{}
};
private:
......
......@@ -153,20 +153,38 @@ void Field::consumeFood(void)
void Field::moveAllBots(void)
{
// first round: move all bots
for(auto &b : m_bots) {
std::unique_ptr<BotThreadPool::Job> job(new BotThreadPool::Job{b, 0});
std::unique_ptr<BotThreadPool::Job> job(new BotThreadPool::Job(BotThreadPool::Move, b));
m_threadPool.addJob(std::move(job));
}
m_threadPool.waitForCompletion();
// collision check for all bots
// FIXME: make this work without temporary vector
std::vector< std::unique_ptr<BotThreadPool::Job> > tmpJobs;
tmpJobs.reserve(m_bots.size());
std::unique_ptr<BotThreadPool::Job> job;
while((job = m_threadPool.getProcessedJob()) != NULL) {
tmpJobs.push_back(std::move(job));
}
// second round: collision check
for(auto &j : tmpJobs) {
j->jobType = BotThreadPool::CollisionCheck;
m_threadPool.addJob(std::move(j));
}
m_threadPool.waitForCompletion();
// collision check for all bots
while((job = m_threadPool.getProcessedJob()) != NULL) {
std::shared_ptr<Bot> victim = job->bot;
std::size_t steps = job->steps;
std::shared_ptr<Bot> killer = victim->checkCollision();
std::shared_ptr<Bot> killer = job->killer;
if (killer)
{
......@@ -175,6 +193,18 @@ void Field::moveAllBots(void)
} else {
// no collision, bot still alive
m_updateTracker->botMoved(victim, steps);
if(victim->getSnake()->boostedLastMove()) {
real_t lossValue =
config::SNAKE_BOOST_LOSS_FACTOR * victim->getSnake()->getMass();
victim->getSnake()->dropFood(lossValue);
if(victim->getSnake()->getMass() < config::SNAKE_SELF_KILL_MASS_THESHOLD) {
// Bot is now too small, so it dies
killBot(victim, victim);
}
}
}
}
......@@ -231,7 +261,12 @@ void Field::createDynamicFood(real_t totalValue, const Vector2D &center, real_t
std::size_t count = 1 + totalValue / config::FOOD_SIZE_MEAN;
for(std::size_t i = 0; i < count; i++) {
real_t value = (*m_foodSizeDistribution)(*m_rndGen);
real_t value;
if(totalValue >= config::FOOD_SIZE_MEAN) {
value = (*m_foodSizeDistribution)(*m_rndGen);
} else {
value = totalValue;
}
real_t rndRadius = radius * (*m_simple0To1Distribution)(*m_rndGen);
real_t rndAngle = (*m_angleRadDistribution)(*m_rndGen);
......
......@@ -158,6 +158,8 @@ std::size_t Snake::move(real_t targetAngle, bool boost)
m_segments[i].setPos(m_field->wrapCoords(m_segments[i].pos()));
}
m_boostedLastMove = boost;
return m_segments.size(); // == number of new segments at head
}
......@@ -197,6 +199,21 @@ void Snake::convertToFood(const std::shared_ptr<Bot> &hunter) const
}
}
void Snake::dropFood(float_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_mass -= value;
if(m_mass < 1e-6) {
m_mass = 1e-6;
}
ensureSizeMatchesMass();
}
real_t Snake::getConsumeRadius()
{
return m_segmentRadius * config::SNAKE_CONSUME_RANGE;
......
......@@ -46,6 +46,8 @@ class Snake
real_t m_movedSinceLastSpawn = 0; //!< Distance the head has moved since the last spawned segment
real_t m_boostedLastMove = false; //!< Track if the snake boosted during the last move
/*!
* Updates the length of m_segments and calculates the current m_segmentRadius
*/
......@@ -111,10 +113,20 @@ class Snake
*/
void convertToFood(const std::shared_ptr<Bot> &hunter) const;
/*!
* Drop food at the end of the Snake. Primarily used for mass loss during boost.
*
* The Snake's mass is reduced by the given amount. The dropped mass is the
* given amount multiplied with SNAKE_CONVERSION_FACTOR.
*/
void dropFood(float_t value);
real_t getMass(void) { return m_mass; }
real_t getConsumeRadius(void);
real_t maxRotationPerStep(void);
bool boostedLastMove(void) const { return m_boostedLastMove; }
};
......@@ -45,6 +45,12 @@ namespace config {
// the Snake’s segment radius.
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;
// Mass below which Snake dies through starvation
static const real_t SNAKE_SELF_KILL_MASS_THESHOLD = 1.0;
// Food particle size log-normal distribution parameters
static const real_t FOOD_SIZE_MEAN = 3.5;
static const real_t FOOD_SIZE_STDDEV = 2.0;
......
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