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