mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 14:02:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			449 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			449 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Hyperbolic Rogue pattern generator
 | |
| 
 | |
| // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
 | |
| 
 | |
| namespace hr {
 | |
| 
 | |
| void spill50(cell *c, eWall w, int r) {
 | |
|   c->wall = w;
 | |
|   if(r) for(int i=0; i<c->type; i++) spill50(createMov(c, i), w, r-1);
 | |
|   }
 | |
| 
 | |
| int style = 3;
 | |
| 
 | |
| struct state50 {
 | |
|   bool polarity1;
 | |
|   bool polarity2;
 | |
|   color_t color, color2, wc2;
 | |
|   };
 | |
| 
 | |
| void progress(cell *c, state50 s);
 | |
| 
 | |
| #include <map>
 | |
| 
 | |
| map<cell*, state50> map50;
 | |
| 
 | |
| void initPatternFifty(cell *c) {
 | |
|   state50 s;
 | |
|   s.polarity1 = 0;
 | |
|   s.polarity2 = 0;
 | |
|   s.color = 0;
 | |
|   s.color2 = 1;
 | |
|   s.wc2 = 0;
 | |
|   map50[c] = s;
 | |
|   }
 | |
| 
 | |
| int par;
 | |
| 
 | |
| int haverule[1<<24][8];
 | |
| 
 | |
| void saveCode(heptagon *H1, int d, heptagon *H2) {
 | |
| 
 | |
| /*
 | |
|   if(!H1 || !H2) return;
 | |
|   if(H1->move[d] != H2) exit(1);
 | |
|   
 | |
|   int h1 = H1->fiftyval;
 | |
|   int h2 = H2->fiftyval;
 | |
| 
 | |
|   if(!h1 || !h2) return;
 | |
| 
 | |
|   if(haverule[h1][d] && haverule[h1][d] != h2) {
 | |
|     printf("rule conflict: %06x, %d, %06x/%06x\n", 
 | |
|       h1, d, h2, haverule[h1][d]);
 | |
|     // exit(1);
 | |
|     }
 | |
|     
 | |
|   if(!haverule[h1][d]) {
 | |
|     haverule[h1][d] = h2;
 | |
|  
 | |
|     printf("RULE50(0x%06x, %d, 0x%06x)\n", h1, d, h2);
 | |
|     } */
 | |
| 
 | |
|   fflush(stdout);
 | |
|   }
 | |
|   
 | |
| void saveCode(cell *c) {
 | |
| 
 | |
| /*  heptagon *hept = c->master;
 | |
|   
 | |
|   if(hept != &origin) 
 | |
|     saveCode(hept->move[0], hept->spin[0], hept); */
 | |
|     
 | |
|   bool allcodes = c->master->fiftyval >= 0;
 | |
| 
 | |
|   for(int i=0; i<7; i++) 
 | |
|     if(c->master->move[i] && c->master->move[i]->fiftyval >= 0) ;
 | |
|     else allcodes = false;
 | |
|   
 | |
|   if(allcodes)  {
 | |
|     printf("RULE50(0x%03x", c->master->fiftyval);
 | |
|     int rulebase = 0;
 | |
|     for(int i=0; i<7; i++) 
 | |
|       if(c->master->move[i]->fiftyval < c->master->move[rulebase]->fiftyval)
 | |
|         rulebase = i;
 | |
|     for(int i=0; i<7; i++) printf(", 0x%03x", c->master->move[(rulebase+i)%7]->fiftyval);
 | |
|     printf(")\n");
 | |
|     }
 | |
|   
 | |
|   // hept->fiftyused = true;
 | |
|   }
 | |
| 
 | |
| void encode(cell *c, state50 s, int mod, int spn) {
 | |
| /*int i = 0;
 | |
|   i *= 16; i += s.color;
 | |
|   i *= 16; i += s.color2;
 | |
|   i *= 16; i += s.polarity1;
 | |
|   i *= 16; i += s.polarity2;
 | |
|   i *= 16; i += mod;
 | |
|   i *= 16; i += spn;
 | |
|   if(c->master->fiftyval) { printf("multiply 50val\n"); exit(1); } 
 | |
|   c->master->fiftyval = i; c->master->fiftyused = false; */
 | |
|   
 | |
|   c->master->fiftyval = 
 | |
|     s.color + s.polarity1 * 8 + s.polarity2 * 16 + mod * 32;
 | |
|   // s.color * 16 + (s.polarity1 ? 128 : 0) + (s.polarity2 ? 256 :0) + mod;
 | |
|   
 | |
|   saveCode(c);
 | |
|   for(int i=0; i<7; i++)
 | |
|     saveCode(createStep(c->master, i)->c7);
 | |
|     
 | |
|   /* for(int i=0; i<7; i++) if(c->master->move[i]) {
 | |
|     saveCode(c->master, i, c->master->move[i]);
 | |
|     saveCode(c->master->move[i], c->master->spin[i], c->master);
 | |
|     } */
 | |
|   }
 | |
| 
 | |
| eWall colorwalls[4] = {waCIsland, waCIsland2, waMineOpen, waDeadfloor };
 | |
| 
 | |
| void patternFiftyAt(cell *c) {
 | |
|   if(!map50.count(c)) return;
 | |
|   
 | |
|   state50 s = map50[c];
 | |
|   
 | |
|   // c->wall = waCIsland;
 | |
|   
 | |
|   // if(c->heat > ii) return;
 | |
|   
 | |
|   // printf("pfifty %p\n", c);
 | |
|   
 | |
|   if(style == 1 && s.polarity2) {
 | |
|       spill50(c, waCamelot, 3);
 | |
|       spill50(c, waNone, 2);
 | |
| 
 | |
|       for(int i=0; i<c->type; i++) {
 | |
|         cellwalker cw(c, i);
 | |
|         cellwalker cw1 = cw + wstep + 4 + wstep;
 | |
|         (cw1+3+wstep).at->wall = waFloorA;
 | |
|         (cw1+4+wstep).at->wall = waFloorA;
 | |
|         }
 | |
|       }
 | |
|    
 | |
|   /*switch(ii) {
 | |
|     case 0:
 | |
|       spill50(c, waNone, 3);
 | |
|       break;
 | |
| 
 | |
|     case 1:
 | |
|       spill50(c, waNone, 3);
 | |
|       break;
 | |
| 
 | |
|     case 2:
 | |
|       spill50(c, waNone, 3);
 | |
|       break;
 | |
| 
 | |
|     case 3:
 | |
|       spill50(c, waNone, 3);
 | |
|       break;
 | |
|     } */
 | |
|     
 | |
|   if(style == 2) {
 | |
|     spill50(c, waCavefloor, 2);
 | |
|     spill50(c, waFloorA, 1);
 | |
|     }
 | |
|   
 | |
|   if(style == 3) {
 | |
|     spill50(c, colorwalls[s.color], 3);
 | |
|     // c->item = itGold;
 | |
| //  if(s.polarity2) return;
 | |
|     }
 | |
| 
 | |
|   encode(c, s, 0, 0);
 | |
|   
 | |
|   int sgn = s.polarity2 ? 1 : -1;
 | |
|   int sgn1 = s.polarity1 ? 1 : -1;
 | |
| 
 | |
|   color_t col2 = s.color2, sw = s.wc2;
 | |
|   
 | |
|   while(col2 != 7-s.color) {
 | |
|     sw += (s.polarity1?1:-1); sw %= 7;
 | |
|     while(true) { col2++; col2 &= 7; if(col2 != s.color) break; }
 | |
|     }  
 | |
| 
 | |
|   for(int i=0; i<c->type; i++) {
 | |
|     auto cw = cellwalker(c, sw) + (sgn1 * i) + wstep + (sgn * 4) + wstep;
 | |
|     if(cw.spin < 0 || cw.spin >= 7 || cw.at->type != 7) exit(1);
 | |
|     encode(cw.c, s, 1+i, cw.spin);
 | |
|     }
 | |
|   
 | |
|   for(int i=0; i<c->type; i++) {
 | |
|     auto cw = cellwalker(c, sw) + (sgn1 * i) + wstep + 3 + wstep + 3 + wstep;
 | |
|     if(cw.spin < 0 || cw.spin >= 7 || cw.at->type != 7) exit(1);
 | |
|     encode(cw.c, s, 8+i, cw.spin);
 | |
|     }
 | |
|   
 | |
|   // c->heat = s.color + 
 | |
|     
 | |
|   for(int i=0; i<c->type; i++) {
 | |
|     cellwalker cw(c, s.wc2);
 | |
|     cw += (sgn1 * i);
 | |
|     cw += wstep;
 | |
|     if(style == 0) cw.at->wall = waCamelot;
 | |
|     // cw.at->item = itSilver;
 | |
|     cw += (sgn*4); //6
 | |
|     cw += wstep; if(style == 0) cw.at->wall = waFloorA;
 | |
| 
 | |
|     // cw.at->item = itSilver;
 | |
|     cw += (sgn*4); //7
 | |
|     cw += wstep; if(style == 0) cw.at->wall = waFloorA;
 | |
|     // cw.at->item = itSilver;
 | |
|     cw += (3); //6
 | |
|     cw += wstep; if(style == 0) cw.at->wall = waFloorA;
 | |
|     // cw.at->item = itSilver;
 | |
|     cw += (3); //6
 | |
|     cw += wstep; if(style == 0) cw.at->wall = waFloorA;
 | |
|     // cw.at->item = itSilver;
 | |
|     cw += (sgn*3); //7
 | |
|     cw += wstep; if(style == 0) cw.at->wall = waCamelot;
 | |
|     // cw.at->item = itSilver;
 | |
|     cw += (sgn*2); //6
 | |
|     cw += wstep; // cw.at->item = itGold;
 | |
|     // setdist(cw.c, 8, NULL);
 | |
|     state50 s2 = s; s2.polarity1 = !s.polarity1;
 | |
|     s2.wc2 = (cw.spin + sgn1 * i + sgn + 42) % 7;
 | |
|     progress(cw.c, s2);
 | |
|     // printf("heat set %f\n", cw.at->heat);
 | |
|     }
 | |
|     
 | |
|   int newcol = s.color2;
 | |
|   
 | |
|   // if(s.polarity2) return;
 | |
|   
 | |
|   for(int i=0; i<c->type; i++) {
 | |
|     cellwalker cw(c, s.wc2);
 | |
|     cw += (sgn1 * i);
 | |
|     cw += wstep; // cw.at->item = itSilver;
 | |
| //  cw.at->item = itDiamond;
 | |
|     cw += (3); // 6
 | |
|     cw += wstep; // cw.at->item = itSilver;
 | |
| //  cw.at->item = itDiamond;
 | |
|     cw += (sgn*4); // 6
 | |
|     cw += wstep; // cw.at->item = itSilver;
 | |
| //  cw.at->item = itDiamond;
 | |
|     cw += (sgn*2); // 6
 | |
|     cw += wstep; // cw.at->item = itSilver;
 | |
| //  cw.at->item = itDiamond;
 | |
|     cw += (3); // 6
 | |
|     cw += wstep; // cw.at->item = itSilver;
 | |
| //  cw.at->item = itDiamond;
 | |
|     cw += (sgn*3); // 7
 | |
|     cw += wstep; // cw.at->item = itSilver;
 | |
| //  cw.at->item = itDiamond;
 | |
|     cw += (sgn*4); // 6
 | |
|     cw += wstep; // cw.at->item = itSilver;
 | |
|     // setdist(cw.c, 8, NULL);
 | |
|     state50 s2 = s; 
 | |
|     s2.polarity2 = !s.polarity2;
 | |
|     if(s.polarity2) s2.polarity1 = !s.polarity1;
 | |
|     s2.color2 = s2.color;
 | |
|     s2.color = newcol;
 | |
|     s2.wc2 = cw.spin;
 | |
|     progress(cw.c, s2);
 | |
|     while(true) { newcol++; newcol &= 7; if(newcol != s2.color && newcol != s.color) break; }
 | |
|     // printf("heat set %f\n", cw.at->heat);
 | |
|     }
 | |
|   
 | |
|   }
 | |
| 
 | |
| void progress(cell *c, state50 s) {
 | |
|   
 | |
|   while(s.wc2) {
 | |
|     s.wc2 += (s.polarity1?1:-1); s.wc2 %= 7;
 | |
|     while(true) { s.color2++; s.color2 &= 7; if(s.color2 != s.color) break; }
 | |
|     }
 | |
|   
 | |
|   if(map50.count(c)) {
 | |
|     state50 s2 = map50[c];
 | |
|     if(s2.polarity1 != s.polarity1 || s2.polarity2 != s.polarity2) {
 | |
|       printf("Polarity mismatch!\n");
 | |
|       exit(1);
 | |
|       }
 | |
|     else {
 | |
|       if(s2.color != s.color || s2.color2 != s.color2 || s2.wc2 != s.wc2)
 | |
|         printf("%d:%d color= %dv%d color2= %dv%d wc2= %dv%d\n", 
 | |
|           s.polarity1, s.polarity2,
 | |
|           s.color, s2.color,
 | |
|           s.color2, s2.color2,
 | |
|           s.wc2, s2.wc2);
 | |
|       }
 | |
|     return;
 | |
|     }
 | |
|   map50[c] = s;
 | |
|   if(c->mpdist <= 7) 
 | |
|     patternFiftyAt(c);
 | |
|   }
 | |
| 
 | |
| long long Q; int qconflict;
 | |
| 
 | |
| string allconflict;
 | |
| 
 | |
| void setzebra(cellwalker cwb, int it, int type, string pathcode, int xmods) {
 | |
|   // printf("spin=%d type=%d\n", cwb.spin, type);
 | |
|   
 | |
|   if(cwb.spin != 1 && cwb.spin != 3 && cwb.spin != 5) {
 | |
|     printf("S WRONG SPIN %d\n", cwb.spin);
 | |
|     exit(1);
 | |
|     }
 | |
|   if(type < 0 || type > 3) {
 | |
|     printf("S WRONG TYPE %d\n", type);
 | |
|     exit(1);
 | |
|     }
 | |
| 
 | |
|   cwb.at->tmp = cwb.spin + 16 * type;
 | |
|   }
 | |
| 
 | |
| void zebra(cellwalker cwb, int it, int type, string pathcode, int xmods) {
 | |
|   if(!it) return;
 | |
|   if(cwb.spin != 1 && cwb.spin != 3 && cwb.spin != 5) {
 | |
|     printf("WRONG SPIN %d\n", cwb.spin);
 | |
|     exit(1);
 | |
|     }
 | |
|   if(type < 0 || type > 3) {
 | |
|     printf("WRONG TYPE %d\n", type);
 | |
|     exit(1);
 | |
|     }
 | |
|   // printf("%p+%d = 0%s\n", cwb.c, cwb.spin, pathcode.c_str());
 | |
|   bool redraw = false;
 | |
|   // int qval = Q + 99;
 | |
|   // redraw = cwb.at->heat == qval;
 | |
|   // cwb.at->heat = qval;
 | |
|   eWall w = colorwalls[type];
 | |
|   cwb.at->wall = w;
 | |
|   for(int i=0; i<6; i+=2) {
 | |
|     cellwalker cw = cwb;
 | |
|     cw += (i);
 | |
|     cw.at->heat = 4 + type + 4 * 9;
 | |
|     cw += wstep; cw += (3); cw.at->wall = w;
 | |
|     int i0 = i; if(type&2 && i0) i0 = 6-i0; i0 /= 2;
 | |
|     cw.at->heat = 4 + type + 4 * (3+i0);
 | |
|     cw += wstep; cw += (3); cw.at->wall = w;
 | |
|     cw.at->heat = 4 + type + 4 * i0;
 | |
|     cw += wstep; cw += (3); cw.at->wall = w;
 | |
|     cw.at->heat = 4 + type + 4 * (6+i0);
 | |
|     cw += wstep; cw += (-3); 
 | |
|     cw += wstep; cw += (-3); 
 | |
|     cw += wstep; cw += (-3); 
 | |
|     cw += wstep; cw += (-i);
 | |
|     cw += (0);
 | |
|     setzebra(cw, it-1, type ^ 1, pathcode +'+'+char('A'+i)+char('0'+type), xmods*2); 
 | |
|     }
 | |
| 
 | |
|   for(int i=0; i<6; i+=2) {
 | |
|     cellwalker cw = cwb;
 | |
|     cw += ((type&2)?-i:i);
 | |
|     cw += wstep; cw += (3); 
 | |
|     cw += wstep; cw += (5); 
 | |
|     if(xmods < 2) {
 | |
|       if(cw.at->item && cw.at->item != (1+i) && redraw && i==0) {
 | |
|         qconflict++;
 | |
|         // allconflict += pathcode; allconflict += "-";
 | |
|         // cwb.at->item = itPalace;
 | |
|         // printf("Conflict at %p\n", cwb.at);
 | |
|         }
 | |
|       // cw.at->item = eItem(1 + i);
 | |
|       // cw.at->heat = 4 + type + 4 * (i/2);
 | |
|       }
 | |
|     cw += wstep; cw += (1); 
 | |
|     if(type < 2) {
 | |
|       // cw += (i);
 | |
|       cw += (i); 
 | |
|       }
 | |
|     else {
 | |
|       cw += (-i); 
 | |
|       }
 | |
|     // cw += (((Q >> (4*type)) & 12));
 | |
|     setzebra(cw, it-1, 2^type, pathcode + '+'+char('a'+i)+char('0'+type), xmods+1);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| void zebraPattern() {
 | |
|   // int bqc = 99;
 | |
|   
 | |
|   /* for(Q=0; Q<65536; Q++) {
 | |
|     if((Q & (Q>>1)) & 0x5555) continue;
 | |
|     qconflict = false;
 | |
|     cellwalker cw(cwt);
 | |
|     cw += wstep; cw += (1);
 | |
|     qconflict = 0;
 | |
|     allconflict = "";
 | |
|     zebra(cw, 3, 0, "");
 | |
|     if(qconflict < bqc) bqc = qconflict;
 | |
|     // if(qconflict == bqc) 
 | |
|     printf("%X - X-%sX\n", Q, allconflict.c_str());
 | |
|     }
 | |
|     
 | |
|   Q = 0xFFFB; */
 | |
|   
 | |
|   cellwalker cw(cwt);
 | |
|   cw += wstep; cw += (1);
 | |
|   setzebra(cw, 7, 0, "", -999);
 | |
|   // cw.at->
 | |
|   // printf("Conflicts: %d\n", qconflict);
 | |
|   }
 | |
| 
 | |
| int bspin(heptagon *h) {
 | |
|   vector<int> xv;
 | |
|   xv.push_back(999);
 | |
|   int besti = -1;
 | |
|   for(int i=0; i<7; i++) {
 | |
|     vector<int> yv;
 | |
|     for(int j=0; j<7; j++) yv.push_back(int(h->move[(i+j)%7]->c7->heat+.1));
 | |
|     if(yv < xv) xv = yv, besti = i;
 | |
|     }
 | |
|   return besti;
 | |
|   }
 | |
| 
 | |
| void buildAutomatonRule(heptagon *h) {
 | |
|   if(!h->c7->heat) return;
 | |
|   for(int i=0; i<7; i++) if(!h->move[i]) return;
 | |
|   for(int i=0; i<7; i++) for(int j=0; j<7; j++) 
 | |
|     if(!h->move[i]->move[j] || !h->move[i]->move[j]->c7->heat) 
 | |
|       return;
 | |
|   int bi = bspin(h);
 | |
|   printf("RULEZEBRA(%2d", int(h->c7->heat+.1));
 | |
|   for(int j=0; j<7; j++) {
 | |
|     heptagon *h2 = h->move[(bi+j)%7];
 | |
|     int bi2 = bspin(h2);
 | |
|     printf(", %2d%d", int(h2->c7->heat+.1), fix7(bi2 - h->spin[(bi+j)%7]));
 | |
|     }
 | |
|   printf(")\n");
 | |
|   }
 | |
| 
 | |
| void buildAutomatonRule(cell *c) {
 | |
|   if(c->type == 7)
 | |
|     buildAutomatonRule(c->master);
 | |
|   else {
 | |
|     int ii[3];
 | |
|     for(int i=0; i<6; i+=2) if(!c->move(i) || !c->move(i)->heat || c->move(i)->type != 7) return;
 | |
|     for(int i=0; i<6; i+=2) ii[i/2] = int(c->move(i)->heat);
 | |
|     int z;
 | |
|     for(int r=0; r<2; r++) 
 | |
|       if(ii[1] < ii[0] || ii[2] < ii[0]) 
 | |
|         z = ii[0], ii[0] = ii[1], ii[1] = ii[2], ii[2] = z;
 | |
|     printf("RULEZEBRA6(%d,%d,%d,%d)\n", int(c->heat), int(ii[0]), int(ii[1]), int(ii[2]));
 | |
|     }
 | |
|   }
 | |
| 
 | |
| // #define BUILDZEBRA
 | |
| }
 | 
