implement the added methods
This commit is contained in:
parent
abae7d6f8e
commit
936aa71b85
@ -97,7 +97,7 @@
|
|||||||
|
|
||||||
当一个玩家掉线后一段时间,适配器认为该玩家无重连的可能性后,会向处理器发送掉线通知。处理器收到掉线通知后,
|
当一个玩家掉线后一段时间,适配器认为该玩家无重连的可能性后,会向处理器发送掉线通知。处理器收到掉线通知后,
|
||||||
|
|
||||||
- 若该玩家是其队伍中唯一一个还未输掉游戏的玩家,则其全部单位变为中立单位。
|
- 若该玩家是其队伍中唯一一个还未输掉游戏的玩家,则其全部单位变为中立单位,并把他的首都变为一个要塞。
|
||||||
- 否则,寻找首都距离该玩家首都最近的同一队伍的玩家,并将该玩家所全部占领的格子所变为该队友所占领,并把他的首都变为一个要塞。这里的距离是指在不经过任何山区和要塞的前提下将单位从一个格子移动到另一个格子的最小步数。
|
- 否则,寻找首都距离该玩家首都最近的同一队伍的玩家,并将该玩家所全部占领的格子所变为该队友所占领,并把他的首都变为一个要塞。这里的距离是指在不经过任何山区和要塞的前提下将单位从一个格子移动到另一个格子的最小步数。
|
||||||
|
|
||||||
### 每半回合处理次序
|
### 每半回合处理次序
|
||||||
|
@ -1,13 +1,23 @@
|
|||||||
#include "GameBoard.h"
|
#include "GameBoard.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
GameBoard::GameBoard(pos_t w, pos_t h, const InitInfo& info)
|
GameBoard::GameBoard(pos_t w, pos_t h, const InitInfo& info)
|
||||||
: n(info.n), t(0), players(info.n + 1), w(w), h(h), board(w * h) {
|
: n(info.n)
|
||||||
|
, t(0)
|
||||||
|
, players(info.n + 1)
|
||||||
|
, w(w)
|
||||||
|
, h(h)
|
||||||
|
, view_radius(1)
|
||||||
|
, board(w * h)
|
||||||
|
, halfturn_id(0) {
|
||||||
for (std::uint8_t i = 1; i <= n; ++i) {
|
for (std::uint8_t i = 1; i <= n; ++i) {
|
||||||
players[i].id = i;
|
players[i].id = i;
|
||||||
players[i].team = info.player_team[i];
|
players[i].team = info.player_team[i];
|
||||||
t = std::max(t, players[i].team);
|
t = std::max(t, players[i].team);
|
||||||
}
|
}
|
||||||
|
diff_tiles.resize(t + 1);
|
||||||
|
cover.resize(t + 1, std::vector(h, std::vector<std::uint8_t>(w)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Tile& GameBoard::at(pos_t x, pos_t y) {
|
Tile& GameBoard::at(pos_t x, pos_t y) {
|
||||||
@ -18,6 +28,35 @@ const Tile& GameBoard::at(pos_t x, pos_t y) const {
|
|||||||
return board[x * w + y];
|
return board[x * w + y];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameBoard::setOwner(pos_t x, pos_t y, Player p) {
|
||||||
|
auto flip = [&](int team, Point pos) {
|
||||||
|
if (!team)
|
||||||
|
return;
|
||||||
|
auto pr = diff_tiles[team].insert(pos);
|
||||||
|
if (!pr.second)
|
||||||
|
diff_tiles[team].erase(pr.first);
|
||||||
|
};
|
||||||
|
auto t1 = players[at(x, y).owner].team, t2 = players[p].team;
|
||||||
|
if (t1 != t2) {
|
||||||
|
pos_t sx = x - std::min(x, view_radius),
|
||||||
|
tx = x + std::min<pos_t>(h - x, view_radius),
|
||||||
|
sy = y - std::min(y, view_radius),
|
||||||
|
ty = y + std::min<pos_t>(w - y, view_radius);
|
||||||
|
for (pos_t xx = sx; xx <= tx; xx++) {
|
||||||
|
for (pos_t yy = sy; yy <= ty; yy++) {
|
||||||
|
cover[t1][xx][yy]--;
|
||||||
|
if (!cover[t1][xx][yy])
|
||||||
|
flip(t1, Point(xx, yy));
|
||||||
|
if (!cover[t2][xx][yy])
|
||||||
|
flip(t2, Point(xx, yy));
|
||||||
|
cover[t2][xx][yy]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
at(x, y).owner = p;
|
||||||
|
updatedPosition(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
bool GameBoard::attack(const PlayerMove& o) {
|
bool GameBoard::attack(const PlayerMove& o) {
|
||||||
if (!o.isValid(w, h))
|
if (!o.isValid(w, h))
|
||||||
return false;
|
return false;
|
||||||
@ -30,6 +69,9 @@ bool GameBoard::attack(const PlayerMove& o) {
|
|||||||
if (sc_tile.unit <= 1)
|
if (sc_tile.unit <= 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (tt_tile.type == TileType::Mountain)
|
||||||
|
return false;
|
||||||
|
|
||||||
auto moving_unit = o.half ? sc_tile.unit - 1 : sc_tile.unit / 2;
|
auto moving_unit = o.half ? sc_tile.unit - 1 : sc_tile.unit / 2;
|
||||||
sc_tile.unit -= moving_unit;
|
sc_tile.unit -= moving_unit;
|
||||||
auto isfriend = isTeammate(o.player, tt_tile.owner);
|
auto isfriend = isTeammate(o.player, tt_tile.owner);
|
||||||
@ -43,7 +85,7 @@ bool GameBoard::attack(const PlayerMove& o) {
|
|||||||
if (delta > 0 && (!isfriend || tt_tile.type != TileType::Capital)) {
|
if (delta > 0 && (!isfriend || tt_tile.type != TileType::Capital)) {
|
||||||
if (!isfriend && tt_tile.type == TileType::Capital)
|
if (!isfriend && tt_tile.type == TileType::Capital)
|
||||||
capitalCaptured(tt_tile.owner, o.player);
|
capitalCaptured(tt_tile.owner, o.player);
|
||||||
tt_tile.owner = o.player;
|
setOwner(o.tx(), o.ty(), o.player);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -52,12 +94,17 @@ void GameBoard::capitalCaptured(Player tt, Player sc) {
|
|||||||
for (pos_t x = 0; x < h; ++x) {
|
for (pos_t x = 0; x < h; ++x) {
|
||||||
for (pos_t y = 0; y < w; ++y) {
|
for (pos_t y = 0; y < w; ++y) {
|
||||||
auto& tile = at(x, y);
|
auto& tile = at(x, y);
|
||||||
if (tile.owner != tt || tile.type == TileType::Capital)
|
if (tile.owner != tt)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tile.owner = sc;
|
|
||||||
tile.unit = std::max(tile.unit / 2, 1);
|
|
||||||
updatedPosition(x, y);
|
updatedPosition(x, y);
|
||||||
|
if (tile.type == TileType::Capital) {
|
||||||
|
tile.type = TileType::Stronghold;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOwner(x, y, sc);
|
||||||
|
tile.unit = std::max(tile.unit / 2, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new_defeated_players.push_back(tt);
|
new_defeated_players.push_back(tt);
|
||||||
@ -80,10 +127,10 @@ void GameBoard::turnUpdate() {
|
|||||||
tile.unit += 1;
|
tile.unit += 1;
|
||||||
|
|
||||||
if (tile.type == TileType::Swamp) {
|
if (tile.type == TileType::Swamp) {
|
||||||
if (tile.unit > 0)
|
if (tile.unit > 0)
|
||||||
tile.unit -= 1;
|
tile.unit -= 1;
|
||||||
if (tile.unit == 0)
|
if (tile.unit == 0)
|
||||||
tile.owner = neutral_player;
|
setOwner(x, y, neutral_player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,6 +167,72 @@ std::uint8_t GameBoard::numTeams() const {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameBoard::appendOrderQueue(const PlayerMove& p) {
|
||||||
|
if (!players[p.player].is_defeated)
|
||||||
|
players[p.player].orders.emplace_back(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameBoard::clearOrderQueue(Player p) {
|
||||||
|
players[p].orders.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameBoard::popOrderQueue(Player p) {
|
||||||
|
players[p].orders.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameBoard::setOffline(Player p) {
|
||||||
|
new_offline_players.push_back(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameBoard::offline(Player p) {
|
||||||
|
if (players[p].is_defeated)
|
||||||
|
return;
|
||||||
|
std::vector<std::vector<std::uint8_t>> vis(h, std::vector<std::uint8_t>(w));
|
||||||
|
std::queue<Point> q;
|
||||||
|
for (pos_t i = 0; i < h; i++) {
|
||||||
|
for (pos_t j = 0; j < w; j++) {
|
||||||
|
if (at(i, j).type == TileType::Capital && at(i, j).owner == p) {
|
||||||
|
vis[i][j] = 1;
|
||||||
|
q.emplace(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Player v = neutral_player;
|
||||||
|
while (!q.empty()) {
|
||||||
|
pos_t x = q.front().x, y = q.front().y;
|
||||||
|
q.pop();
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
pos_t xx = x + direction_dx[i], yy = y + direction_dy[i];
|
||||||
|
Tile& tile = at(xx, yy);
|
||||||
|
if (xx >= h || yy >= w || tile.type == TileType::Mountain
|
||||||
|
|| tile.type != TileType::Stronghold || vis[xx][yy])
|
||||||
|
continue;
|
||||||
|
if (tile.type == TileType::Capital) {
|
||||||
|
if (players[tile.owner].team != players[p].team)
|
||||||
|
continue;
|
||||||
|
v = tile.owner;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vis[xx][yy] = 1;
|
||||||
|
q.emplace(xx, yy);
|
||||||
|
}
|
||||||
|
if (v != neutral_player)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (pos_t i = 0; i < h; i++) {
|
||||||
|
for (pos_t j = 0; j < w; j++) {
|
||||||
|
Tile& tile = at(i, j);
|
||||||
|
if (tile.owner == p) {
|
||||||
|
setOwner(i, j, v);
|
||||||
|
if (tile.type == TileType::Capital)
|
||||||
|
tile.type = TileType::Stronghold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_defeated_players.push_back(p);
|
||||||
|
players[p].is_defeated = 1;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<TeamRanking> GameBoard::leaderboard() const {
|
std::vector<TeamRanking> GameBoard::leaderboard() const {
|
||||||
std::vector<TeamRanking> res(t);
|
std::vector<TeamRanking> res(t);
|
||||||
std::vector<PlayerRanking> prank(n);
|
std::vector<PlayerRanking> prank(n);
|
||||||
@ -164,6 +277,68 @@ std::vector<TeamRanking> GameBoard::leaderboard() const {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TeamViewDiff GameBoard::teamViewDiff(Team team) {
|
||||||
|
TeamViewDiff res;
|
||||||
|
res.team = team;
|
||||||
|
for (const auto& pos : updated_tiles) {
|
||||||
|
if (cover[team][pos.x][pos.y])
|
||||||
|
diff_tiles[team].insert(pos);
|
||||||
|
}
|
||||||
|
for (const auto& pos : diff_tiles[team]) {
|
||||||
|
auto x = pos.x, y = pos.y;
|
||||||
|
res.diffs.emplace_back(x, y, cover[team][x][y] ? at(x, y) : Tile());
|
||||||
|
}
|
||||||
|
diff_tiles[team].clear();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Tile> GameBoard::getViewOf(Team team) const {
|
||||||
|
std::vector<Tile> res(h * w);
|
||||||
|
for (pos_t x = 0; x < h; x++) {
|
||||||
|
for (pos_t y = 0; y < w; y++) {
|
||||||
|
if (cover[team][x][y])
|
||||||
|
res[x * w + y] = at(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameState GameBoard::tick() {
|
||||||
|
halfturn_id++;
|
||||||
|
|
||||||
|
for (int _i = 1; _i <= n; _i++) {
|
||||||
|
int i = (halfturn_id & 1) ? _i : n - _i + 1;
|
||||||
|
if (!players[i].orders.empty()) {
|
||||||
|
if (!attack(players[i].orders.front()))
|
||||||
|
players[i].orders.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(halfturn_id % 50))
|
||||||
|
roundUpdate();
|
||||||
|
if (!(halfturn_id & 1))
|
||||||
|
turnUpdate();
|
||||||
|
|
||||||
|
for (auto p : new_offline_players)
|
||||||
|
offline(p);
|
||||||
|
new_offline_players.clear();
|
||||||
|
|
||||||
|
GameState res;
|
||||||
|
res.halfturn_id = halfturn_id;
|
||||||
|
res.defeated_players = new_defeated_players;
|
||||||
|
new_defeated_players.clear();
|
||||||
|
for (Player i = 1; i <= n; i++) {
|
||||||
|
if (!players[i].is_defeated)
|
||||||
|
res.alive_players.push_back(i);
|
||||||
|
}
|
||||||
|
res.leaderboard = leaderboard();
|
||||||
|
res.diffs.resize(t);
|
||||||
|
for (Team i = 1; i <= t; i++)
|
||||||
|
res.diffs[i] = teamViewDiff(i);
|
||||||
|
updated_tiles.clear();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
PlayerState::PlayerState() {
|
PlayerState::PlayerState() {
|
||||||
is_defeated = false;
|
is_defeated = false;
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
#ifndef OGLG_GAMEBOARD_H_
|
#ifndef OGLG_GAMEBOARD_H_
|
||||||
#define OGLG_GAMEBOARD_H_
|
#define OGLG_GAMEBOARD_H_
|
||||||
|
|
||||||
#include <vector>
|
#include "PlayerMove.h"
|
||||||
|
#include "pc/astuple.h"
|
||||||
|
#include "pc/commcode.h"
|
||||||
|
#include "pc/pctypes.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "PlayerMove.h"
|
#include <vector>
|
||||||
#include "pc/pctypes.h"
|
|
||||||
#include "pc/commcode.h"
|
|
||||||
#include "pc/astuple.h"
|
|
||||||
|
|
||||||
struct PlayerState {
|
struct PlayerState {
|
||||||
Player id;
|
Player id;
|
||||||
@ -19,19 +19,13 @@ struct PlayerState {
|
|||||||
PlayerState();
|
PlayerState();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ImportedTerrain;
|
||||||
|
|
||||||
class GameBoard {
|
class GameBoard {
|
||||||
public:
|
public:
|
||||||
GameBoard(pos_t w, pos_t h, const InitInfo &info);
|
GameBoard(pos_t w, pos_t h, const InitInfo& info);
|
||||||
|
|
||||||
const Tile& at(pos_t x, pos_t y) const;
|
friend ImportedTerrain;
|
||||||
Tile& at(pos_t x, pos_t y);
|
|
||||||
|
|
||||||
bool attack(const PlayerMove &o);
|
|
||||||
|
|
||||||
void turnUpdate();
|
|
||||||
void roundUpdate();
|
|
||||||
|
|
||||||
std::vector<TeamRanking> leaderboard() const;
|
|
||||||
|
|
||||||
bool isTeammate(Player x, Player y) const;
|
bool isTeammate(Player x, Player y) const;
|
||||||
Team teamOf(Player x) const;
|
Team teamOf(Player x) const;
|
||||||
@ -40,26 +34,46 @@ public:
|
|||||||
std::uint8_t numPlayers() const;
|
std::uint8_t numPlayers() const;
|
||||||
std::uint8_t numTeams() const;
|
std::uint8_t numTeams() const;
|
||||||
|
|
||||||
void appendOrderQueue(const PlayerMove &p);
|
void appendOrderQueue(const PlayerMove& p);
|
||||||
void clearOrderQueue(Player p);
|
void clearOrderQueue(Player p);
|
||||||
void popOrderQueue(Player p);
|
void popOrderQueue(Player p);
|
||||||
void setOffline(Player x);
|
void setOffline(Player p);
|
||||||
|
|
||||||
std::vector<Tile> getViewOf(Team x) const;
|
std::vector<Tile> getViewOf(Team x) const;
|
||||||
GameState tick();
|
GameState tick();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const Tile& at(pos_t x, pos_t y) const;
|
||||||
|
Tile& at(pos_t x, pos_t y);
|
||||||
|
void setOwner(pos_t x, pos_t y, Player p);
|
||||||
|
|
||||||
|
bool attack(const PlayerMove& o);
|
||||||
void capitalCaptured(Player target, Player source);
|
void capitalCaptured(Player target, Player source);
|
||||||
|
|
||||||
|
void turnUpdate();
|
||||||
|
void roundUpdate();
|
||||||
void updatedPosition(pos_t x, pos_t y);
|
void updatedPosition(pos_t x, pos_t y);
|
||||||
|
|
||||||
|
void offline(Player p);
|
||||||
|
|
||||||
|
std::vector<TeamRanking> leaderboard() const;
|
||||||
|
|
||||||
|
TeamViewDiff teamViewDiff(Team team);
|
||||||
|
|
||||||
std::uint8_t n, t;
|
std::uint8_t n, t;
|
||||||
std::vector<PlayerState> players;
|
std::vector<PlayerState> players;
|
||||||
|
|
||||||
pos_t w, h;
|
pos_t w, h, view_radius;
|
||||||
std::vector<Tile> board;
|
std::vector<Tile> board;
|
||||||
|
|
||||||
|
std::uint32_t halfturn_id;
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<std::uint8_t>>> cover;
|
||||||
|
std::vector<std::set<Point>> diff_tiles;
|
||||||
|
|
||||||
|
std::vector<Player> new_offline_players;
|
||||||
std::set<Point> updated_tiles;
|
std::set<Point> updated_tiles;
|
||||||
std::vector<Player> new_defeated_players;
|
std::vector<Player> new_defeated_players;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -123,16 +123,10 @@ GameBoard ImportedTerrain::makeGameBoard(const InitInfo& init_info) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
GameBoard g(w, h, init_info);
|
GameBoard g(w, h, init_info);
|
||||||
for (pos_t i = 0; i < h; i++) {
|
|
||||||
for (pos_t j = 0; j < w; j++) {
|
|
||||||
g.at(i, j).type = tiles[i][j].type;
|
|
||||||
g.at(i, j).unit = tiles[i][j].unit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto arrange = [&perm, &g](const vector<Player>& players,
|
auto arrange = [&](const vector<Player>& players,
|
||||||
const vector<vector<Point>>& capitals,
|
const vector<vector<Point>>& capitals,
|
||||||
vector<Player>& rest) {
|
vector<Player>& rest) {
|
||||||
vector<Point> caps;
|
vector<Point> caps;
|
||||||
for (const auto& v : capitals) {
|
for (const auto& v : capitals) {
|
||||||
for (const auto& p : v)
|
for (const auto& p : v)
|
||||||
@ -145,10 +139,17 @@ GameBoard ImportedTerrain::makeGameBoard(const InitInfo& init_info) {
|
|||||||
rest.push_back(players[C[j]]);
|
rest.push_back(players[C[j]]);
|
||||||
for (size_t j = 0; j < min(C.size(), D.size()); j++) {
|
for (size_t j = 0; j < min(C.size(), D.size()); j++) {
|
||||||
g.at(caps[D[j]].x, caps[D[j]].y).type = TileType::Capital;
|
g.at(caps[D[j]].x, caps[D[j]].y).type = TileType::Capital;
|
||||||
g.at(caps[D[j]].x, caps[D[j]].y).owner = players[C[j]];
|
g.setOwner(caps[D[j]].x, caps[D[j]].y, players[C[j]]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (pos_t i = 0; i < h; i++) {
|
||||||
|
for (pos_t j = 0; j < w; j++) {
|
||||||
|
g.at(i, j).type = tiles[i][j].type;
|
||||||
|
g.at(i, j).unit = tiles[i][j].unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vector<vector<Player>> players(g.numTeams());
|
vector<vector<Player>> players(g.numTeams());
|
||||||
for (int i = 1, n = g.numPlayers(); i <= n; i++)
|
for (int i = 1, n = g.numPlayers(); i <= n; i++)
|
||||||
players[g.teamOf(i) - 1].push_back(i);
|
players[g.teamOf(i) - 1].push_back(i);
|
||||||
@ -201,7 +202,7 @@ GameBoard ImportedTerrain::makeGameBoard(const InitInfo& init_info) {
|
|||||||
|
|
||||||
for (size_t i = 0; i < rest2.size(); i++) {
|
for (size_t i = 0; i < rest2.size(); i++) {
|
||||||
g.at(pr.second[i].x, pr.second[i].y).type = TileType::Capital;
|
g.at(pr.second[i].x, pr.second[i].y).type = TileType::Capital;
|
||||||
g.at(pr.second[i].x, pr.second[i].y).owner = rest2[i];
|
g.setOwner(pr.second[i].x, pr.second[i].y, rest2[i]);
|
||||||
}
|
}
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,5 @@ PlayerRanking::PlayerRanking() : player(neutral_player)
|
|||||||
|
|
||||||
TeamRanking::TeamRanking() : team(neutral_team), land(0), unit(0) {}
|
TeamRanking::TeamRanking() : team(neutral_team), land(0), unit(0) {}
|
||||||
|
|
||||||
Tile::Tile() : owner(neutral_player), unit(0) {}
|
Tile::Tile() : owner(neutral_player), type(TileType::Misty), unit(0) {}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user