rm *.cpp
This commit is contained in:
parent
f2434a5953
commit
8f94811cb0
@ -1,148 +0,0 @@
|
|||||||
Language: Cpp
|
|
||||||
AccessModifierOffset: -4
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignArrayOfStructures: Left
|
|
||||||
AlignConsecutiveMacros: None
|
|
||||||
AlignConsecutiveAssignments: None
|
|
||||||
AlignConsecutiveBitFields: None
|
|
||||||
AlignConsecutiveDeclarations: None
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
AlignOperands: Align
|
|
||||||
AlignTrailingComments: true
|
|
||||||
AllowAllArgumentsOnNextLine: false
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
|
||||||
AllowShortEnumsOnASingleLine: false
|
|
||||||
AllowShortBlocksOnASingleLine: Empty
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AllowShortFunctionsOnASingleLine: Empty
|
|
||||||
AllowShortLambdasOnASingleLine: All
|
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
|
||||||
AllowShortLoopsOnASingleLine: false
|
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
|
||||||
AttributeMacros: []
|
|
||||||
BinPackArguments: false
|
|
||||||
BinPackParameters: false
|
|
||||||
BraceWrapping:
|
|
||||||
AfterCaseLabel: false
|
|
||||||
AfterClass: false
|
|
||||||
AfterControlStatement: Never
|
|
||||||
AfterEnum: false
|
|
||||||
AfterFunction: false
|
|
||||||
AfterNamespace: false
|
|
||||||
AfterObjCDeclaration: false
|
|
||||||
AfterStruct: false
|
|
||||||
AfterUnion: false
|
|
||||||
AfterExternBlock: false
|
|
||||||
BeforeCatch: false
|
|
||||||
BeforeElse: false
|
|
||||||
BeforeLambdaBody: false
|
|
||||||
BeforeWhile: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: false
|
|
||||||
SplitEmptyRecord: false
|
|
||||||
SplitEmptyNamespace: false
|
|
||||||
BreakBeforeBinaryOperators: All
|
|
||||||
BreakBeforeConceptDeclarations: true
|
|
||||||
BreakBeforeBraces: Attach
|
|
||||||
BreakBeforeInheritanceComma: false
|
|
||||||
BreakInheritanceList: BeforeComma
|
|
||||||
BreakBeforeTernaryOperators: true
|
|
||||||
BreakConstructorInitializersBeforeComma: true
|
|
||||||
BreakConstructorInitializers: BeforeComma
|
|
||||||
BreakStringLiterals: true
|
|
||||||
ColumnLimit: 80
|
|
||||||
QualifierAlignment: Left
|
|
||||||
CompactNamespaces: false
|
|
||||||
ConstructorInitializerIndentWidth: 4
|
|
||||||
ContinuationIndentWidth: 4
|
|
||||||
Cpp11BracedListStyle: true
|
|
||||||
DeriveLineEnding: true
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
DisableFormat: false
|
|
||||||
EmptyLineAfterAccessModifier: Never
|
|
||||||
EmptyLineBeforeAccessModifier: Always
|
|
||||||
ExperimentalAutoDetectBinPacking: false
|
|
||||||
PackConstructorInitializers: NextLine
|
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
|
||||||
AllowAllConstructorInitializersOnNextLine: false
|
|
||||||
FixNamespaceComments: true
|
|
||||||
ForEachMacros: []
|
|
||||||
IfMacros: []
|
|
||||||
IncludeBlocks: Merge
|
|
||||||
IndentAccessModifiers: false
|
|
||||||
IndentCaseLabels: false
|
|
||||||
IndentCaseBlocks: false
|
|
||||||
IndentGotoLabels: false
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentExternBlock: AfterExternBlock
|
|
||||||
IndentRequires: false
|
|
||||||
IndentWidth: 4
|
|
||||||
IndentWrappedFunctionNames: false
|
|
||||||
InsertTrailingCommas: Wrapped
|
|
||||||
InsertBraces: false
|
|
||||||
InsertNewlineAtEOF: true
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
|
||||||
LambdaBodyIndentation: Signature
|
|
||||||
MacroBlockBegin: ''
|
|
||||||
MacroBlockEnd: ''
|
|
||||||
MaxEmptyLinesToKeep: 1
|
|
||||||
NamespaceIndentation: None
|
|
||||||
PenaltyBreakAssignment: 2
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 1
|
|
||||||
PenaltyBreakComment: 300
|
|
||||||
PenaltyBreakFirstLessLess: 120
|
|
||||||
PenaltyBreakOpenParenthesis: 0
|
|
||||||
PenaltyBreakString: 1000
|
|
||||||
PenaltyBreakTemplateDeclaration: 10
|
|
||||||
PenaltyExcessCharacter: 1000000
|
|
||||||
PenaltyReturnTypeOnItsOwnLine: 200
|
|
||||||
PenaltyIndentedWhitespace: 0
|
|
||||||
PointerAlignment: Left
|
|
||||||
PPIndentWidth: -1
|
|
||||||
ReferenceAlignment: Pointer
|
|
||||||
ReflowComments: true
|
|
||||||
RemoveBracesLLVM: false
|
|
||||||
SeparateDefinitionBlocks: Leave
|
|
||||||
ShortNamespaceLines: 1
|
|
||||||
SortIncludes: CaseSensitive
|
|
||||||
SortJavaStaticImport: Before
|
|
||||||
SortUsingDeclarations: true
|
|
||||||
SpaceAfterCStyleCast: false
|
|
||||||
SpaceAfterLogicalNot: false
|
|
||||||
SpaceAfterTemplateKeyword: false
|
|
||||||
SpaceBeforeAssignmentOperators: true
|
|
||||||
SpaceBeforeCaseColon: false
|
|
||||||
SpaceBeforeCpp11BracedList: false
|
|
||||||
SpaceBeforeCtorInitializerColon: false
|
|
||||||
SpaceBeforeInheritanceColon: true
|
|
||||||
SpaceBeforeParens: ControlStatements
|
|
||||||
SpaceBeforeParensOptions:
|
|
||||||
AfterControlStatements: true
|
|
||||||
AfterFunctionDefinitionName: false
|
|
||||||
AfterFunctionDeclarationName: false
|
|
||||||
AfterOverloadedOperator: false
|
|
||||||
BeforeNonEmptyParentheses: false
|
|
||||||
SpaceAroundPointerQualifiers: Default
|
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
|
||||||
SpaceInEmptyBlock: false
|
|
||||||
SpaceInEmptyParentheses: false
|
|
||||||
SpacesBeforeTrailingComments: 1
|
|
||||||
SpacesInAngles: Never
|
|
||||||
SpacesInConditionalStatement: false
|
|
||||||
SpacesInContainerLiterals: false
|
|
||||||
SpacesInCStyleCastParentheses: false
|
|
||||||
SpacesInLineCommentPrefix:
|
|
||||||
Minimum: 1
|
|
||||||
Maximum: -1
|
|
||||||
SpacesInParentheses: false
|
|
||||||
SpacesInSquareBrackets: false
|
|
||||||
SpaceBeforeSquareBrackets: false
|
|
||||||
BitFieldColonSpacing: Both
|
|
||||||
Standard: Latest
|
|
||||||
TabWidth: 4
|
|
||||||
UseCRLF: false
|
|
||||||
UseTab: Always
|
|
||||||
|
|
@ -1,344 +0,0 @@
|
|||||||
#include "GameBoard.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
GameBoard::GameBoard(pos_t w, pos_t h, const InitInfo& info)
|
|
||||||
: 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) {
|
|
||||||
players[i].id = i;
|
|
||||||
players[i].team = info.player_team[i];
|
|
||||||
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) {
|
|
||||||
return board[x * w + y];
|
|
||||||
}
|
|
||||||
|
|
||||||
const Tile& GameBoard::at(pos_t x, pos_t y) const {
|
|
||||||
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) {
|
|
||||||
if (!o.isValid(w, h))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto& sc_tile = at(o.x, o.y);
|
|
||||||
auto& tt_tile = at(o.tx(), o.ty());
|
|
||||||
if (sc_tile.owner != o.player)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (sc_tile.unit <= 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (tt_tile.type == TileType::Mountain)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto moving_unit = o.half ? sc_tile.unit - 1 : sc_tile.unit / 2;
|
|
||||||
sc_tile.unit -= moving_unit;
|
|
||||||
auto isfriend = isTeammate(o.player, tt_tile.owner);
|
|
||||||
auto delta
|
|
||||||
= isfriend ? moving_unit + tt_tile.unit : moving_unit - tt_tile.unit;
|
|
||||||
|
|
||||||
updatedPosition(o.x, o.y);
|
|
||||||
updatedPosition(o.ty(), o.ty());
|
|
||||||
|
|
||||||
tt_tile.unit = std::abs(delta);
|
|
||||||
if (delta > 0 && (!isfriend || tt_tile.type != TileType::Capital)) {
|
|
||||||
if (!isfriend && tt_tile.type == TileType::Capital)
|
|
||||||
capitalCaptured(tt_tile.owner, o.player);
|
|
||||||
setOwner(o.tx(), o.ty(), o.player);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameBoard::capitalCaptured(Player tt, Player sc) {
|
|
||||||
for (pos_t x = 0; x < h; ++x) {
|
|
||||||
for (pos_t y = 0; y < w; ++y) {
|
|
||||||
auto& tile = at(x, y);
|
|
||||||
if (tile.owner != tt)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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);
|
|
||||||
players[tt].is_defeated = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GameBoard::isTeammate(Player x, Player y) const {
|
|
||||||
return teamOf(x) == teamOf(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameBoard::turnUpdate() {
|
|
||||||
for (pos_t x = 0; x < h; ++x) {
|
|
||||||
for (pos_t y = 0; y < w; ++y) {
|
|
||||||
auto& tile = at(x, y);
|
|
||||||
if (tile.owner == neutral_player)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (tile.type == TileType::Stronghold
|
|
||||||
|| tile.type == TileType::Capital)
|
|
||||||
tile.unit += 1;
|
|
||||||
|
|
||||||
if (tile.type == TileType::Swamp) {
|
|
||||||
if (tile.unit > 0)
|
|
||||||
tile.unit -= 1;
|
|
||||||
if (tile.unit == 0)
|
|
||||||
setOwner(x, y, neutral_player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameBoard::roundUpdate() {
|
|
||||||
for (pos_t x = 0; x < h; ++x) {
|
|
||||||
for (pos_t y = 0; y < w; ++y) {
|
|
||||||
auto& tile = at(x, y);
|
|
||||||
if (tile.owner == neutral_player)
|
|
||||||
continue;
|
|
||||||
tile.unit += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameBoard::updatedPosition(pos_t x, pos_t y) {
|
|
||||||
updated_tiles.emplace(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
Team GameBoard::teamOf(Player x) const {
|
|
||||||
return players[x].team;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GameBoard::isDefeated(Player x) const {
|
|
||||||
return players[x].is_defeated;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint8_t GameBoard::numPlayers() const {
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint8_t GameBoard::numTeams() const {
|
|
||||||
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> res(t);
|
|
||||||
std::vector<PlayerRanking> prank(n);
|
|
||||||
|
|
||||||
for (Player i = 1; i <= n; ++i) {
|
|
||||||
prank[i - 1].player = i;
|
|
||||||
prank[i - 1].is_defeated = players[i].is_defeated;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Team i = 1; i <= t; ++i)
|
|
||||||
res[i - 1].team = i;
|
|
||||||
|
|
||||||
for (pos_t x = 0; x < h; ++x) {
|
|
||||||
for (pos_t y = 0; y < w; ++y) {
|
|
||||||
auto& tile = at(x, y);
|
|
||||||
if (tile.owner == neutral_player)
|
|
||||||
continue;
|
|
||||||
prank[tile.owner - 1].land += 1;
|
|
||||||
prank[tile.owner - 1].unit += tile.unit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& p : prank)
|
|
||||||
res[teamOf(p.player) - 1].players.push_back(p);
|
|
||||||
for (auto& team : res) {
|
|
||||||
for (const auto& p : team.players) {
|
|
||||||
team.land += p.land;
|
|
||||||
team.unit += p.unit;
|
|
||||||
}
|
|
||||||
sort(team.players.begin(),
|
|
||||||
team.players.end(),
|
|
||||||
[](const PlayerRanking& a, const PlayerRanking& b) {
|
|
||||||
return a.unit != b.unit ? a.unit > b.unit
|
|
||||||
: a.player < b.player;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
sort(res.begin(),
|
|
||||||
res.end(),
|
|
||||||
[](const TeamRanking& a, const TeamRanking& b) {
|
|
||||||
return a.unit != b.unit ? a.unit > b.unit : a.team < b.team;
|
|
||||||
});
|
|
||||||
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() {
|
|
||||||
is_defeated = false;
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
#ifndef OGLG_GAMEBOARD_H_
|
|
||||||
#define OGLG_GAMEBOARD_H_
|
|
||||||
|
|
||||||
#include "PlayerMove.h"
|
|
||||||
#include "pc/astuple.h"
|
|
||||||
#include "pc/commcode.h"
|
|
||||||
#include "pc/pctypes.h"
|
|
||||||
#include <cstdint>
|
|
||||||
#include <deque>
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
struct PlayerState {
|
|
||||||
Player id;
|
|
||||||
Team team;
|
|
||||||
bool is_defeated;
|
|
||||||
std::deque<PlayerMove> orders;
|
|
||||||
|
|
||||||
PlayerState();
|
|
||||||
};
|
|
||||||
|
|
||||||
class ImportedTerrain;
|
|
||||||
|
|
||||||
class GameBoard {
|
|
||||||
public:
|
|
||||||
GameBoard(pos_t w, pos_t h, const InitInfo& info);
|
|
||||||
|
|
||||||
friend ImportedTerrain;
|
|
||||||
|
|
||||||
bool isTeammate(Player x, Player y) const;
|
|
||||||
Team teamOf(Player x) const;
|
|
||||||
bool isDefeated(Player x) const;
|
|
||||||
|
|
||||||
std::uint8_t numPlayers() const;
|
|
||||||
std::uint8_t numTeams() const;
|
|
||||||
|
|
||||||
void appendOrderQueue(const PlayerMove& p);
|
|
||||||
void clearOrderQueue(Player p);
|
|
||||||
void popOrderQueue(Player p);
|
|
||||||
void setOffline(Player p);
|
|
||||||
|
|
||||||
std::vector<Tile> getViewOf(Team x) const;
|
|
||||||
GameState tick();
|
|
||||||
|
|
||||||
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 turnUpdate();
|
|
||||||
void roundUpdate();
|
|
||||||
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::vector<PlayerState> players;
|
|
||||||
|
|
||||||
pos_t w, h, view_radius;
|
|
||||||
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::vector<Player> new_defeated_players;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,26 +0,0 @@
|
|||||||
#include <cstdint>
|
|
||||||
#include "PlayerMove.h"
|
|
||||||
#include "pc/commcode.h"
|
|
||||||
|
|
||||||
bool PlayerMove::isValid(pos_t w, pos_t h) const {
|
|
||||||
if (x >= h || y >= w)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((int)dir >= 4)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto xx = tx(), yy = ty();
|
|
||||||
if (xx >= h || yy >= w)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos_t PlayerMove::tx() const {
|
|
||||||
return x + direction_dx[(std::size_t)dir];
|
|
||||||
}
|
|
||||||
|
|
||||||
pos_t PlayerMove::ty() const {
|
|
||||||
return y + direction_dy[(std::size_t)dir];
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
#ifndef OGLG_PLAYERMOVE_H_
|
|
||||||
#define OGLG_PLAYERMOVE_H_
|
|
||||||
|
|
||||||
#include "pc/astuple.h"
|
|
||||||
#include "pc/commcode.h"
|
|
||||||
#include "pc/pctypes.h"
|
|
||||||
|
|
||||||
struct PlayerMove {
|
|
||||||
Player player;
|
|
||||||
pos_t x, y;
|
|
||||||
Direction dir;
|
|
||||||
bool half;
|
|
||||||
|
|
||||||
bool isValid(pos_t w, pos_t h) const;
|
|
||||||
pos_t tx() const;
|
|
||||||
pos_t ty() const;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(player, x, y, dir, half)
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,307 +0,0 @@
|
|||||||
#include "terrain.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#include <functional>
|
|
||||||
#include <random>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
BadImportTerrainConfig::BadImportTerrainConfig(size_t pt): pt(pt) {}
|
|
||||||
|
|
||||||
const char* BadImportTerrainConfig::what() const noexcept {
|
|
||||||
return ("ImportTerrainConfig " + to_string(pt)).c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* BadCapitalAssign::what() const noexcept {
|
|
||||||
return "Bad Capital Assign";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline namespace {
|
|
||||||
|
|
||||||
mt19937 rnd(19260817);
|
|
||||||
enum class VertexType : std::uint8_t {
|
|
||||||
Ordinary,
|
|
||||||
Mountain,
|
|
||||||
Capital,
|
|
||||||
Cut
|
|
||||||
};
|
|
||||||
|
|
||||||
bool ban(VertexType t) {
|
|
||||||
return t == VertexType::Mountain || t == VertexType::Capital;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void upmin(T& x, const T& y) {
|
|
||||||
if (y < x)
|
|
||||||
x = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool findCut(pos_t w, pos_t h, vector<vector<VertexType>>& vertex_type) {
|
|
||||||
int idx = 0;
|
|
||||||
vector<vector<int>> dfn(h, vector<int>(w)), low = dfn;
|
|
||||||
function<void(pos_t, pos_t, pos_t, pos_t, bool)> tarjan =
|
|
||||||
[&](pos_t x, pos_t y, pos_t fx, pos_t fy, bool rt) {
|
|
||||||
dfn[x][y] = low[x][y] = ++idx;
|
|
||||||
int ch = 0;
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
const pos_t xx = x + direction_dx[i], yy = y + direction_dy[i];
|
|
||||||
if (xx >= h || yy >= w)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (vertex_type[xx][yy] == VertexType::Capital)
|
|
||||||
vertex_type[x][y] = VertexType::Cut;
|
|
||||||
|
|
||||||
if (ban(vertex_type[xx][yy]) || (xx == fx && yy == fy))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!dfn[xx][yy]) {
|
|
||||||
ch++;
|
|
||||||
tarjan(xx, yy, x, y, 0);
|
|
||||||
upmin(low[x][y], low[xx][yy]);
|
|
||||||
if (!rt && low[xx][yy] >= dfn[x][y])
|
|
||||||
vertex_type[x][y] = VertexType::Cut;
|
|
||||||
} else {
|
|
||||||
upmin(low[x][y], dfn[xx][yy]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rt && ch >= 2)
|
|
||||||
vertex_type[x][y] = VertexType::Cut;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool flag = false;
|
|
||||||
for (pos_t i = 0; i < h; i++) {
|
|
||||||
for (pos_t j = 0; j < w; j++) {
|
|
||||||
if (!ban(vertex_type[i][j]) && !dfn[i][j]) {
|
|
||||||
if (flag)
|
|
||||||
return false;
|
|
||||||
flag = 1;
|
|
||||||
tarjan(i, j, -1, -1, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
pair<bool, vector<Point>> generateCapital(
|
|
||||||
pos_t w,
|
|
||||||
pos_t h,
|
|
||||||
vector<vector<VertexType>>& vertex_type,
|
|
||||||
int r) {
|
|
||||||
vector<Point> res(r);
|
|
||||||
for (int i = 0; i <= r; i++) {
|
|
||||||
if (!findCut(w, h, vertex_type))
|
|
||||||
return {false, vector<Point>()};
|
|
||||||
|
|
||||||
if (i == r)
|
|
||||||
break;
|
|
||||||
vector<Point> options;
|
|
||||||
for (pos_t x = 0; x < h; x++) {
|
|
||||||
for (pos_t y = 0; y < w; y++) {
|
|
||||||
if (vertex_type[x][y] == VertexType::Ordinary)
|
|
||||||
options.emplace_back(x, y);
|
|
||||||
if (vertex_type[x][y] == VertexType::Cut)
|
|
||||||
vertex_type[x][y] = VertexType::Ordinary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.empty())
|
|
||||||
return {false, {}};
|
|
||||||
|
|
||||||
res[i] = options[rnd() % options.size()];
|
|
||||||
vertex_type[res[i].x][res[i].y] = VertexType::Capital;
|
|
||||||
}
|
|
||||||
return {true, res};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
GameBoard ImportedTerrain::makeGameBoard(const InitInfo& init_info) {
|
|
||||||
auto perm = [](std::uint8_t n) {
|
|
||||||
vector<std::uint8_t> vec(n);
|
|
||||||
iota(vec.begin(), vec.end(), 0);
|
|
||||||
shuffle(vec.begin(), vec.end(), rnd);
|
|
||||||
return vec;
|
|
||||||
};
|
|
||||||
|
|
||||||
GameBoard g(w, h, init_info);
|
|
||||||
|
|
||||||
auto arrange = [&](const vector<Player>& players,
|
|
||||||
const vector<vector<Point>>& capitals,
|
|
||||||
vector<Player>& rest) {
|
|
||||||
vector<Point> caps;
|
|
||||||
for (const auto& v : capitals) {
|
|
||||||
for (const auto& p : v)
|
|
||||||
caps.push_back(p);
|
|
||||||
if (caps.size() >= players.size())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto C = perm(players.size()), D = perm(caps.size());
|
|
||||||
for (size_t j = D.size(); j < C.size(); j++)
|
|
||||||
rest.push_back(players[C[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.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());
|
|
||||||
for (int i = 1, n = g.numPlayers(); i <= n; i++)
|
|
||||||
players[g.teamOf(i) - 1].push_back(i);
|
|
||||||
auto A = perm(players.size()), B = perm(capitals.size() - 1);
|
|
||||||
vector<Player> rest1;
|
|
||||||
for (size_t i = B.size(); i < A.size(); i++) {
|
|
||||||
for (auto id : players[A[i]])
|
|
||||||
rest1.push_back(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < min(A.size(), B.size()); i++)
|
|
||||||
arrange(players[A[i]], capitals[B[i]], rest1);
|
|
||||||
|
|
||||||
vector<Player> rest2;
|
|
||||||
arrange(rest1, capitals.back(), rest2);
|
|
||||||
|
|
||||||
for (pos_t x = 0; x < h; x++) {
|
|
||||||
for (pos_t y = 0; y < w; y++) {
|
|
||||||
if (g.at(x, y).type == TileType::Capital) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
const pos_t xx = x + direction_dx[i],
|
|
||||||
yy = y + direction_dy[i];
|
|
||||||
if (xx >= h || yy >= w)
|
|
||||||
continue;
|
|
||||||
if (g.at(xx, yy).type == TileType::Capital)
|
|
||||||
throw BadCapitalAssign();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int T = 5;
|
|
||||||
|
|
||||||
while (T--) {
|
|
||||||
vector<vector<VertexType>> vertex_type(
|
|
||||||
h,
|
|
||||||
vector<VertexType>(w, VertexType::Ordinary));
|
|
||||||
for (pos_t i = 0; i < h; i++) {
|
|
||||||
for (pos_t j = 0; j < w; j++) {
|
|
||||||
if (g.at(i, j).type == TileType::Mountain)
|
|
||||||
vertex_type[i][j] = VertexType::Mountain;
|
|
||||||
if (g.at(i, j).type == TileType::Capital)
|
|
||||||
vertex_type[i][j] = VertexType::Capital;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pr = generateCapital(w, h, vertex_type, rest2.size());
|
|
||||||
if (!pr.first)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < rest2.size(); i++) {
|
|
||||||
g.at(pr.second[i].x, pr.second[i].y).type = TileType::Capital;
|
|
||||||
g.setOwner(pr.second[i].x, pr.second[i].y, rest2[i]);
|
|
||||||
}
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw BadCapitalAssign();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImportedTerrain importTerrain(const ImportTerrainConfig& in) {
|
|
||||||
ImportedTerrain t;
|
|
||||||
t.w = in.w;
|
|
||||||
t.h = in.h;
|
|
||||||
t.tiles.resize(t.h, vector<ImportedTerrain::TerrainTile>(t.w));
|
|
||||||
|
|
||||||
size_t pt = 0;
|
|
||||||
auto error = [&]() { throw BadImportTerrainConfig(pt); };
|
|
||||||
auto view = [&](char c) {
|
|
||||||
return pt < in.value.size() && in.value[pt] == c ? (pt++, true) : false;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto jump = [&](char c) {
|
|
||||||
if (!view(c))
|
|
||||||
error();
|
|
||||||
};
|
|
||||||
|
|
||||||
auto read = [&](int l = -99999, int r = 99999) {
|
|
||||||
bool neg = view('-');
|
|
||||||
if (!(pt < in.value.size() && isdigit(in.value[pt])))
|
|
||||||
error();
|
|
||||||
|
|
||||||
std::int32_t x = 0;
|
|
||||||
while (pt < in.value.size() && isdigit(in.value[pt])) {
|
|
||||||
x = x * 10 + (in.value[pt] ^ '0');
|
|
||||||
if (x > 99999)
|
|
||||||
error();
|
|
||||||
pt++;
|
|
||||||
}
|
|
||||||
if (neg)
|
|
||||||
x = -x;
|
|
||||||
if (x < l || x > r)
|
|
||||||
error();
|
|
||||||
return x;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (t.w < 5 || t.h < 5)
|
|
||||||
error();
|
|
||||||
|
|
||||||
vector<vector<vector<Point>>> vec(27, vector<vector<Point>>(101));
|
|
||||||
vector<vector<VertexType>> vertex_type(
|
|
||||||
t.h,
|
|
||||||
vector<VertexType>(t.w, VertexType::Ordinary));
|
|
||||||
for (pos_t i = 0; i < t.h; i++) {
|
|
||||||
for (pos_t j = 0; j < t.w; j++) {
|
|
||||||
auto& p = t.tiles[i][j];
|
|
||||||
if (view(' ')) {
|
|
||||||
p.type = TileType::Blank;
|
|
||||||
} else if (view('m')) {
|
|
||||||
p.type = TileType::Mountain;
|
|
||||||
vertex_type[i][j] = VertexType::Mountain;
|
|
||||||
} else if (view('n')) {
|
|
||||||
p.type = TileType::Blank;
|
|
||||||
p.unit = read();
|
|
||||||
} else if (view('s')) {
|
|
||||||
p.type = TileType::Swamp;
|
|
||||||
} else if (view('g')) {
|
|
||||||
p.type = TileType::Blank;
|
|
||||||
bool tag = 1;
|
|
||||||
int team = (pt < in.value.size() && isupper(in.value[pt])
|
|
||||||
? in.value[pt++] - 'A'
|
|
||||||
: (tag = view(' '), 26));
|
|
||||||
|
|
||||||
int priority
|
|
||||||
= (tag && pt < in.value.size() && isdigit(in.value[pt])
|
|
||||||
? read(1, 99)
|
|
||||||
: 100);
|
|
||||||
vec[team][priority].emplace_back(i, j);
|
|
||||||
} else {
|
|
||||||
p.type = TileType::Stronghold;
|
|
||||||
p.unit = read();
|
|
||||||
}
|
|
||||||
if (i + 1 < t.h || j + 1 < t.w)
|
|
||||||
jump(',');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pt != in.value.size())
|
|
||||||
error();
|
|
||||||
if (!findCut(t.w, t.h, vertex_type))
|
|
||||||
error();
|
|
||||||
t.capitals.emplace_back();
|
|
||||||
|
|
||||||
for (int i = 0; i <= 26; i++) {
|
|
||||||
for (int j = 100; j >= 1; j--) {
|
|
||||||
if (!vec[i][j].empty()) {
|
|
||||||
t.capitals.back().emplace_back().swap(vec[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!t.capitals.back().empty() && i != 26) {
|
|
||||||
t.capitals.emplace_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
#ifndef OGLG_TERRAIN_H_
|
|
||||||
#define OGLG_TERRAIN_H_
|
|
||||||
|
|
||||||
#include "logic/GameBoard.h"
|
|
||||||
#include "pc/Point.h"
|
|
||||||
#include "pc/commcode.h"
|
|
||||||
#include "pc/pctypes.h"
|
|
||||||
#include <exception>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class BadImportTerrainConfig : std::exception {
|
|
||||||
public:
|
|
||||||
BadImportTerrainConfig(size_t);
|
|
||||||
virtual ~BadImportTerrainConfig() = default;
|
|
||||||
virtual const char* what() const noexcept override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t pt;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BadCapitalAssign : std::exception {
|
|
||||||
public:
|
|
||||||
virtual ~BadCapitalAssign() = default;
|
|
||||||
virtual const char* what() const noexcept override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ImportedTerrain {
|
|
||||||
public:
|
|
||||||
friend ImportedTerrain importTerrain(const ImportTerrainConfig& in);
|
|
||||||
GameBoard makeGameBoard(const InitInfo& init_info);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct TerrainTile {
|
|
||||||
TileType type;
|
|
||||||
std::int32_t unit;
|
|
||||||
};
|
|
||||||
pos_t w, h;
|
|
||||||
std::vector<std::vector<TerrainTile>> tiles;
|
|
||||||
std::vector<std::vector<std::vector<Point>>> capitals;
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportedTerrain importTerrain(const ImportTerrainConfig& in);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,47 +0,0 @@
|
|||||||
#include "BinaryBuffer.h"
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
BinaryBuffer::BinaryBuffer() {}
|
|
||||||
|
|
||||||
BinaryBuffer::BinaryBuffer(std::size_t n, const byte *buf) {
|
|
||||||
for (std::size_t i = 0; i < n; ++i)
|
|
||||||
data.push_back(buf[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
BinaryBuffer& BinaryBuffer::operator<<(const std::string_view& x) {
|
|
||||||
std::uint32_t len = x.size();
|
|
||||||
*this << len;
|
|
||||||
for (char c : x)
|
|
||||||
*this << c;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BinaryBuffer& BinaryBuffer::operator>>(std::string& x) {
|
|
||||||
std::uint32_t len;
|
|
||||||
*this >> len;
|
|
||||||
x.resize(len);
|
|
||||||
for (char& c : x)
|
|
||||||
*this >> c;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t BinaryBuffer::size() const {
|
|
||||||
return data.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BinaryBuffer::empty() const {
|
|
||||||
return data.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &out, const BinaryBuffer &x) {
|
|
||||||
for (auto v : x.data)
|
|
||||||
out.put(v);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinaryBuffer::writeTo(std::FILE *out) const {
|
|
||||||
auto sz = size();
|
|
||||||
for (std::size_t i = 0; i < sz; ++i)
|
|
||||||
fputc(data[i], out);
|
|
||||||
}
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
|||||||
#ifndef OG_BINARY_BUFFER_H_
|
|
||||||
#define OG_BINARY_BUFFER_H_
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <tuple>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <deque>
|
|
||||||
#include <concepts>
|
|
||||||
#include <string_view>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using byte = unsigned char;
|
|
||||||
|
|
||||||
inline namespace {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept IsTupleLike = requires(T t) {
|
|
||||||
std::tuple_size<T>::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept IsBasicType = std::integral<T> || std::is_enum<T>::value
|
|
||||||
|| std::same_as<T, float> || std::same_as<T, double>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept IsTupleConvertable = requires(T t) {
|
|
||||||
IsTupleLike<decltype(t.asTuple())>;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(IsTupleLike<std::tuple<int, int, int>>);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class BinaryBuffer {
|
|
||||||
public:
|
|
||||||
BinaryBuffer();
|
|
||||||
BinaryBuffer(std::size_t n, const byte *buf);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
requires IsBasicType<T>
|
|
||||||
BinaryBuffer& operator>>(T& x) {
|
|
||||||
if (sizeof(T) <= data.size()) {
|
|
||||||
auto ptr = reinterpret_cast<byte*>(&x);
|
|
||||||
for (std::size_t i = 0; i < sizeof(T); ++i) {
|
|
||||||
ptr[i] = data.front();
|
|
||||||
data.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
requires IsBasicType<T>
|
|
||||||
BinaryBuffer& operator<<(const T& x) {
|
|
||||||
auto ptr = reinterpret_cast<const byte*>(&x);
|
|
||||||
for (std::size_t i = 0; i < sizeof(T); ++i) {
|
|
||||||
data.push_back(ptr[i]);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
BinaryBuffer& operator<<(const std::vector<T>& x) {
|
|
||||||
uint32_t len = x.size();
|
|
||||||
*this << len;
|
|
||||||
for (const T& element : x)
|
|
||||||
*this << element;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
BinaryBuffer& operator>>(std::vector<T>& x) {
|
|
||||||
uint32_t len;
|
|
||||||
*this >> len;
|
|
||||||
x.resize(len);
|
|
||||||
for (std::uint32_t i = 0; i < len; ++i)
|
|
||||||
*this >> x[i];
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
requires IsTupleLike<T>
|
|
||||||
BinaryBuffer& operator<<(const T& x) {
|
|
||||||
std::apply([this](const auto&... elements) {
|
|
||||||
(*this << ... << elements);
|
|
||||||
}, x);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
requires IsTupleLike<T>
|
|
||||||
BinaryBuffer& operator>>(T& x) {
|
|
||||||
std::apply([this](auto&... elements) {
|
|
||||||
(*this >> ... >> elements);
|
|
||||||
}, x);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
requires IsTupleConvertable<T>
|
|
||||||
BinaryBuffer& operator<<(const T &x) {
|
|
||||||
*this << x.asTuple();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
requires IsTupleConvertable<T>
|
|
||||||
BinaryBuffer& operator>>(T &x) {
|
|
||||||
*this >> x.asTuple();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BinaryBuffer& operator<<(const std::string_view &);
|
|
||||||
BinaryBuffer& operator>>(std::string&);
|
|
||||||
|
|
||||||
std::size_t size() const;
|
|
||||||
bool empty() const;
|
|
||||||
void writeTo(std::FILE *out) const;
|
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream &, const BinaryBuffer &);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::deque<byte> data;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &, const BinaryBuffer &);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
|||||||
#include "Point.h"
|
|
||||||
|
|
||||||
Point::Point() : x(0), y(0) {}
|
|
||||||
|
|
||||||
Point::Point(pos_t x, pos_t y) : x(x), y(y) {}
|
|
||||||
|
|
||||||
bool Point::operator<(const Point &o) const {
|
|
||||||
return x == o.x ? y < o.y : x < o.x;
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
#ifndef OGPC_POINT_H_
|
|
||||||
#define OGPC_POINT_H_
|
|
||||||
|
|
||||||
#include "basictypes.h"
|
|
||||||
#include "astuple.h"
|
|
||||||
|
|
||||||
struct Point {
|
|
||||||
pos_t x, y;
|
|
||||||
Point(pos_t x, pos_t y);
|
|
||||||
Point();
|
|
||||||
|
|
||||||
bool operator<(const Point &o) const;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(x, y);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
#include "ProcedureManager.h"
|
|
||||||
|
|
||||||
ProcedureManager::ProcedureManager() {}
|
|
||||||
|
|
||||||
struct ProcedureCallHeader {
|
|
||||||
uint64_t rd;
|
|
||||||
int32_t method;
|
|
||||||
uint32_t len;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProcedureReturnHeader {
|
|
||||||
uint64_t rd;
|
|
||||||
uint32_t len;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ProcedureManager::handleCall(FILE *in, FILE *out) const {
|
|
||||||
ProcedureCallHeader header;
|
|
||||||
auto ptr = reinterpret_cast<byte*>(&header);
|
|
||||||
std::size_t sz = 0;
|
|
||||||
while (sz < sizeof(header))
|
|
||||||
sz += fread(ptr + sz, 1, sizeof(header) - sz, in);
|
|
||||||
|
|
||||||
auto buf = new byte[header.len];
|
|
||||||
sz = 0;
|
|
||||||
while (sz < header.len)
|
|
||||||
sz += fread(buf + sz, 1, header.len - sz, in);
|
|
||||||
|
|
||||||
BinaryBuffer bb(header.len, buf);
|
|
||||||
delete[] buf;
|
|
||||||
if (procedures.count(header.method)) {
|
|
||||||
auto res = procedures.at(header.method)(bb);
|
|
||||||
ProcedureReturnHeader rh;
|
|
||||||
rh.rd = header.rd;
|
|
||||||
rh.len = header.len;
|
|
||||||
fwrite(&rh, 1, sizeof(rh), out);
|
|
||||||
res.writeTo(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
|||||||
#ifndef OGPC_PMANAGER_H_
|
|
||||||
#define OGPC_PMANAGER_H_
|
|
||||||
|
|
||||||
#include "BinaryBuffer.h"
|
|
||||||
#include <map>
|
|
||||||
#include <functional>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <tuple>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
inline namespace {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct FuncArgTraits;
|
|
||||||
|
|
||||||
template <typename R, typename... T>
|
|
||||||
struct FuncArgTraits<R(*)(T...)> {
|
|
||||||
using type = std::tuple<T...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename R, typename... T>
|
|
||||||
struct FuncArgTraits<std::function<R(T...)>> {
|
|
||||||
using type = std::tuple<T...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Callable>
|
|
||||||
struct FuncArgTraits : FuncArgTraits<decltype(&Callable::operator())> {};
|
|
||||||
|
|
||||||
template <typename ReturnType, typename ClassType, typename... Args>
|
|
||||||
struct FuncArgTraits<ReturnType(ClassType::*)(Args...) const> {
|
|
||||||
using type = std::tuple<Args...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class ProcedureManager {
|
|
||||||
public:
|
|
||||||
ProcedureManager();
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void registerProcedure(const std::uint32_t &id, T&& func) {
|
|
||||||
procedures[id] = [&func](BinaryBuffer &b) -> BinaryBuffer {
|
|
||||||
using Arg = typename FuncArgTraits<typename std::decay<T>::type>::type;
|
|
||||||
Arg x;
|
|
||||||
b >> x;
|
|
||||||
auto y = std::apply(func, std::move(x));
|
|
||||||
BinaryBuffer res;
|
|
||||||
res << y;
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleCall(FILE *in, FILE *out) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<std::uint32_t, std::function<BinaryBuffer(BinaryBuffer&)>> procedures;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
#ifndef OGPC_PROCEDURETYPE_H_
|
|
||||||
#define OGPC_PROCEDURETYPE_H_
|
|
||||||
|
|
||||||
enum class ProcedureType : std::int32_t {
|
|
||||||
setSeed = 0,
|
|
||||||
setLogLevel = 1,
|
|
||||||
getError = 2,
|
|
||||||
getErrorInfo = 3,
|
|
||||||
importTerrain = 10,
|
|
||||||
randomTerrain = 11,
|
|
||||||
appendOrderQueue = 20,
|
|
||||||
clearOrderQueue = 21,
|
|
||||||
popOrderQueue = 22,
|
|
||||||
setOffline = 23,
|
|
||||||
init = 30,
|
|
||||||
tick = 31,
|
|
||||||
getKeyFrame = 40,
|
|
||||||
saveReplay = 50,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
|||||||
#ifndef OGPC_ASTUPLE_H_
|
|
||||||
#define OGPC_ASTUPLE_H_
|
|
||||||
|
|
||||||
#include "utility/macros.h"
|
|
||||||
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_1(x) decltype(x)&
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_2(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_1(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_3(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_2(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_4(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_3(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_5(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_4(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_6(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_5(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_7(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_6(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_8(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_7(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_9(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_8(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_10(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_9(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_11(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_10(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_12(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_11(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_13(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_12(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_14(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_13(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_15(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_14(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE_16(x, ...) decltype(x)&, OGPC_T__AS_DECLARETYPE_15(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_DECLARETYPE(...) OG_M_CONCAT(OGPC_T__AS_DECLARETYPE_, OG_M_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)
|
|
||||||
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_1(x) const decltype(x)&
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_2(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_1(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_3(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_2(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_4(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_3(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_5(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_4(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_6(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_5(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_7(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_6(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_8(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_7(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_9(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_8(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_10(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_9(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_11(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_10(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_12(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_11(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_13(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_12(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_14(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_13(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_15(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_14(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE_16(x, ...) const decltype(x)&, OGPC_T__AS_CONST_DECLARETYPE_15(__VA_ARGS__)
|
|
||||||
#define OGPC_T__AS_CONST_DECLARETYPE(...) OG_M_CONCAT(OGPC_T__AS_CONST_DECLARETYPE_, OG_M_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)
|
|
||||||
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
#define OGPC_DECLARE_ASTUPLE(...) \
|
|
||||||
std::tuple<OGPC_T__AS_DECLARETYPE(__VA_ARGS__)> asTuple() { \
|
|
||||||
return {__VA_ARGS__}; \
|
|
||||||
}\
|
|
||||||
std::tuple<OGPC_T__AS_CONST_DECLARETYPE(__VA_ARGS__)> asTuple() const { \
|
|
||||||
return {__VA_ARGS__}; \
|
|
||||||
}\
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
#ifndef OGPC_BASICTYPES_H_
|
|
||||||
#define OGPC_BASICTYPES_H_
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
using Player = std::uint8_t;
|
|
||||||
using Team = std::uint8_t;
|
|
||||||
using pos_t = std::uint8_t;
|
|
||||||
using Void = std::tuple<>;
|
|
||||||
|
|
||||||
const Player neutral_player = 0;
|
|
||||||
const Team neutral_team = 0;
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,48 +0,0 @@
|
|||||||
#ifndef OGPC_COMMCODE_H_
|
|
||||||
#define OGPC_COMMCODE_H_
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
enum class Direction : std::uint8_t {
|
|
||||||
N = 0x00,
|
|
||||||
S = 0x01,
|
|
||||||
W = 0x02,
|
|
||||||
E = 0x03,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr int direction_dx[] = {-1, 1, 0, 0};
|
|
||||||
constexpr int direction_dy[] = {0, 0, -1, 1};
|
|
||||||
|
|
||||||
enum class LogLevel : std::uint8_t {
|
|
||||||
Debug = 0x00,
|
|
||||||
Info = 0x01,
|
|
||||||
Warn = 0x02,
|
|
||||||
Error = 0x03,
|
|
||||||
Fatal = 0x04,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class TileType : std::uint8_t {
|
|
||||||
Misty = 0x00,
|
|
||||||
Mountain = 0x01,
|
|
||||||
Stronghold = 0x02,
|
|
||||||
Blank = 0x03,
|
|
||||||
Capital = 0x04,
|
|
||||||
Swamp = 0x05,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class MistyTileType : std::uint8_t {
|
|
||||||
MountainLike = 0x01,
|
|
||||||
BlankLike = 0x02,
|
|
||||||
Swamp = 0x03,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ModifierType : std::uint8_t {
|
|
||||||
Leapfrog = 0x01,
|
|
||||||
CityState = 0x02,
|
|
||||||
MistyVeil = 0x03,
|
|
||||||
CrystalClear = 0x04,
|
|
||||||
SilentWar = 0x05,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
#include "pctypes.h"
|
|
||||||
|
|
||||||
PlayerRanking::PlayerRanking() : player(neutral_player)
|
|
||||||
, is_defeated(false), land(0), unit(0) {}
|
|
||||||
|
|
||||||
TeamRanking::TeamRanking() : team(neutral_team), land(0), unit(0) {}
|
|
||||||
|
|
||||||
Tile::Tile() : owner(neutral_player), type(TileType::Misty), unit(0) {}
|
|
||||||
|
|
@ -1,147 +0,0 @@
|
|||||||
#ifndef OGPC_PCTYPES_H_
|
|
||||||
#define OGPC_PCTYPES_H_
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include "basictypes.h"
|
|
||||||
#include "astuple.h"
|
|
||||||
#include "commcode.h"
|
|
||||||
#include "Point.h"
|
|
||||||
|
|
||||||
struct uuid {
|
|
||||||
std::uint64_t low, high;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(low, high)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ImportTerrainConfig {
|
|
||||||
pos_t w, h;
|
|
||||||
std::string value;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(w, h, value)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RandomTerrainConfig {
|
|
||||||
pos_t w, h;
|
|
||||||
std::uint8_t city_dense, mountain_dense, swamp_dense, light_dense;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(w, h, city_dense, mountain_dense, swamp_dense, light_dense)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PlayerRanking {
|
|
||||||
Player player;
|
|
||||||
bool is_defeated;
|
|
||||||
std::uint16_t land;
|
|
||||||
std::int32_t unit;
|
|
||||||
|
|
||||||
PlayerRanking();
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(player, is_defeated, land, unit)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TeamRanking {
|
|
||||||
Team team;
|
|
||||||
std::uint16_t land;
|
|
||||||
std::int32_t unit;
|
|
||||||
std::vector<PlayerRanking> players;
|
|
||||||
|
|
||||||
TeamRanking();
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(team, land, unit, players)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Tile {
|
|
||||||
Player owner;
|
|
||||||
TileType type;
|
|
||||||
std::int32_t unit;
|
|
||||||
|
|
||||||
Tile();
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(owner, type, unit)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TileDiff {
|
|
||||||
pos_t x, y;
|
|
||||||
Tile value;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(x, y, value)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TeamViewDiff {
|
|
||||||
Team team;
|
|
||||||
std::vector<TileDiff> diffs;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(team, diffs)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GameState {
|
|
||||||
std::uint32_t halfturn_id;
|
|
||||||
std::vector<Player> defeated_players;
|
|
||||||
std::vector<Player> alive_players;
|
|
||||||
std::vector<TeamRanking> leaderboard;
|
|
||||||
std::vector<TeamViewDiff> diffs;
|
|
||||||
std::vector<std::string> msg;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(halfturn_id, defeated_players, alive_players, leaderboard, diffs, msg)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Modifier {
|
|
||||||
ModifierType key;
|
|
||||||
std::int32_t value;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(key, value)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PlayerMove;
|
|
||||||
|
|
||||||
struct ReplayStep {
|
|
||||||
std::uint32_t halfturn_id;
|
|
||||||
std::vector<PlayerMove> player_moves;
|
|
||||||
std::vector<Player> offline_events;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(halfturn_id, player_moves, offline_events)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PlayerInfo {
|
|
||||||
uuid uid;
|
|
||||||
Player id;
|
|
||||||
Team team;
|
|
||||||
std::string name;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(uid, id, team, name)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct InitInfo {
|
|
||||||
std::uint8_t n;
|
|
||||||
std::vector<Player> player_team;
|
|
||||||
std::vector<Modifier> modifiers;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(n, player_team, modifiers)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Replay {
|
|
||||||
uuid rid;
|
|
||||||
std::uint64_t timestamp;
|
|
||||||
std::int8_t speed;
|
|
||||||
InitInfo init_info;
|
|
||||||
std::uint32_t length;
|
|
||||||
std::uint8_t player_num;
|
|
||||||
std::vector<PlayerInfo> players;
|
|
||||||
Team winner;
|
|
||||||
std::vector<Tile> terrain;
|
|
||||||
std::vector<ReplayStep> steps;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(rid, timestamp, speed, init_info, length, player_num, players, winner, terrain, steps)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GameInfo {
|
|
||||||
uuid rid;
|
|
||||||
std::int8_t speed;
|
|
||||||
std::vector<PlayerInfo> players;
|
|
||||||
|
|
||||||
OGPC_DECLARE_ASTUPLE(rid, speed, players)
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
|||||||
#include "pc/BinaryBuffer.h"
|
|
||||||
#include "pc/astuple.h"
|
|
||||||
#include "test/u.hpp"
|
|
||||||
|
|
||||||
inline namespace {
|
|
||||||
|
|
||||||
struct Point {
|
|
||||||
int x, y, z;
|
|
||||||
OGPC_DECLARE_ASTUPLE(x, y, z);
|
|
||||||
};
|
|
||||||
|
|
||||||
AddTestCase _(10, "BinaryBuffer", [](TestCase& t) {
|
|
||||||
t.expectEq<int>([] {
|
|
||||||
BinaryBuffer bb;
|
|
||||||
int x, y = 10;
|
|
||||||
bb << y;
|
|
||||||
bb >> x;
|
|
||||||
return x;
|
|
||||||
}, 10);
|
|
||||||
|
|
||||||
t.expectEq<std::tuple<int, int, int>>([] {
|
|
||||||
BinaryBuffer bb;
|
|
||||||
Point x{1, 2, 4};
|
|
||||||
std::tuple<int, int, int> y;
|
|
||||||
bb << x;
|
|
||||||
bb >> y;
|
|
||||||
return y;
|
|
||||||
}, {1, 2, 4});
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
#include "pc/ProcedureManager.h"
|
|
||||||
#include "pc/BinaryBuffer.h"
|
|
||||||
#include "test/u.hpp"
|
|
||||||
#include <tuple>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
inline namespace {
|
|
||||||
|
|
||||||
using Void = std::tuple<>;
|
|
||||||
|
|
||||||
AddTestCase _(20, "ProcedureManager", [](TestCase& t) {
|
|
||||||
t.expectEq<int>([] {
|
|
||||||
std::int32_t x = 0;
|
|
||||||
auto f1 = [&x] (std::int32_t d) -> Void {
|
|
||||||
x += d;
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
auto f2 = [&x] (std::int32_t d) -> Void {
|
|
||||||
x -= d;
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcedureManager pm;
|
|
||||||
pm.registerProcedure(1, f1);
|
|
||||||
pm.registerProcedure(2, f2);
|
|
||||||
|
|
||||||
unsigned char ibuf[256] = {
|
|
||||||
0x45, 0x27, 0xd1, 0xf2, 0x93, 0x43, 0xfc, 0xb1,
|
|
||||||
0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x04, 0x00, 0x00, 0x00,
|
|
||||||
0x02, 0x00, 0x00, 0x00,
|
|
||||||
0x45, 0x27, 0xd1, 0xf2, 0x93, 0x43, 0xfc, 0xb2,
|
|
||||||
0x02, 0x00, 0x00, 0x00,
|
|
||||||
0x04, 0x00, 0x00, 0x00,
|
|
||||||
0x01, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
FILE *in = fopen(".in.tmp", "wb");
|
|
||||||
fwrite(ibuf, 128, 1, in);
|
|
||||||
fclose(in);
|
|
||||||
in = fopen(".in.tmp", "rb");
|
|
||||||
FILE *out = fopen(".out.tmp", "wb");
|
|
||||||
|
|
||||||
pm.handleCall(in, out);
|
|
||||||
pm.handleCall(in, out);
|
|
||||||
fclose(in);
|
|
||||||
fclose(out);
|
|
||||||
return x;
|
|
||||||
}, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
|||||||
#include "test/u.hpp"
|
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
AddTestCase _(0, "tester", [](TestCase& t) {
|
|
||||||
t.expectTrue([] { return true; });
|
|
||||||
t.expectFalse([] { return false; });
|
|
||||||
t.expectTrue([] {
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
t.expectEq<int>([] { return 42; }, 42);
|
|
||||||
t.expectEq<float>([] { return 10 + 1e-7; }, 10);
|
|
||||||
t.expectEq<double>([] { return 10 + 1e-10; }, 10);
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
#include "test/u.hpp"
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
return TestSuit::getInstance()->evalTestCases();
|
|
||||||
}
|
|
@ -1,205 +0,0 @@
|
|||||||
#ifndef HEADER_TEST_U_HPP
|
|
||||||
#define HEADER_TEST_U_HPP
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <exception>
|
|
||||||
#include <functional>
|
|
||||||
#include <optional>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <tuple>
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct TestDefaultEps {};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct TestDefaultEps<float> {
|
|
||||||
static constexpr float value = 1e-6;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct TestDefaultEps<double> {
|
|
||||||
static constexpr double value = 1e-9;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct TestDefaultEps<long double> {
|
|
||||||
static constexpr long double value = 1e-12;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestCase {
|
|
||||||
public:
|
|
||||||
TestCase(int id, const char* title): ok(0), fail(0), n(0), ended(false), time_used(0) {
|
|
||||||
std::printf("[%02d]Testing %s:\n", id, title);
|
|
||||||
}
|
|
||||||
|
|
||||||
void expectTrue(std::function<bool()> func) noexcept {
|
|
||||||
expectEq<bool>(func, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void expectFalse(std::function<bool()> func) noexcept {
|
|
||||||
expectEq<bool>(func, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename EPS = TestDefaultEps<T>>
|
|
||||||
typename std::enable_if<std::is_floating_point<T>::value>::type expectEq(
|
|
||||||
std::function<T()> func,
|
|
||||||
T&& answer) noexcept {
|
|
||||||
auto res = runTask(func);
|
|
||||||
if (!res.has_value()) {
|
|
||||||
return onError();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std::abs(res.value() - answer) < EPS::value) {
|
|
||||||
onPass();
|
|
||||||
} else {
|
|
||||||
onFail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename std::enable_if<!std::is_floating_point<T>::value>::type expectEq(
|
|
||||||
std::function<T()> func,
|
|
||||||
T&& answer) noexcept {
|
|
||||||
auto res = runTask(func);
|
|
||||||
if (!res.has_value()) {
|
|
||||||
return onError();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.value() == answer) {
|
|
||||||
onPass();
|
|
||||||
} else {
|
|
||||||
onFail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void end() noexcept {
|
|
||||||
if (ended) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ended = true;
|
|
||||||
|
|
||||||
std::putchar('\n');
|
|
||||||
for (int i = 0; i < 20; ++i) {
|
|
||||||
std::putchar('-');
|
|
||||||
}
|
|
||||||
std::putchar('\n');
|
|
||||||
if (fail) {
|
|
||||||
if (fail == 1) {
|
|
||||||
std::puts("1 test failed.");
|
|
||||||
} else {
|
|
||||||
std::printf("%d tests failed.\n", fail);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ok == 1) {
|
|
||||||
std::printf("OK. 1 test passed");
|
|
||||||
} else {
|
|
||||||
std::printf("OK. %d tests passed", ok);
|
|
||||||
}
|
|
||||||
std::printf(" in %lldms.\n", static_cast<long long>(time_used.count()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasFail() const noexcept {
|
|
||||||
return fail > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void putchar(char c) noexcept {
|
|
||||||
n += 1;
|
|
||||||
if (n > 1 && n % 15 == 1) {
|
|
||||||
std::putchar('\n');
|
|
||||||
}
|
|
||||||
std::putchar(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onPass() noexcept {
|
|
||||||
ok += 1;
|
|
||||||
putchar('.');
|
|
||||||
}
|
|
||||||
|
|
||||||
void onFail() noexcept {
|
|
||||||
fail += 1;
|
|
||||||
putchar('F');
|
|
||||||
}
|
|
||||||
|
|
||||||
void onError() noexcept {
|
|
||||||
fail += 1;
|
|
||||||
putchar('E');
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
std::optional<T> runTask(std::function<T()> func) noexcept {
|
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
|
||||||
try {
|
|
||||||
T res = func();
|
|
||||||
auto end = std::chrono::high_resolution_clock::now();
|
|
||||||
auto dt = end - start;
|
|
||||||
time_used += std::chrono::duration_cast<std::chrono::milliseconds>(dt);
|
|
||||||
return {res};
|
|
||||||
} catch (...) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ok, fail, n;
|
|
||||||
bool ended;
|
|
||||||
std::chrono::milliseconds time_used;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestSuit {
|
|
||||||
TestSuit(const TestSuit&) = delete;
|
|
||||||
TestSuit(TestSuit&&) = delete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static TestSuit* getInstance() {
|
|
||||||
if (!instance) {
|
|
||||||
instance = new TestSuit();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addTestCase(int id, const char* title, std::function<void(TestCase&)> f) {
|
|
||||||
tc.emplace_back(id, title, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
int evalTestCases() {
|
|
||||||
std::sort(tc.begin(), tc.end(), [](const auto &x, const auto &y) {
|
|
||||||
return std::get<0>(x) < std::get<0>(y);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (auto [id, title, func] : tc) {
|
|
||||||
TestCase t(id, title);
|
|
||||||
func(t);
|
|
||||||
t.end();
|
|
||||||
std::putchar('\n');
|
|
||||||
if (t.hasFail()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tc.clear();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static inline TestSuit* instance = nullptr;
|
|
||||||
TestSuit() {}
|
|
||||||
|
|
||||||
std::vector<std::tuple<int, const char*, std::function<void(TestCase&)>>> tc;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AddTestCase {
|
|
||||||
AddTestCase() = delete;
|
|
||||||
AddTestCase(const AddTestCase&) = delete;
|
|
||||||
AddTestCase(AddTestCase&&) = delete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AddTestCase(int id, const char* tilte, std::function<void(TestCase&)> func) {
|
|
||||||
TestSuit::getInstance()->addTestCase(id, tilte, func);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // HEADER_TEST_U_HPP
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
|||||||
#include "log.h"
|
|
||||||
#include <cstdio>
|
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
Logger* Logger::getInstance() {
|
|
||||||
return instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::debug(const std::string& s) const {
|
|
||||||
_log(LogLevel::Debug, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::info(const std::string& s) const {
|
|
||||||
_log(LogLevel::Info, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::warn(const std::string& s) const {
|
|
||||||
_log(LogLevel::Warn, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::error(const std::string& s) const {
|
|
||||||
_log(LogLevel::Error, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::fatal(const std::string& s) const {
|
|
||||||
_log(LogLevel::Fatal, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::setLogLeval(LogLevel v) {
|
|
||||||
filter = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::Logger() {
|
|
||||||
filter = LogLevel::Warn;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger* const Logger::instance_ = new Logger();
|
|
||||||
|
|
||||||
void Logger::_log(LogLevel v, const std::string& s) const {
|
|
||||||
if (v >= filter) {
|
|
||||||
time_t now = time(NULL);
|
|
||||||
static char buff[100];
|
|
||||||
strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", localtime(&now));
|
|
||||||
const char* mp = "DIWEF";
|
|
||||||
fprintf(stderr, "%s [%c] %s\n", buff, mp[(int)v], s.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger* Log() {
|
|
||||||
return Logger::getInstance();
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
#ifndef OG_LOG_H_
|
|
||||||
#define OG_LOG_H_
|
|
||||||
|
|
||||||
#include "pc/commcode.h"
|
|
||||||
#include <cstdio>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class Logger {
|
|
||||||
public:
|
|
||||||
static Logger* getInstance();
|
|
||||||
|
|
||||||
void debug(const std::string&) const;
|
|
||||||
void info(const std::string&) const;
|
|
||||||
void warn(const std::string&) const;
|
|
||||||
void error(const std::string&) const;
|
|
||||||
void fatal(const std::string&) const;
|
|
||||||
void setLogLeval(LogLevel v);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Logger();
|
|
||||||
static Logger* const instance_;
|
|
||||||
|
|
||||||
void _log(LogLevel v, const std::string&) const;
|
|
||||||
|
|
||||||
LogLevel filter;
|
|
||||||
};
|
|
||||||
|
|
||||||
Logger* Log();
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,27 +0,0 @@
|
|||||||
#ifndef OG_MACROS_H_
|
|
||||||
#define OG_MACROS_H_
|
|
||||||
|
|
||||||
#define OG_M_ARG_COUNT__( \
|
|
||||||
_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
|
||||||
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
|
|
||||||
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
|
|
||||||
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
|
|
||||||
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
|
|
||||||
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
|
|
||||||
_61, _62, _63, N, ...) \
|
|
||||||
N
|
|
||||||
|
|
||||||
#define OG_M_ARG_COUNT(...) OG_M_ARG_COUNT__(__VA_ARGS__ \
|
|
||||||
, 63, 62, 61, 60, \
|
|
||||||
59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \
|
|
||||||
49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
|
|
||||||
39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \
|
|
||||||
29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
|
|
||||||
19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
|
|
||||||
9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
|
||||||
|
|
||||||
#define OG_M_CONCAT__(a, b) a##b
|
|
||||||
#define OG_M_CONCAT(a, b) OG_M_CONCAT__(a, b)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
set_project("opengenerals-processor")
|
|
||||||
set_basename("ogprocessor")
|
|
||||||
set_version("0.1.0")
|
|
||||||
set_languages("c++20")
|
|
||||||
set_targetdir("build")
|
|
||||||
|
|
||||||
add_includedirs(".", "pc", "utility", "logic")
|
|
||||||
|
|
||||||
add_files("pc/*.cpp", "utility/*.cpp", "logic/*.cpp")
|
|
||||||
target("main")
|
|
||||||
set_default(true)
|
|
||||||
set_kind("binary")
|
|
||||||
add_files("main.cpp")
|
|
||||||
set_warnings("allextra")
|
|
||||||
|
|
||||||
target("test")
|
|
||||||
set_default(false)
|
|
||||||
set_kind("binary")
|
|
||||||
set_prefixname("test-")
|
|
||||||
|
|
||||||
add_files("test/**/*.cpp")
|
|
||||||
add_files("test/main.cpp")
|
|
||||||
|
|
||||||
set_warnings("allextra")
|
|
||||||
set_optimize("none")
|
|
||||||
set_symbols("debug")
|
|
||||||
add_defines("DEBUG")
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user