summaryrefslogtreecommitdiffstats
path: root/kbattleship/kbattleship/kbdestroyshipstrategy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kbattleship/kbattleship/kbdestroyshipstrategy.cpp')
-rw-r--r--kbattleship/kbattleship/kbdestroyshipstrategy.cpp390
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);
+ }
+}