diff options
Diffstat (limited to 'kbattleship/kbattleship/kbdestroyshipstrategy.cpp')
-rw-r--r-- | kbattleship/kbattleship/kbdestroyshipstrategy.cpp | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/kbattleship/kbattleship/kbdestroyshipstrategy.cpp b/kbattleship/kbattleship/kbdestroyshipstrategy.cpp new file mode 100644 index 00000000..714bdd7c --- /dev/null +++ b/kbattleship/kbattleship/kbdestroyshipstrategy.cpp @@ -0,0 +1,390 @@ +/*************************************************************************** + kbdestroyshipstrategy.cpp + ---------- + Developers: (c) 2001 Kevin Krammer <kevin.krammer@gmx.at> + (c) 2001 Nikolas Zimmermann <wildfox@kde.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "kbdestroyshipstrategy.h" + +KBDestroyShipStrategy::KBDestroyShipStrategy(KBStrategy *parent) : KBStrategy(parent) +{ + m_working = false; +} + +void KBDestroyShipStrategy::init(KBattleField *field, const QRect &field_rect) +{ + KBStrategy::init(field, field_rect); + m_working = false; +} + +const QPoint KBDestroyShipStrategy::nextShot() +{ + if(hasMoreShots()) + return QPoint(m_column, m_row); + else + return m_start; +} + +bool KBDestroyShipStrategy::hasMoreShots() +{ + if(!m_working) + return false; + + if(shipDestroyed()) + { + m_working = false; + markBorderingFields(); + return false; + } + + if(enemyFieldStateAt(m_column, m_row) != KBStrategy::SHOT) + return true; + + // last shot was no success :( + if(m_battleField->ownState(m_column, m_row) == KBattleField::WATER) + { + m_column = m_start.x(); + m_row = m_start.y(); + } + + switch(m_direction) + { + case VERTICAL: + if(searchUp() || searchDown()) + return true; + else + { + //kdDebug << "KBDestroyShipStrategy: failed vertical search!" << endl; + m_working = false; + } + break; + + case HORIZONTAL: + if(searchLeft() || searchRight()) + return true; + else + { + //kdDebug << "KBDestroyShipStrategy: failed horizontal search!" << endl; + m_working = false; + } + break; + + default: + int up = m_row > 0 ? m_battleField->ownState(m_column, m_row - 1) : -1; + int down = m_row < (m_fieldRect.height() - 1) ? m_battleField->ownState(m_column, m_row + 1) : -1; + int left = m_column > 0 ? m_battleField->ownState(m_column - 1, m_row) : -1; + int right = m_column < (m_fieldRect.width() - 1) ? m_battleField->ownState(m_column + 1, m_row) : -1; + + if((up != -1 && up == KBattleField::HIT) || (down != -1 && down == KBattleField::HIT)) + { + m_direction = VERTICAL; + return hasMoreShots(); + } + + if((left != -1 && left == KBattleField::HIT) || (right != -1 && right == KBattleField::HIT)) + { + m_direction = HORIZONTAL; + return hasMoreShots(); + } + + if(searchUp() || searchDown() || searchLeft() || searchRight()) + return true; + else + { + //kdDebug << "KBDestroyStrategy: ship unsinkable?" << endl; + m_working = false; + } + break; + } + return false; +} + +void KBDestroyShipStrategy::shotAt(const QPoint &pos) +{ + m_prevShots.append(pos); +} + +void KBDestroyShipStrategy::destroyShipAt(const QPoint pos) +{ + if(enemyFieldStateAt(pos.x(), pos.y()) == FREE || m_battleField->ownState(pos.x(), pos.y()) == KBattleField::DEATH || m_battleField->ownState(pos.x(), pos.y()) == KBattleField::WATER) + m_working = false; + else + { + m_working = true; + m_start = pos; + m_column = pos.x(); + m_row = pos.y(); + m_direction = NODIR; + } +} + +bool KBDestroyShipStrategy::searchUp() +{ + int row = m_row; + int prevCol = m_column - 1; + int nextCol = m_column + 1; + + while(row >= 0 && (m_row - row) < 4 && enemyFieldStateAt(m_column, row) == KBStrategy::SHOT) + { + if(m_battleField->ownState(m_column, row) == KBattleField::WATER) + return false; + + row--; + + bool leftOK = true; + bool rightOK = true; + if(prevCol >= 0) + leftOK = (enemyFieldStateAt(prevCol, row) == FREE) || (m_battleField->ownState(prevCol, row) == KBattleField::WATER); + + if(nextCol < m_fieldRect.width()) + rightOK = (enemyFieldStateAt(nextCol, row) == FREE) || (m_battleField->ownState(nextCol, row) == KBattleField::WATER); + + if(!(rightOK && leftOK)) + return false; + } + + if(row < 0 || (m_row - row) >= 4) + return false; + + m_row = row; + return true; +} + +bool KBDestroyShipStrategy::searchDown() +{ + int row = m_row; + int prevCol = m_column - 1; + int nextCol = m_column + 1; + + while(row < m_fieldRect.height() && (row - m_row) < 4 && enemyFieldStateAt(m_column, row) == KBStrategy::SHOT) + { + if(m_battleField->ownState(m_column, row) == KBattleField::WATER) + return false; + + row++; + + bool leftOK = true; + bool rightOK = true; + if(prevCol >= 0) + leftOK = (enemyFieldStateAt(prevCol, row) == FREE) || (m_battleField->ownState(prevCol, row) == KBattleField::WATER); + + if(nextCol < m_fieldRect.width()) + rightOK = (enemyFieldStateAt(nextCol, row) == FREE) || (m_battleField->ownState(nextCol, row) == KBattleField::WATER); + + if(!(rightOK && leftOK)) + return false; + } + + if(row >= m_fieldRect.height() || (row - m_row) >= 4) + return false; + + m_row = row; + return true; +} + +bool KBDestroyShipStrategy::searchLeft() +{ + int col = m_column; + int prevRow = m_row - 1; + int nextRow = m_row + 1; + + while(col >= 0 && (m_column - col) < 4 && enemyFieldStateAt(col, m_row) == KBStrategy::SHOT) + { + if(m_battleField->ownState(col, m_row) == KBattleField::WATER) + return false; + + col--; + + bool upOK = true; + bool downOK = true; + if(prevRow >= 0) + upOK = (enemyFieldStateAt(col, prevRow) == FREE) || (m_battleField->ownState(col, prevRow) == KBattleField::WATER); + + if(nextRow < m_fieldRect.height()) + downOK = (enemyFieldStateAt(col, nextRow) == FREE) || (m_battleField->ownState(col, nextRow) == KBattleField::WATER); + + if(!(upOK && downOK)) + return false; + } + + if(col < 0 || (m_column - col) >= 4) + return false; + + m_column = col; + return true; +} + +bool KBDestroyShipStrategy::searchRight() +{ + int col = m_column; + int prevRow = m_row - 1; + int nextRow = m_row + 1; + + while(col < m_fieldRect.width() && (col - m_column) < 4 && enemyFieldStateAt(col, m_row) == KBStrategy::SHOT) + { + if(m_battleField->ownState(col, m_row) == KBattleField::WATER) + return false; + + col++; + + bool upOK = true; + bool downOK = true; + if(prevRow >= 0) + upOK = (enemyFieldStateAt(col, prevRow) == FREE) || (m_battleField->ownState(col, prevRow) == KBattleField::WATER); + + if(nextRow < m_fieldRect.height()) + downOK = (enemyFieldStateAt(col, nextRow) == FREE) || (m_battleField->ownState(col, nextRow) == KBattleField::WATER); + + if(!(upOK && downOK)) + return false; + } + + if(col >= m_fieldRect.width() || (col - m_column) >= 4) + return false; + + m_column = col; + return true; +} + +bool KBDestroyShipStrategy::shipDestroyed() +{ + int col = m_start.x(); + int row = m_start.y(); + int state = m_battleField->ownState(col, row); + + while(m_direction != HORIZONTAL && row >= 0 && state != KBattleField::FREE && state != KBattleField::WATER) + { + if(enemyFieldStateAt(col, row) == SHIP) + return false; + + row--; + if(row >= 0) + state = m_battleField->ownState(col, row); + } + + row = m_start.y(); + state = m_battleField->ownState(col, row); + while(m_direction != HORIZONTAL && row < m_fieldRect.height() && state != KBattleField::FREE && state != KBattleField::WATER) + { + if(enemyFieldStateAt(col, row) == SHIP) + return false; + + row++; + if(row < m_fieldRect.height()) + state = m_battleField->ownState(col, row); + } + + row = m_start.y(); + state = m_battleField->ownState(col, row); + while(m_direction != VERTICAL && col >= 0 && state != KBattleField::FREE && state != KBattleField::WATER) + { + if(enemyFieldStateAt(col, row) == SHIP) + return false; + + col--; + if(col >= 0) + state = m_battleField->ownState(col, row); + } + + col = m_start.x(); + state = m_battleField->ownState(col, row); + while(m_direction != VERTICAL && col < m_fieldRect.width() && state != KBattleField::FREE && state != KBattleField::WATER) + { + if(enemyFieldStateAt(col, row) == SHIP) + return false; + + col++; + if(col < m_fieldRect.width()) + state = m_battleField->ownState(col, row); + } + + return true; +} + +void KBDestroyShipStrategy::markBorderingFields() +{ + int col = m_start.x(); + int row = m_start.y(); + int i,j; + + if (m_direction == VERTICAL) + { + while (m_fieldRect.contains(col, row) && + m_battleField->ownState(col, row) == KBattleField::HIT) + { + row--; + } + if (row >= 0) + { // above the ship + setViablePos(col, row, false); + } + row++; + i = col+1; // right of the ship + j = col-1; // left of the ship + while (m_fieldRect.contains(col, row) && + m_battleField->ownState(col, row) == KBattleField::HIT) + { + if (m_fieldRect.contains(i, row)) + setViablePos(i, row, false); + if (m_fieldRect.contains(j, row)) + setViablePos(j, row, false); + setViablePos(col, row, false); + row++; + } + if (m_fieldRect.contains(col, row)) + { // below the ship + setViablePos(col, row, false); + } + } + else if (m_direction == HORIZONTAL) + { + while (m_fieldRect.contains(col, row) && + m_battleField->ownState(col, row) == KBattleField::HIT) + { + col--; + } + if (col >= 0) + { // left of the ship + setViablePos(col, row, false); + } + col++; + i = row+1; // below the ship + j = row-1; // above the ship + while (m_fieldRect.contains(col, row) && + m_battleField->ownState(col, row) == KBattleField::HIT) + { + if (m_fieldRect.contains(col, i)) + setViablePos(col, i, false); + if (m_fieldRect.contains(col, j)) + setViablePos(col, j, false); + setViablePos(col, row, false); + col++; + } + if (m_fieldRect.contains(col, row)) + { // right of the ship + setViablePos(col, row, false); + } + } + else + { + if (row > 0) + setViablePos(col, (row-1), false); + if (row < (m_fieldRect.height()-1)) + setViablePos(col, (row+1), false); + if (col > 0) + setViablePos((col-1), row, false); + if (col < (m_fieldRect.width()-1)) + setViablePos((col+1), row, false); + } +} |