Как убрать повторение из этой простой функции? - PullRequest
1 голос
/ 10 февраля 2010

У меня есть игра, состоящая из кораблей, которые летают по двумерной сетке. Я пишу функцию, которая берет местоположение и выясняет, можно ли оттуда попасть (предопределенную) цель. Это просто требует проверки всех квадратов сетки на линии огня потенциального агрессора.

В большинстве случаев это крест, сформированный так:

(currX +/- SHOT_RANGE, currY) and (currX, currY +/- SHOT_RANGE)

Где SHOT_RANGE - максимальное расстояние, на которое может пройти выстрел, и в настоящее время стреляющий корабль находится на (currX, currY).

Код для проверки этих двух строк довольно прост:

        for (int i = x - SHOT_RANGE; i < x + SHOT_RANGE; i++) {
            if (target.TileX == i && target.TileY == y) {
                return true;
            }
        }

        for (int j = y - SHOT_RANGE; j < y + SHOT_RANGE; j++) {
            if (target.TileX == x && target.TileY == j) {
                return true;
            }
        }

Однако на некоторых «силовых клетках» корабль также может стрелять по диагонали. Все эти квадраты тоже должны быть проверены. Вот где приходит повторение. Можете ли вы найти способ сделать это с меньшим количеством кода?

    /// <param name="x">Current x-coord of the potential ship</param>
    /// <param name="y">Current y-coord of the potential ship</param>
            private bool CanShootTargetFrom(int x, int y) {

        if ((target.TileX == x && Math.Abs(target.TileY - y) <= SHOT_RANGE) || (target.TileY == y && Math.Abs(target.TileX - x) <= SHOT_RANGE)) {
            return true;
        }

        if (board.IsPowerTileAt(x, y)) {
            int i = x - SHOT_RANGE;
            int j = y - SHOT_RANGE;
            while (i != x + SHOT_RANGE && j != y + SHOT_RANGE) {
                if (target.TileX == i && target.TileY == j) {
                    return true;
                }
                i++;
                j++;
            }
            i = x - SHOT_RANGE;
            j = y + SHOT_RANGE;
            while (i != x + SHOT_RANGE && j != y - SHOT_RANGE) {
                if (target.TileX == i && target.TileY == j) {
                    return true;
                }
                i++;
                j--;
            }
        }

        return false;
    }

Обновлен, чтобы использовать предложение Карры, и я понял, что могу устранить две петли, проверяющие диагонали, увеличив верхние границы.

Ответы [ 2 ]

1 голос
/ 10 февраля 2010

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

class Ship{int x;int y}

Ship s;//your ship
Ship t;//target

if(
  (s.y == t.y && abs(s.x-t.x) <= SHOT_RANGE) 
  ||
  (s.x == t.x && abs(s.y-t.y) <= SHOT_RANGE)
  )
   return true;

Что касается диагоналей, то это треугольник с углом 90 градусов: (a² + b²

int a = abs(s.x - t.x)
int b = abs(s.y - t.y)
if(a == b && a * a + b * b <= shot_range * shot_range)
  return true;

Надеюсь, это то, что вы ищете?

0 голосов
/ 10 февраля 2010

Я думаю, что лучше было бы изменить вашу функцию, чтобы иметь сигнатуру, похожую на:
public bool CanShoot(IShootable potentialTarget)

Этот метод может быть членом класса Ship. Каждый Корабельный объект будет знать свои собственные огневые возможности. Все, что вы хотели бы иметь возможность выстрелить, могло бы реализовать IShootable.

Что касается вашего вопроса, то, похоже, есть более простой способ. Как и в случае с Каррой, вы можете просто проверить, меньше ли абсолютное значение разности каждой координаты, чем ваш диапазон стрельбы. Если нет, верните false. В противном случае, если они находятся на плитке власти, верните true. Если они не находятся на плитке мощности, убедитесь, что либо x-координата, либо y-координата совпадают, если не возвращают false, в противном случае возвращают true.

Предполагается, что корабль с дальностью стрельбы 2 в (0,0) может вести огонь по кораблю в (2,2). Я предполагаю это, потому что код, который вы разместили, позволил бы это.

...