This commit is contained in:
方而静 2024-03-05 12:11:17 +08:00
parent f2434a5953
commit 8f94811cb0
Signed by: szTom
GPG Key ID: 072D999D60C6473C
28 changed files with 0 additions and 2020 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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];
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {}

View File

@ -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

View File

@ -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});
});
}

View File

@ -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);
});
}

View File

@ -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);
});
}

View File

@ -1,5 +0,0 @@
#include "test/u.hpp"
int main() {
return TestSuit::getInstance()->evalTestCases();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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")