Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

Как можно максимально сократить этот код?

#java #инспекция_кода


Морской бой. Пишу метод для поворота корабля.

tt - это текущее положение корабля:


  0 - вертикально (по умолчанию)
  
  1 - горизонтально (0 + 90°)
  
  2 - вертикально (0 вверх ногами)
  
  3 - горизонтально (0 - 90°)


ckw - это флаг поворота:


  true - по часовой стрелке
  
  false - против часовой стрелки


Код метода поворота:

public void turn (boolean ckw) {
    if ((tt == 0 && !ckw) || (tt == 1 && ckw)) {
        //b -> c
    }
    else if ((tt == 1 && !ckw) || (tt == 2 && ckw)) {
        //c -> d
    }
    else if ((tt == 2 && !ckw) || (tt == 3 && ckw)) {
        //d -> a
    }
    else if ((tt == 3 && !ckw) || (tt == 0 && ckw)) {
        //a -> b
    }
    if (ckw)
        tt++;
    else
        tt--;
}


Комментариями обозначены 4 цикла for-each с логикой разворота. Мне бы вот эту лесенку
if-ов сократить. Это возможно?

Логика поворота

Корабль представляет собой ArrayList позиций в сетке. Например, 4-палубный, находящийся
в середине поля: 35, 45, 55, 65. Чтобы его повернуть по часовой стрелке, надо прибавить
к каждой позиции её индекс, умноженный на 11.

b -> c (90° -> 180°) или (0° -> 270°)

for (int i = 0; i < col.size(); i++) {
    int num = col.get(i);
    int new_num = num + 11 * i;
    col.set(i, new_num);
}


И т.д.
    


Ответы

Ответ 1



Храним только базовые координаты, длину и текущее состояние разворота. Всё остальное вычисляемо из этих данных. Демка на коленке: public class Main { public static void main(String[] args) { Ship ship = new Ship(4, 1, 3, 5); // 35, ship.print(); System.out.println("Clockwise"); ship.turn(true).print(); ship.turn(true).print(); ship.turn(true).print(); ship.turn(true).print(); System.out.println("Counter-clockwise"); ship.turn(false).print(); ship.turn(false).print(); ship.turn(false).print(); ship.turn(false).print(); } } public class Ship { private int state; private int x; private int y; private int length; public Ship(int length, int initialState, int x, int y) { state = initialState; this.x = x; this.y = y; this.length = length; } public Ship turn(boolean clockwise) { if (clockwise) { state = (state + 1) % 4; } else { state = (state + 3) % 4; } return this; } public Ship print() { for (int i = 0; i < length; i++) { switch (state) { case 0: System.out.print("("+(10*x+y-i)+")"); break; // N case 1: System.out.print("("+(10*(x+i)+y)+")"); break; // E case 2: System.out.print("("+(10*x+y+i)+")"); break; // S case 3: System.out.print("("+(10*(x-i)+y)+")"); break; // W } } System.out.println(""); return this; } }

Ответ 2



Мы выполняем ту или иную операцию в случае если tt == n и ckw == false или tt == n + 1 и ckw == true. Следовательно, если для случая ckw == false мы увеличим сравниваемое значение на 1, то потом нам нужно будет проверить только случай tt == n + 1. Такую цепочку проверок легко организовать при помощи оператора switch Update как поправил меня @vp_arth вместо switch (val) лучше использовать switch (val % 4). Тогда можно убрать проверку case 4: public void turn(boolean ckw) { int val = tt; if (!ckw) val++; switch (val % 4) { case 1: //b -> c break; case 2: //c -> d break; case 3: //d -> a break; case 0: //a -> b break; } if (ckw) tt++ else tt--; }

Ответ 3



Если не отходить от того, что координаты корабля хранятся в ArrayList, то можно сделать так. В методе turn вычисляется новое значение tt, после чего координаты корабля считаются заново с учетом нового значения tt и фиксированной точки корабля (например, головы). public void turn(boolean ckw) { tt += ckw ? 1 : -1; tt = (tt + 4) % 4; int sign = (tt == 1 || tt == 2) ? 1 : -1; int shift = (tt % 2 == 0) ? 10 : 1; int head = col.get(0); for (int i = 1; i < col.size(); i++) { int newNum = head + sign * shift * i; col.set(i, newNum); } } Предполагается, что корабли могут быть только в виде одной линии. Также не учитывается то, что после поворота корабль может "выйти" за край поля.

Комментариев нет:

Отправить комментарий