How to combine all similar array looping methods? Java 1.8



In order to study programming, I am making a game 2048 in java. The game has a class in which there are many repetitive fragments – field iteration loops. The question is, is it possible to create such a method that will accept the values of the enumeration bounds and the executable code?

Something like this both for assignment and comparison.

public void forField(int borderX, int borderY, ??? code){
    for (int x = 0; x < borderX; x++)
        for (int y = 0; y < borderY; y++)
            do code;
}

public boolean checkField(int borderX, int borderY, ??? code, boolean default_answer){
    for (int x = 0; x < borderX; x++)
        for (int y = 0; y < borderY; y++)
            return code;
    return default_answer;
}

If not, can you recommend how to make my code better? Thank you for your attention.

public class Field {
    private int[][] field;
    private int width, heigth;

    public Field(int sizeX, int sizeY) {
        this.width = sizeX;
        this.heigth = sizeY;
        this.field = new int[sizeX][sizeY];
    }

    public int getCell(int x, int y) {
        return this.field[x][y];
    }

    public void setCell(int val, int x, int y) {
        this.field[x][y] = val;
    }

    // for restart
    public void reset() {
        for (int x = 0; x < width; x++)
            for (int y = 0; y < heigth; y++)
                this.field[x][y] = 0;
    }

    // for step cancelling function
    public void copyOf(Field f) {
        for (int x = 0; x < width; x++)
            for (int y = 0; y < heigth; y++)
                this.field[x][y] = f.getCell(x, y);
    }

    // can field changed after pressing a key
    public boolean isEqualTo(Field f) {
        for (int x = 0; x < width; x++)
            for (int y = 0; y < heigth; y++)
                if (field[x][y] != f.getCell(x, y))
                    return false;
        return true;
    }

    private boolean canMergeByY() {
        for (int x = 0; x < width; x++)
            for (int y = 0; y < heigth - 1; y++)
                if (field[x][y] == field[x][y + 1])
                    return true;
        return false;
    }

    private boolean canMergeByX() {
        for (int x = 0; x < width - 1; x++)
            for (int y = 0; y < heigth; y++)
                if (field[x][y] == field[x + 1][y])
                    return true;
        return false;
    }

    // checking the possibility of continuing the game
    public boolean canMerge() {
        return canMergeByX() && canMergeByY();
    }

    // checking 0 and 2048 cells for different tasks
    public boolean contains(int i) {
        for (int x = 0; x < width; x++)
            for (int y = 0; y < heigth; y++)
                if (field[x][y] == i)
                    return true;
        return false;
    }
}

Answer

The ??? in forField can just be a BiConsumer<Integer, Integer>, or you can declare your own IntBiConsumer interface if you don’t like boxing:

interface IntBiConsumer {
    void accept(int i, int j);
}

forField can then be declared as:

public void forField(int borderX, int borderY, IntBiConsumer code){
    for (int x = 0; x < borderX; x++)
        for (int y = 0; y < borderY; y++)
           code.accept(x, y);
}

copyOf can then be written as:

public void copyOf(Field f) {
    forField(width, height, (x, y) -> {
        this.field[x][y] = f.getCell(x, y);
    });
}

checkField is a little bit more tricky, your proposed code wouldn’t actually work, because you are not checking anything before you return in the inner loop. The loops will only loop once, and return immediately. It should be more like:

public boolean checkField(int borderX, int borderY, ??? condition, boolean default_answer){
    for (int x = 0; x < borderX; x++)
        for (int y = 0; y < borderY; y++)
            if (condition) 
                return !default_answer;
    return default_answer;
}

??? here can be a BiPredicate<Integer, Integer>, or your own interface like this:

interface IntBiPredicate {
    boolean test(int i, int j);
}

checkField can then be declared like this:

public boolean checkField(int borderX, int borderY, IntBiPredicate condition, boolean defaultAnswer){
    for (int x = 0; x < borderX; x++)
        for (int y = 0; y < borderY; y++)
            if (condition.test()) 
                return !defaultAnswer;
    return defaultAnswer;
}

isEqualTo can be rewritten as:

public boolean isEqualTo(Field f) {
    return checkField(width, height, (x, y) -> field[x][y] != f.getCell(x, y), true);
}


Source: stackoverflow