Stage.cpp

//------------------------------------------------------------------------------
/// @file
/// @author   ハル研究所プログラミングコンテスト実行委員会
///
/// @copyright  (C)HAL Laboratory, Inc.
/// @attention  このファイルの利用は、同梱のREADMEにある
///             利用条件に従ってください。
//------------------------------------------------------------------------------

#pragma once
#include "Stage.hpp"

//------------------------------------------------------------------------------
#include "Assert.hpp"
#include "Math.hpp"
#include "Print.hpp"

//------------------------------------------------------------------------------
namespace hpc {

//------------------------------------------------------------------------------
Stage::Stage()
: mTurn()
, mRabbit()
, mScrolls()
, mMap()
{
}

//------------------------------------------------------------------------------
int Stage::turn() const
{
    return mTurn;
}

//------------------------------------------------------------------------------
const Rabbit& Stage::rabbit() const
{
    return mRabbit;
}

//------------------------------------------------------------------------------
const Scrolls& Stage::scrolls() const
{
    return mScrolls;
}

//------------------------------------------------------------------------------
Terrain Stage::terrain(const Vector2& aPos) const
{
    return mMap[static_cast<int>(aPos.y)][static_cast<int>(aPos.x)];
}

//------------------------------------------------------------------------------
bool Stage::isOutOfBounds(const Vector2 aPos) const
{
    if(aPos.x < 0.0f || Parameter::StageWidth <= aPos.x || aPos.y < 0.0f || Parameter::StageHeight <= aPos.y) {
        return true;
    } else {
        return false;
    }
}

//------------------------------------------------------------------------------
Vector2 Stage::getNextPos(const Vector2& aPos, float aPower, const Vector2& aTargetPos) const
{
    auto t = terrain(aPos);
    auto maxlen = Parameter::JumpTerrianCoefficient[(int)t] * aPower;

    Vector2 dir(aTargetPos.x - aPos.x, aTargetPos.y - aPos.y);
    auto len = Math::Sqrt(dir.x * dir.x + dir.y * dir.y);
    if(len == 0.0f) {
        return aTargetPos;
    }
    if (len > maxlen) {
        dir = Vector2(dir.x * (maxlen / len), dir.y * (maxlen / len));
    }
    Vector2 nextPos(aPos.x + dir.x, aPos.y + dir.y);
    return nextPos;
}

//------------------------------------------------------------------------------
void Stage::initialize(int aScrollCount, const RandomSeed& aStageRandomSeed)
{
    Random random(aStageRandomSeed);
    mTurn = 0;

    auto startPosX = random.randMinTerm(1, Parameter::StageWidth - 1) + 0.5f;
    auto startPosY = random.randMinTerm(1, Parameter::StageHeight - 1) + 0.5f;
    Vector2 startPos(startPosX, startPosY);
    mRabbit.setPos(startPos);

    for (int h = 0; h < Parameter::StageHeight; h++) {
        for (int w = 0; w < Parameter::StageWidth; w++) {
            mMap[h][w] = Terrain::Plain;
        }
    }

    for (int i = 0; i < 40; i++) {
        auto t = (Terrain)random.randMinTerm(1, 4);
        auto w = random.randMinTerm(1, 16);
        auto h = random.randMinTerm(1, 16);
        auto x = random.randTerm(Parameter::StageWidth - (w - 1));
        auto y = random.randTerm(Parameter::StageHeight - (h - 1));
        for (int ii = y; ii < y + h; ii++) {
            for (int jj = x; jj < x + w; jj++) {
                mMap[ii][jj] = t;
            }
        }
    }

    // 初期位置は必ずPlain
    mMap[static_cast<int>(startPos.y)][static_cast<int>(startPos.x)] = Terrain::Plain;

    bool scrollMap[Parameter::StageHeight][Parameter::StageWidth] = {};
    // 初期位置には巻物は置かない
    scrollMap[static_cast<int>(startPos.y)][static_cast<int>(startPos.x)] = true;
    for (int i = 0; i < aScrollCount; i++) {
        for(; ;) {
            auto x = random.randMinTerm(0, Parameter::StageWidth);
            auto y = random.randMinTerm(0, Parameter::StageHeight);
            if (!scrollMap[y][x]) {
                mScrolls.add(Scroll(Vector2(x + 0.5f, y + 0.5f)));
                scrollMap[y][x] = true;
                break;
            }
        }
    }
}

//------------------------------------------------------------------------------
void Stage::update(const Vector2& aTargetPos)
{
    auto nextPos = getNextPos(mRabbit.pos(), mRabbit.power(), aTargetPos);
    mRabbit.setPos(nextPos);

    for (auto& scroll : mScrolls) {
        if (scroll.isGotten()) {
            continue;
        }
        
        if (static_cast<int>(scroll.pos().x) == static_cast<int>(nextPos.x) 
            && static_cast<int>(scroll.pos().y) == static_cast<int>(nextPos.y)) {
            scroll.setIsGotten(true);
            
            auto nextPower = mRabbit.power() * Parameter::JumpPowerUpRate;
            mRabbit.setPower(nextPower);
        }
    }
}

//------------------------------------------------------------------------------
void Stage::advanceTurn()
{
    ++mTurn;
}

//------------------------------------------------------------------------------
bool Stage::isEnd() const
{
    for (auto scroll : mScrolls) {
        if (!scroll.isGotten()) {
            return false;
        }
    }
    return true;
}

} // namespace
// EOF