9 #ifndef DynamicWeightedGrid_h
10 #define DynamicWeightedGrid_h
59 template <
int sectorSize>
61 uint8_t
cells[sectorSize][sectorSize];
62 uint8_t
region[sectorSize][sectorSize];
69 template <
int sectorSize>
75 void SaveMap(
const char *filename);
120 int numSectors =
sectors.size();
124 numEdges += i.edges.size();
125 numRegions += i.regionCenters.size();
136 numEdges += i.edges.size();
145 numRegions += i.regionCenters.size();
153 bool FindEdge(
int fromSector,
int fromRegion,
int toSector,
int toRegion)
const;
178 uint8_t val = (uint8_t)t;
207 #pragma mark DynamicWeightedGridEnvironment
216 void GetActions(
const xyLoc &nodeID, std::vector<tDirection> &actions)
const;
261 #pragma mark DynamicWeightedGrid Implementation
265 template <
int sectorSize>
271 for (uint16_t y = 0; y <
mHeight; y++)
273 for (uint16_t x = 0; x <
mWidth; x++)
281 template <
int sectorSize>
284 drawAbstraction =
false;
285 FILE *f = fopen(map,
"r");
288 printf(
"Unable to open file '%s'\n", map);
292 int num = fscanf(f,
"type %s\nheight %d\nwidth %d\nmap\n", format, &mHeight, &mWidth);
295 printf(
"Bad file format: '%s'\n", map);
298 sectors.resize(GetNumSectors());
300 for (uint16_t y = 0; y < mHeight; y++)
302 for (uint16_t x = 0; x < mWidth; x++)
304 fscanf(f,
"%c", &what);
307 fscanf(f,
"%c", &what);
309 printf(
"Error loading\n");
311 EliminateSmallRegions(minRegionSize);
315 template <
int sectorSize>
318 FILE *f = fopen(filename,
"w");
321 printf(
"Error opening '%s'\n", filename);
324 fprintf(f,
"type octile\nheight %d\nwidth %d\nmap\n", mHeight, mWidth);
325 for (uint16_t y = 0; y < mHeight; y++)
327 for (uint16_t x = 0; x < mWidth; x++)
329 fprintf(f,
"%c",
'A'+(
char)GetTerrainType({x, y}));
336 template <
int sectorSize>
340 template <
int sectorSize>
344 template <
int sectorSize>
347 int sec = GetSector(l);
349 GetSectorOffset(l, x, y);
350 if (sectors[sec].cells[x][y] != t)
352 sectors[sec].cells[x][y] = t;
357 GetEdges(sec-GetNumXSectors());
358 GetEdges(sec-GetNumXSectors()+1);
359 GetEdges(sec-GetNumXSectors()-1);
360 GetEdges(sec+GetNumXSectors());
361 GetEdges(sec+GetNumXSectors()+1);
362 GetEdges(sec+GetNumXSectors()-1);
366 template <
int sectorSize>
369 int sec = GetSector(l);
371 GetSectorOffset(l, x, y);
372 return static_cast<TerrainType>(sectors[sec].cells[x][y]);
376 template <
int sectorSize>
379 for (
int x = 0; x < GetNumSectors(); x++)
383 for (
int x = 0; x < GetNumSectors(); x++)
389 template <
int sectorSize>
393 d.regionCenters.clear();
394 int regionOffsetX = (sector%GetNumXSectors())*sectorSize;
395 int regionOffsetY = (sector/GetNumXSectors())*sectorSize;
397 for (
int x = 0; x < sectorSize; x++)
399 for (
int y = 0; y < sectorSize; y++)
405 for (
int x = 0; x < sectorSize; x++)
407 for (
int y = 0; y < sectorSize; y++)
411 d.regionCenters.push_back(
BFS(
d, x, y, whichRegion));
412 d.regionCenters.back().center.x += regionOffsetX;
413 d.regionCenters.back().center.y += regionOffsetY;
420 template <
int sectorSize>
423 int avgx = 0, avgy = 0;
425 static std::vector<std::pair<int, int>> inRegion;
426 static std::vector<std::pair<int, int>> stack;
429 stack.push_back({x, y});
430 while (stack.size() > 0)
432 auto i = stack.back();
436 d.region[i.first][i.second] = whichRegion;
437 inRegion.push_back({i.first, i.second});
441 if (i.first+1 < sectorSize && (
d.cells[i.first][i.second] ==
d.cells[i.first+1][i.second]))
442 stack.push_back({i.first+1, i.second});
443 if (i.first > 0 && (
d.cells[i.first][i.second] ==
d.cells[i.first-1][i.second]))
444 stack.push_back({i.first-1, i.second});
445 if (i.second+1 < sectorSize && (
d.cells[i.first][i.second] ==
d.cells[i.first][i.second+1]))
446 stack.push_back({i.first, i.second+1});
447 if (i.second > 0 && (
d.cells[i.first][i.second] ==
d.cells[i.first][i.second-1]))
448 stack.push_back({i.first, i.second-1});
451 xyLoc middle(avgx/count, avgy/count);
452 xyLoc best(inRegion[0].first, inRegion[0].second);
453 for (
auto &
loc : inRegion)
455 if ((
loc.first-middle.
x)*(
loc.first-middle.
x)+(
loc.second-middle.
y)*(
loc.second-middle.
y) <
456 (best.
x-middle.
x)*(best.
x-middle.
x)+(best.
y-middle.
y)*(best.
y-middle.
y))
462 return {best,
static_cast<uint8_t
>(
d.cells[x][y]),
static_cast<uint16_t
>(count)};
466 template <
int sectorSize>
469 if (sector < 0 || sector >= GetNumSectors())
474 int regionOffsetX = (sector%GetNumXSectors())*sectorSize;
475 int regionOffsetY = (sector/GetNumXSectors())*sectorSize;
477 for (
int x = 0; x < sectorSize; x++)
479 for (
int y = 0; y < sectorSize; y++)
481 xyLoc middle(regionOffsetX+x, regionOffsetY+y);
482 int r = GetRegion(middle);
483 int s = GetSector(middle);
485 for (
int x1 = -1; x1 <= 1; x1++)
487 for (
int y1 = -1; y1 <= 1; y1++)
489 xyLoc next(middle.
x+x1, middle.
y+y1);
490 if (next.
x >= mWidth || next.
y >= mHeight)
492 int r1 = GetRegion(next);
493 int s1 = GetSector(next);
494 if (r1 != r || s1 != s)
496 AddEdge(
d, s, r, s1, r1);
504 template <
int sectorSize>
507 for (
auto &e :
d.edges)
509 if (e.sectorFrom == s1 && e.sectorTo == s2 && e.regionFrom == r1 && e.regionTo == r2)
512 edge e = {s1, r1, s2, r2};
513 d.edges.push_back(e);
516 template <
int sectorSize>
520 for (
const auto &s : sectors)
522 for (
const auto &e : s.edges)
524 bool result = FindEdge(e.sectorTo, e.regionTo, e.sectorFrom, e.regionFrom);
527 assert(
fequal(HCost(f, t), HCost(t, f)));
530 printf(
"Found edge from %d:%d to %d:%d, but missing reverse edge\n", e.sectorFrom, e.regionFrom, e.sectorTo, e.regionTo);
536 printf(
"Edges validated\n");
538 printf(
"Edges did not validate\n");
541 template <
int sectorSize>
544 for (
const auto &e : sectors[fromSector].edges)
545 if (e.sectorFrom == fromSector && e.regionFrom == fromRegion &&
546 e.sectorTo == toSector && e.regionTo == toRegion)
551 template <
int sectorSize>
554 std::vector<int> regionCount;
555 std::vector<int32_t> regions(mWidth*mHeight, -1);
557 for (
int x = 0; x < mWidth; x++)
559 for (
int y = 0; y < mHeight; y++)
561 if (regions[y*mWidth+x] == -1)
563 regionCount.resize(regionCount.size()+1);
564 std::vector<xyLoc> stack;
565 stack.push_back({
static_cast<uint16_t
>(x),
static_cast<uint16_t
>(y)});
566 while (stack.size() > 0)
568 xyLoc i = stack.back();
570 if (regions[i.
y*mWidth+i.
x] == -1)
572 regions[i.
y*mWidth+i.
x] = whichRegion;
573 regionCount[whichRegion]++;
576 if (tmp.
x < mWidth && (GetTerrainType(i) == GetTerrainType(tmp)))
577 stack.push_back(tmp);
579 if (i.
x > 0 && (GetTerrainType(i) == GetTerrainType(tmp)))
580 stack.push_back(tmp);
582 if (tmp.
y < mHeight && (GetTerrainType(i) == GetTerrainType(tmp)))
583 stack.push_back(tmp);
585 if (i.
y > 0 && (GetTerrainType(i) == GetTerrainType(tmp)))
586 stack.push_back(tmp);
593 printf(
"%d regions after first BFS\n", whichRegion);
594 for (
int x = 0; x < mWidth; x++)
596 for (
int y = 0; y < mHeight; y++)
598 if (regionCount[regions[y*mWidth+x]] > limit)
602 if (tmp.
x < mWidth && (regionCount[regions[tmp.
y*mWidth+tmp.
x]]) <= limit)
604 SetTerrainTypeNoRepair(tmp, GetTerrainType(i));
605 regions[tmp.
y*mWidth+tmp.
x] = regions[y*mWidth+x];
608 if (i.x > 0 && (regionCount[regions[tmp.
y*mWidth+tmp.
x]]) <= limit)
610 SetTerrainTypeNoRepair(tmp, GetTerrainType(i));
611 regions[tmp.
y*mWidth+tmp.
x] = regions[y*mWidth+x];
614 if (tmp.
y < mHeight && (regionCount[regions[tmp.
y*mWidth+tmp.
x]]) <= limit)
616 SetTerrainTypeNoRepair(tmp, GetTerrainType(i));
617 regions[tmp.
y*mWidth+tmp.
x] = regions[y*mWidth+x];
620 if (i.y > 0 && (regionCount[regions[tmp.
y*mWidth+tmp.
x]]) <= limit)
622 SetTerrainTypeNoRepair(tmp, GetTerrainType(i));
623 regions[tmp.
y*mWidth+tmp.
x] = regions[y*mWidth+x];
628 regionCount.resize(0);
629 for (
auto &x : regions)
632 for (
int x = 0; x < mWidth; x++)
634 for (
int y = 0; y < mHeight; y++)
636 if (regions[y*mWidth+x] == -1)
638 regionCount.resize(regionCount.size()+1);
639 std::vector<xyLoc> stack;
640 stack.push_back({
static_cast<uint16_t
>(x),
static_cast<uint16_t
>(y)});
641 while (stack.size() > 0)
643 xyLoc i = stack.back();
645 if (regions[i.
y*mWidth+i.
x] == -1)
647 regions[i.
y*mWidth+i.
x] = whichRegion;
648 regionCount[whichRegion]++;
651 if (tmp.
x < mWidth && (GetTerrainType(i) == GetTerrainType(tmp)))
652 stack.push_back(tmp);
654 if (i.
x > 0 && (GetTerrainType(i) == GetTerrainType(tmp)))
655 stack.push_back(tmp);
657 if (tmp.
y < mHeight && (GetTerrainType(i) == GetTerrainType(tmp)))
658 stack.push_back(tmp);
660 if (i.
y > 0 && (GetTerrainType(i) == GetTerrainType(tmp)))
661 stack.push_back(tmp);
668 printf(
"%d regions after second BFS\n", whichRegion);
673 template <
int sectorSize>
682 template <
int sectorSize>
685 return sectors[a.
sector].regionCenters[a.
region].center;
688 template <
int sectorSize>
691 return ((mWidth+sectorSize-1)/sectorSize)*((mHeight+sectorSize-1)/sectorSize);
695 template <
int sectorSize>
698 return ((mWidth+sectorSize-1)/sectorSize);
702 template <
int sectorSize>
705 return ((mHeight+sectorSize-1)/sectorSize);
709 template <
int sectorSize>
713 GetSectorOffset(l, x, y);
714 return sectors[GetSector(l)].region[x][y];
717 template <
int sectorSize>
720 int secx = l.
x/sectorSize;
721 int secy = l.
y/sectorSize;
722 return secy*GetNumXSectors()+secx;
725 template <
int sectorSize>
732 template <
int sectorSize>
735 int sec = GetSector(l);
737 GetSectorOffset(l, x, y);
738 if (sectors[sec].cells[x][y] != t)
740 sectors[sec].cells[x][y] = t;
744 template <
int sectorSize>
749 for (
auto e :
d.edges)
751 if (e.regionFrom != nodeID.
region)
753 neighbors.push_back({e.sectorTo, e.regionTo});
757 template <
int sectorSize>
762 for (
auto e :
d.edges)
764 if (e.regionFrom != nodeID.
region)
766 actions.push_back(e);
770 template <
int sectorSize>
777 template <
int sectorSize>
785 template <
int sectorSize>
788 assert(!
"Not implemented");
792 template <
int sectorSize>
798 const double DIAGONAL_COST = M_SQRT2;
799 double a = ((l1.
x>l2.
x)?(l1.
x-l2.
x):(l2.
x-l1.
x));
800 double b = ((l1.
y>l2.
y)?(l1.
y-l2.
y):(l2.
y-l1.
y));
803 return ((a>b)?(b*DIAGONAL_COST+a-b):(a*DIAGONAL_COST+b-a));
806 template <
int sectorSize>
812 const double DIAGONAL_COST = M_SQRT2;
813 double a = ((l1.
x>l2.
x)?(l1.
x-l2.
x):(l2.
x-l1.
x));
814 double b = ((l1.
y>l2.
y)?(l1.
y-l2.
y):(l2.
y-l1.
y));
819 return 0.5*(c1+c2)*((a>b)?(b*DIAGONAL_COST+a-b):(a*DIAGONAL_COST+b-a));
822 template <
int sectorSize>
826 ApplyAction(tmp, act);
827 return GCost(
node, tmp);
830 template <
int sectorSize>
836 template <
int sectorSize>
839 uint64_t a =
node.sector;
840 uint64_t b =
node.region;
844 template <
int sectorSize>
847 assert(!
"not implemented");
851 template <
int sectorSize>
854 float _scale, xOffset, yOffset;
855 if (mHeight > mWidth)
857 _scale = 2.0/(float)(mHeight);
858 xOffset = (2.0-mWidth*_scale)*0.5;
862 _scale = 2.0/(float)(mWidth);
863 yOffset = (2.0-mHeight*_scale)*0.5;
866 float epsilon = _scale/2.0;
867 x = -1+l.
x*_scale+epsilon+xOffset;
868 y = -1+l.
y*_scale+epsilon+yOffset;
874 template <
int sectorSize>
878 double _scale, xOffset, yOffset;
879 if (mHeight > mWidth)
881 _scale = 2.0/(double)(mHeight);
882 xOffset = (2.0-mWidth*_scale)*0.5;
886 _scale = 2.0/(double)(mWidth);
887 yOffset = (2.0-mHeight*_scale)*0.5;
890 double epsilon = _scale/2.0;
892 _x = (
loc.
x-epsilon+1-xOffset)/_scale;
893 _y = (
loc.
y-epsilon+1-yOffset)/_scale;
897 if ((px < 0) || (py < 0) || (px >= mWidth) || (py >= mHeight))
903 template <
int sectorSize>
906 auto &s = sectors[sector];
907 int regionOffsetX = (sector%GetNumXSectors())*sectorSize;
908 int regionOffsetY = (sector/GetNumXSectors())*sectorSize;
909 uint16_t largest = 0;
910 for (
size_t x = 1; x < s.regionCenters.size(); x++)
912 if (s.regionCenters[x].count > s.regionCenters[largest].count)
917 xyLoc l(regionOffsetX, regionOffsetY);
918 GetCoordinate(l, x, y, r);
920 display.
FillSquare({x-r+r*sectorSize, y-r+r*sectorSize}, r*sectorSize,
921 GetTerrainColor((
TerrainType)s.regionCenters[largest].terrain));
922 for (
int yy = 0; yy < sectorSize; yy++)
926 for (
int xx = 0; xx < sectorSize; xx++)
929 if (s.cells[xx][yy] == s.cells[startx][starty])
933 if (s.cells[startx][starty] != (
TerrainType)s.regionCenters[largest].terrain)
935 l.
x = regionOffsetX+startx;
936 l.
y = regionOffsetY+starty;
937 GetCoordinate(l, x, y, r);
938 display.
FillRect({x-r, y-r, x-r+2*r*(xx-startx), y+r},
939 GetTerrainColor((
TerrainType)s.cells[startx][starty]));
943 if (startx < sectorSize)
945 if (s.cells[startx][starty] != (
TerrainType)s.regionCenters[largest].terrain)
947 l.
x = regionOffsetX+startx;
948 l.
y = regionOffsetY+starty;
949 GetCoordinate(l, x, y, r);
950 display.
FillRect({x-r, y-r, x-r+2*r*(sectorSize-startx), y+r},
951 GetTerrainColor((
TerrainType)s.cells[startx][starty]));
957 template <
int sectorSize>
960 for (
int t = 0; t < sectors.size(); t++)
962 DrawSector(display, t);
964 if (!drawAbstraction)
968 for (
int x = 0; x < mWidth; x+=sectorSize)
970 float xx1, yy1, rr, xx2, yy2;
971 xyLoc l1(x, 0), l2(x, mHeight);
972 GetCoordinate(l1, xx1, yy1, rr);
973 GetCoordinate(l2, xx2, yy2, rr);
976 for (
int y = 0; y < mHeight; y+=sectorSize)
978 float xx1, yy1, rr, xx2, yy2;
979 xyLoc l1(0, y), l2(mWidth, y);
980 GetCoordinate(l1, xx1, yy1, rr);
981 GetCoordinate(l2, xx2, yy2, rr);
985 for (
int s = 0; s < GetNumSectors(); s++)
988 for (
auto i :
d.regionCenters)
991 GetCoordinate(i.center, x, y, r);
994 for (
auto e :
d.edges)
996 xyLoc l1 = sectors[e.sectorFrom].regionCenters[e.regionFrom].center;
997 xyLoc l2 = sectors[e.sectorTo].regionCenters[e.regionTo].center;
999 float xx1, yy1, rr, xx2, yy2;
1000 GetCoordinate(l1, xx1, yy1, rr);
1001 GetCoordinate(l2, xx2, yy2, rr);
1007 template <
int sectorSize>
1012 GetCoordinate(l, x, y, r);