hyperrogue/quotient.cpp

431 lines
13 KiB
C++

// Hyperbolic Rogue -- quotient spaces
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
/** \file quotient.cpp
* \brief quotient spaces
*/
#include "hyper.h"
namespace hr {
/** \brief quotient spaces */
EX namespace quotientspace {
int cod(heptagon *h) {
return zebra40(h->c7);
}
code get(heptspin hs) {
code res;
res.connections.resize(S7+1);
res.connections[0] = cod(hs.at);
for(int i=1; i<=S7; i++) {
res.connections[i] = cod((hs + wstep).at);
hs += 1;
}
return res;
}
EX int rvadd = 0;
EX int rvdir = 1;
int rv(int x) { return (rvadd+x*rvdir) % S7; }
#if HDR
constexpr int symmask = (1<<30);
struct code {
vector<int> connections;
bool operator == (const code &c2) const { return connections == c2.connections; }
bool operator < (const code &c2) const { return connections < c2.connections; }
};
struct hrmap_quotient : hrmap_standard {
hrmap_hyperbolic base;
vector<cell*> celllist;
cell *origin;
map<quotientspace::code, int> reachable;
vector<heptspin> bfsq;
vector<int> connections;
void add(const heptspin& hs);
vector<heptagon*> allh;
void generate_connections();
void build();
explicit hrmap_quotient() {
generate_connections();
build();
}
explicit hrmap_quotient(const vector<int>& con) : connections(con) {
build();
}
heptagon *getOrigin() override { return allh[0]; }
~hrmap_quotient() {
for(int i=0; i<isize(allh); i++) {
clearHexes(allh[i]);
tailored_delete(allh[i]);
}
}
vector<cell*>& allcells() override { return celllist; }
};
#endif
void hrmap_quotient::add(const heptspin& hs) {
code g = get(hs);
if(!reachable.count(g)) {
reachable[g] = bfsq.size();
bfsq.push_back(hs);
add(hs + 1);
}
}
void hrmap_quotient::generate_connections() {
dynamicval<hrmap*> cmap(currentmap, this);
connections.clear();
switch(geometry) {
#if CAP_FIELD
case gFieldQuotient: {
connections = currfp.connections;
break;
}
#endif
case gZebraQuotient: {
heptspin hs(base.origin);
reachable.clear();
bfsq.clear();
add(hs);
for(int i=0; i<(int)bfsq.size(); i++) {
hs = bfsq[i] + wstep;
add(hs);
connections.push_back(reachable[get(hs)]);
}
break;
}
case gMinimal: {
int altzebra[6][7] = {
{ 16,125,111, 45, 32, 56, 20 },
{ 26,102,146,152, 35,124, 00 },
{ 06, 55,143,134,115,101, 10 },
{ 41, 50, 04, 44,123, 14,153 },
{ 51, 30,154,122, 33, 03,112 },
{ 31, 40,113,136,142, 21, 05 }
};
// int ok = 0;
for(int a=0; a<6; a++) {
for(int b=0; b<7; b++) {
int s = altzebra[a][b];
int mirr = s/100; s %= 100;
int which = s/10; s %= 10;
int shouldbe = a*10+b+mirr*100;
if(altzebra[which][s] != shouldbe) {
printf("error at %d:%d (is=%d shouldbe=%d)\n", a, b, altzebra[which][s], shouldbe);
}
connections.push_back(which * 7 + s + (mirr ? symmask : 0) );
}
}
break;
}
case gKleinQuartic: {
connections = {
/* 000 */ 7, 14, 21, 28, 35, 42, 49,
/* 001 */ 0, 55, 56, 63, 70, 77, 15,
/* 002 */ 1, 13, 83, 84, 91, 98, 22,
/* 003 */ 2, 20, 104, 105, 112, 119, 29,
/* 004 */ 3, 27, 125, 74, 126, 133, 36,
/* 005 */ 4, 34, 139, 95, 66, 140, 43,
/* 006 */ 5, 41, 146, 116, 87, 147, 50,
/* 007 */ 6, 48, 153, 130, 108, 57, 8,
/* 008 */ 9, 54, 107, 102, 154, 142, 64,
/* 009 */ 10, 62, 141, 39, 94, 161, 71,
/* 010 */ 11, 69, 167, 127, 31, 124, 78,
/* 011 */ 12, 76, 123, 158, 149, 85, 16,
/* 012 */ 17, 82, 148, 46, 115, 163, 92,
/* 013 */ 18, 90, 162, 67, 38, 138, 99,
/* 014 */ 19, 97, 137, 155, 59, 106, 23,
/* 015 */ 24, 103, 58, 53, 129, 165, 113,
/* 016 */ 25, 111, 164, 88, 45, 145, 120,
/* 017 */ 26, 118, 144, 159, 79, 75, 30,
/* 018 */ 32, 73, 166, 109, 52, 152, 134,
/* 019 */ 33, 132, 151, 156, 100, 96, 37,
/* 020 */ 40, 65, 61, 160, 121, 117, 44,
/* 021 */ 47, 86, 81, 157, 135, 131, 51,
/* 022 */ 60, 101, 136, 150, 80, 122, 143,
/* 023 */ 68, 93, 89, 114, 110, 128, 72,
};
break;
}
case gBolza: {
connections = {
/* 000 */ 8, 16, 24, 32, 12, 20, 28, 36,
/* 001 */ 0, 35, 47, 21, 4, 39, 43, 17,
/* 002 */ 1, 15, 42, 29, 5, 11, 46, 25,
/* 003 */ 2, 23, 45, 37, 6, 19, 41, 33,
/* 004 */ 3, 31, 40, 9, 7, 27, 44, 13,
/* 005 */ 34, 30, 18, 14, 38, 26, 22, 10,
};
break;
}
case gBolza2: {
connections = {
/* 000 */ 16, 32, 48, 64, 24, 40, 56, 72,
/* 001 */ 20, 44, 52, 76, 28, 36, 60, 68,
/* 002 */ 0, 79, 83, 45, 8, 67, 95, 33,
/* 003 */ 4, 71, 87, 37, 12, 75, 91, 41,
/* 004 */ 1, 23, 94, 61, 13, 27, 86, 49,
/* 005 */ 5, 31, 90, 53, 9, 19, 82, 57,
/* 006 */ 2, 39, 85, 77, 10, 43, 89, 65,
/* 007 */ 6, 47, 81, 69, 14, 35, 93, 73,
/* 008 */ 3, 55, 88, 21, 15, 59, 80, 25,
/* 009 */ 7, 63, 92, 29, 11, 51, 84, 17,
/* 010 */ 70, 58, 46, 18, 78, 50, 38, 26,
/* 011 */ 66, 54, 42, 30, 74, 62, 34, 22,
};
break;
}
case gMacbeath: {
connections = {
/* 000 */ 359, 498, 189, 215, 424, 381, 20,
/* 001 */ 366, 491, 217, 187, 431, 346, 27,
/* 002 */ 380, 484, 168, 208, 438, 360, 6,
/* 003 */ 345, 477, 196, 180, 445, 367, 13,
/* 004 */ 352, 470, 203, 173, 396, 388, 48,
/* 005 */ 373, 463, 175, 201, 403, 339, 55,
/* 006 */ 387, 456, 210, 194, 410, 353, 34,
/* 007 */ 338, 449, 182, 222, 417, 374, 41,
/* 008 */ 254, 459, 140, 138, 414, 248, 69,
/* 009 */ 247, 480, 112, 166, 435, 255, 62,
/* 010 */ 233, 452, 161, 117, 407, 269, 83,
/* 011 */ 268, 487, 133, 145, 442, 234, 76,
/* 012 */ 261, 473, 126, 152, 400, 241, 97,
/* 013 */ 240, 494, 154, 124, 421, 262, 90,
/* 014 */ 226, 466, 119, 159, 393, 276, 111,
/* 015 */ 275, 501, 147, 131, 428, 227, 104,
/* 016 */ 65, 479, 343, 355, 408, 73, 167,
/* 017 */ 100, 465, 371, 383, 422, 94, 160,
/* 018 */ 86, 472, 350, 348, 429, 108, 153,
/* 019 */ 79, 486, 378, 376, 415, 59, 146,
/* 020 */ 58, 458, 385, 369, 443, 80, 139,
/* 021 */ 107, 500, 357, 341, 401, 87, 132,
/* 022 */ 93, 493, 364, 390, 394, 101, 125,
/* 023 */ 72, 451, 336, 362, 436, 66, 118,
/* 024 */ 16, 483, 294, 313, 397, 31, 209,
/* 025 */ 37, 462, 322, 285, 446, 24, 202,
/* 026 */ 51, 448, 287, 334, 432, 10, 223,
/* 027 */ 2, 497, 315, 306, 411, 45, 216,
/* 028 */ 23, 476, 308, 299, 404, 38, 181,
/* 029 */ 30, 469, 280, 327, 439, 17, 174,
/* 030 */ 44, 455, 329, 292, 425, 3, 195,
/* 031 */ 9, 490, 301, 320, 418, 52, 188,
/* 032 */ 324, 467, 98, 110, 427, 332, 258,
/* 033 */ 289, 453, 70, 82, 441, 283, 265,
/* 034 */ 303, 495, 91, 89, 399, 297, 272,
/* 035 */ 310, 481, 63, 61, 413, 318, 279,
/* 036 */ 331, 460, 56, 68, 434, 325, 230,
/* 037 */ 282, 474, 84, 96, 420, 290, 237,
/* 038 */ 296, 488, 77, 75, 406, 304, 244,
/* 039 */ 317, 502, 105, 103, 392, 311, 251,
/* 040 */ 205, 475, 259, 236, 447, 178, 328,
/* 041 */ 184, 454, 231, 264, 426, 213, 335,
/* 042 */ 170, 489, 266, 243, 405, 199, 314,
/* 043 */ 219, 496, 238, 271, 412, 192, 321,
/* 044 */ 198, 482, 245, 278, 398, 171, 300,
/* 045 */ 191, 503, 273, 250, 419, 220, 307,
/* 046 */ 177, 468, 224, 257, 440, 206, 286,
/* 047 */ 212, 461, 252, 229, 433, 185, 293,
/* 048 */ 163, 450, 49, 40, 402, 150, 363,
/* 049 */ 114, 478, 21, 12, 430, 129, 356,
/* 050 */ 128, 471, 28, 47, 409, 115, 349,
/* 051 */ 149, 499, 0, 19, 437, 164, 342,
/* 052 */ 156, 492, 7, 26, 444, 143, 391,
/* 053 */ 121, 464, 35, 54, 416, 136, 384,
/* 054 */ 135, 485, 14, 5, 423, 122, 377,
/* 055 */ 142, 457, 42, 33, 395, 157, 370,
/* 056 */ 277, 102, 158, 389, 32, 172, 312,
/* 057 */ 242, 88, 151, 340, 39, 200, 298,
/* 058 */ 270, 74, 116, 354, 46, 193, 305,
/* 059 */ 249, 60, 137, 375, 53, 221, 319,
/* 060 */ 263, 95, 123, 382, 4, 214, 291,
/* 061 */ 228, 109, 130, 347, 11, 186, 333,
/* 062 */ 256, 67, 165, 361, 18, 207, 326,
/* 063 */ 235, 81, 144, 368, 25, 179, 284,
/* 064 */ 183, 50, 337, 162, 71, 232, 288,
/* 065 */ 211, 43, 386, 141, 57, 253, 330,
/* 066 */ 176, 36, 372, 120, 99, 225, 323,
/* 067 */ 204, 29, 351, 127, 85, 260, 281,
/* 068 */ 197, 22, 344, 113, 64, 246, 309,
/* 069 */ 169, 15, 379, 134, 78, 267, 295,
/* 070 */ 218, 8, 365, 155, 92, 239, 302,
/* 071 */ 190, 1, 358, 148, 106, 274, 316,
};
break;
}
case gBring: {
connections = {
/* 000 */ 5, 92, 46, 33, 14,
/* 001 */ 0, 62, 56, 38, 24,
/* 002 */ 15, 97, 76, 63, 4,
/* 003 */ 10, 32, 86, 68, 29,
/* 004 */ 25, 67, 106, 93, 9,
/* 005 */ 20, 37, 116, 98, 19,
/* 006 */ 35, 102, 16, 3, 44,
/* 007 */ 30, 72, 26, 8, 54,
/* 008 */ 45, 107, 66, 73, 34,
/* 009 */ 40, 2, 81, 78, 59,
/* 010 */ 55, 77, 96, 103, 39,
/* 011 */ 50, 7, 111, 108, 49,
/* 012 */ 65, 112, 6, 13, 74,
/* 013 */ 60, 42, 21, 18, 84,
/* 014 */ 75, 117, 36, 43, 64,
/* 015 */ 70, 12, 51, 48, 89,
/* 016 */ 85, 47, 91, 113, 69,
/* 017 */ 80, 17, 101, 118, 79,
/* 018 */ 95, 82, 1, 23, 104,
/* 019 */ 90, 52, 11, 28, 114,
/* 020 */ 105, 87, 31, 53, 94,
/* 021 */ 100, 22, 41, 58, 119,
/* 022 */ 115, 57, 61, 83, 99,
/* 023 */ 110, 27, 71, 88, 109,
};
break;
}
case gHalfBring: {
connections = {
5, 12, 16, 23, 29,
0, 32, 36, 43, 49,
50, 41|symmask, 1, 48, 34|symmask,
53|symmask, 2, 42|symmask, 45|symmask, 39,
40, 31|symmask, 37|symmask, 3, 54|symmask,
38|symmask, 52, 47|symmask, 33, 4,
55, 21|symmask, 6, 28, 14|symmask,
58|symmask, 7, 22|symmask, 25|symmask, 19,
20, 11|symmask, 17|symmask, 8, 59|symmask,
18|symmask, 57, 27|symmask, 13, 9,
10, 56|symmask, 26, 15|symmask, 24|symmask,
30, 51|symmask, 46, 35|symmask, 44|symmask
};
break;
};
case gSchmutzM2: {
connections = {
23, 47, 27, 14, 38, 30, 17, 41, 33, 20, 44, 24,
35, 39, 3, 26, 42, 6, 29, 45, 9, 32, 36, 0,
11, 43, 15, 2, 46, 18, 5, 37, 21, 8, 40, 12,
22, 31, 4, 13, 34, 7, 16, 25, 10, 19, 28, 1,
};
break;
}
case gSchmutzM3: {
connections = {
23, 47, 64, 28, 15, 39, 68, 32, 19, 43, 60, 24,
35, 52, 40, 4, 27, 56, 44, 8, 31, 48, 36, 0,
11, 71, 57, 16, 3, 63, 49, 20, 7, 67, 53, 12,
22, 59, 69, 5, 14, 51, 61, 9, 18, 55, 65, 1,
21, 30, 62, 41, 13, 34, 66, 45, 17, 26, 70, 37,
10, 42, 50, 29, 2, 46, 54, 33, 6, 38, 58, 25,
};
break;
}
default: break;
}
}
void hrmap_quotient::build() {
dynamicval<hrmap*> cmap(currentmap, this);
int TOT = connections.size() / S7;
// printf("heptagons = %d\n", TOT);
// printf("all cells = %d\n", TOT*(S7+S3)/S3);
if(!TOT) exit(1);
allh.resize(TOT);
for(int i=0; i<TOT; i++) allh[i] = init_heptagon(S7);
// heptagon *oldorigin = origin;
allh[0]->alt = base.origin;
for(int i=0; i<TOT; i++) {
heptagon *h = allh[i];
if(true) {
h->s = hsOrigin;
h->fieldval = S7*i;
if(!IRREGULAR) h->c7 = newCell(S7, h);
}
for(int j=0; j<S7; j++) {
int co = connections[i*S7+j];
bool swapped = co & symmask;
co &= ~symmask;
h->move(rv(j)) = allh[co/S7];
h->c.setspin(rv(j), rv(co%S7), swapped);
}
}
vector<heptagon*> by_dist;
by_dist.push_back(allh[0]);
for(int i=0; i<TOT; i++) {
if(i >= isize(by_dist)) { printf("too fast\n"); exit(1); }
for(int a=0; a<S7; a++) if(by_dist[i]->move(a)->alt == NULL) by_dist.push_back(by_dist[i]->move(a));
currentmap->extend_altmap(by_dist[i], 0, false);
}
for(int i=0; i<TOT; i++) {
allh[i]->emeraldval = allh[i]->alt->emeraldval;
allh[i]->zebraval = allh[i]->alt->zebraval;
allh[i]->fiftyval = allh[i]->alt->fiftyval;
allh[i]->distance = allh[i]->alt->distance;
/* for(int j=0; j<7; j++)
allh[i]->move[j]->alt = createStep(allh[i]->alt, j); */
}
#if CAP_IRR
if(IRREGULAR) {
irr::link_start(allh[0]);
for(int i=0; i<TOT; i++)
for(int j=0; j<S7; j++)
irr::may_link_next(allh[i], j);
}
#endif
celllister cl(gamestart(), 100, 100000000, NULL);
celllist = cl.lst;
}
EX struct hrmap_quotient* new_map() { return new hrmap_quotient; }
EX }
}