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