1 // Hyperbolic Rogue -- Heptagon
2 // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
3
4 /** \file heptagon.cpp
5 * \brief implementation of Heptagons
6 *
7 * Start with locations.cpp
8 */
9
10 #include "hyper.h"
11 namespace hr {
12
13 #define MIRR(x) x.mirrored
14
15 int heptacount = 0;
16
17 struct cell;
18 cell *newCell(int type, heptagon *master);
19
20 /** the automaton is used to generate each heptagon in an unique way.
21 * See http://roguetemple.com/z/dev.php for more help.
22 * From the origin we can go further in any direction, and from other heptagons
23 * we can go in directions 3 and 4 (0 is back to origin, so 3 and 4 go forward),
24 * and sometimes in direction 5
25 */
26
transition(hstate s,int dir)27 EX hstate transition(hstate s, int dir) {
28 if(sphere) {
29 if(S7 == 4) {
30 if(s == hsOrigin) return dir == 0 ? hsB0 : hsB1;
31 }
32 if(S7 == 3 && S3 == 3) {
33 if(s == hsOrigin) return hsB1;
34 }
35 if(S7 == 3 && S3 == 4) {
36 if(s == hsOrigin) return dir == 0 ? hsA0 : hsA1;
37 if(s == hsA0 && dir == 1) return hsB0;
38 if(s == hsA1 && dir == 1) return hsB1;
39 if(s == hsB0 && dir == 2) return hsC;
40 return hsError;
41 }
42 if(s == hsOrigin) return dir == 0 ? hsA0 : hsA1;
43 if(s == hsA0 && dir == 2) return hsB0;
44 if(s == hsA1 && dir == 2) return hsB1;
45 if(s == hsB0 && dir == S7-2) return hsC;
46 return hsError;
47 }
48 else if(S6 == 8) {
49 if(s == hsOrigin) return hsA;
50 if(s == hsA && (dir >= 2 && dir < S7-1)) return hsA;
51 if(s == hsA && (dir == S7-1)) return hsB;
52 if(s == hsB && (dir >= 2 && dir < S7-2)) return hsA;
53 if(s == hsB && (dir == S7-2)) return hsB;
54 }
55 else if(S3 >= OINF) {
56 if(s == hsOrigin) return hsA;
57 if(s == hsA && dir) return hsA;
58 }
59 else {
60 if(s == hsOrigin) return hsA;
61 if(s == hsA && dir >= 3 && dir <= S7-3) return hsA;
62 if(s == hsA && dir == S7-2) return hsB;
63 if(s == hsB && dir >= 3 && dir <= S7-4) return hsA;
64 if(s == hsB && dir == S7-3) return hsB;
65 }
66 return hsError;
67 }
68
69 #define COMPUTE -1000000
70
71 // create a new heptagon
72 EX heptagon *buildHeptagon1(heptagon *h, heptagon *parent, int d, hstate s, int pard IS(0)) {
73 h->alt = NULL;
74 h->s = s;
75 h->c.connect(pard, parent, d, false);
76 h->cdata = NULL;
77 return h;
78 }
79
init_heptagon(int type)80 EX heptagon *init_heptagon(int type) {
81 heptagon *h = tailored_alloc<heptagon> (type);
82 h->emeraldval = 0;
83 h->zebraval = 0;
84 h->fiftyval = 0;
85 h->fieldval = 0;
86 h->rval0 = h->rval1 = 0;
87 h->cdata = NULL;
88 h->alt = NULL;
89 h->c7 = NULL;
90 h->distance = 0;
91 h->dm4 = 0;
92 return h;
93 }
94
buildHeptagon(heptagon * parent,int d,hstate s,int pard=0,int fixdistance=COMPUTE)95 heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0, int fixdistance = COMPUTE) {
96 heptagon *h = buildHeptagon1(tailored_alloc<heptagon> (S7), parent, d, s, pard);
97 if(bt::in() || arcm::in()) return h;
98 if(parent->c7) {
99 #if CAP_IRR
100 if(IRREGULAR)
101 irr::link_next(parent, d);
102 else
103 #endif
104 h->c7 = newCell(S7, h);
105 h->rval0 = h->rval1 = 0;
106 h->emeraldval = emerald_heptagon(parent->emeraldval, d);
107 h->zebraval = zebra_heptagon(parent->zebraval, d);
108 #if CAP_FIELD
109 if(&currfp != &fieldpattern::fp_invalid)
110 h->fieldval = currfp.connections[fieldpattern::btspin(parent->fieldval, d)];
111 #endif
112 if(a38)
113 h->fiftyval = fifty_38(parent->fiftyval, d);
114 else if(parent->s == hsOrigin)
115 h->fiftyval = firstfiftyval(d);
116 else
117 h->fiftyval = nextfiftyval(parent->fiftyval, parent->move(0)->fiftyval, d);
118 }
119 else {
120 h->c7 = NULL;
121 h->emeraldval = 0;
122 h->fiftyval = 0;
123 h->cdata = NULL;
124 }
125 //generateEmeraldval(parent);
126 //generateEmeraldval(h);
127 if(pard == 0) {
128 h->dm4 = parent->dm4+1;
129 if(fixdistance != COMPUTE) h->distance = fixdistance;
130 else if(S3 == 4 && BITRUNCATED) {
131 h->distance = parent->distance + 2;
132 if(h->c.spin(0) == 2 || (h->c.spin(0) == 3 && S7 <= 5))
133 h->distance = min<short>(h->distance, createStep(h->move(0), 0)->distance + 3);
134 if(h->c.spin(0) == 2 && h->move(0)) {
135 int d = h->c.spin(0);
136 int d1 = (d+S7-1)%S7;
137 bool missing0 = !h->move(0)->move(d1);
138 if(missing0) {
139 if(s == 1)
140 h->distance = h->move(0)->distance + 1;
141 }
142 else {
143 heptagon* h1 = createStep(h->move(0), d1);
144 if(h1->distance <= h->move(0)->distance)
145 h->distance = h->move(0)->distance+1;
146 }
147 }
148 if((h->s == hsB && h->move(0)->s == hsB) || h->move(0)->s == hsA) {
149 int d = h->c.spin(0);
150 heptagon* h1 = createStep(h->move(0), (d+1)%S7);
151 if(h1->distance <= h->move(0)->distance)
152 h->distance = h->move(0)->distance+1;
153 }
154 if(h->c.spin(0) == S7-1 && (h->move(0)->s != hsOrigin) && BITRUNCATED) {
155 bool missing = !h->move(S7-1);
156 if(missing) {
157 h->distance = parent->distance;
158 if(
159 parent->distance - h->move(0)->move(0)->distance == 1 &&
160 h->c.spin(0) == S7 - 1 &&
161 h->move(0)->c.spin(0) == 2)
162 h->distance++;
163 }
164 else {
165 h->distance = min(
166 h->move(0)->move(0)->distance + 2,
167 createStep(h, S7-1)->distance + 1
168 );
169 }
170 }
171 }
172 else if(parent->s == hsOrigin) h->distance = parent->distance + gp::dist_2();
173 #if CAP_GP
174 else if(S3 == 4 && GOLDBERG && h->c.spin(0) == S7-2 && h->move(0)->c.spin(0) >= S7-2 && h->move(0)->move(0)->s != hsOrigin) {
175 heptspin hs(h, 0);
176 hs += wstep;
177 int d1 = hs.at->distance;
178 hs += 1; hs += wstep;
179 int dm = hs.at->distance;
180 hs += -1; hs += wstep;
181 int d0 = hs.at->distance;
182 h->distance = gp::solve_triangle(dm, d0, d1, gp::param * gp::loc(-1,1));
183 }
184 else if(S3 == 4 && GOLDBERG && h->c.spin(0) == S7-1 && among(h->move(0)->c.spin(0), S7-2, S7-3) && h->move(0)->move(0)->s != hsOrigin) {
185 heptspin hs(h, 0);
186 hs += wstep;
187 int d0 = hs.at->distance;
188 hs += 1; hs += wstep;
189 int dm = hs.at->distance;
190 hs += 1; hs += wstep;
191 int d1 = hs.at->distance;
192 h->distance = gp::solve_triangle(dm, d0, d1, gp::param * gp::loc(1,1));
193 }
194 else if(S3 == 4 && GOLDBERG && h->c.spin(0) >= 2 && h->c.spin(0) <= S7-2) {
195 h->distance = parent->distance + gp::dist_2();
196 }
197 #endif
198 else if(h->c.spin(0) == S7-2) {
199 #if CAP_GP
200 if(GOLDBERG) {
201 int d0 = parent->distance;
202 int d1 = createStep(parent, S7-1)->distance;
203 int dm = createStep(parent, 0)->distance;
204 h->distance = gp::solve_triangle(dm, d0, d1, gp::param * gp::loc(1,1));
205 } else
206 #endif
207 h->distance = parent->distance + gp::dist_1();
208 }
209 else if(h->c.spin(0) == S7-3 && h->move(0)->s == hsB) {
210 #if CAP_GP
211 if(GOLDBERG) {
212 int d0 = parent->distance;
213 int d1 = createStep(parent, S7-2)->distance;
214 int dm = createStep(parent, S7-1)->distance;
215 h->distance = gp::solve_triangle(dm, d0, d1, gp::param * gp::loc(1,1));
216 } else
217 #endif
218 h->distance = createStep(h->move(0), (h->c.spin(0)+2)%S7)->distance + gp::dist_3();
219 }
220 else if(h->c.spin(0) == S7-1 && S3 == 4 && GOLDBERG) {
221 h->distance = parent->distance + gp::dist_1();
222 }
223 else h->distance = parent->distance + gp::dist_2();
224 }
225 else {
226 h->distance = parent->distance - gp::dist_2();
227 if(S3 == 4 && S7 > 5 && BITRUNCATED) {
228 h->distance = parent->distance - 2;
229 }
230 if(S3 == 4 && S7 == 5) {
231 if(h->s == hsOrigin) {
232 printf("had to cheat!\n");
233 h->distance = parent->distance - 2;
234 }
235 else {
236 h->distance = parent->distance - 1;
237 buildHeptagon(h, 2, hsA, 0, h->distance + 2);
238 buildHeptagon(h, 4, hsB, 0, h->distance);
239 }
240 }
241 h->dm4 = parent->dm4-1;
242 }
243 return h;
244 }
245
246 int recsteps;
247
addSpin(heptagon * h,int d,heptagon * from,int rot,int spin)248 void addSpin(heptagon *h, int d, heptagon *from, int rot, int spin) {
249 rot = h->c.fix(rot);
250 auto h1 = createStep(from, rot);
251 int fr = h1->c.fix(from->c.spin(rot) + spin);
252 h->c.connect(d, from->move(rot), fr, false);
253 }
254
255 extern int hrand(int);
256
257 EX hookset<void(heptagon*, int)> hooks_createStep;
258
259 // create h->move(d) if not created yet
createStep(heptagon * h,int d)260 heptagon *createStep(heptagon *h, int d) {
261 d = h->c.fix(d);
262 if(h->move(d)) return h->move(d);
263 callhooks(hooks_createStep, h, d);
264 return currentmap->create_step(h, d);
265 }
266
create_step(heptagon * h,int d)267 heptagon *hrmap_standard::create_step(heptagon *h, int d) {
268 if(!h->move(0) && h->s != hsOrigin && !bt::in() && !cryst) {
269 // cheating:
270 int pard=0;
271 if(S3 == 3)
272 pard = 3 + hrand(2);
273 else if(S3 == 4 && S7 == 5)
274 pard = 3; // to do: randomize
275 else if(S3 == 4)
276 pard = 3;
277 buildHeptagon(h, 0, h->distance < -global_distance_limit - 200 ? hsOrigin : hsA, pard);
278 }
279 if(h->move(d)) return h->move(d);
280 if(h->s == hsOrigin) {
281 buildHeptagon(h, d, hsA);
282 }
283 else if(S3 == 4) {
284 if(d == 1) {
285 heptspin hs(h, 0, false);
286 hs = hs + wstep - 1 + wstep - 1 + wstep - 1;
287 h->c.connect(d, hs);
288 }
289 else if(h->s == hsB && d == S7-1) {
290 heptspin hs(h, 0, false);
291 hs = hs + wstep + 1 + wstep + 1 + wstep + 1;
292 h->c.connect(d, hs);
293 }
294 else
295 buildHeptagon(h, d, transition(h->s, d));
296 }
297 else if(S3 > 4 && quotient) {
298 /* this branch may be used for some >4-valent quotient spaces outside of standard HyperRogue */
299 /* this is wrong, but we don't care in quotient */
300 h->move(d) = h;
301 // buildHeptagon(h, d, transition(h->s, d));
302 }
303 else if(d == 1) {
304 addSpin(h, d, h->move(0), h->c.spin(0)-1, -1);
305 }
306 else if(d == S7-1) {
307 addSpin(h, d, h->move(0), h->c.spin(0)+1, +1);
308 }
309 else if(d == 2) {
310 createStep(h->move(0), h->c.spin(0)-1);
311 addSpin(h, d, h->move(0)->modmove(h->c.spin(0)-1), S7-2 + h->move(0)->c.modspin(h->c.spin(0)-1), -1);
312 }
313 else if(d == S7-2 && h->s == hsB) {
314 createStep(h->move(0), h->c.spin(0)+1);
315 addSpin(h, d, h->move(0)->modmove(h->c.spin(0)+1), 2 + h->move(0)->c.modspin(h->c.spin(0)+1), +1);
316 }
317 else
318 buildHeptagon(h, d, (d == S7-2 || (h->s == hsB && d == S7-3)) ? hsB : hsA);
319 return h->move(d);
320 }
321
322 // display the coordinates of the heptagon
backtrace(heptagon * pos)323 void backtrace(heptagon *pos) {
324 if(pos->s == hsOrigin) return;
325 backtrace(pos->move(0));
326 printf(" %d", pos->c.spin(0));
327 }
328
hsshow(const heptspin & t)329 void hsshow(const heptspin& t) {
330 printf("ORIGIN"); backtrace(t.at); printf(" (spin %d)\n", t.spin);
331 }
332
333 }
334