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.
391 lines
9.8 KiB
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);
|
|
}
|
|
}
|