00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "Rules.h"
00010
00011 #include "Cube.h"
00012 #include "MarkMask.h"
00013
00014 #include "Log.h"
00015 #include "LayoutException.h"
00016 #include "OnStack.h"
00017 #include "OnWall.h"
00018 #include "OnStrongPad.h"
00019
00020 #include <assert.h>
00021
00022
00023
00024
00025
00026 Rules::Rules(Cube *model)
00027 {
00028 m_readyToDie = false;
00029 m_readyToTurn = false;
00030 m_readyToActive = false;
00031 m_dir = Dir::DIR_NO;
00032 m_pushing = false;
00033 m_outDepth = 0;
00034 m_touchDir = Dir::DIR_NO;
00035
00036 m_model = model;
00037 m_mask = NULL;
00038 m_lastFall = false;
00039 }
00040
00041
00042
00043
00044 Rules::~Rules()
00045 {
00046 if (m_mask) {
00047 m_mask->unmask();
00048 delete m_mask;
00049 }
00050 }
00051
00052
00053
00054
00055
00056 void
00057 Rules::takeField(Field *field)
00058 {
00059 if (m_mask) {
00060 m_mask->unmask();
00061 delete m_mask;
00062 m_mask = NULL;
00063 }
00064
00065 m_mask = new MarkMask(m_model, field);
00066 Cube::t_models resist = m_mask->getResist(Dir::DIR_NO);
00067 if (!resist.empty()) {
00068 throw LayoutException(ExInfo("position is occupied")
00069 .addInfo("model", m_model->toString())
00070 .addInfo("resist", resist.front()->toString()));
00071 }
00072
00073 m_mask->mask();
00074 }
00075
00076
00077
00078
00079
00080
00081
00082 void
00083 Rules::occupyNewPos()
00084 {
00085 m_touchDir = Dir::DIR_NO;
00086 if (m_dir != Dir::DIR_NO) {
00087 m_pushing = false;
00088
00089 V2 shift = Dir::dir2xy(m_dir);
00090 V2 oldLoc = m_model->getLocation();
00091 m_model->change_setLocation(oldLoc.plus(shift));
00092
00093 m_mask->mask();
00094 }
00095 }
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 bool
00110 Rules::checkDead(Cube::eAction lastAction)
00111 {
00112
00113 bool dead = false;
00114
00115 if (m_model->isAlive()) {
00116 switch (lastAction) {
00117 case Cube::ACTION_FALL:
00118 dead = checkDeadFall();
00119 break;
00120 case Cube::ACTION_MOVE:
00121 dead = checkDeadMove();
00122 if (!dead) {
00123 dead = checkDeadStress();
00124 }
00125 break;
00126 default:
00127 dead = false;
00128 break;
00129 }
00130
00131 if (dead) {
00132 m_readyToDie = true;
00133 }
00134 }
00135
00136 return dead;
00137 }
00138
00139
00140
00141
00142
00143
00144
00145 bool
00146 Rules::checkDeadMove()
00147 {
00148 Cube::t_models resist = m_mask->getResist(Dir::DIR_UP);
00149 Cube::t_models::iterator end = resist.end();
00150 for (Cube::t_models::iterator i = resist.begin(); i != end; ++i) {
00151 if (!(*i)->isAlive()) {
00152 Dir::eDir resist_dir = (*i)->rules()->getDir();
00153 if (resist_dir != Dir::DIR_NO && resist_dir != Dir::DIR_UP) {
00154 if (!(*i)->rules()->isOnStack()) {
00155 return true;
00156 }
00157 }
00158 }
00159 }
00160
00161 return false;
00162 }
00163
00164
00165
00166
00167
00168
00169 bool
00170 Rules::checkDeadFall()
00171 {
00172 Cube::t_models killers = whoIsFalling();
00173
00174 Cube::t_models::iterator end = killers.end();
00175 for (Cube::t_models::iterator i = killers.begin(); i != end; ++i) {
00176 if (!(*i)->rules()->isOnWall()) {
00177 return true;
00178 }
00179 }
00180
00181 return false;
00182 }
00183
00184
00185
00186
00187
00188
00189 bool
00190 Rules::checkDeadStress()
00191 {
00192 Cube::t_models killers = whoIsHeavier(m_model->getPower());
00193
00194 Cube::t_models::iterator end = killers.end();
00195 for (Cube::t_models::iterator i = killers.begin(); i != end; ++i) {
00196 if (!(*i)->rules()->isOnStrongPad((*i)->getWeight())) {
00197 return true;
00198 }
00199 }
00200
00201 return false;
00202 }
00203
00204
00205
00206
00207
00208
00209 void
00210 Rules::changeState()
00211 {
00212 m_dir = Dir::DIR_NO;
00213
00214 if (!m_model->isLost() && m_model->isDisintegrated()) {
00215 m_mask->unmask();
00216 m_model->change_remove();
00217 }
00218
00219 if (m_readyToTurn) {
00220 m_readyToTurn = false;
00221 m_model->change_turnSide();
00222 }
00223
00224 m_readyToActive = false;
00225
00226 if (m_readyToDie) {
00227 m_readyToDie = false;
00228 m_model->change_die();
00229 }
00230 }
00231
00232
00233
00234
00235
00236
00237 int
00238 Rules::actionOut()
00239 {
00240 if (!m_model->isWall() && !m_model->isLost()
00241 && !m_model->isBusy())
00242 {
00243
00244 if (m_model->shouldGoOut()) {
00245 Dir::eDir borderDir = m_mask->getBorderDir();
00246 if (borderDir != Dir::DIR_NO) {
00247 m_dir = borderDir;
00248 m_outDepth += 1;
00249 }
00250 else {
00251 if (m_outDepth > 0) {
00252 m_model->change_goOut();
00253 m_outDepth = -1;
00254 }
00255 }
00256 }
00257 }
00258
00259 return m_outDepth;
00260 }
00261
00262
00263
00264
00265 void
00266 Rules::actionFall()
00267 {
00268 m_dir = Dir::DIR_DOWN;
00269 m_lastFall = true;
00270 }
00271
00272
00273
00274
00275
00276 bool
00277 Rules::clearLastFall()
00278 {
00279 bool last = m_lastFall;
00280 m_lastFall = false;
00281 return last;
00282 }
00283
00284
00285
00286
00287 void
00288 Rules::finishRound()
00289 {
00290 freeOldPos();
00291 }
00292
00293
00294
00295
00296 void
00297 Rules::freeOldPos()
00298 {
00299 if (m_dir != Dir::DIR_NO) {
00300 m_mask->unmask();
00301 }
00302 }
00303
00304
00305
00306
00307
00308
00309 bool
00310 Rules::isOnCond(const OnCondition &cond)
00311 {
00312 bool result = false;
00313 if (cond.isSatisfy(m_model)) {
00314 result = true;
00315 }
00316 else if (cond.isWrong(m_model)) {
00317 result = false;
00318 }
00319 else {
00320 m_mask->unmask();
00321
00322 result = false;
00323 Cube::t_models resist = m_mask->getResist(Dir::DIR_DOWN);
00324 Cube::t_models::iterator end = resist.end();
00325 for (Cube::t_models::iterator i = resist.begin(); i != end; ++i) {
00326 if ((*i)->rules()->isOnCond(cond)) {
00327
00328 result = true;
00329 break;
00330 }
00331 }
00332
00333 m_mask->mask();
00334 }
00335
00336 return result;
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346 bool
00347 Rules::isOnStack()
00348 {
00349 return isOnCond(OnStack());
00350 }
00351
00352
00353
00354
00355 bool
00356 Rules::isOnWall()
00357 {
00358 return isOnCond(OnWall());
00359 }
00360
00361
00362
00363
00364
00365
00366
00367 bool
00368 Rules::isOnStrongPad(Cube::eWeight weight)
00369 {
00370 return isOnCond(OnStrongPad(weight));
00371 }
00372
00373
00374
00375
00376
00377 bool
00378 Rules::isFalling() const
00379 {
00380 bool result = false;
00381 if (!m_model->isAlive()) {
00382 result = (m_dir == Dir::DIR_DOWN);
00383 }
00384 return result;
00385 }
00386
00387
00388
00389
00390
00391 Cube::t_models
00392 Rules::whoIsFalling()
00393 {
00394 Cube::t_models result;
00395 m_mask->unmask();
00396
00397 Cube::t_models resist = m_mask->getResist(Dir::DIR_UP);
00398 Cube::t_models::iterator end = resist.end();
00399 for (Cube::t_models::iterator i = resist.begin(); i != end; ++i) {
00400
00401 if (!(*i)->isWall() && !(*i)->isAlive()) {
00402 if ((*i)->rules()->isFalling()) {
00403 result.push_back(*i);
00404 }
00405 else {
00406 Cube::t_models distance_killers = (*i)->rules()->whoIsFalling();
00407 result.insert(result.end(), distance_killers.begin(),
00408 distance_killers.end());
00409 }
00410 }
00411 }
00412
00413 m_mask->mask();
00414 return result;
00415 }
00416
00417
00418
00419
00420
00421
00422 bool
00423 Rules::isHeavier(Cube::eWeight power) const
00424 {
00425 bool result = false;
00426 if (!m_model->isWall() && !m_model->isAlive()) {
00427 if (m_model->getWeight() > power) {
00428 result = true;
00429 }
00430 }
00431
00432 return result;
00433 }
00434
00435
00436
00437
00438
00439
00440 Cube::t_models
00441 Rules::whoIsHeavier(Cube::eWeight power)
00442 {
00443 Cube::t_models result;
00444 m_mask->unmask();
00445
00446 Cube::t_models resist = m_mask->getResist(Dir::DIR_UP);
00447 Cube::t_models::iterator end = resist.end();
00448 for (Cube::t_models::iterator i = resist.begin(); i != end; ++i) {
00449 if (!(*i)->isWall()) {
00450 if ((*i)->rules()->isHeavier(power)) {
00451 result.push_back(*i);
00452 }
00453 else {
00454 Cube::t_models distance_killers =
00455 (*i)->rules()->whoIsHeavier(power);
00456 result.insert(result.end(), distance_killers.begin(),
00457 distance_killers.end());
00458 }
00459 }
00460 }
00461
00462 m_mask->mask();
00463 return result;
00464 }
00465
00466
00467
00468
00469
00470
00471
00472 bool
00473 Rules::canMoveOthers(Dir::eDir dir, Cube::eWeight power)
00474 {
00475 bool result = true;
00476
00477 m_mask->unmask();
00478
00479 Cube::t_models resist = m_mask->getResist(dir);
00480 Cube::t_models::iterator end = resist.end();
00481 for (Cube::t_models::iterator i = resist.begin(); i != end; ++i) {
00482 if (!(*i)->rules()->canDir(dir, power)) {
00483 result = false;
00484 break;
00485 }
00486 }
00487
00488 m_mask->mask();
00489 return result;
00490 }
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 bool
00502 Rules::canDir(Dir::eDir dir, Cube::eWeight power)
00503 {
00504 bool result = false;
00505 if (!m_model->isAlive() && power >= m_model->getWeight()) {
00506 result = canMoveOthers(dir, power);
00507 }
00508
00509 return result;
00510 }
00511
00512
00513
00514
00515
00516
00517 bool
00518 Rules::touchSpec(Dir::eDir dir)
00519 {
00520 bool result = false;
00521 Cube::t_models resist = m_mask->getResist(dir);
00522 if (resist.size() == 1) {
00523 if (resist[0]->isOutDir(dir)) {
00524 resist[0]->decOutCapacity();
00525 m_mask->unmask();
00526 m_model->change_goOut();
00527 result = true;
00528 }
00529 }
00530 return result;
00531 }
00532
00533
00534
00535
00536 void
00537 Rules::setTouched(Dir::eDir dir)
00538 {
00539 m_touchDir = dir;
00540 if (!m_model->isWall()) {
00541 m_mask->unmask();
00542 Cube::t_models resist = m_mask->getResist(dir);
00543 Cube::t_models::iterator end = resist.end();
00544 for (Cube::t_models::iterator i = resist.begin(); i != end; ++i) {
00545 if (!(*i)->isAlive()) {
00546 (*i)->rules()->setTouched(dir);
00547 }
00548 }
00549 m_mask->mask();
00550 }
00551 }
00552
00553
00554
00555
00556
00557
00558
00559
00560 bool
00561 Rules::actionMoveDir(Dir::eDir dir)
00562 {
00563 bool result = false;
00564 if (canMoveOthers(dir, m_model->getPower())) {
00565 moveDirBrute(dir);
00566 result = true;
00567 }
00568 else {
00569 if (touchSpec(dir)) {
00570 result = true;
00571 }
00572 else {
00573 setTouched(dir);
00574 }
00575 }
00576
00577 return result;
00578 }
00579
00580
00581
00582
00583
00584
00585 void
00586 Rules::moveDirBrute(Dir::eDir dir)
00587 {
00588
00589 m_mask->unmask();
00590
00591 Cube::t_models resist = m_mask->getResist(dir);
00592 Cube::t_models::iterator end = resist.end();
00593 if (end != resist.begin()) {
00594 m_pushing = true;
00595 }
00596 for (Cube::t_models::iterator i = resist.begin(); i != end; ++i) {
00597 (*i)->rules()->moveDirBrute(dir);
00598 }
00599
00600 m_dir = dir;
00601 m_mask->mask();
00602 }
00603
00604
00605
00606
00607
00608
00609
00610 std::string
00611 Rules::getAction() const
00612 {
00613 if (m_readyToTurn) {
00614 return "turn";
00615 }
00616 else if (m_readyToActive) {
00617 return "activate";
00618 }
00619 else if (m_model->isBusy()) {
00620 return "busy";
00621 }
00622
00623 switch (m_dir) {
00624 case Dir::DIR_LEFT: return "move_left";
00625 case Dir::DIR_RIGHT: return "move_right";
00626 case Dir::DIR_UP: return "move_up";
00627 case Dir::DIR_DOWN: return "move_down";
00628 case Dir::DIR_NO: return "rest";
00629 default: assert(!"unknown dir"); break;
00630 }
00631
00632 return "rest";
00633 }
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 std::string
00647 Rules::getState() const
00648 {
00649 if (m_outDepth == 1) {
00650 return "goout";
00651 }
00652 else if (!m_model->isAlive()) {
00653 return "dead";
00654 }
00655 else if (m_model->isTalking()) {
00656 return "talking";
00657 }
00658 else if (m_pushing) {
00659 return "pushing";
00660 }
00661 else {
00662 return "normal";
00663 }
00664 }
00665
00666 bool
00667 Rules::isAtBorder() const
00668 {
00669 return m_mask->getBorderDir() != Dir::DIR_NO;
00670 }
00671
00672 bool
00673 Rules::isFreePlace(const V2 &loc) const
00674 {
00675 return m_mask->getPlacedResist(loc).empty();
00676 }
00677
00678 const Cube::t_models
00679 Rules::getResist(Dir::eDir dir) const
00680 {
00681 return m_mask->getResist(dir);
00682 }
00683