Home > Back-end >  How to find a >3 line of consecutive elements in a 2d array
How to find a >3 line of consecutive elements in a 2d array

Time:12-28

I'm a game where you have to make a line in a row/column of 3 or more (up to 7) consecutive elements in a 2d array. Every time there is one of those lines you add the score and delete those consecutive elements from the row/column (Similar as to candycrash disappearing candies.

If you have something like this ['a' 'b' 'b' 'b' 'a'] the result should be ['a' '' '' '' 'a'] The problem comes to more complex cases like ['b' 'b' ' ' 'b' 'b'], that ends up like this ['' '' '' '' ''] because its also detected as a >=3 elem. consecutive line. I know its due to the counter that keeps adding to the value it already has, but I couldnt come to any other solution till now

The code I have up to now is this: **

public int[] checkRows() {
        int[] results = new int[BOARD_SIZE];
        
        for (int i = 0; i < BOARD_SIZE; i  ) {
            int counter = 1;
            int counterHead = 1;
            int j = 0;
            
            while (j < BOARD_SIZE) {
                if (j 1 < BOARD_SIZE) {
                    if (getBoard()[i][j].getType() == getBoard()[i][j 1].getType() && getBoard()[i][j].getType() != ' ') {
                        counter  ;
                    }
                }
                if (counter >= 3)
                    deleteRows(i, j);
                j  ;
            }
            
            results[i] = counter;       
        }
        
        return results;
    }

**

CodePudding user response:

So we want to see if there are 3 consecutive elements with the same value, but what it looks like to me is we are simply testing if there are three values in a row of the board that are equal. This works if we find a section of consecutive equivalent elements, but as soon as we find a space or non-equal element the logic fails.

Things we need to consider:

  1. If the counter reaches 3 we can break out of your conditional and delete. This case is covered.
  2. If your counter is updated from its original value (counter > 1) and never reaches 3 we know we must have encountered either a space or a non-equivalent value. In this case we should reset the counter and continue our test for the rest of the row.

CodePudding user response:

Your problem is that you are not counting consecutive values, but rather pairs of consecutive values. For 'b', 'b', 'b', there are three b characters, but only 2 pairs of values, 1) the first and second b, and 2) the second and third b. Your counter should start at 1 rather than 0 because every value is by itself a run of 1 "consecutive" values. This, along with resetting the counter when you see a non-matching letter should give you the result you desire.

I haven't tried this as I don't have your data or the structures that this code uses, but try this:

public int[] checkRows() { int[] results = new int[BOARD_SIZE];

    for (int i = 0; i < BOARD_SIZE; i  ) {
        int counter = 1;
        int counterHead = 1;
        int j = 1;
        
        while (j < BOARD_SIZE) {
            if (j 1 < BOARD_SIZE) {
                if (getBoard()[i][j].getType() == getBoard()[i][j 1].getType() && getBoard()[i][j].getType() != ' ') {
                    counter  ;
                }
                else {
                    counter = 1;
                }

            }
            if (counter >= 3)
                deleteRows(i, j);
            j  ;
        }
        
        results[i] = counter;       
    }
    
    return results;
}

CodePudding user response:

First of all, I would suggest that for such complex problems, always try to break your problems and then merge those pieces together.

Below is the algorithm for your problem, just for simplicity and ease of explanation I used an Integer array which you can easily replace with a string or character array and change the condition.

A basic function for performing candyCrush Algorithm.

public void candyCrush(){
    int[][] result = new int[][]{{1,2,2,2,2},
                                 {1,2,2,2,1},
                                 {1,2,1,1,1},
                                 {2,1,2,1,1}
    };

    int count = 0;

    for (int i = 0; i < result.length; i  ) {
        for (int j = 0; j < result[i].length; j  ) {
            if(result[i][j]==-1){
                continue;
            }
            boolean hasRowElements = checkRowForCurrentIndex(result, i, j);
            boolean hasColumnElements = checkColumnForCurrentIndex(result, i, j);
            if(hasRowElements || hasColumnElements){
                count  ;
            }
        }
    }

    System.out.println(count);
}



private boolean checkRowForCurrentIndex(int[][] result, int row, int col) {
    int forTop = row, forBottom = row;
    int topStartingLimit = 0, bottomEndingLimit = 0;
    while(forTop>= 0){
        if(result[row][col] == result[forTop][col] && result[forTop][col]!=-1){
            topStartingLimit = forTop;
        }else{
            break;
        }
        forTop--;
    }

    while(forBottom< result.length){
        if(result[row][col] == result[forBottom][col] && result[forBottom][col]!=-1){
            bottomEndingLimit = forBottom;
        }else{
            break;
        }
        forBottom  ;
    }

    if(topStartingLimit==bottomEndingLimit){
        return false;
    }

    if(bottomEndingLimit-topStartingLimit>=2 && bottomEndingLimit-topStartingLimit<= 6) {
        deleteRows(result, topStartingLimit, bottomEndingLimit, row, col);
        return true;
    }

    return false;
}


private void deleteRows(int[][] result, int topStartingLimit, int bottomEndingLimit, int row, int col) {
    while(topStartingLimit<= bottomEndingLimit){
        result[topStartingLimit][col] = -1;
        topStartingLimit  ;
    }
    return;
}


private boolean checkColumnForCurrentIndex(int[][] result, int row, int col) {
    int forLeft = col, forRight = col;
    int leftStartingLimit = 0, rightEndingLimit = 0;
    while(forLeft>= 0){
        if(result[row][col] == result[row][forLeft] && result[row][forLeft]!=-1){
            leftStartingLimit = forLeft;
        }else{
            break;
        }
        forLeft--;
    }

    while(forRight< result[row].length){
        if(result[row][col] == result[row][forRight] && result[row][forRight]!=-1){
            rightEndingLimit = forRight;
        }else{
            break;
        }
        forRight  ;
    }

    if(leftStartingLimit==rightEndingLimit){
        return false;
    }
    if(rightEndingLimit-leftStartingLimit>=2 && rightEndingLimit-leftStartingLimit<= 6) {
        deleteCols(result, leftStartingLimit, rightEndingLimit, row, col);
        return true;
    }
    return false;
}


private void deleteCols(int[][] result, int leftStartingLimit, int rightEndingLimit, int row, int col) {
    while(leftStartingLimit<= rightEndingLimit){
        result[row][leftStartingLimit] = -1;
        leftStartingLimit  ;
    }
    return;
}

Definitely, you can optimize this code better by using the same function again for Rows and Cols, but for sake of simplicity. I tried to break everything so that the solution becomes more clear.

Hope this algorithm would work.

  • Related