Как избежать дублирования кода

Есть метод класса, который добавляет корабль на игровое поле. Корабль может быть повёрнут в разные стороны, быть разной длины. Для добавления имеется такой код:

bool SeaBattleCore::addShip(PlayerNumber pn, Ship *s)
{
if (s == nullptr
        || s->getX() >= m_fieldSize || s->getX() < 0
        || s->getY() >= m_fieldSize || s->getY() < 0)
{
    return false;
}

switch (s->getDir())
{
default:
case Direction::right:
    if (s->getX() + s->getShipSize() > m_fieldSize)
    {
        return false;
    }
    for (unsigned int x = s->getX(); x < s->getX() + s->getShipSize(); ++x)
    {
        if (m_gameField[pn.getNumber()][x][s->getY()].haveShipInThisSquare())
        {
            return false;
        }
    }
    for (unsigned int x = s->getX(); x < s->getX() + s->getShipSize(); ++x)
    {
        m_gameField[pn.getNumber()][x][s->getY()].setShip(s);
    }
    break;
case Direction::left:
    if (s->getX() >= s->getShipSize() - 1)
    {
        return false;
    }
    for (unsigned int x = s->getX() + s->getShipSize() - 1; x >= s->getX() ; --x)
    {
        if (m_gameField[pn.getNumber()][x][s->getY()].haveShipInThisSquare())
        {
            return false;
        }
    }
    for (unsigned int x = s->getX() + s->getShipSize() - 1; x >= s->getX() ; --x)
    {
        m_gameField[pn.getNumber()][x][s->getY()].setShip(s);
    }
    break;
case Direction::up:
    if (s->getY() >= s->getShipSize() - 1)
    {
        return false;
    }
    for (unsigned int y = s->getY() + s->getShipSize() - 1; y >= s->getX() ; --y)
    {
        if (m_gameField[pn.getNumber()][s->getX()][y].haveShipInThisSquare())
        {
            return false;
        }
    }
    for (unsigned int y = s->getY() + s->getShipSize() - 1; y >= s->getX() ; --y)
    {
        m_gameField[pn.getNumber()][s->getX()][y].setShip(s);
    }
    break;
case Direction::down:
    if (s->getY() + s->getShipSize() > m_fieldSize)
    {
        return false;
    }
    for (unsigned int y = s->getX(); y < s->getX() + s->getShipSize(); ++y)
    {
        if (m_gameField[pn.getNumber()][s->getX()][y].haveShipInThisSquare())
        {
            return false;
        }
    }
    for (unsigned int y = s->getX(); y < s->getX() + s->getShipSize(); ++y)
    {
        m_gameField[pn.getNumber()][s->getX()][y].setShip(s);
    }
    break;
}

}

Есть какие-нибудь идеи как избежать дублирование кода? Просто я дурачек |:b


Ответы (1 шт):

Автор решения: Zhihar
switch (s->getDir())
{
default:
case Direction::right:

а что так можно было? а в чем тогда смысл default?

если у вас корабли имеют одинаковую структуру, то вам надо только горизонтальная и вертикальная расположение

и тогда вам нужно будет только 2 цикла-проверки

для горизонтали:

bool is_correct = true;

for (int deck = 0; deck < decks_count; deck++)
{
    if (pos_x + deck >= width) || (m_field[pos_x + deck][pos_y] != 0)
        is_correct = false;
}

if (is_corrent) 
{
     for (int deck = 0; deck < decks_count; deck++)
         m_field[pos_x + deck][pos_y] = 1;
}

для вертикали такой же:

при этом если правильно выбирать начало корабля, то проверка на выход за границы поля вообще не нужна:

const int pos_x = random(0, width - decks_count); // псевдокод - просто поставил функцию random чтобы показать диапазон значений

и тогда код станет таким:

bool is_correct = true;

for (int deck = 0; deck < decks_count; deck++)
{
    if (m_field[pos_x + deck][pos_y] != 0)
        is_correct = false;
}

if (is_corrent) 
{
    for (int deck = 0; deck < decks_count; deck++)
        m_field[pos_x + deck][pos_y] = 1;
}
→ Ссылка