Recorder.cpp
//------------------------------------------------------------------------------
/// @file
/// @author ハル研究所プログラミングコンテスト実行委員会
///
/// @copyright Copyright (c) 2018 HAL Laboratory, Inc.
/// @attention このファイルの利用は、同梱のREADMEにある
/// 利用条件に従ってください。
//------------------------------------------------------------------------------
#pragma once
#include "Recorder.hpp"
//------------------------------------------------------------------------------
#include "ArrayNum.hpp"
#include "Print.hpp"
//------------------------------------------------------------------------------
namespace hpc {
//------------------------------------------------------------------------------
Recorder::Recorder()
: mGameRecord()
, mCurrentStageNumber()
, mCurrentTurn()
, mCurrentScore()
{
}
//------------------------------------------------------------------------------
void Recorder::dumpJson() const
{
// Json の先頭
HPC_PRINTF("["); {
// 合計ターン数、スコア
HPC_PRINTF("%d,", mGameRecord.totalTurn);
HPC_PRINTF("%d,", mGameRecord.totalScore);
// 定数
HPC_PRINTF("["); {
HPC_PRINTF("%d", Parameter::GameTurnLimit);
} HPC_PRINTF("],");
// ステージログ
HPC_PRINTF("["); {
for (int i = 0; i < Parameter::GameStageCount; ++i) {
if(i != 0) {
HPC_PRINTF(",");
}
dumpJsonStage(mGameRecord.stageRecords[i]);
}
} HPC_PRINTF("]");
} HPC_PRINTF("]");
HPC_PRINTF("\n");
}
//------------------------------------------------------------------------------
void Recorder::dumpResult(bool aIsSilent) const
{
if (!aIsSilent) {
HPC_PRINTF("stage | score\n");
for (int i = 0; i < Parameter::GameStageCount; ++i) {
HPC_PRINTF("% 5d | % 4d\n", i, mGameRecord.stageRecords[i].score);
}
}
HPC_PRINTF("TotalScore: %d\n", mGameRecord.totalScore);
}
//------------------------------------------------------------------------------
void Recorder::afterInitStage(const Stage& aStage)
{
StageRecord& stageRecord = mGameRecord.stageRecords[mCurrentStageNumber];
mCurrentTurn = 0;
mCurrentScore = 0;
stageRecord.score = 0;
stageRecord.turnRecordCount = 0;
stageRecord.ovenRecipeRecord.width = aStage.oven().width();
stageRecord.ovenRecipeRecord.height = aStage.oven().height();
writeTurnRecord(mCurrentStageNumber, 0, aStage);
}
//------------------------------------------------------------------------------
void Recorder::afterAdvanceTurn(const Stage& aStage)
{
++mCurrentTurn;
writeTurnRecord(mCurrentStageNumber, mCurrentTurn, aStage);
}
//------------------------------------------------------------------------------
void Recorder::afterFinishStage()
{
StageRecord& stageRecord = mGameRecord.stageRecords[mCurrentStageNumber];
// + 1 しているのは
// レコードにはステージの初期状態が「0ターン目」として入っているから。
stageRecord.turnRecordCount = mCurrentTurn + 1;
stageRecord.score = mCurrentScore;
mGameRecord.totalTurn += mCurrentTurn;
mGameRecord.totalScore += mCurrentScore;
++mCurrentStageNumber;
}
//------------------------------------------------------------------------------
void Recorder::afterFinishAllStages()
{
int total = 0;
for (int i = 0; i < Parameter::GameStageCount; ++i) {
total += mGameRecord.stageRecords[i].score;
}
HPC_ASSERT(total == mGameRecord.totalScore);
}
//------------------------------------------------------------------------------
int Recorder::totalTurn() const
{
return mGameRecord.totalTurn;
}
//------------------------------------------------------------------------------
int Recorder::totalScore() const
{
return mGameRecord.totalScore;
}
//------------------------------------------------------------------------------
Recorder::PieceRecord& Recorder::PieceRecord::setup(const Oven* aOven, const Piece& aPiece)
{
if (aOven == nullptr) {
fieldType = FieldType_Candidate;
} else {
fieldType = FieldType_Oven;
}
posX = static_cast<char>(aPiece.pos().x);
posY = static_cast<char>(aPiece.pos().y);
width = static_cast<char>(aPiece.width());
height = static_cast<char>(aPiece.height());
currentHeatTurnCount = static_cast<short>(aPiece.currentHeatTurnCount());
requiredHeatTurnCount = static_cast<short>(aPiece.requiredHeatTurnCount());
score = static_cast<short>(aPiece.score());
return *this;
}
//------------------------------------------------------------------------------
void Recorder::PieceRecord::dumpJson() const
{
HPC_PRINTF("["); {
// 置いた位置
HPC_PRINTF("["); {
HPC_PRINTF("%d,%d", int(posX), int(posY));
} HPC_PRINTF("],");
// 縦横
HPC_PRINTF("%d,", int(width));
HPC_PRINTF("%d,", int(height));
// 加熱ターン数関係
HPC_PRINTF("%d,", int(currentHeatTurnCount));
HPC_PRINTF("%d,", int(requiredHeatTurnCount));
// 焼き上がりで発生するスコア
HPC_PRINTF("%d", int(score));
} HPC_PRINTF("]");
}
//------------------------------------------------------------------------------
Recorder::PieceRecord& Recorder::OvenRecord::bakingPieces(int aIndex)
{
if (0 <= aIndex && aIndex < bakingPieceCount) {
return prvBakingPieces[aIndex];
}
HPC_ASSERT_NOT_REACHED_MSG(
"0 <= index:%d < bakingPieceCount:%d, failed",
aIndex,
bakingPieceCount
);
return prvBakingPieces[0];
}
//------------------------------------------------------------------------------
const Recorder::PieceRecord& Recorder::OvenRecord::bakingPieces(int aIndex) const
{
if (0 <= aIndex && aIndex < bakingPieceCount) {
return prvBakingPieces[aIndex];
}
HPC_ASSERT_NOT_REACHED_MSG(
"0 <= index:%d < bakingPieceCount:%d, failed",
aIndex,
bakingPieceCount
);
return prvBakingPieces[0];
}
//------------------------------------------------------------------------------
Recorder::PieceRecord& Recorder::OvenRecord::bakedPieces(int aIndex)
{
if (0 <= aIndex && aIndex < bakedPieceCount) {
return prvBakedPieces[aIndex];
}
HPC_ASSERT_NOT_REACHED_MSG(
"0 <= index:%d < bakedPieceCount:%d, failed",
aIndex,
bakedPieceCount
);
return prvBakedPieces[0];
}
//------------------------------------------------------------------------------
const Recorder::PieceRecord& Recorder::OvenRecord::bakedPieces(int aIndex) const
{
if (0 <= aIndex && aIndex < bakedPieceCount) {
return prvBakedPieces[aIndex];
}
HPC_ASSERT_NOT_REACHED_MSG(
"0 <= index:%d < bakedPieceCount:%d, failed",
aIndex,
bakedPieceCount
);
return prvBakedPieces[0];
}
//------------------------------------------------------------------------------
int Recorder::StageRecord::turn() const
{
// - 1 しているのは
// レコードにはステージの初期状態が「0ターン目」として入っているから。
return turnRecordCount - 1;
}
//------------------------------------------------------------------------------
void Recorder::dumpJsonStage(const StageRecord& aRecord) const
{
HPC_PRINTF("["); {
// ターン数、スコア
HPC_PRINTF("%d,", aRecord.turn());
HPC_PRINTF("%d,", aRecord.score);
// ステージ情報
HPC_PRINTF("["); {
// オーブン全体情報
HPC_PRINTF("["); {
// オーブン個体情報
HPC_PRINTF("["); {
HPC_PRINTF("%d,", int(aRecord.ovenRecipeRecord.width));
HPC_PRINTF("%d,", int(aRecord.ovenRecipeRecord.height));
HPC_PRINTF("%d", 1); ///< オーブンの加熱速度(1で固定)
} HPC_PRINTF("]");
} HPC_PRINTF("]");
} HPC_PRINTF("],");
// ターンのログ
HPC_PRINTF("["); {
for (int i = 0; i < aRecord.turnRecordCount; ++i) {
if (i != 0) {
HPC_PRINTF(",");
}
dumpJsonTurn(aRecord.turnRecords[i]);
}
} HPC_PRINTF("]");
} HPC_PRINTF("]");
}
//------------------------------------------------------------------------------
void Recorder::dumpJsonTurn(const TurnRecord& aRecord) const
{
HPC_PRINTF("["); {
// このターンで生じたスコア
HPC_PRINTF("%d,", aRecord.turnScore);
// このターン終了時のスコア
HPC_PRINTF("%d,", aRecord.turnEndScore);
// 生地置き場
HPC_PRINTF("["); {
for (int laneType = 0; laneType < CandidateLaneType_TERM; ++laneType) {
if (laneType != 0) {
HPC_PRINTF(",");
}
HPC_PRINTF("["); {
for (int i = 0; i < aRecord.candidatePieceCount[laneType]; ++i) {
if (i != 0) {
HPC_PRINTF(",");
}
// 生地
aRecord.candidateLane[laneType][i].dumpJson();
}
} HPC_PRINTF("]");
}
} HPC_PRINTF("],");
// オーブン
HPC_PRINTF("["); {
HPC_PRINTF("["); {
const auto& ovenRecord = aRecord.ovenRecord;
// このオーブンがこのターン終了時に獲得したスコア
HPC_PRINTF("%d,", ovenRecord.turnScore);
// 焼いている生地
HPC_PRINTF("["); {
for (
int pieceIndex = 0;
pieceIndex < ovenRecord.bakingPieceCount;
++pieceIndex)
{
if (pieceIndex != 0) {
HPC_PRINTF(",");
}
ovenRecord.bakingPieces(pieceIndex).dumpJson();
}
} HPC_PRINTF("],");
// このターン終了時に焼き上がった生地
HPC_PRINTF("["); {
for (
int pieceIndex = 0;
pieceIndex < ovenRecord.bakedPieceCount;
++pieceIndex)
{
if (pieceIndex != 0) {
HPC_PRINTF(",");
}
ovenRecord.bakedPieces(pieceIndex).dumpJson();
}
} HPC_PRINTF("]");
} HPC_PRINTF("]");
} HPC_PRINTF("]");
} HPC_PRINTF("]");
}
//------------------------------------------------------------------------------
void Recorder::writeTurnRecord(int aStageNumber, int aTurn, const Stage& aStage)
{
TurnRecord& turnRecord =
mGameRecord.stageRecords[aStageNumber].turnRecords[aTurn];
// 初期化
for (int laneType = 0; laneType < CandidateLaneType_TERM; ++laneType) {
turnRecord.candidatePieceCount[laneType] = 0;
}
turnRecord.turnScore = 0;
// 生地置き場
for (int laneType = 0; laneType < CandidateLaneType_TERM; ++laneType) {
const auto& lane = aStage.candidateLane(static_cast<CandidateLaneType>(laneType));
turnRecord.candidatePieceCount[laneType] = lane.pieces().count();
for (
int pieceIndex = 0;
pieceIndex < turnRecord.candidatePieceCount[laneType];
++pieceIndex
)
{
const Piece& piece = lane.pieces()[pieceIndex];
turnRecord.candidateLane[laneType][pieceIndex].setup(nullptr, piece);
}
}
// オーブン
{
const Oven& oven = aStage.oven();
OvenRecord& ovenRecord = turnRecord.ovenRecord;
{
// 焼いているもの
const int pieceCount = oven.bakingPieces().count();
ovenRecord.bakingPieceCount = pieceCount;
for (int pieceIndex = 0; pieceIndex < pieceCount; ++pieceIndex) {
const Piece& piece = oven.bakingPieces()[pieceIndex];
ovenRecord.bakingPieces(pieceIndex).setup(&oven, piece);
}
}
{
// このターン焼けたもの
const int pieceCount = oven.lastBakedPieces().count();
ovenRecord.bakedPieceCount = pieceCount;
ovenRecord.turnScore = 0;
for (int pieceIndex = 0; pieceIndex < pieceCount; ++pieceIndex) {
const Piece& piece = oven.lastBakedPieces()[pieceIndex];
auto score = ovenRecord.bakedPieces(pieceIndex).setup(&oven, piece).score;
turnRecord.turnScore += score;
ovenRecord.turnScore += score;
}
}
}
// スコア更新
mCurrentScore += turnRecord.turnScore;
turnRecord.turnEndScore = mCurrentScore;
}
} // namespace
// EOF