File indexing completed on 2024-10-13 03:43:41
0001 /* 0002 SPDX-FileCopyrightText: 2009 Ian Wadham <iandw.au@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kgrlevelgrid.h" 0008 #include "kgrrulebook.h" 0009 #include "kgrdebug.h" 0010 0011 KGrRuleBook::KGrRuleBook (QObject * parent) 0012 : 0013 QObject (parent), 0014 mVariableTiming (true), 0015 mAlwaysCollectNugget (true), 0016 mRunThruHole (true), 0017 mReappearAtTop (true), 0018 mReappearRow (2), 0019 mPointsPerCell (4), 0020 mTurnAnywhere (false) 0021 { 0022 } 0023 0024 KGrRuleBook::~KGrRuleBook() 0025 { 0026 } 0027 0028 void KGrRuleBook::setTiming (const int enemyCount) 0029 { 0030 Timing varTiming[6] = { 0031 {40, 58, 78, 88, 340, 23}, // No enemies. 0032 {50, 68, 78, 88, 340, 32}, // 1 enemy. 0033 {57, 67, 114, 128, 540, 37}, // 2 enemies. 0034 {60, 70, 134, 136, 660, 40}, // 3 enemies. 0035 {63, 76, 165, 150, 800, 46}, // 4 enemies. 0036 {70, 80, 189, 165, 920, 51} // >4 enemies. 0037 }; 0038 if (mVariableTiming) { 0039 int choice = std::clamp(enemyCount, 0, 5); 0040 times = varTiming [choice]; 0041 } 0042 } 0043 0044 0045 // Initialise the flags for the rules. 0046 0047 KGrTraditionalRules::KGrTraditionalRules (QObject * parent) 0048 : 0049 KGrRuleBook (parent) 0050 { 0051 mRules = TraditionalRules; 0052 0053 mVariableTiming = true; ///< More enemies imply less speed. 0054 mAlwaysCollectNugget = true; ///< Enemies always collect nuggets. 0055 mRunThruHole = true; ///< Enemy can run L/R through dug hole. 0056 mReappearAtTop = true; ///< Enemies reborn at top of screen. 0057 mReappearRow = 2; ///< Row where enemies reappear. 0058 mPointsPerCell = 4; ///< Number of points in each grid-cell. 0059 mTurnAnywhere = false; ///< Change direction only at next cell. 0060 mEnemiesShowGold = true; ///< Show enemies carrying gold. 0061 0062 Timing t = {40, 58, 78, 88, 340, 23}; 0063 times = t; 0064 } 0065 0066 KGrTraditionalRules::~KGrTraditionalRules() 0067 { 0068 } 0069 0070 Direction KGrTraditionalRules::findBestWay (const int eI, const int eJ, 0071 const int hI, const int hJ, 0072 KGrLevelGrid * pGrid, 0073 bool /* leftRightSearch unused */) 0074 { 0075 grid = pGrid; 0076 if (grid->cellType (eI, eJ) == USEDHOLE) { // Could not get out of hole 0077 return UP; // (e.g. brick above is closed): 0078 } // but keep trying. 0079 0080 bool canStand = (grid->enemyMoves (eI, eJ) & dFlag [STAND]) || 0081 (grid->enemyOccupied (eI, eJ + 1) > 0); 0082 if (! canStand) { 0083 dbk2 << "can stand" << (grid->enemyMoves (eI, eJ) & dFlag [STAND]) 0084 << "occ-below" << grid->enemyOccupied (eI, eJ + 1); 0085 return DOWN; 0086 } 0087 dbk2 << "not DOWN yet"; 0088 0089 // Traditional search strategy. 0090 Direction dirn = STAND; 0091 if (eJ == hJ) { 0092 dirn = getHero (eI, eJ, hI); // Hero on same row. 0093 if (dirn != STAND) { 0094 return dirn; // Can go towards him. 0095 } 0096 } 0097 0098 if (eJ >= hJ) { // Hero above or on same row. 0099 dirn = searchUp (eI, eJ, hJ); // Find a way that leads up. 0100 } 0101 else { // Hero below enemy. 0102 dirn = searchDown (eI, eJ, hJ); // Find way that leads down. 0103 dbk2 << "searchDown1" << eI << eJ << hJ << "ret" << dirn; 0104 if (dirn == STAND) { 0105 dirn = searchUp (eI, eJ, hJ); // No go: try going up first. 0106 } 0107 } 0108 0109 if (dirn == STAND) { // When all else fails, look for 0110 dirn = searchDown (eI, eJ, eJ - 1); // a way below the hero. 0111 dbk2 << "searchDown2" << eI << eJ << (eJ - 1) << "ret" << dirn; 0112 } 0113 0114 return dirn; 0115 } 0116 0117 Direction KGrTraditionalRules::searchUp (int ew, int eh, int hh) 0118 { 0119 int i, ilen, ipos, j, jlen, jpos, deltah, rungs; 0120 0121 deltah = eh - hh; // Get distance up to hero's level. 0122 0123 // Search for the best ladder right here or on the left. 0124 i = ew; ilen = 0; ipos = -1; 0125 while (i >= 1) { 0126 rungs = distanceUp (i, eh, deltah); 0127 if (rungs > ilen) { 0128 ilen = rungs; // This the best yet. 0129 ipos = i; 0130 } 0131 if (searchOK (-1, i, eh)) 0132 i--; // Look further to the left. 0133 else 0134 i = -1; // Cannot go any further to the left. 0135 } 0136 0137 // Search for the best ladder on the right. 0138 j = ew; jlen = 0; jpos = -1; 0139 while (j < FIELDWIDTH) { 0140 if (searchOK (+1, j, eh)) { 0141 j++; // Look further to the right. 0142 rungs = distanceUp (j, eh, deltah); 0143 if (rungs > jlen) { 0144 jlen = rungs; // This the best yet. 0145 jpos = j; 0146 } 0147 } 0148 else 0149 j = FIELDWIDTH+1; // Cannot go any further to the right. 0150 } 0151 0152 if ((ilen == 0) && (jlen == 0)) // No ladder found. 0153 return STAND; 0154 0155 // Choose a ladder to go to. 0156 if (ilen != jlen) { // If the ladders are not the same 0157 // length, choose the longer one. 0158 if (ilen > jlen) { 0159 if (ipos == ew) // If already on the best ladder, go up. 0160 return UP; 0161 else 0162 return LEFT; 0163 } 0164 else 0165 return RIGHT; 0166 } 0167 else { // Both ladders are the same length. 0168 0169 if (ipos == ew) // If already on the best ladder, go up. 0170 return UP; 0171 else if (ilen == deltah) { // If both reach the hero's level, 0172 if ((ew - ipos) <= (jpos - ew)) // choose the closest. 0173 return LEFT; 0174 else 0175 return RIGHT; 0176 } 0177 else return LEFT; // Else choose the left ladder. 0178 } 0179 } 0180 0181 Direction KGrTraditionalRules::searchDown (int ew, int eh, int hh) 0182 { 0183 int i, ilen, ipos, j, jlen, jpos, deltah, rungs, path; 0184 0185 deltah = hh - eh; // Get distance down to hero's level. 0186 0187 // Search for the best way down, right here or on the left. 0188 ilen = 0; ipos = -1; 0189 i = (willNotFall (ew, eh)) ? ew : -1; 0190 rungs = distanceDown (ew, eh, deltah); 0191 if (rungs > 0) { 0192 ilen = rungs; ipos = ew; 0193 } 0194 0195 while (i >= 1) { 0196 rungs = distanceDown (i - 1, eh, deltah); 0197 if (((rungs > 0) && (ilen == 0)) || 0198 ((deltah > 0) && (rungs > ilen)) || 0199 ((deltah <= 0) && (rungs < ilen) && (rungs != 0))) { 0200 ilen = rungs; // This the best way yet. 0201 ipos = i - 1; 0202 } 0203 if (searchOK (-1, i, eh)) 0204 i--; // Look further to the left. 0205 else 0206 i = -1; // Cannot go any further to the left. 0207 } 0208 0209 // Search for the best way down, on the right. 0210 j = ew; jlen = 0; jpos = -1; 0211 while (j < FIELDWIDTH) { 0212 rungs = distanceDown (j + 1, eh, deltah); 0213 if (((rungs > 0) && (jlen == 0)) || 0214 ((deltah > 0) && (rungs > jlen)) || 0215 ((deltah <= 0) && (rungs < jlen) && (rungs != 0))) { 0216 jlen = rungs; // This the best way yet. 0217 jpos = j + 1; 0218 } 0219 if (searchOK (+1, j, eh)) { 0220 j++; // Look further to the right. 0221 } 0222 else 0223 j = FIELDWIDTH+1; // Cannot go any further to the right. 0224 } 0225 0226 if ((ilen == 0) && (jlen == 0)) // Found no way down. 0227 return STAND; 0228 0229 // Choose a way down to follow. 0230 if (ilen == 0) 0231 path = jpos; 0232 else if (jlen == 0) 0233 path = ipos; 0234 else if (ilen != jlen) { // If the ways down are not same length, 0235 // choose closest to hero's level. 0236 if (deltah > 0) { 0237 if (jlen > ilen) 0238 path = jpos; 0239 else 0240 path = ipos; 0241 } 0242 else { 0243 if (jlen > ilen) 0244 path = ipos; 0245 else 0246 path = jpos; 0247 } 0248 } 0249 else { // Both ways down are the same length. 0250 if ((deltah > 0) && // If both reach the hero's level, 0251 (ilen == deltah)) { // choose the closest. 0252 if ((ew - ipos) <= (jpos - ew)) 0253 path = ipos; 0254 else 0255 path = jpos; 0256 } 0257 else 0258 path = ipos; // Else, go left or down. 0259 } 0260 0261 if (path == ew) 0262 return DOWN; 0263 else if (path < ew) 0264 return LEFT; 0265 else 0266 return RIGHT; 0267 } 0268 0269 Direction KGrTraditionalRules::getHero (int eI, int eJ, int hI) 0270 { 0271 int i, inc, returnValue; 0272 0273 inc = (eI > hI) ? -1 : +1; 0274 i = eI; 0275 while (i != hI) { 0276 returnValue = canWalkLR (inc, i, eJ); 0277 if (returnValue > 0) 0278 i = i + inc; // Can run further towards the hero. 0279 else if (returnValue < 0) 0280 break; // Will run into a wall regardless. 0281 else 0282 return STAND; // Won't run over a hole. 0283 } 0284 0285 if (i < eI) return LEFT; 0286 else if (i > eI) return RIGHT; 0287 else return STAND; 0288 } 0289 0290 int KGrTraditionalRules::distanceUp (int x, int y, int deltah) 0291 { 0292 int rungs = 0; 0293 0294 // If there is a ladder at (x,y), return its length, else return zero. 0295 while (grid->cellType (x, y - rungs) == LADDER) { 0296 rungs++; 0297 if (rungs >= deltah) { // To hero's level is enough. 0298 break; 0299 } 0300 } 0301 return rungs; 0302 } 0303 0304 int KGrTraditionalRules::distanceDown (int x, int y, int deltah) 0305 { 0306 // When deltah > 0, we want an exit sideways at the hero's level or above. 0307 // When deltah <= 0, we can go down any distance (as a last resort). 0308 0309 int rungs = -1; 0310 int exitRung = 0; 0311 bool canGoThru = true; 0312 char objType; 0313 0314 // If there is a way down at (x,y), return its length, else return zero. 0315 // Because rungs == -1, we first check that level y is not blocked here. 0316 while (canGoThru) { 0317 objType = grid->cellType (x, y + rungs + 1); 0318 switch (objType) { 0319 case BRICK: 0320 case CONCRETE: 0321 case HOLE: // Enemy cannot go DOWN through a hole. 0322 case USEDHOLE: 0323 if ((deltah > 0) && (rungs <= deltah)) 0324 exitRung = rungs; 0325 if ((objType == HOLE) && (rungs < 0)) 0326 rungs = 0; // Enemy can go SIDEWAYS through a hole. 0327 else 0328 canGoThru = false; // Cannot go through here. 0329 break; 0330 case LADDER: 0331 case BAR: // Can go through or stop. 0332 rungs++; // Add to path length. 0333 if ((deltah > 0) && (rungs >= 0)) { 0334 // If at or above hero's level, check for an exit from ladder. 0335 if ((rungs - 1) <= deltah) { 0336 // Maybe can stand on top of ladder and exit L or R. 0337 if ((objType == LADDER) && (searchOK (-1, x, y+rungs-1) || 0338 searchOK (+1, x, y+rungs-1))) 0339 exitRung = rungs - 1; 0340 // Maybe can exit L or R from ladder body or pole. 0341 if ((rungs <= deltah) && (searchOK (-1, x, y+rungs) || 0342 searchOK (+1, x, y+rungs))) 0343 exitRung = rungs; 0344 } 0345 else 0346 canGoThru = false; // Should stop at hero's level. 0347 } 0348 break; 0349 default: 0350 rungs++; // Can go through. Add to path length. 0351 break; 0352 } 0353 } 0354 if (rungs == 1) { 0355 if (grid->enemyOccupied (x, y + 1) > 0) { 0356 dbk2 << "Pit block =" << grid->enemyOccupied (x, y + 1) 0357 << "at" << x << (y + 1); 0358 rungs = 0; // Pit is blocked. Find another way. 0359 } 0360 } 0361 if (rungs <= 0) 0362 return 0; // There is no way down. 0363 else if (deltah > 0) 0364 return exitRung; // We want to take an exit, if any. 0365 else 0366 return rungs; // We can go down all the way. 0367 } 0368 0369 bool KGrTraditionalRules::searchOK (int direction, int x, int y) 0370 { 0371 // Check whether it is OK to search left or right. 0372 if (canWalkLR (direction, x, y) > 0) { 0373 // Can go into that cell, but check for a fall. 0374 if (willNotFall (x+direction, y)) 0375 return true; 0376 } 0377 return false; // Cannot go into and through that cell. 0378 } 0379 0380 int KGrTraditionalRules::canWalkLR (int direction, int x, int y) 0381 { 0382 if (willNotFall (x, y)) { 0383 switch (grid->cellType (x+direction, y)) { 0384 case CONCRETE: 0385 case BRICK: 0386 case USEDHOLE: 0387 return -1; // Will be halted in current cell. 0388 break; 0389 default: 0390 // NB. FREE, LADDER, HLADDER, NUGGET and BAR are OK of course, 0391 // but enemies can also walk left/right through a HOLE and 0392 // THINK they can walk left/right through a FBRICK. 0393 0394 return +1; // Can walk into next cell. 0395 break; 0396 } 0397 } 0398 else 0399 return 0; // Will fall before getting there. 0400 } 0401 0402 bool KGrTraditionalRules::willNotFall (int x, int y) 0403 { 0404 // Check the ceiling. 0405 switch (grid->cellType (x, y)) { 0406 case LADDER: 0407 case BAR: 0408 return true; break; // OK, can hang on ladder or pole. 0409 default: 0410 break; 0411 } 0412 0413 // Check the floor. 0414 switch (grid->cellType (x, y + 1)) { 0415 0416 // Cases where the enemy knows he will fall. 0417 // N.B. The enemy THINKS he can run over a NUGGET, a buried BAR or a HOLE. 0418 // The last of these cases allows the hero to trap the enemy, of course. 0419 0420 // Note that there are several Traditional levels that require an enemy to 0421 // be trapped permanently in a pit containing a nugget, as he runs towards 0422 // you. It is also possible to use a buried BAR in the same way. 0423 case FREE: 0424 case HLADDER: 0425 case FBRICK: 0426 if (grid->enemyOccupied (x, y + 1) > 0) { 0427 dbk2 << "Occupied =" << grid->enemyOccupied (x, y + 1) 0428 << "at" << x << (y + 1); 0429 return true; 0430 } 0431 return false; // Will fall: there is no floor. 0432 break; 0433 0434 default: 0435 return true; // OK, will not fall. 0436 break; 0437 } 0438 } 0439 0440 0441 KGrKGoldrunnerRules::KGrKGoldrunnerRules (QObject * parent) 0442 : 0443 KGrRuleBook (parent) 0444 { 0445 mRules = KGoldrunnerRules; 0446 0447 mVariableTiming = false; ///< Speed same for any no. of enemies. 0448 mAlwaysCollectNugget = false; ///< Enemies sometimes collect nuggets. 0449 mRunThruHole = false; ///< Enemy cannot run through dug hole. 0450 mReappearAtTop = false; ///< Enemies reborn at start position. 0451 mReappearRow = -1; ///< Row where enemies reappear (N/A). 0452 mPointsPerCell = 4; ///< Number of points in each grid-cell. 0453 mTurnAnywhere = false; ///< Change direction only at next cell. 0454 mEnemiesShowGold = true; ///< Show enemies carrying gold. 0455 0456 Timing t = {45, 50, 55, 100, 1000, 40}; 0457 times = t; 0458 } 0459 0460 KGrKGoldrunnerRules::~KGrKGoldrunnerRules() 0461 { 0462 } 0463 0464 Direction KGrKGoldrunnerRules::findBestWay (const int eI, const int eJ, 0465 const int hI, const int hJ, 0466 KGrLevelGrid * pGrid, 0467 bool leftRightSearch) 0468 { 0469 dbk2 << eI << eJ << hI << hJ; 0470 grid = pGrid; 0471 0472 if (grid->cellType (eI, eJ) == USEDHOLE) { // Could not get out of hole 0473 return UP; // (e.g. brick above is closed): 0474 } // but keep trying. 0475 0476 bool canStand = (grid->enemyMoves (eI, eJ) & dFlag [STAND]) || 0477 (grid->enemyOccupied (eI, eJ + 1) > 0); 0478 if (! canStand) { 0479 dbk2 << "can stand" << (grid->enemyMoves (eI, eJ) & dFlag [STAND]) 0480 << "occ-below" << grid->enemyOccupied (eI, eJ + 1); 0481 return DOWN; 0482 } 0483 0484 // KGoldrunner search strategy. 0485 if (leftRightSearch) { 0486 if (eI > hI) { 0487 return findWayLeft (eI, eJ); 0488 } 0489 if (eI < hI) { 0490 return findWayRight (eI, eJ); 0491 } 0492 } 0493 else { 0494 if (eJ > hJ) { 0495 return findWayUp (eI, eJ); 0496 } 0497 if (eJ < hJ) { 0498 return findWayDown (eI, eJ); 0499 } 0500 } 0501 0502 return STAND; 0503 } 0504 0505 Direction KGrKGoldrunnerRules::findWayUp (const int eI, const int eJ) 0506 { 0507 int i, k; 0508 i = k = eI; 0509 0510 // Must be able to stand AND move through cells when looking left or right. 0511 Flags leftOK = (dFlag [LEFT] | dFlag [STAND]); 0512 Flags rightOK = (dFlag [RIGHT] | dFlag [STAND]); 0513 0514 if (grid->enemyMoves (eI, eJ) & dFlag [UP]) { 0515 return UP; // Go up from current position. 0516 } 0517 else { 0518 while ((i >= 0) || (k <= FIELDWIDTH)) { 0519 if (i >= 0) { 0520 if (grid->enemyMoves (i, eJ) & dFlag [UP]) { 0521 return LEFT; // Go left, then up later. 0522 } 0523 else if ((grid->enemyMoves (i--, eJ) & leftOK) != leftOK) { 0524 i = -1; 0525 } 0526 } 0527 if (k <= FIELDWIDTH) { 0528 if (grid->enemyMoves (k, eJ) & dFlag [UP]) { 0529 return RIGHT; // Go right, then up later. 0530 } 0531 else if ((grid->enemyMoves (k++, eJ) & rightOK) != rightOK) { 0532 k = FIELDWIDTH + 1; 0533 } 0534 } 0535 } 0536 } 0537 return STAND; 0538 } 0539 0540 Direction KGrKGoldrunnerRules::findWayDown (const int eI, const int eJ) 0541 { 0542 int i, k; 0543 i = k = eI; 0544 0545 // In this search, no need to test for STAND. Fall and ladder are both OK. 0546 if (grid->enemyMoves (eI, eJ) & dFlag [DOWN]) { 0547 return DOWN; // Go down from current position. 0548 } 0549 else { 0550 while ((i >= 0) || (k <= FIELDWIDTH)) { 0551 if (i >= 0) { 0552 if (grid->enemyMoves (i, eJ) & dFlag [DOWN]) { 0553 return LEFT; // Go left, then down later. 0554 } 0555 else if (! (grid->enemyMoves (i--, eJ) & dFlag [LEFT])) { 0556 i = -1; 0557 } 0558 } 0559 if (k <= FIELDWIDTH) { 0560 if (grid->enemyMoves (k, eJ) & dFlag [DOWN]) { 0561 return RIGHT; // Go right, then down later. 0562 } 0563 else if (! (grid->enemyMoves (k++, eJ) & dFlag [RIGHT])) { 0564 k = FIELDWIDTH + 1; 0565 } 0566 } 0567 } 0568 } 0569 return STAND; // Cannot go down. 0570 } 0571 0572 Direction KGrKGoldrunnerRules::findWayLeft (const int eI, const int eJ) 0573 { 0574 int i, k; 0575 i = k = eJ; 0576 0577 // Must be able to stand and move through cells when checking move-left. 0578 Flags leftOK = (dFlag [LEFT] | dFlag [STAND]); 0579 0580 if ((grid->enemyMoves (eI, eJ) & leftOK) == leftOK) { 0581 return LEFT; // Go left from current position. 0582 } 0583 else { 0584 while ((i >= 0) || (k <= FIELDHEIGHT)) { 0585 if (i >= 0) { 0586 if ((grid->enemyMoves (eI, i) & leftOK) == leftOK) { 0587 return UP; // Go up, then left later. 0588 } 0589 else if (! (grid->enemyMoves (eI, i--) & dFlag [UP])) { 0590 i = -1; 0591 } 0592 } 0593 if (k <= FIELDHEIGHT) { 0594 if ((grid->enemyMoves (eI, k) & leftOK) == leftOK) { 0595 return DOWN; // Go down, then left later. 0596 } 0597 else if (! (grid->enemyMoves (eI, k++) & dFlag [DOWN])) { 0598 k = FIELDHEIGHT + 1; 0599 } 0600 } 0601 } 0602 } 0603 return STAND; // Cannot go left. 0604 } 0605 0606 Direction KGrKGoldrunnerRules::findWayRight (const int eI, const int eJ) 0607 { 0608 int i, k; 0609 i = k = eJ; 0610 0611 // Must be able to stand and move through cells when checking move-right. 0612 Flags rightOK = (dFlag [RIGHT] | dFlag [STAND]); 0613 0614 if ((grid->enemyMoves (eI, eJ) & rightOK) == rightOK) { 0615 return RIGHT; // Go right from current position. 0616 } 0617 else { 0618 while ((i >= 0) || (k <= FIELDHEIGHT)) { 0619 if (i >= 0) { 0620 if ((grid->enemyMoves (eI, i) & rightOK) == rightOK) { 0621 return UP; // Go up, then right later. 0622 } 0623 else if (!(grid->enemyMoves (eI, i--) & dFlag [UP])) { 0624 i = -1; 0625 } 0626 } 0627 if (k <= FIELDHEIGHT) { 0628 if ((grid->enemyMoves (eI, k) & rightOK) == rightOK) { 0629 return DOWN; // Go down, then right later. 0630 } 0631 else if (! (grid->enemyMoves (eI, k++) & dFlag [DOWN])) { 0632 k = FIELDHEIGHT + 1; 0633 } 0634 } 0635 } 0636 } 0637 return STAND; // Cannot go right. 0638 } 0639 0640 0641 KGrScavengerRules::KGrScavengerRules (QObject * parent) 0642 : 0643 KGrRuleBook (parent) 0644 { 0645 mRules = ScavengerRules; 0646 0647 mVariableTiming = false; ///< Speed same for any no. of enemies. 0648 mAlwaysCollectNugget = true; ///< Enemies always collect nuggets. 0649 mRunThruHole = true; ///< Enemy can run L/R through dug hole. 0650 mReappearAtTop = true; ///< Enemies reborn at top of screen. 0651 mReappearRow = 1; ///< Row where enemies reappear. 0652 mPointsPerCell = 12; ///< Number of points in each grid-cell. 0653 mTurnAnywhere = true; ///< Change direction anywhere in cell. 0654 mEnemiesShowGold = false; ///< Conceal enemies carrying gold. 0655 0656 Timing t = {45, 50, 55, 100, 1000, 40}; 0657 times = t; 0658 } 0659 0660 KGrScavengerRules::~KGrScavengerRules() 0661 { 0662 } 0663 0664 Direction KGrScavengerRules::findBestWay (const int eI, const int eJ, 0665 const int hI, const int hJ, 0666 KGrLevelGrid * pGrid, 0667 bool /* leftRightSearch unused */) 0668 { 0669 dbk2 << eI << eJ << hI << hJ; 0670 grid = pGrid; 0671 return RIGHT; 0672 } 0673 0674 #include "moc_kgrrulebook.cpp"