Stage.cpp
//------------------------------------------------------------------------------
/// @file
/// @author ハル研究所プログラミングコンテスト実行委員会
///
/// @copyright Copyright (c) 2019 HAL Laboratory, Inc.
/// @attention このファイルの利用は、同梱のREADMEにある
/// 利用条件に従ってください。
//------------------------------------------------------------------------------
#pragma once
#include "Stage.hpp"
//------------------------------------------------------------------------------
#include "Assert.hpp"
#include "Math.hpp"
#include "Print.hpp"
//------------------------------------------------------------------------------
namespace hpc {
//------------------------------------------------------------------------------
Stage::Stage()
: mTurn()
, mTurtlePositions()
, mFoods()
{
}
//------------------------------------------------------------------------------
int Stage::turn() const
{
return mTurn;
}
//------------------------------------------------------------------------------
const TurtlePositions& Stage::turtlePositions() const
{
return mTurtlePositions;
}
//------------------------------------------------------------------------------
const Foods& Stage::foods() const
{
return mFoods;
}
//------------------------------------------------------------------------------
void Stage::initialize(int aTurtleCount, int aFoodCount, int aDistribution, const RandomSeed& aStageRandomSeed)
{
Random random(aStageRandomSeed);
mTurn = 0;
bool isEmpty[Parameter::StageHeight][Parameter::StageWidth];
for (int y = 0; y < Parameter::StageHeight; ++y) {
for (int x = 0; x < Parameter::StageWidth; ++x) {
isEmpty[y][x] = true;
}
}
// カメの初期化
int turtleCount = 0;
while (turtleCount < aTurtleCount) {
int x = random.randTerm(Parameter::StageWidth);
int y = random.randTerm(Parameter::StageHeight);
// 何も配置されていない座標にカメを配置する。
if (isEmpty[y][x]) {
Point pos(x, y);
mTurtlePositions.add(pos);
isEmpty[y][x] = false;
++turtleCount;
}
}
// エサの初期化
int foodCount = 0;
while (foodCount < aFoodCount) {
int x = random.randTerm(Parameter::StageWidth);
int y = random.randTerm(Parameter::StageHeight);
// 何も配置されていない座標にエサを配置する。
if (isEmpty[y][x]) {
Point pos(x, y);
int height = random.randMinTerm(1, aTurtleCount + 1);
// 一様な乱数から、aDistributionで指定された回数だけ、1に寄せる。
// 低いものを増やして分業を促すため。
for (int i = 0; i < aDistribution; ++i) {
height = random.randMinTerm(1, height + 1);
}
Food food(pos, height);
mFoods.add(food);
isEmpty[y][x] = false;
++foodCount;
}
}
}
//------------------------------------------------------------------------------
void Stage::update(const Actions& aActions)
{
HPC_ASSERT(aActions.count() == mTurtlePositions.count());
// カメを移動させる。
int turtleCount[Parameter::StageHeight][Parameter::StageWidth] = {};
for (int i = 0; i < mTurtlePositions.count(); ++i) {
Point nextPoint = mTurtlePositions[i];
// 移動先の座標をステージの範囲内に収める。
switch (aActions[i]) {
case Action_Wait:
break;
case Action_MoveUp:
nextPoint.y = Math::Max(nextPoint.y - 1, 0);
break;
case Action_MoveDown:
nextPoint.y = Math::Min(nextPoint.y + 1, Parameter::StageHeight - 1);
break;
case Action_MoveLeft:
nextPoint.x = Math::Max(nextPoint.x - 1, 0);
break;
case Action_MoveRight:
nextPoint.x = Math::Min(nextPoint.x + 1, Parameter::StageWidth - 1);
break;
default:
HPC_ASSERT_NOT_REACHED();
}
mTurtlePositions[i] = nextPoint;
++turtleCount[nextPoint.y][nextPoint.x];
}
// エサを食べる。
for (int i = 0; i < mFoods.count(); ++i) {
Point foodPos = mFoods[i].pos();
if (!mFoods[i].isEaten() && mFoods[i].height() <= turtleCount[foodPos.y][foodPos.x]) {
mFoods[i].setIsEaten(true);
}
}
}
//------------------------------------------------------------------------------
void Stage::advanceTurn()
{
++mTurn;
}
//------------------------------------------------------------------------------
bool Stage::isEnd() const
{
for (Food food : mFoods) {
if (!food.isEaten()) {
return false;
}
}
return true;
}
} // namespace
// EOF