mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-30 13:32:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			262 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			262 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // algorithms to compute distances between mycells, and an implementation of tally counter
 | |
| 
 | |
| namespace dhrg {
 | |
| 
 | |
| int segmentcount;
 | |
| 
 | |
| struct qtybox {
 | |
|   int minv, maxv;
 | |
|   int qty[BOXSIZE];
 | |
|   int& operator [] (int i) { 
 | |
|     if(i>=BOXSIZE)
 | |
|       throw hr_exception("not enough memory reserved -- increase BOXSIZE constant");
 | |
|     return qty[i]; 
 | |
|     }
 | |
|   qtybox() { for(int i=0; i<BOXSIZE; i++) qty[i] = 0; minv = BOXSIZE; maxv = 0; }
 | |
|   };
 | |
|   
 | |
| struct segment {
 | |
|   mycell *left;
 | |
|   mycell *right;
 | |
|   segment *nextleft;
 | |
|   segment *nextright;
 | |
|   segment *parent;
 | |
|   segment *nextchild;
 | |
|   segment *firstchild;
 | |
|   qtybox qty;
 | |
|   int seen;
 | |
|   segment() { seen = -1; segmentcount++; }
 | |
|   ~segment() { segmentcount--; }
 | |
|   };
 | |
| 
 | |
| segment *getsegment(mycell *pleft, mycell *pright, int setid, bool docreate = true) {
 | |
|   pleft->build(); pright->build();
 | |
|   segment *c1 = pleft->byleft[setid];
 | |
|   while(c1) {
 | |
|     if(c1->right == pright) {
 | |
|       return c1;
 | |
|       }
 | |
|     c1 = c1 -> nextleft;
 | |
|     }
 | |
|   if(!docreate) return c1;
 | |
|   segment *p = new segment;
 | |
|   p->left = pleft;
 | |
|   p->right = pright;
 | |
|   p->nextleft = pleft->byleft[setid]; pleft->byleft[setid] = p;
 | |
|   p->nextright = pright->byright[setid]; pright->byright[setid] = p;
 | |
|   p->nextchild = NULL; p->firstchild = NULL;
 | |
|   if(pleft->leftparent) {
 | |
|     p->parent = getsegment(pleft->leftparent, pright->rightparent, setid);
 | |
|     p->nextchild = p->parent->firstchild;
 | |
|     p->parent->firstchild = p;
 | |
|     }
 | |
|   else 
 | |
|     p->parent = NULL;
 | |
|   #ifdef LONG_BRACKETS
 | |
|   if(pleft != pright) {
 | |
|     pleft = pleft->grightsibling();
 | |
|     int slen = 0;
 | |
|     while(pleft != pright) {
 | |
|       segmentlist *n = new segmentlist;
 | |
|       slen++;
 | |
|       n->s = p;
 | |
|       n->next = pleft->bracketing;
 | |
|       pleft->bracketing = n;
 | |
|       pleft = pleft->grightsibling();
 | |
|       }
 | |
|     if(slen > 10) throw hr_exception("bad bracket");
 | |
|     }
 | |
|   #endif
 | |
|   return p;
 | |
|   }
 | |
| 
 | |
| ll tally[MAXDIST];
 | |
| 
 | |
| ll *whichtally = tally;
 | |
| 
 | |
| vector<segment*> acknowledged;
 | |
| 
 | |
| void tallybox(qtybox& box, int d, int mul) {
 | |
|   for(int i=box.minv; i<box.maxv; i++)
 | |
|     whichtally[i+d] += box[i] * mul;
 | |
|   }
 | |
| 
 | |
| void acknowledge(segment *p, int d) {
 | |
|   if(!p) return;
 | |
|   if(p->seen == -1) {
 | |
|     p->seen = d;
 | |
|     acknowledged.emplace_back(p);
 | |
|     }
 | |
|   else if(p->seen > d) 
 | |
|     p->seen = d;
 | |
|   }
 | |
| 
 | |
| void acknowledgments(int mul) {
 | |
|   for(segment* p: acknowledged) {
 | |
|     tallybox(p->qty, p->seen, mul);
 | |
|     segment *p2 = p->parent;
 | |
|     int dist = 1;
 | |
|     while(p2) {
 | |
|       if(p2->seen != -1) {
 | |
|         tallybox(p->qty, p2->seen+dist, -mul);
 | |
|         break;
 | |
|         }
 | |
|       p2=p2->parent; dist++;
 | |
|       }
 | |
|     p->seen = -1;
 | |
|     }
 | |
|   acknowledged.clear();
 | |
|   }
 | |
| 
 | |
| void trim(qtybox& b) {
 | |
|   while(b.minv < b.maxv && !b[b.minv]) b.minv++;
 | |
|   if(b.minv == b.maxv) b.minv = BOXSIZE, b.maxv = 0;
 | |
|   else while(!b[b.maxv-1]) b.maxv--;
 | |
|   }
 | |
| 
 | |
| void add_to_set(mycell *c, int mul, int setid) {
 | |
|   // assume mul does not equal 0 !
 | |
|   segment *p = getsegment(c, c, setid);
 | |
|   int d = 0;
 | |
|   while(p) {    
 | |
|     p->qty[d] += mul;
 | |
|     if(p->qty[d]) {
 | |
|       p->qty.minv = min(p->qty.minv, d);
 | |
|       p->qty.maxv = max(p->qty.maxv, d+1);
 | |
|       }
 | |
|     else trim(p->qty);
 | |
|     d++; p = p->parent;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| int segmentdist(segment *p1, segment *p2, int d);
 | |
| 
 | |
| void build_ack(mycell *c, int setid) {
 | |
|   segment *p = getsegment(c, c, setid);
 | |
|   int d = 0;
 | |
|   
 | |
|   #ifdef LONG_BRACKETS
 | |
|   segmentlist *brackets = c->bracketing;
 | |
|   while(brackets) {
 | |
|     acknowledge(brackets->s, 0);
 | |
|     brackets = brackets->next;
 | |
|     }
 | |
|   #else
 | |
|   acknowledge(getsegment(c->gleftsibling(), c->grightsibling(), setid, false), 0); // larger!
 | |
|   #endif
 | |
| 
 | |
|   while(p) {
 | |
|     if(p->left != p->right) {
 | |
|       mycell *cc = p->left->grightsibling();
 | |
|       while(cc != p->right) {
 | |
|         acknowledge(getsegment(cc, cc, setid, false), d);
 | |
|         cc = cc->grightsibling();
 | |
|         }
 | |
|       }
 | |
|     
 | |
|     int sl = cgi.expansion->sibling_limit;
 | |
| 
 | |
|     mycell *mright = p->right;    
 | |
|     mycell *mright0 = mright;
 | |
|     for(int u=0; u<=sl; u++) {
 | |
|       mright->build();
 | |
|       segment *mrightbyleft = mright->byleft[setid];
 | |
|       while(mrightbyleft) {
 | |
|         if(u == 3 && p->right->rightparent == mright->leftparent)
 | |
|           acknowledge(mrightbyleft, d+2);
 | |
|         else if(u > 3)
 | |
|           acknowledge(mrightbyleft, segmentdist(getsegment(mright0, mright0, setid), mrightbyleft, d));
 | |
|         else 
 | |
|           acknowledge(mrightbyleft, d+u);
 | |
|         mrightbyleft = mrightbyleft->nextleft;
 | |
|         }
 | |
|       mright=mright->grightsibling();
 | |
|       }
 | |
|     
 | |
|     mycell *mleft = p->left;
 | |
|     mycell *mleft0 = mleft;
 | |
|     for(int u=0; u<=sl; u++) {
 | |
|       mleft->build();
 | |
|       segment *mleftbyright = mleft->byright[setid];
 | |
|       while(mleftbyright) {
 | |
|         if(u == 3 && p->left -> leftparent == mleft->rightparent)
 | |
|           acknowledge(mleftbyright, d+2);
 | |
|         else if(u > 3)
 | |
|           acknowledge(mleftbyright, segmentdist(mleftbyright, getsegment(mleft0, mleft0, setid), d));
 | |
|         else 
 | |
|           acknowledge(mleftbyright, d+u);
 | |
|         mleftbyright = mleftbyright->nextright;
 | |
|         }
 | |
|       mleft=mleft->gleftsibling();
 | |
|       }
 | |
|  
 | |
|     // go forth
 | |
|     d++; p = p->parent;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| void add_to_tally(mycell *c, int mul, int setid) {
 | |
|   build_ack(c, setid);
 | |
|   acknowledgments(mul);
 | |
|   }
 | |
| 
 | |
| bool is_insegment(mycell *c, segment *p) {
 | |
|   mycell *p1 = p->left;
 | |
|   mycell *p2 = p->right;
 | |
|   while(true) {
 | |
|     if(c == p1) return true;
 | |
|     if(p1 == p2) return false;
 | |
|     p1 = p1->grightsibling();
 | |
|     }
 | |
|   }
 | |
| 
 | |
| int segmentdist(segment *p1, segment *p2, int d) {
 | |
| 
 | |
|   if(p1->left == p1->right && is_insegment(p1->left, p2)) return d;
 | |
|   if(p2->left == p2->right && is_insegment(p2->left, p1)) return d;
 | |
|   
 | |
|   int best = 1000000;
 | |
|   
 | |
|   while(true) {
 | |
|     if(d >= best) return best;
 | |
|     mycell *mright;
 | |
|     
 | |
|     int sl = cgi.expansion->sibling_limit;
 | |
|     
 | |
|     mright = p1->right;
 | |
|     for(int u=0; u<=sl; u++) {
 | |
|       mright->build();
 | |
|       if(mright == p2->left) best = min(best, d+u);
 | |
|       mright = mright->grightsibling();
 | |
|       }
 | |
| 
 | |
|     mright = p2->right;
 | |
|     for(int u=0; u<=sl; u++) {
 | |
|       mright->build();
 | |
|       if(mright == p1->left) best = min(best, d+u);
 | |
|       mright = mright->grightsibling();
 | |
|       }
 | |
|     
 | |
|     p1 = p1->parent;
 | |
|     p2 = p2->parent;
 | |
|     d += 2;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| int quickdist(mycell *c1, mycell *c2, int setid=0) {
 | |
|   int d = 0;
 | |
|   c1->build();
 | |
|   c2->build();
 | |
|   int d1 = c1->lev;
 | |
|   int d2 = c2->lev;
 | |
|   segment *p1 = getsegment(c1, c1, setid);
 | |
|   segment *p2 = getsegment(c2, c2, setid);
 | |
|   
 | |
|   while(d1>d2) { p1 = p1->parent; d1--; d++; }
 | |
|   while(d2>d1) { p2 = p2->parent; d2--; d++; }
 | |
|   
 | |
|   return segmentdist(p1, p2, d);
 | |
|   }
 | |
|   
 | |
| }
 | 
