You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/kbattleship/kbattleship/kbdestroyshipstrategy.cpp

391 lines
9.8 KiB

/***************************************************************************
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 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);
}
}