30#include "MazeDynamic.h"
41static double aRandsSequence[] = {0.5129719235575136, 0.34348663304017557, 0.6661675989013662, 0.8596401856537104, 0.7144370682013301, 0.6571361789295214, 0.34061865256273527, 0.26202101108360587, 0.8688143512246322, 0.28898641980463524, 0.5304491684794037, 0.5554456481914671, 0.885355280505715, 0.8190719526946917, 0.6974568050485852, 0.8828828341655219, 0.276211699397634, 0.5462919073561716, 0.4671018356657537, 0.9350492706174056, 0.4779938422203398, 0.14721994418484585, 0.07612282547423832, 0.08780624670671422, 0.5943574517779637, 0.5221223829803883, 0.950987812197468, 0.2515330680939367, 0.14530868975510303, 0.2141918743985214, 0.74386825375617, 0.04525929141234375, 0.5753222964802585, 0.09554464411922603, 0.3460382031154865, 0.5435667417622243, 0.5786996323071909, 0.7541216428297157, 0.815797431679153, 0.6148391444621712, 0.013622973716154396, 0.26998664508467574, 0.3755701627468324, 0.7366815337453705, 0.8647608188233733, 0.13491547393494874, 0.2651724843447003, 0.6839982200395627, 0.670120029478374, 0.4513346589990226, 0.148727134762499, 0.47898349686439845, 0.352502337478225, 0.013382332037334077, 0.4780248626694803, 0.11471872347846479, 0.772679046209471, 0.08110571353164886, 0.9184054717229515, 0.15836324769915255, 0.2670807865518203, 0.43575980318532426, 0.19995378915659767, 0.8578353258248839, 0.023989304783126553, 0.39804897722056665, 0.4524796211277611, 0.18039796942653386, 0.04254758763279742, 0.2051481413629721, 0.5348289162359152, 0.3487847843118419, 0.7850501537804806, 0.9191684131753015, 0.8660164189740158, 0.9956579431789447, 0.6957477848968698, 0.03147128686622458, 0.9029694124616181, 0.4411391854837914, 0.52393126757956, 0.6292688283103802, 0.5824683335701215, 0.0279643412305417, 0.7908692161361748, 0.7254442799010183, 0.8205915580620644 };
42static Sint32 iRandsSequenceSize = 87;
45Maze::Maze(Sint32 iR, Sint32 iC)
49 memset(tallRows, 0,
sizeof(tallRows));
50 memset(narrowCols, 0,
sizeof(narrowCols));
55 Main::Instance().ITool().randSeedWELL(29031978, randSeed);
64Sint32 Maze::createMaze(vector<Uint8>& vTiles)
73 if(!isDesirable())
continue;
77 if(!createTunnels())
continue;
80 generateTiles(vTiles);
82 for(Sint32 i = 0; i < tileCells.size(); ++i) tileCells[i].info();
102 final_x = final_w = final_y = final_h = 0;
103 isRaiseHeightCandidate =
false;
104 isShrinkWidthCandidate =
false;
107 isJoinCandidate =
false;
109 singleDeadEndDir =
false;
110 isEdgeTunnelCandidate =
false;
111 isVoidTunnelCandidate =
false;
112 isSingleDeadEndCandidate =
false;
113 isDoubleDeadEndCandidate =
false;
116#ifdef DEBUG_GENERATOR
117void Maze::stCell::info()
120 Main& mC64 = Main::Instance();
121 Log& mLog = *mC64.ILogMgr().get();
122 mLog.msg(LML_NORMAL,
"(%d,%d)-%s-", x, y, (filled ==
true) ?
"true" :
"false");
123 mLog.msg(LML_NORMAL,
"%s.%s.%s.%s-",
124 (connect[0] ==
true) ?
"true" :
"false", (connect[1] ==
true) ?
"true" :
"false", (connect[2] ==
true) ?
"true" :
"false", (connect[3] ==
true) ?
"true" :
"false");
125 mLog.msg(LML_NORMAL,
"%s.%s.%s.%s-",
126 (next[0] ==
nullptr) ?
"null" :
"defined", (next[1] ==
nullptr) ?
"null" :
"defined", (next[2] ==
nullptr) ?
"null" :
"defined", (next[3] ==
nullptr) ?
"null" :
"defined");
127 mLog.msg(LML_NORMAL,
"%d-%d-", no, group);
128 mLog.msg(LML_NORMAL,
"%d.%d.%d.%d-", final_x, final_w, final_y, final_h);
129 mLog.msg(LML_NORMAL,
"%s.%s.%s.%s.%s.%s\n",
130 (isRaiseHeightCandidate) ?
"isRaiseHeightCandidate" :
"",
131 (isShrinkWidthCandidate) ?
"isShrinkWidthCandidate" :
"",
132 (shrinkWidth) ?
"shrinkWidth" :
"",
133 (raiseHeight) ?
"raiseHeight" :
"",
134 (isJoinCandidate) ?
"isJoinCandidate" :
"",
135 (topTunnel) ?
"topTunnel" :
""
143 stCell sCell, *pCell;
149 for(i = 0; i < rows * cols; i++)
152 sCell.y = (Sint32)floor(i / cols);
153 vCells.push_back(sCell);
157 for(i = 0; i < rows * cols; i++)
160 if(pCell->x > 0) pCell->next[LEFT] = &vCells[i - 1];
161 if(pCell->x < cols - 1) pCell->next[RIGHT] = &vCells[i + 1];
162 if(pCell->y > 0) pCell->next[UP] = &vCells[i - cols];
163 if(pCell->y < rows - 1) pCell->next[DOWN] = &vCells[i + cols];
169 pCell->filled =
true;
170 pCell->connect[LEFT] = pCell->connect[RIGHT] = pCell->connect[DOWN] =
true;
174 pCell->filled =
true;
175 pCell->connect[LEFT] = pCell->connect[DOWN] =
true;
179 pCell->filled =
true;
180 pCell->connect[LEFT] = pCell->connect[UP] = pCell->connect[RIGHT] =
true;
184 pCell->filled =
true;
185 pCell->connect[UP] = pCell->connect[LEFT] =
true;
187 numFilled = numGroups = iNumRands = 0;
191#ifdef DEBUG_GENERATOR
193Sint32 Maze::getRandomInt(Sint32 min, Sint32 max)
197 iRnd = aRandsSequence[iNumRands % iRandsSequenceSize];
198 iRet = (Sint32)floor(iRnd * (max - min + 1)) + min;
204double Maze::getRandomReal()
206 double iRnd = aRandsSequence[iNumRands % iRandsSequenceSize];
213Sint32 Maze::getRandomInt(Sint32 min, Sint32 max)
216 return (Sint32)floor(Main::Instance().ITool().randRealWELL(&randState, randSeed) * (max - min + 1)) + min;
220double Maze::getRandomReal()
223 return Main::Instance().ITool().randRealWELL(&randState, randSeed);
227Maze::stCell* Maze::randomElement(vector<stCell*>& vList)
231 return vList[getRandomInt(0, (Sint32)vList.size() - 1)];
236Sint32 Maze::suffle(vector<stCell*>& vSuffle)
238 Sint32 iLen = (Sint32)vSuffle.size();
242 for(i = 0; i < iLen; i++)
244 j = getRandomInt(0, iLen - 1);
246 vSuffle[i] = vSuffle[j];
252void Maze::getOpenCells(stCell& cell, Sint32 prevDir, Sint32 size, vector<Sint32>& openCells)
257 for(i = 0; i < 4; i++)
259 if(isOpenCell(cell, i, prevDir, size))
261 openCells.push_back(i);
266Sint32 Maze::getLeftMostEmptyCells(vector<stCell*>& leftCells)
272 for(x = 0; x < cols; x++)
274 for(y = 0; y < rows; y++)
276 pCell = &vCells[x + y * cols];
277 if(!pCell->filled) leftCells.push_back(pCell);
280 if(leftCells.size() > 0)
break;
285bool Maze::isOpenCell(stCell& cell, Sint32 i, Sint32 prevDir, Sint32 size)
288 if(cell.y == 6 && cell.x == 0 && i == DOWN || cell.y == 7 && cell.x == 0 && i == UP)
return false;
291 if(size == 2 && (i == prevDir || (i + 2) % 4 == prevDir))
return false;
294 if(cell.next[i] && !cell.next[i]->filled)
297 if(cell.next[i]->next[LEFT] && !cell.next[i]->next[LEFT]->filled) {}
303void Maze::connectCell(stCell& cell, Sint32 dir)
305 cell.connect[dir] =
true;
306 cell.next[dir]->connect[(dir + 2) % 4] =
true;
307 if(cell.x == 0 && dir == RIGHT) cell.connect[LEFT] =
true;
310void Maze::setResizeCandidates()
317 for(i = 0; i < rows * cols; i++)
319 stCell& c = vCells[i];
321 y = (Sint32)floor(i / cols);
330 if((c.x == 0 || !q[LEFT]) && (c.x == cols - 1 || !q[RIGHT]) && q[UP] != q[DOWN]) c.isRaiseHeightCandidate =
true;
335 stCell* c2 = c.next[RIGHT];
339 if(((c.x == 0 || !q[LEFT]) && !q[UP] && !q[DOWN]) && ((c2->x == cols - 1 || !q2[RIGHT]) && !q2[UP] && !q2[DOWN])) c.isRaiseHeightCandidate = c2->isRaiseHeightCandidate =
true;
344 if(c.x == cols - 1 && q[RIGHT]) c.isShrinkWidthCandidate =
true;
353 if((c.y == 0 || !q[UP]) && (c.y == rows - 1 || !q[DOWN]) && q[LEFT] != q[RIGHT]) c.isShrinkWidthCandidate =
true;
358bool Maze::cellIsCrossCenter(stCell& c)
360 return c.connect[UP] && c.connect[RIGHT] && c.connect[DOWN] && c.connect[LEFT];
363bool Maze::canShrinkWidth(Sint32 x, Sint32 y)
366 Sint32 numCandidates = 0;
368 vector<stCell*> pCandidates;
371 if(y == rows - 1)
return true;
374 for(i = x; i < cols; i++)
376 stCell& c = vCells[i + y * cols];
378 if((!c.connect[RIGHT] || cellIsCrossCenter(c)) && (!c2->connect[RIGHT] || cellIsCrossCenter(*c2)))
break;
382 for(; c2; c2 = c2->next[LEFT])
384 if(c2->isShrinkWidthCandidate)
386 pCandidates.push_back(c2);
391 if((!c2->connect[LEFT] || cellIsCrossCenter(*c2)) && (!c2->next[UP]->connect[LEFT] || cellIsCrossCenter(*c2->next[UP])))
break;
397 for(i = 0; i < numCandidates; i++)
400 if(canShrinkWidth(c2->x, c2->y))
402 c2->shrinkWidth =
true;
403 narrowCols[c2->y] = c2->x;
410bool Maze::chooseNarrowCols()
414 for(x = cols - 1; x >= 0; x--)
416 stCell& c = vCells[x];
417 if(c.isShrinkWidthCandidate && canShrinkWidth(x, 0))
419 c.shrinkWidth =
true;
420 narrowCols[c.y] = c.x;
427bool Maze::canRaiseHeight(Sint32 x, Sint32 y)
430 Sint32 numCandidates = 0;
432 vector<stCell*> pCandidates;
435 if(x == cols - 1)
return true;
438 for(i = y; i >= 0; i--)
440 stCell& c = vCells[x + i * cols];
442 if((!c.connect[UP] || cellIsCrossCenter(c)) && (!c2->connect[UP] || cellIsCrossCenter(*c2)))
break;
446 for(; c2; c2 = c2->next[DOWN])
448 if(c2->isRaiseHeightCandidate)
450 pCandidates.push_back(c2);
455 if((!c2->connect[DOWN] || cellIsCrossCenter(*c2)) && (!c2->next[LEFT]->connect[DOWN] || cellIsCrossCenter(*c2->next[LEFT])))
break;
461 for(i = 0; i < numCandidates; i++)
464 if(canRaiseHeight(c2->x, c2->y))
466 c2->raiseHeight =
true;
467 tallRows[c2->x] = c2->y;
475bool Maze::chooseTallRows()
480 for(y = 0; y < 3; y++)
482 stCell& c = vCells[y*cols];
483 if(c.isRaiseHeightCandidate && canRaiseHeight(0, y))
485 c.raiseHeight =
true;
494bool Maze::isHori(Sint32 x, Sint32 y)
496 bool* q1 = vCells[x + y * cols].connect;
497 bool* q2 = vCells[x + 1 + y * cols].connect;
498 return !q1[UP] && !q1[DOWN] && (x == 0 || !q1[LEFT]) && q1[RIGHT] && !q2[UP] && !q2[DOWN] && q2[LEFT] && !q2[RIGHT];
501bool Maze::isVert(Sint32 x, Sint32 y)
503 bool* q1 = vCells[x + y * cols].connect;
504 bool* q2 = vCells[x + (y + 1)*cols].connect;
508 return !q1[LEFT] && !q1[UP] && !q1[DOWN] && !q2[LEFT] && !q2[UP] && !q2[DOWN];
510 return !q1[LEFT] && !q1[RIGHT] && !q1[UP] && q1[DOWN] && !q2[LEFT] && !q2[RIGHT] && q2[UP] && !q2[DOWN];
514bool Maze::isDesirable()
519 stCell& rCTR = vCells[4];
520 if(rCTR.connect[UP] || rCTR.connect[RIGHT])
return false;
523 stCell& rCBR = vCells[rows*cols - 1];
524 if(rCBR.connect[DOWN] || rCBR.connect[RIGHT])
return false;
526 for(y = 0; y < rows - 1; y++)
528 for(x = 0; x < cols - 1; x++)
530 if(isHori(x, y) && isHori(x, y + 1) || isVert(x, y) && isVert(x + 1, y))
533 if(x == 0)
return false;
536 vCells[x + y * cols].connect[DOWN] =
true;
537 vCells[x + y * cols].connect[RIGHT] =
true;
538 g = vCells[x + y * cols].group;
540 vCells[x + 1 + y * cols].connect[DOWN] =
true;
541 vCells[x + 1 + y * cols].connect[LEFT] =
true;
542 vCells[x + 1 + y * cols].group = g;
544 vCells[x + (y + 1)*cols].connect[UP] =
true;
545 vCells[x + (y + 1)*cols].connect[RIGHT] =
true;
546 vCells[x + (y + 1)*cols].group = g;
548 vCells[x + 1 + (y + 1)*cols].connect[UP] =
true;
549 vCells[x + 1 + (y + 1)*cols].connect[LEFT] =
true;
550 vCells[x + 1 + (y + 1)*cols].group = g;
555 if(!chooseTallRows())
return false;
557 if(!chooseNarrowCols())
return false;
563void Maze::setUpScaleCoords()
566 for(i = 0; i < rows * cols; i++)
568 stCell& c = vCells[i];
570 if(narrowCols[c.y] < c.x) c.final_x--;
572 if(tallRows[c.x] < c.y) c.final_y++;
573 c.final_w = c.shrinkWidth ? 2 : 3;
574 c.final_h = c.raiseHeight ? 4 : 3;
579void Maze::joinWalls()
584 for(x = 0; x < cols; x++)
586 stCell& c = vCells[x];
587 if(!c.connect[LEFT] && !c.connect[RIGHT] && !c.connect[UP] && (!c.connect[DOWN] || !c.next[DOWN]->connect[DOWN]))
590 if((!c.next[LEFT] || !c.next[LEFT]->connect[UP]) && (c.next[RIGHT] && !c.next[RIGHT]->connect[UP]))
593 if(!(c.next[DOWN] && c.next[DOWN]->connect[RIGHT] && c.next[DOWN]->next[RIGHT]->connect[RIGHT]))
595 c.isJoinCandidate =
true;
596 if(getRandomReal() <= 0.25) c.connect[UP] =
true;
603 for(x = 0; x < cols; x++)
605 stCell& c = vCells[x + (rows - 1)*cols];
606 if(!c.connect[LEFT] && !c.connect[RIGHT] && !c.connect[DOWN] && (!c.connect[UP] || !c.next[UP]->connect[UP]))
609 if((!c.next[LEFT] || !c.next[LEFT]->connect[DOWN]) && (c.next[RIGHT] && !c.next[RIGHT]->connect[DOWN]))
612 if(!(c.next[UP] && c.next[UP]->connect[RIGHT] && c.next[UP]->next[RIGHT]->connect[RIGHT]))
614 c.isJoinCandidate =
true;
615 if(getRandomReal() <= 0.25) c.connect[DOWN] =
true;
622 for(y = 1; y < rows - 1; y++)
624 stCell& c = vCells[cols - 1 + y * cols];
625 if(c.raiseHeight)
continue;
626 if(!c.connect[RIGHT] && !c.connect[UP] && !c.connect[DOWN] && !c.next[UP]->connect[RIGHT] && !c.next[DOWN]->connect[RIGHT])
630 stCell* c2 = c.next[LEFT];
631 if(!c2->connect[UP] && !c2->connect[DOWN] && !c2->connect[LEFT])
633 c.isJoinCandidate =
true;
634 if(getRandomReal() <= 0.5) c.connect[RIGHT] =
true;
641void Maze::fillCell(stCell& cell)
644 cell.no = numFilled++;
645 cell.group = numGroups;
648void Maze::selectSingleDeadEnd(stCell* c)
650 c->connect[RIGHT] =
true;
651 if(c->singleDeadEndDir == UP)
657 c->next[DOWN]->topTunnel =
true;
661void Maze::replaceGroup(Sint32 oldg, Sint32 newg)
665 for(i = 0; i < rows*cols; i++)
667 stCell& c = vCells[i];
668 if(c.group == oldg) c.group = newg;
672bool Maze::createTunnels()
675 vector<stCell*> edgeTunnelCells;
676 vector<stCell*> topEdgeTunnelCells;
677 vector<stCell*> botEdgeTunnelCells;
678 vector<stCell*> voidTunnelCells;
679 vector<stCell*> topVoidTunnelCells;
680 vector<stCell*> botVoidTunnelCells;
681 vector<stCell*> singleDeadEndCells;
682 vector<stCell*> topSingleDeadEndCells;
683 vector<stCell*> botSingleDeadEndCells;
684 vector<stCell*> doubleDeadEndCells;
686 Sint32 numTunnelsCreated = 0;
688 bool upDead, downDead;
692 for(y = 0; y < rows; y++)
694 stCell& c = vCells[cols - 1 + y * cols];
699 if(c.y > 1 && c.y < rows - 2)
701 c.isEdgeTunnelCandidate =
true;
702 edgeTunnelCells.push_back(&c);
705 topEdgeTunnelCells.push_back(&c);
709 botEdgeTunnelCells.push_back(&c);
712 upDead = (!c.next[UP] || c.next[UP]->connect[RIGHT]);
713 downDead = (!c.next[DOWN] || c.next[DOWN]->connect[RIGHT]);
718 c.isVoidTunnelCandidate =
true;
719 voidTunnelCells.push_back(&c);
722 topVoidTunnelCells.push_back(&c);
726 botVoidTunnelCells.push_back(&c);
736 if(upDead != downDead)
738 if(!c.raiseHeight && y < rows - 1 && !c.next[LEFT]->connect[LEFT])
740 singleDeadEndCells.push_back(&c);
741 c.isSingleDeadEndCandidate =
true;
742 c.singleDeadEndDir = upDead ? UP : DOWN;
743 Sint32 offset = upDead ? 1 : 0;
744 if(c.y <= 1 + offset)
746 topSingleDeadEndCells.push_back(&c);
748 else if(c.y >= 5 + offset)
750 botSingleDeadEndCells.push_back(&c);
754 else if(upDead && downDead)
756 if(y > 0 && y < rows - 1)
758 if(c.next[LEFT]->connect[UP] && c.next[LEFT]->connect[DOWN])
760 c.isDoubleDeadEndCandidate =
true;
761 if(c.y >= 2 && c.y <= 5)
763 doubleDeadEndCells.push_back(&c);
772 Sint32 numTunnelsDesired = getRandomReal() <= 0.45 ? 2 : 1;
773 if(numTunnelsDesired == 1)
775 if(pCell = randomElement(voidTunnelCells))
777 pCell->topTunnel =
true;
779 else if(pCell = randomElement(singleDeadEndCells))
781 selectSingleDeadEnd(pCell);
783 else if(pCell = randomElement(edgeTunnelCells))
785 pCell->topTunnel =
true;
792 else if(numTunnelsDesired == 2)
794 if(pCell = randomElement(doubleDeadEndCells))
796 pCell->connect[RIGHT] =
true;
797 pCell->topTunnel =
true;
798 pCell->next[DOWN]->topTunnel =
true;
802 numTunnelsCreated = 1;
803 if(pCell = randomElement(topVoidTunnelCells))
805 pCell->topTunnel =
true;
807 else if(pCell = randomElement(topSingleDeadEndCells))
809 selectSingleDeadEnd(pCell);
811 else if(pCell = randomElement(topEdgeTunnelCells))
813 pCell->topTunnel =
true;
818 numTunnelsCreated = 0;
821 if(pCell = randomElement(botVoidTunnelCells))
823 pCell->topTunnel =
true;
825 else if(pCell = randomElement(botSingleDeadEndCells))
827 selectSingleDeadEnd(pCell);
829 else if(pCell = randomElement(botEdgeTunnelCells))
831 pCell->topTunnel =
true;
836 if(numTunnelsCreated == 0)
847 for(y = 0; y < rows; y++)
849 pCell = &vCells[cols - 1 + y * cols];
853 topy = pCell->final_y;
854 while(pCell->next[LEFT])
856 pCell = pCell->next[LEFT];
857 if(!pCell->connect[UP] && pCell->final_y == topy)
875 Sint32 len = (Sint32)voidTunnelCells.size();
877 for(i = 0; i < len; i++)
879 pCell = voidTunnelCells[i];
880 if(!pCell->topTunnel)
882 replaceGroup(pCell->group, pCell->next[UP]->group);
883 pCell->connect[UP] =
true;
884 pCell->next[UP]->connect[DOWN] =
true;
894 vector<stCell*> openCells;
896 vector<Sint32> nearCells;
897 stCell* newCell =
nullptr;
903 double probStopGrowingAtSize[] = {
913 std::map<Sint32, Sint32> singleCount;
914 singleCount.insert(std::pair<Sint32, Sint32>(0, 0));
915 singleCount.insert(std::pair<Sint32, Sint32>(rows - 1, 0));
916 double probTopAndBotSingleCellJoin = 0.35;
919 Sint32 longPieces = 0;
920 Sint32 maxLongPieces = 1;
921 Sint32 probExtendAtSize2 = 1;
922 double probExtendAtSize3or4 = 0.5;
924 for(numGroups = 0; ; numGroups++)
927 getLeftMostEmptyCells(openCells);
930 numOpenCells = (Sint32)openCells.size();
931 if(numOpenCells == 0)
break;
934 stCell* firstCell = openCells[getRandomInt(0, numOpenCells - 1)];
935 stCell* pCell = firstCell;
940 if(pCell->x < cols - 1 && (singleCount.count(pCell->y)) && getRandomReal() <= probTopAndBotSingleCellJoin)
942 if(singleCount[pCell->y] == 0)
944 pCell->connect[pCell->y == 0 ? UP : DOWN] =
true;
945 singleCount[pCell->y]++;
953 if(pCell->x == cols - 1)
956 pCell->connect[RIGHT] =
true;
957 pCell->isRaiseHeightCandidate =
true;
969 stCell& c = *firstCell;
970 if(c.x > 0 && c.connect[RIGHT] && c.next[RIGHT] && c.next[RIGHT]->next[RIGHT])
972 if(longPieces < maxLongPieces && getRandomReal() <= probExtendAtSize2)
974 stCell* pC = c.next[RIGHT]->next[RIGHT];
975 std::map<Sint32, bool> dirs;
976 if(isOpenCell(*pC, UP)) dirs[UP] =
true;
977 if(isOpenCell(*pC, DOWN)) dirs[DOWN] =
true;
978 if(dirs[UP] && dirs[DOWN]) i = (getRandomInt(0, 1) == 0 ? UP : DOWN);
979 else if(dirs[UP]) i = UP;
980 else if(dirs[DOWN]) i = DOWN;
985 connectCell(*pC, LEFT);
988 fillCell(*pC->next[i]);
1000 getOpenCells(*pCell, dir, size, nearCells);
1001 numOpenCells = (Sint32)nearCells.size();
1006 if(nearCells.size() == 0 && size == 2)
1009 getOpenCells(*pCell, dir, size, nearCells);
1010 numOpenCells = (Sint32)nearCells.size();
1014 if(numOpenCells == 0) stop =
true;
1018 dir = nearCells[getRandomInt(0, numOpenCells - 1)];
1019 newCell = pCell->next[dir];
1022 connectCell(*pCell, dir);
1031 if(firstCell->x == 0 && size == 3) stop =
true;
1034 if(getRandomReal() <= probStopGrowingAtSize[size]) stop =
true;
1048 stCell& c = *firstCell;
1052 if(c.connect[UP]) c = *c.next[UP];
1053 c.connect[RIGHT] = c.next[DOWN]->connect[RIGHT] =
true;
1056 else if(size == 3 || size == 4)
1059 if(longPieces < maxLongPieces && firstCell->x > 0 && getRandomReal() <= probExtendAtSize3or4)
1061 vector<Sint32> dirs;
1063 Sint32 dirsLength = 0;
1064 for(i = 0; i < 4; i++)
1066 if(pCell->connect[i] && isOpenCell(*pCell->next[i], i))
1074 i = dirs[getRandomInt(0, dirsLength - 1)];
1075 stCell& c = *pCell->next[i];
1077 fillCell(*c.next[i]);
1087 setResizeCandidates();
1091void Maze::setTile(Sint32 x, Sint32 y, Uint8 v, vector<Uint8>& tiles)
1093 if(x<0 || x>subcols - 1 || y<0 || y>subrows - 1)
return;
1095 tiles[midcols + x + y * fullcols] = v;
1096 tiles[midcols - 1 - x + y * fullcols] = v;
1099Sint32 Maze::getTile(Sint32 x, Sint32 y, vector<Uint8>& tiles)
1101 if(x<0 || x>subcols - 1 || y<0 || y>subrows - 1)
return -1;
1103 return tiles[midcols + x + y * fullcols];
1107void Maze::setTileCell(Sint32 x, Sint32 y, stCell& cell)
1109 if(x<0 || x>subcols - 1 || y<0 || y>subrows - 1)
return;
1111 tileCells[x + y * subcols] = cell;
1114Maze::stCell* Maze::getTileCell(Sint32 x, Sint32 y)
1117 if(x<0 || x>subcols - 1 || y<0 || y>subrows - 1)
return nullptr;
1119 i = x + y * subcols;
1120 if(i < 0)
return nullptr;
1121 if(tileCells[i].x == -1)
return nullptr;
1122 return &tileCells[i];
1125bool Maze::getTopEnergizerRange(Sint32& miny, Sint32& maxy, vector<Uint8>& tiles)
1127 Sint32 x = subcols - 2;
1131 for(y = 2; y < maxy; y++)
1133 if(getTile(x, y, tiles) ==
'.' && getTile(x, y + 1, tiles) ==
'.')
1139 maxy = (std::min)(maxy, miny + 7);
1140 for(y = miny + 1; y < maxy; y++)
1142 if(getTile(x - 1, y, tiles) ==
'.')
1151bool Maze::getBotEnergizerRange(Sint32& miny, Sint32& maxy, vector<Uint8>& tiles)
1153 Sint32 x = subcols - 2;
1156 for(y = subrows - 3; y >= miny; y--)
1158 if(getTile(x, y, tiles) ==
'.' && getTile(x, y + 1, tiles) ==
'.')
1164 miny = (std::max)(miny, maxy - 7);
1165 for(y = maxy - 1; y > miny; y--)
1167 if(getTile(x - 1, y, tiles) ==
'.')
1177void Maze::eraseUntilIntersection(Sint32 x, Sint32 y, vector<Uint8>& tiles)
1188 if(getTile(x - 1, y, tiles) ==
'.')
1192 vAdj.push_back(sAdjust);
1194 if(getTile(x + 1, y, tiles) ==
'.')
1198 vAdj.push_back(sAdjust);
1200 if(getTile(x, y - 1, tiles) ==
'.')
1204 vAdj.push_back(sAdjust);
1206 if(getTile(x, y + 1, tiles) ==
'.')
1210 vAdj.push_back(sAdjust);
1212 if(vAdj.size() == 1)
1214 setTile(x, y,
' ', tiles);
1225#ifdef DEBUG_GENERATOR
1231Sint32 Maze::generateTiles(vector<Uint8>& vTiles)
1233 Sint32 i, j, x, y, x0, y0;
1237 subrows = rows * 3 + 1 + 3;
1238 subcols = cols * 3 - 1 + 2;
1239 midcols = subcols - 2;
1240 fullcols = (subcols - 2) * 2;
1243 stCell cellContainer;
1244 for(i = 0; i < subrows*fullcols; i++) vTiles.push_back(
'_');
1245 for(i = 0; i < subrows*subcols; i++) tileCells.push_back(cellContainer);
1248 for(i = 0; i < rows*cols; i++)
1251 for(x0 = 0; x0 < c->final_w; x0++)
1253 for(y0 = 0; y0 < c->final_h; y0++)
1255 setTileCell(c->final_x + x0, c->final_y + 1 + y0, *c);
1261 stCell* cl; stCell* cu;
1262 for(y = 0; y < subrows; y++)
1264 for(x = 0; x < subcols; x++)
1266 c = getTileCell(x, y);
1267 cl = getTileCell(x - 1, y);
1268 cu = getTileCell(x, y - 1);
1273 if(cl && c->group != cl->group ||
1274 cu && c->group != cu->group ||
1275 !cu && !c->connect[UP])
1277 setTile(x, y,
'.', vTiles);
1283 if(cl && (!cl->connect[RIGHT] || getTile(x - 1, y, vTiles) ==
'.') ||
1284 cu && (!cu->connect[DOWN] || getTile(x, y - 1, vTiles) ==
'.'))
1286 setTile(x, y,
'.', vTiles);
1291 if(getTile(x - 1, y, vTiles) ==
'.' && getTile(x, y - 1, vTiles) ==
'.' && getTile(x - 1, y - 1, vTiles) ==
'_') setTile(x, y,
'.', vTiles);
1295 #ifdef DEBUG_GENERATOR
1297 std::ofstream vFile(
"DumpC-Tiles.txt");
1298 if(!vFile)
return -1;
1299 for(i = 0; i < vTiles.size(); ++i)
1301 vFile << vTiles[i] << std::endl;
1307 for(c = &vCells[cols - 1]; c; c = c->next[DOWN])
1312 setTile(subcols - 1, y,
'.', vTiles);
1313 setTile(subcols - 2, y,
'.', vTiles);
1318 for(y = 0; y < subrows; y++)
1320 for(x = 0; x < subcols; x++)
1323 if(getTile(x, y, vTiles) !=
'.' && (getTile(x - 1, y, vTiles) ==
'.' || getTile(x, y - 1, vTiles) ==
'.' || getTile(x + 1, y, vTiles) ==
'.' || getTile(x, y + 1, vTiles) ==
'.' ||
1324 getTile(x - 1, y - 1, vTiles) ==
'.' || getTile(x + 1, y - 1, vTiles) ==
'.' || getTile(x + 1, y + 1, vTiles) ==
'.' || getTile(x - 1, y + 1, vTiles) ==
'.'))
1326 setTile(x, y,
'|', vTiles);
1332 setTile(2, 12,
'-', vTiles);
1338 if(getTopEnergizerRange(miny, maxy, vTiles))
1340 y = getRandomInt(miny, maxy);
1341 setTile(x, y,
'o', vTiles);
1343 if(getBotEnergizerRange(miny, maxy, vTiles))
1345 y = getRandomInt(miny, maxy);
1346 setTile(x, y,
'o', vTiles);
1350 for(y = 0; y < subrows; y++)
1352 if(getTile(x, y, vTiles) ==
'.')
1354 eraseUntilIntersection(x, y, vTiles);
1359 setTile(1, subrows - 8,
' ', vTiles);
1362 for(i = 0; i < 7; i++)
1368 setTile(i, y,
' ', vTiles);
1370 while(getTile(i, y + j, vTiles) ==
'.' &&
1371 getTile(i - 1, y + j, vTiles) ==
'|' &&
1372 getTile(i + 1, y + j, vTiles) ==
'|')
1374 setTile(i, y + j,
' ', vTiles);
1382 setTile(i, y,
' ', vTiles);
1384 while(getTile(i, y - j, vTiles) ==
'.' &&
1385 getTile(i - 1, y - j, vTiles) ==
'|' &&
1386 getTile(i + 1, y - j, vTiles) ==
'|')
1388 setTile(i, y - j,
' ', vTiles);
1393 for(i = 0; i < 7; i++)
1399 y = subrows - 14 - i;
1400 setTile(x, y,
' ', vTiles);
1402 while(getTile(x + j, y, vTiles) ==
'.' &&
1403 getTile(x + j, y - 1, vTiles) ==
'|' &&
1404 getTile(x + j, y + 1, vTiles) ==
'|')
1406 setTile(x + j, y,
' ', vTiles);