/*************************************************************************** kbdestroyshipstrategy.cpp ---------- Developers: (c) 2001 Kevin Krammer (c) 2001 Nikolas Zimmermann ***************************************************************************/ /*************************************************************************** * * * 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 *tqparent) : KBStrategy(tqparent) { m_working = false; } void KBDestroyShipStrategy::init(KBattleField *field, const TQRect &field_rect) { KBStrategy::init(field, field_rect); m_working = false; } const TQPoint KBDestroyShipStrategy::nextShot() { if(hasMoreShots()) return TQPoint(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 TQPoint &pos) { m_prevShots.append(pos); } void KBDestroyShipStrategy::destroyShipAt(const TQPoint 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); } }