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