152 lines
3.8 KiB
C++
152 lines
3.8 KiB
C++
#include <cstdio>
|
|
#include <iostream>
|
|
|
|
#include "board2d.hpp"
|
|
|
|
using namespace core;
|
|
|
|
Board2D::Board2D(const size_type w, const size_type h)
|
|
{
|
|
init(w, h);
|
|
}
|
|
|
|
void Board2D::add_unit(const Coord c)
|
|
{
|
|
std::cerr << "add_unit " << c.x << "," << c.y << std::endl;
|
|
auto& space = at(c);
|
|
if (!(space.capacity >= space.value)) throw InvalidMove {"Space is overloaded"};
|
|
|
|
space.value++;
|
|
}
|
|
|
|
void Board2D::capture(const Coord c, const Player p) noexcept
|
|
{
|
|
std::cerr << static_cast<int>(p) << " captures " << c.x << "," << c.y << std::endl;
|
|
at(c).owner = p;
|
|
}
|
|
|
|
void Board2D::init(const size_type w, const size_type h)
|
|
{
|
|
_width = w;
|
|
_height = h;
|
|
|
|
_spaces.reserve(w * h); // NOLINT
|
|
for (size_type y = 0; y < h; y++) {
|
|
for (size_type x = 0; x < w; x++) {
|
|
_spaces.push_back(Coord(x, y));
|
|
if (x == 0 || x == w - 1) {
|
|
if (y == 0 || y == h - 1) {
|
|
_spaces.back().capacity = 1;
|
|
}
|
|
else {
|
|
_spaces.back().capacity = 2;
|
|
}
|
|
}
|
|
else {
|
|
if (y == 0 || y == h - 1) {
|
|
_spaces.back().capacity = 2;
|
|
}
|
|
else {
|
|
_spaces.back().capacity = 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto Board2D::move(const Coord c, const Player p) -> Generator<Board2D>
|
|
{
|
|
const auto& space = at(c);
|
|
if (space.owner == Player::NONE) capture(c, p);
|
|
else if (space.owner != p) throw InvalidMove {"Player is not the Space owner"};
|
|
add_unit(c);
|
|
co_yield *this;
|
|
|
|
std::vector<Coord> overloaded;
|
|
if (is_overloaded(c)) {
|
|
overloaded.push_back(c);
|
|
do {
|
|
const auto src = overloaded.back();
|
|
const auto targets = neighbours(src);
|
|
overloaded.pop_back();
|
|
|
|
auto spreader = spread(src, targets, p);
|
|
while (spreader) co_yield spreader();
|
|
|
|
for (const auto t : targets) {
|
|
if (is_overloaded(t)) {
|
|
std::cerr << "overloaded: " << t.x << "," << t.y << std::endl;
|
|
overloaded.push_back(t);
|
|
};
|
|
}
|
|
} while (!overloaded.empty());
|
|
}
|
|
}
|
|
|
|
auto Board2D::neighbours(const Coord c) const noexcept -> std::vector<Coord>
|
|
{
|
|
std::vector<Coord> nghbrs;
|
|
|
|
if (c.x > 0) nghbrs.push_back({c.x - 1, c.y});
|
|
if (c.x < _width - 1) nghbrs.push_back({c.x + 1, c.y});
|
|
if (c.y > 0) nghbrs.push_back({c.x, c.y - 1});
|
|
if (c.y < _height - 1) nghbrs.push_back({c.x, c.y + 1});
|
|
|
|
return nghbrs;
|
|
}
|
|
|
|
auto Board2D::is_overloaded(Coord c) const noexcept -> bool
|
|
{
|
|
const auto& s = at(c);
|
|
return s.value > s.capacity;
|
|
}
|
|
|
|
auto Board2D::size() const noexcept -> std::array<size_type, 2>
|
|
{
|
|
return {_width, _height};
|
|
}
|
|
|
|
auto Board2D::spread(const Coord src, const std::vector<Coord>& targets, Player p)
|
|
-> Generator<Board2D>
|
|
{
|
|
auto& s = at(src);
|
|
std::cerr << "spread " << src.x << "," << src.y << " " << s.value << "/"
|
|
<< s.capacity << std::endl;
|
|
{
|
|
const auto count = targets.size();
|
|
if (s.value != static_cast<int>(count)) {
|
|
throw std::logic_error("cannot spread: unit count and target "
|
|
"spaces count differ");
|
|
}
|
|
}
|
|
|
|
s.reset();
|
|
co_yield *this;
|
|
|
|
for (const auto& c : targets) {
|
|
capture(c, p);
|
|
add_unit(c);
|
|
co_yield *this;
|
|
}
|
|
}
|
|
|
|
auto Board2D::operator()(const Coord c) const noexcept -> const Board2D::Space&
|
|
{
|
|
return _spaces.at(coord2idx(c));
|
|
}
|
|
|
|
auto Board2D::at(const Coord c) noexcept -> Space&
|
|
{
|
|
return _spaces.at(coord2idx(c));
|
|
}
|
|
|
|
auto Board2D::at(const Coord c) const noexcept -> const Space&
|
|
{
|
|
return _spaces.at(coord2idx(c));
|
|
}
|
|
|
|
auto Board2D::coord2idx(const Coord c) const noexcept -> size_type
|
|
{
|
|
return c.y * _width + c.x;
|
|
}
|