完成地图导入部分(未验证)
This commit is contained in:
parent
1df4cfd9bb
commit
97fbd11f8a
194
processor/logic/terrain.cpp
Normal file
194
processor/logic/terrain.cpp
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#include "terrain.h"
|
||||||
|
#include <random>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
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;}
|
||||||
|
pair<bool,vector<Point>> generateCapital(pos_t w,pos_t h,vector<vector<VertexType>> &vertex_type,int r){
|
||||||
|
auto findCut=[&](){
|
||||||
|
int idx=0; vector<vector<int>> dfn(h,vector<int>(w)),low=dfn;
|
||||||
|
function<void(int,int,int,int,bool)> tarjan=[&](int x,int y,int fx,int fy,bool rt){
|
||||||
|
dfn[x][y]=low[x][y]=++idx;
|
||||||
|
int ch=0;
|
||||||
|
for(int i=0;i<4;i++){
|
||||||
|
static const int dx[]={0,0,-1,1},dy[]={-1,1,0,0};
|
||||||
|
const int xx=x+dx[i],yy=y+dy[i];
|
||||||
|
if(xx<0||xx>=h||yy<0||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=0;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
vector<Point> res(r);
|
||||||
|
for(int i=0;i<=r;i++){
|
||||||
|
if(!findCut()) 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,vector<Point>()};
|
||||||
|
res[i]=options[rnd()%options.size()];
|
||||||
|
vertex_type[res[i].x][res[i].y]=VertexType::Capital;
|
||||||
|
}
|
||||||
|
return {true,res};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
for(pos_t i=0;i<h;i++){
|
||||||
|
for(pos_t j=0;j<w;j++){
|
||||||
|
g.at(i,j).type=tiles[i][j].type;
|
||||||
|
g.at(i,j).unit=tiles[i][j].unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto arrange=[&perm,&g](const vector<Player> &players,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.at(caps[D[j]].x,caps[D[j]].y).owner=players[C[j]];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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);
|
||||||
|
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.at(pr.second[i].x,pr.second[i].y).owner=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;
|
||||||
|
};
|
||||||
|
static vector<Point> vec[27][101];
|
||||||
|
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;
|
||||||
|
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();
|
||||||
|
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;
|
||||||
|
}
|
42
processor/logic/terrain.h
Normal file
42
processor/logic/terrain.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef OGLG_TERRAIN_H_
|
||||||
|
#define OGLG_TERRAIN_H_
|
||||||
|
|
||||||
|
#include "pc/Point.h"
|
||||||
|
#include "pc/pctypes.h"
|
||||||
|
#include "pc/commcode.h"
|
||||||
|
#include "logic/GameBoard.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
class BadImportTerrainConfig:std::exception{
|
||||||
|
public:
|
||||||
|
BadImportTerrainConfig(size_t);
|
||||||
|
~BadImportTerrainConfig()=default;
|
||||||
|
const char* what() const noexcept;
|
||||||
|
private:
|
||||||
|
size_t pt;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BadCapitalAssign:std::exception{
|
||||||
|
public:
|
||||||
|
~BadCapitalAssign()=default;
|
||||||
|
const char* what() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
@ -4,7 +4,7 @@ set_version("0.1.0")
|
|||||||
set_languages("c++20")
|
set_languages("c++20")
|
||||||
set_targetdir("build")
|
set_targetdir("build")
|
||||||
|
|
||||||
add_includedirs(".", "pc", "utility")
|
add_includedirs(".", "pc", "utility", "logic")
|
||||||
|
|
||||||
add_files("pc/*.cpp", "utility/*.cpp", "logic/*.cpp")
|
add_files("pc/*.cpp", "utility/*.cpp", "logic/*.cpp")
|
||||||
target("main")
|
target("main")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user