Недавно случилась задача. В ходе реализации алгоритма игры 2048.
Был двухмерный массив - поле. И (допустим) один полезный метод, с какой-о сложной логикой модификации содержимого поля.
- сверху вниз, слева направо
- слева направо, снизу вверх
- слева направо, сверху вниз
Но писать еще три метода методом копипаста как-то не хотелось. Так же была попытка написать мострообразный метод, в котором циклы тюнятся через спец константы - свой набор констант для своего кейса. Это было громоздко и не читабельно.
Решение приснилось :) Им и поделююсь. Суть вкратце в том, что для начала мы вводим интерфейс доступа к массиву вместо непосредственного его использования
Был двухмерный массив - поле. И (допустим) один полезный метод, с какой-о сложной логикой модификации содержимого поля.
public class Numbers { public static final int NONE = 0; private final int size; private int[][] data; public Numbers(int size) { this.size = size; data = new int[size][size]; } private void merge() { for (int y = 0; y < size; y++) { for (int x = 0; x <= size - 1; x++) { if (data[x][y] == NONE) continue; for (int x2 = x - 1; x2 > -1; x2--) { if (data[x2][y] == NONE) { data[x2][y] = data[x2 + 1][y]; data[x2 + 1][y] = NONE; } else if (data[x2][y] == data[x2 + 1][y]) { int val = 2 * data[x2 + 1][y]; data[x2][y] = val; data[x2 + 1][y] = NONE; break; } else { break; } } } } } }Реализован был случай прохода сверху вниз, справа налево. Так случилось, что надо еще 3 версии подобного метода, в котором перебор будет еще:
- сверху вниз, слева направо
- слева направо, снизу вверх
- слева направо, сверху вниз
Но писать еще три метода методом копипаста как-то не хотелось. Так же была попытка написать мострообразный метод, в котором циклы тюнятся через спец константы - свой набор констант для своего кейса. Это было громоздко и не читабельно.
Решение приснилось :) Им и поделююсь. Суть вкратце в том, что для начала мы вводим интерфейс доступа к массиву вместо непосредственного его использования
public class Numbers { public static final int NONE = 0; private final int size; private int[][] data; public Numbers(int size) { this.size = size; data = new int[size][size]; } private void merge(Mirror data) { for (int y = 0; y < size; y++) { for (int x = 0; x <= size - 1; x++) { if (data.get(x, y) == NONE) continue; for (int x2 = x - 1; x2 > -1; x2--) { if (data.get(x2, y) == NONE) { data.set(x2, y, data.get(x2 + 1, y)); data.set(x2 + 1, y, NONE); } else if (data.get(x2, y) == data.get(x2 + 1, y)) { int val = 2 * data.get(x2 + 1, y); data.set(x2, y, val); data.set(x2 + 1, y, NONE); break; } else { break; } } } } } interface Mirror { int get(int x, int y); void set(int x, int y, int val); }После этого используем разные реализации этого фильтра, один нормальный:
class XY implements Mirror { @Override public int get(int x, int y) { return data[x][y]; } @Override public void set(int x, int y, int val) { data[x][y] = val; } }и три зеркальных
class _XY implements Mirror { @Override public int get(int x, int y) { return data[size - 1 - x][y]; } @Override public void set(int x, int y, int val) { data[size - 1 - x][y] = val; } } class Y_X implements Mirror { @Override public int get(int x, int y) { return data[y][size - 1 - x]; } @Override public void set(int x, int y, int val) { data[y][size - 1 - x] = val; } } class YX implements Mirror { @Override public int get(int x, int y) { return data[y][x]; } @Override public void set(int x, int y, int val) { data[y][x] = val; } }А метод merge дергаем как-то так
merge(this.new _XY()); merge(this.new Y_X()); merge(this.new XY()); merge(this.new YX());Вот и вся магия...
Эм итераторы???
ОтветитьУдалитьНаверное, хз :)
Удалить