Недавно случилась задача. В ходе реализации алгоритма игры 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());Вот и вся магия...

Эм итераторы???
ОтветитьУдалитьНаверное, хз :)
Удалить