1 // Hyperbolic Rogue -- infinite-order tessellations
2 // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
3
4 /** \file inforder3.cpp
5 * \brief infinite-order tessellations
6 *
7 * very simple
8 */
9
10 #include "../hyper.h"
11
12 namespace hr {
13
14 namespace rewriting {
15
16 bool symmetric;
17
18 string start;
19 vector<pair<string, string> > rules;
20 set<pair<string, string> > ruleset;
21
find_matches(string s)22 map<string, int> find_matches(string s) {
23 map<string, int> res;
24 for(auto& p: rules) {
25 size_t next = s.find(p.first);
26 while(next != string::npos) {
27 string t = s.substr(0, next) + p.second + s.substr(next+isize(p.first));
28 auto& r = res[t];
29 if(ruleset.count({p.second, p.first})) r = 2;
30 else r = max(r, 1);
31 next = s.find(p.first, next+1);
32 }
33 }
34 return res;
35 }
36
37 struct hrmap_rewrite : hrmap_hyperbolic {
38
39 map<heptagon*, pair<heptagon*, string> > asg;
40 map<pair<heptagon*, string>, heptagon*> asg_rev;
41
create_stephr::rewriting::hrmap_rewrite42 heptagon *create_step(heptagon *h, int direction) {
43 if(h->move(direction)) return h->move(direction);
44 if(asg.empty()) { asg[h] = {h, start}; h->zebraval = 0; }
45
46 auto s = asg[h].second;
47 auto root = asg[h].first;
48
49 auto matches = find_matches(s);
50
51 int next = h->zebraval;
52
53 if(matches.empty() && next == 0) {
54 h->c.connect(0, h, 0, false);
55 return h;
56 }
57
58 for(auto& match: matches) {
59 if(h->move(next)) { next++; continue; }
60 bool symmetric = match.second == 2;
61 const string& m = match.first;
62 if(symmetric) {
63 auto matches1 = find_matches(m);
64 heptagon *h1;
65 if(asg_rev[{root, m}]) h1 = asg_rev[{root, m}];
66 else {
67 h1 = tailored_alloc<heptagon> (isize(matches1));
68 h1->alt = NULL;
69 h1->s = hsA;
70 h1->cdata = NULL;
71 h1->distance = h->distance;
72 h1->zebraval = 0;
73 h1->c7 = newCell(isize(matches1), h1);
74 asg[h1] = {root, m};
75 asg_rev[{root, m}] = h1;
76 }
77 int next1 = 0;
78 for(auto& match2: matches1) { if(match2.first == s) break; next1++; }
79 h->c.connect(next, h1, next1, false);
80 }
81 else {
82 int deg = 1 + isize(find_matches(m));
83 auto h1 = tailored_alloc<heptagon> (deg);
84 h->c.connect(next, h1, 0, false);
85
86 h1->alt = NULL;
87 h1->s = hsA;
88 h1->cdata = NULL;
89 h1->distance = h->distance + 1;
90 h1->zebraval = 1;
91 h1->c7 = newCell(deg, h1);
92
93 asg[h1] = {h1, m};
94 asg_rev[{h1, m}] = h1;
95 }
96 next++;
97 }
98
99 if(next != h->type) { println(hlog, "degree error"); exit(1); }
100
101 return h->move(direction);
102 }
103
104 };
105
labeller(cell * c,const shiftmatrix & V)106 bool labeller(cell* c, const shiftmatrix& V) {
107 auto m = dynamic_cast<hrmap_rewrite*> (currentmap);
108 if(m) {
109 string s = m->asg[c->master].second;
110 cgi.scalefactor = 1;
111 queuestr(V, 0.5, s, colortables['j'][c->master->distance+1]);
112 }
113 return false;
114 }
115
load_rules(vector<string> vs)116 void load_rules(vector<string> vs) {
117
118 stop_game();
119 set_geometry(gInfOrderMixed);
120 ginf[gInfOrderMixed].distlimit = {{1, 1}};
121 ginf[gInfOrderMixed].flags |= qEXPERIMENTAL;
122
123 start = "";
124 rules.clear();
125 ruleset.clear();
126 for(string line: vs) {
127 if(line == "") continue;
128
129 auto i = line.find("->");
130 if(i != string::npos) {
131 rules.emplace_back(line.substr(0, i), line.substr(i+2));
132 ruleset.emplace(line.substr(0, i), line.substr(i+2));
133 }
134 else start = line;
135 }
136
137 ginf[gInfOrderMixed].sides = isize(find_matches(start));
138 if(!ginf[gInfOrderMixed].sides) ginf[gInfOrderMixed].sides = 1;
139 ginf[gInfOrderMixed].flags |= qANYQ;
140 }
141
142 #if ISWEB
143 extern "C" {
load_web_rules()144 void load_web_rules() {
145 string s = get_value("rules") + '\n';
146 vector<string> split;
147 string cc = "";
148 for(char c: s) if(c == '\n' || c == '\r') split.push_back(cc), cc = ""; else cc += c;
149 load_rules(split);
150 start_game();
151 clearMessages();
152
153 bfs();
154 resetview();
155 drawthemap();
156 centerpc(INF);
157 centerover = cwt.at;
158 }
159 }
160 #endif
161
162 auto hooks =
__anon24d438020102null163 addHook(hooks_args, 100, [] {
164 using namespace arg;
165
166 if(0) ;
167 #if ISWEB
168 else if(argis("-rww")) {
169 load_web_rules();
170 }
171 #endif
172 else if(argis("-rwr")) {
173 shift();
174 fhstream ss(argcs(), "rt");
175 vector<string> vs;
176 string line;
177 while(scan(ss, line)) vs.push_back(line);
178 load_rules(vs);
179 }
180 else return 1;
181 return 0;
182 }) +
183
__anon24d438020202null184 addHook(hooks_newmap, 100, [] {
185 if(geometry == gInfOrderMixed && !rules.empty()) return (hrmap*) new hrmap_rewrite;
186 return (hrmap*) nullptr;
187 })
188
189 + addHook(hooks_drawcell, 100, labeller);
190
191 }
192 }
193