Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
ハル研プロコン
#include "HPCAnswerInclude.hpp"
namespace {
using namespace hpc;
}
namespace hpc {
void Answer::Init(const StageAccessor& aStageAccessor) {}
// 自分史上最小のINF
const int INF = 20;
// このまま加速しなかった場合、目標の蓮に到達するのは何ターン後かを返す
// 加速無しで到達できない場合はINFを返す
int cross(Vec2 vec, Vec2 vel, const Vec2& flow, const Lotus& lotus) {
for (int i = 1; i < INF; ++i) {
vec -= vel + flow;
if (vec.length() < Parameter::CharaRadius() + lotus.radius()) return i;
if (vel.length() <= Parameter::CharaDecelSpeed()) return INF;
vel.normalize(vel.length() - Parameter::CharaDecelSpeed());
}
return INF;
}
// 謎の便利関数
// TODO ちゃんとした説明を書く
float len(int n) {
return Parameter::CharaAccelSpeed() - Parameter::CharaDecelSpeed() * (Parameter::CharaAddAccelWaitTurn + n);
}
Action Answer::GetNextAction(const StageAccessor& aStageAccessor) {
const Chara& player = aStageAccessor.player();
const LotusCollection& lotuses = aStageAccessor.lotuses();
const Lotus& lotus = lotuses[player.targetLotusNo()];
const Lotus& nextL = lotuses[(player.targetLotusNo() + 1) % lotuses.count()];
const Field& field = aStageAccessor.field();
const EnemyAccessor& enemies = aStageAccessor.enemies();
// 加速できない
if (player.accelCount() == 0) return Action::Wait();
Vec2 vel = player.vel() + field.flowVel();
Vec2 vec = lotus.pos() - player.pos();
// 最後の1手
if (player.roundCount() == Parameter::StageRoundCount - 1 && player.targetLotusNo() == lotuses.count() - 1) {
if (vec.length() - Parameter::CharaRadius() - lotus.radius() < Parameter::CharaAccelSpeed() * player.accelCount() * 10) {
return Action::Accel(lotus.pos());
}
}
// 加速なしで目標の蓮に届く
// TODO 待ち過ぎ?
if (cross(vec, player.vel(), field.flowVel(), lotus) < INF) return Action::Wait();
// 速度が落ちてたら残り加速回数を見て適宜加速する
// TODO たぶん流れを考慮するべき
if (player.accelCount() >= 9) {
if (vec.length() - (vec - vel).length() >= len(-1)) return Action::Wait();
} else if (player.accelCount() >= 3) {
if (vec.length() - (vec - vel).length() >= len(0)) return Action::Wait();
} else if (player.accelCount() >= 2) {
if (vec.length() - (vec - vel).length() >= len(2)) return Action::Wait();
} else {
// 加速回数が残り1の場合は近づいている限り加速しない
if (vec.length() - (vec - vel).length() >= 0) return Action::Wait();
}
// 次の次の蓮の方向を考慮
Vec2 nextLotus = nextL.pos() - lotus.pos();
nextLotus.normalize(lotus.radius());
Vec2 next = vec + nextLotus;
next.normalize(Parameter::CharaAccelSpeed());
// 流れを考慮
// 2はマジックナンバーだが、ごにょごにょすると近い値が出ると信じている。
// TODO 要検証
// TODO 全体的に流れの扱いが雑すぎるので余裕があれば何とかする
next -= 2 * field.flowVel();
next.normalize(Parameter::CharaAccelSpeed());
Vec2 next2 = vec + nextLotus - vel;
next2.normalize(Parameter::CharaAccelSpeed());
next2 -= 2 * field.flowVel();
next2.normalize(Parameter::CharaAccelSpeed());
int c1 = cross(vec, next, field.flowVel(), lotus);
int c2 = cross(vec - vel, next2, field.flowVel(), lotus);
// 加速しなくても目標の蓮に同じターン数以下で到達できるなら加速しない
if (c1 != INF && c1 > c2) return Action::Wait();
// 加速したら次のターンで先輩忍者にぶつかる場合は加速回数が余っていない限り加速しない
// TODO 2ターン以上先も考慮
// TODO 先輩忍者の加速を考慮
if (player.accelCount() <= 5) {
for (int i = 0; i < enemies.count(); ++i) {
Chara enemy = enemies[i];
Vec2 eNext = enemy.pos() + enemy.vel();
if ((player.pos() + next - eNext).length() < 2 * Parameter::CharaRadius()) return Action::Wait();
}
}
return Action::Accel(next + player.pos());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment