Game.cpp
//------------------------------------------------------------------------------
/// @file
/// @author ハル研究所プログラミングコンテスト実行委員会
///
/// @copyright Copyright (c) 2018 HAL Laboratory, Inc.
/// @attention このファイルの利用は、同梱のREADMEにある
/// 利用条件に従ってください。
//------------------------------------------------------------------------------
#pragma once
#include "Game.hpp"
//------------------------------------------------------------------------------
#include "Assert.hpp"
#include "Stage.hpp"
//------------------------------------------------------------------------------
namespace hpc {
//------------------------------------------------------------------------------
Game::Game()
: mIsRandomSeedSet(false)
, mGivenRandomSeed(RandomSeed::DefaultSeed())
, mRecorder()
, mTimer()
{
}
//------------------------------------------------------------------------------
void Game::changeSeed(RandomSeed aSeed)
{
mIsRandomSeedSet = true;
mGivenRandomSeed = aSeed;
}
//------------------------------------------------------------------------------
void Game::run(Answer* aAnswer)
{
HPC_ASSERT(aAnswer != nullptr);
// 乱数関連の定数定義。
// ここの randomSeed および randomSpin は
// サーバーの評価環境と配布パッケージとで異なります。
const uint randomSeedX = 0x1c8bebfc;
const uint randomSeedY = 0xdf7b3c3c;
const uint randomSeedZ = 0x16bf5f2d;
const uint randomSeedW = 0x5aee504a;
const int randomSpinX = 0xFFF;
const int randomSpinY = 0xFF;
const int randomSpinZ = 0xF;
Random gameRandom =
Random(
mIsRandomSeedSet ?
mGivenRandomSeed :
RandomSeed(
randomSeedX,
randomSeedY,
randomSeedZ,
randomSeedW
)
);
// ゲーム開始
mTimer.start();
gameRandom.spin(randomSpinX);
for (int i = 0; i < Parameter::GameStageCount; ++i) {
// ステージ開始
gameRandom.spin(randomSpinY);
// 生地置き場専用の乱数。
// 出現生地が生地置き場の使用順序に依存しないようにするために、
// 各生地置き場は自前の乱数を持っている。
// また、 Random はデフォルトコンストラクタを持たないので、
// std::array で初期化するタイプの Array コンストラクタで
// CandidateLaneRandoms を構築している。
// 初期化子リストは先頭から評価されることが保証されているので、
// generateRandomSeed をその場で使っている。
CandidateLaneRandoms laneRandom(
CandidateLaneRandoms::ArrayType(
{{
Random(gameRandom.generateRandomSeed()),
Random(gameRandom.generateRandomSeed())
}}
)
);
// ステージ生成
Stage stage;
{
auto randomSeed = gameRandom.generateRandomSeed();
stage.init(randomSeed, &laneRandom);
}
aAnswer->init(stage);
mRecorder.afterInitStage(stage);
while (!stage.isEnd() && stage.turn() < Parameter::GameTurnLimit) {
// ターン開始
for (auto& random : laneRandom) {
random.spin(randomSpinZ);
}
// まずは開始フェーズ
stage.processStartPhase();
// その後プレイヤーからの干渉を処理
Action action;
action = aAnswer->decideNextAction(stage);
stage.processPlayerPhase(action);
// 最後に終了フェーズを処理
stage.processEndPhase(&laneRandom);
// これで 1 ターン終了
stage.advanceTurn();
mRecorder.afterAdvanceTurn(stage);
}
mRecorder.afterFinishStage();
aAnswer->finalize(stage);
}
mRecorder.afterFinishAllStages();
mTimer.stop();
}
//------------------------------------------------------------------------------
const Recorder& Game::recorder() const
{
return mRecorder;
}
//------------------------------------------------------------------------------
const Timer& Game::timer() const
{
return mTimer;
}
} // namespace
// EOF