simplify
This commit is contained in:
parent
50d7ec0416
commit
7d9692efa4
78
2018/15.cpp
78
2018/15.cpp
|
@ -37,15 +37,24 @@ Coord const reading_order[] {{0,-1}, {-1,0}, {1,0}, {0,1}};
|
|||
|
||||
struct Game {
|
||||
Grid grid_;
|
||||
std::map<Coord, int> hp_;
|
||||
std::map<Coord, int> units_;
|
||||
int e_damage_;
|
||||
int g_damage_;
|
||||
bool no_elves_can_die;
|
||||
std::ostream * debug_out_;
|
||||
|
||||
Game(Grid grid)
|
||||
Game(Grid grid);
|
||||
|
||||
|
||||
auto Simulate() -> std::optional<int>;
|
||||
auto PickTarget(Coord my_coord, char my_team)
|
||||
-> std::map<Coord, int>::iterator;
|
||||
auto Move(Coord my_coord, char my_team) -> std::optional<Coord>;
|
||||
};
|
||||
|
||||
Game::Game(Grid grid)
|
||||
: grid_(std::move(grid))
|
||||
, hp_{}
|
||||
, units_{}
|
||||
, e_damage_(3)
|
||||
, g_damage_(3)
|
||||
, no_elves_can_die{false}
|
||||
|
@ -54,17 +63,12 @@ struct Game {
|
|||
// set each unit to its initial hit points
|
||||
grid_.each([&](auto k, auto v) {
|
||||
if (IsUnit(v)) {
|
||||
hp_[k] = initial_hp;
|
||||
units_[k] = initial_hp;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto Simulate() -> std::optional<int>;
|
||||
auto PickTarget(Coord my_coord, char my_team)
|
||||
-> std::optional<std::map<Coord, int>::iterator>;
|
||||
auto Move(Coord my_coord, char my_team) -> std::optional<Coord>;
|
||||
};
|
||||
|
||||
// Render the game as seen in the examples
|
||||
auto operator<<(std::ostream & out, Game const& game) -> std::ostream & {
|
||||
for (std::size_t y = 0; y < game.grid_.rows.size(); ++y) {
|
||||
out << game.grid_.rows[y];
|
||||
|
@ -78,8 +82,8 @@ auto operator<<(std::ostream & out, Game const& game) -> std::ostream & {
|
|||
} else {
|
||||
out << ", ";
|
||||
}
|
||||
Coord coord {std::int64_t(x),std::int64_t(y)};
|
||||
out << c << "(" << game.hp_.at(coord) << ")";
|
||||
Coord const coord {std::int64_t(x),std::int64_t(y)};
|
||||
out << c << "(" << game.units_.at(coord) << ")";
|
||||
}
|
||||
}
|
||||
out << std::endl;
|
||||
|
@ -88,18 +92,15 @@ auto operator<<(std::ostream & out, Game const& game) -> std::ostream & {
|
|||
}
|
||||
|
||||
// Determine the best target to attack from the current position, if there is one.
|
||||
auto Game::PickTarget(Coord my_coord, char my_team)
|
||||
-> std::optional<std::map<Coord, int>::iterator>
|
||||
auto Game::PickTarget(Coord my_coord, char my_team) -> std::map<Coord, int>::iterator
|
||||
{
|
||||
std::optional<std::map<Coord, int>::iterator> best;
|
||||
int best_hp;
|
||||
std::map<Coord, int>::iterator best = units_.end();
|
||||
for (auto const dir : reading_order) {
|
||||
auto here = dir + my_coord;
|
||||
auto const here = dir + my_coord;
|
||||
if (IsOpposed(my_team, grid_[here])) {
|
||||
auto it = hp_.find(here);
|
||||
if (!best || best_hp > it->second) {
|
||||
auto it = units_.find(here);
|
||||
if (best == units_.end() || best->second > it->second) {
|
||||
best = it;
|
||||
best_hp = it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,22 +110,21 @@ auto Game::PickTarget(Coord my_coord, char my_team)
|
|||
// Determine the best location to move to, if there is one.
|
||||
auto Game::Move(Coord my_coord, char my_team) -> std::optional<Coord>
|
||||
{
|
||||
int best_distance;
|
||||
std::optional<Coord> best_start;
|
||||
Coord best_end;
|
||||
Coord best_end; // initialized when best_start is non-empty
|
||||
int best_distance; // initialized when best_start is non-empty
|
||||
|
||||
std::set<Coord> seen;
|
||||
std::deque<std::tuple<Coord, Coord, int>> todo;
|
||||
|
||||
for (auto const dir : reading_order) {
|
||||
auto start = my_coord + dir;
|
||||
auto const start = my_coord + dir;
|
||||
if (grid_[start] == '.') {
|
||||
todo.push_back({start,start,1});
|
||||
todo.push_back({start, start, 1});
|
||||
}
|
||||
}
|
||||
|
||||
std::set<Coord> seen;
|
||||
while (!todo.empty()) {
|
||||
auto [start, cursor, steps] = todo.front();
|
||||
auto const [start, cursor, steps] = todo.front();
|
||||
todo.pop_front();
|
||||
|
||||
if (best_start) {
|
||||
|
@ -139,7 +139,7 @@ auto Game::Move(Coord my_coord, char my_team) -> std::optional<Coord>
|
|||
}
|
||||
}
|
||||
}
|
||||
if (PickTarget(cursor, my_team)) {
|
||||
if (PickTarget(cursor, my_team) != units_.end()) {
|
||||
best_start = start;
|
||||
best_end = cursor;
|
||||
best_distance = steps;
|
||||
|
@ -158,21 +158,21 @@ auto Game::Simulate() -> std::optional<int> {
|
|||
|
||||
// determine order of unit updates
|
||||
std::set<Coord, IsBefore> turn_order;
|
||||
for (auto const& [k,_] : hp_) {
|
||||
for (auto const& [k,_] : units_) {
|
||||
turn_order.insert(k);
|
||||
}
|
||||
|
||||
for (auto active_coord : turn_order) {
|
||||
char active_team = grid_[active_coord];
|
||||
auto const active_team = grid_[active_coord];
|
||||
|
||||
// Detect when no targets remain for this unit and end the game
|
||||
bool game_over = true;
|
||||
auto game_over = true;
|
||||
grid_.each([&](auto k, auto v) {
|
||||
if (IsOpposed(active_team, v)) game_over = false;
|
||||
});
|
||||
if (game_over) {
|
||||
int total_hp = 0;
|
||||
for (auto const& [_,v] : hp_) { total_hp += v; }
|
||||
for (auto const& [_,v] : units_) { total_hp += v; }
|
||||
return {rounds * total_hp};
|
||||
}
|
||||
|
||||
|
@ -180,14 +180,14 @@ auto Game::Simulate() -> std::optional<int> {
|
|||
auto target = PickTarget(active_coord, active_team);
|
||||
|
||||
// only move when necessary
|
||||
if (!target) {
|
||||
if (target == units_.end()) {
|
||||
// move if we can
|
||||
if (auto const destination = Move(active_coord, active_team)) {
|
||||
std::swap(grid_[*destination], grid_[active_coord]);
|
||||
|
||||
auto const it = hp_.find(active_coord);
|
||||
hp_[*destination] = it->second;
|
||||
hp_.erase(it);
|
||||
auto const it = units_.find(active_coord);
|
||||
units_[*destination] = it->second;
|
||||
units_.erase(it);
|
||||
|
||||
active_coord = *destination;
|
||||
}
|
||||
|
@ -196,8 +196,8 @@ auto Game::Simulate() -> std::optional<int> {
|
|||
}
|
||||
|
||||
// target in range, do the attack
|
||||
if (target) {
|
||||
auto & [target_coord, target_hp] = **target;
|
||||
if (target != units_.end()) {
|
||||
auto & [target_coord, target_hp] = *target;
|
||||
auto damage = active_team == 'G' ? g_damage_ : e_damage_;
|
||||
|
||||
// lethal
|
||||
|
@ -206,7 +206,7 @@ auto Game::Simulate() -> std::optional<int> {
|
|||
|
||||
grid_[target_coord] = '.';
|
||||
turn_order.erase(target_coord);
|
||||
hp_.erase(*target); // invalidates target, target_coord, target_hp
|
||||
units_.erase(target); // invalidates target, target_coord, target_hp
|
||||
} else {
|
||||
target_hp -= damage;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user