hyperrogue/rogueviz/rewriting.cpp

193 lines
4.7 KiB
C++
Raw Permalink Normal View History

2020-01-18 23:34:38 +00:00
// Hyperbolic Rogue -- infinite-order tessellations
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
/** \file inforder3.cpp
* \brief infinite-order tessellations
*
* very simple
*/
#include "../hyper.h"
namespace hr {
namespace rewriting {
bool symmetric;
string start;
vector<pair<string, string> > rules;
2020-01-19 10:50:04 +00:00
set<pair<string, string> > ruleset;
2020-01-18 23:34:38 +00:00
2020-01-19 20:52:14 +00:00
map<string, int> find_matches(string s) {
map<string, int> res;
2020-01-18 23:34:38 +00:00
for(auto& p: rules) {
size_t next = s.find(p.first);
while(next != string::npos) {
2020-01-19 20:52:14 +00:00
string t = s.substr(0, next) + p.second + s.substr(next+isize(p.first));
auto& r = res[t];
if(ruleset.count({p.second, p.first})) r = 2;
else r = max(r, 1);
2020-01-18 23:34:38 +00:00
next = s.find(p.first, next+1);
}
}
return res;
}
struct hrmap_rewrite : hrmap_hyperbolic {
2020-01-19 20:52:14 +00:00
map<heptagon*, pair<heptagon*, string> > asg;
map<pair<heptagon*, string>, heptagon*> asg_rev;
2020-01-18 23:34:38 +00:00
2022-07-05 17:19:39 +00:00
heptagon *create_step(heptagon *h, int direction) override {
2020-01-18 23:34:38 +00:00
if(h->move(direction)) return h->move(direction);
2020-01-19 20:52:14 +00:00
if(asg.empty()) { asg[h] = {h, start}; h->zebraval = 0; }
2020-01-18 23:34:38 +00:00
2020-01-19 20:52:14 +00:00
auto s = asg[h].second;
auto root = asg[h].first;
auto matches = find_matches(s);
2020-01-18 23:34:38 +00:00
2020-01-19 10:50:04 +00:00
int next = h->zebraval;
2020-01-18 23:34:38 +00:00
2020-01-19 10:50:04 +00:00
if(matches.empty() && next == 0) {
h->c.connect(0, h, 0, false);
return h;
}
2020-01-19 20:52:14 +00:00
for(auto& match: matches) {
2020-01-19 10:50:04 +00:00
if(h->move(next)) { next++; continue; }
2020-01-19 20:52:14 +00:00
bool symmetric = match.second == 2;
const string& m = match.first;
2020-01-18 23:34:38 +00:00
if(symmetric) {
auto matches1 = find_matches(m);
heptagon *h1;
2020-01-19 20:52:14 +00:00
if(asg_rev[{root, m}]) h1 = asg_rev[{root, m}];
2020-01-18 23:34:38 +00:00
else {
h1 = tailored_alloc<heptagon> (isize(matches1));
h1->alt = NULL;
h1->s = hsA;
h1->cdata = NULL;
2020-01-19 10:50:04 +00:00
h1->distance = h->distance;
h1->zebraval = 0;
2020-01-18 23:34:38 +00:00
h1->c7 = newCell(isize(matches1), h1);
2020-01-19 20:52:14 +00:00
asg[h1] = {root, m};
asg_rev[{root, m}] = h1;
2020-01-18 23:34:38 +00:00
}
int next1 = 0;
2020-01-19 20:52:14 +00:00
for(auto& match2: matches1) { if(match2.first == s) break; next1++; }
2020-01-18 23:34:38 +00:00
h->c.connect(next, h1, next1, false);
}
else {
int deg = 1 + isize(find_matches(m));
auto h1 = tailored_alloc<heptagon> (deg);
h->c.connect(next, h1, 0, false);
h1->alt = NULL;
h1->s = hsA;
h1->cdata = NULL;
h1->distance = h->distance + 1;
2020-01-19 10:50:04 +00:00
h1->zebraval = 1;
2020-01-18 23:34:38 +00:00
h1->c7 = newCell(deg, h1);
2020-01-19 20:52:14 +00:00
asg[h1] = {h1, m};
asg_rev[{h1, m}] = h1;
2020-01-18 23:34:38 +00:00
}
next++;
}
2020-01-19 10:50:04 +00:00
if(next != h->type) { println(hlog, "degree error"); exit(1); }
2020-01-18 23:34:38 +00:00
return h->move(direction);
}
};
2020-07-29 21:34:00 +00:00
bool labeller(cell* c, const shiftmatrix& V) {
2020-01-18 23:34:38 +00:00
auto m = dynamic_cast<hrmap_rewrite*> (currentmap);
if(m) {
2020-01-19 20:52:14 +00:00
string s = m->asg[c->master].second;
cgi.scalefactor = 1;
2024-05-05 18:20:00 +00:00
queuestr(V, 0.5, s, ccolor::jmap.ctab[c->master->distance+1]);
2020-01-18 23:34:38 +00:00
}
return false;
}
2020-01-19 10:50:04 +00:00
void load_rules(vector<string> vs) {
stop_game();
set_geometry(gInfOrderMixed);
ginf[gInfOrderMixed].distlimit = {{1, 1}};
2020-01-19 10:50:04 +00:00
ginf[gInfOrderMixed].flags |= qEXPERIMENTAL;
start = "";
rules.clear();
ruleset.clear();
for(string line: vs) {
if(line == "") continue;
auto i = line.find("->");
if(i != string::npos) {
rules.emplace_back(line.substr(0, i), line.substr(i+2));
ruleset.emplace(line.substr(0, i), line.substr(i+2));
}
else start = line;
}
ginf[gInfOrderMixed].sides = isize(find_matches(start));
if(!ginf[gInfOrderMixed].sides) ginf[gInfOrderMixed].sides = 1;
ginf[gInfOrderMixed].flags |= qANYQ;
}
#if ISWEB
extern "C" {
void load_web_rules() {
string s = get_value("rules") + '\n';
vector<string> split;
string cc = "";
for(char c: s) if(c == '\n' || c == '\r') split.push_back(cc), cc = ""; else cc += c;
load_rules(split);
start_game();
clearMessages();
2020-01-19 20:52:14 +00:00
bfs();
resetview();
drawthemap();
centerpc(INF);
centerover = cwt.at;
2020-01-19 10:50:04 +00:00
}
}
#endif
2020-01-18 23:34:38 +00:00
auto hooks =
addHook(hooks_args, 100, [] {
using namespace arg;
if(0) ;
2020-01-19 10:50:04 +00:00
#if ISWEB
else if(argis("-rww")) {
load_web_rules();
}
#endif
2020-01-18 23:34:38 +00:00
else if(argis("-rwr")) {
shift();
fhstream ss(argcs(), "rt");
2020-01-19 10:50:04 +00:00
vector<string> vs;
2020-01-18 23:34:38 +00:00
string line;
2020-01-19 10:50:04 +00:00
while(scan(ss, line)) vs.push_back(line);
load_rules(vs);
2020-01-18 23:34:38 +00:00
}
else return 1;
return 0;
}) +
addHook(hooks_newmap, 100, [] {
if(geometry == gInfOrderMixed && !rules.empty()) return (hrmap*) new hrmap_rewrite;
return (hrmap*) nullptr;
})
+ addHook(hooks_drawcell, 100, labeller);
}
}