控制台中的Java Connect Four - 水平和垂直获胜条件

时间:2016-11-16 17:34:33

标签: java

我正在为Java中的控制台开发Connect Four游戏。我对获胜条件有疑问,因为我不知道如何编程。这是我的代码我的主要:

public class Main {

public static char[] playerNumber = new char[]{'1', '2'};
public static char[] Badge = new char[]{'X', 'O'};

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int moves = 7 * 6;
    int whichPlayer = 0;

    for (int i = 0; i < 10; i++) {
    System.out.println("                    FOUR IN A ROW");
    System.out.println("-------------------------------------------------------");
    System.out.println("Welcome to the amazing game Four In A Row:");
    System.out.println("Enter a number between 0 and 6 for choosing a column.");
    System.out.println();

        Board board = new Board();
        board.fillBoard();
        board.presentBoard();

        do {
            // 1. get a badge
            char Player = playerNumber[whichPlayer];
            char badge = Badge[whichPlayer];

            // 2. make a turn
            board.makeTurn(badge, Player);
            board.presentBoard();

            // 3. Tjek om der er vinder
            if (board.checkWinHorizontal() || board.checkWinVertical()) {
                System.out.println("Player " + Player + " has won!");
                break;
            }

            // 4. change the player
            whichPlayer = 1 - whichPlayer;

            // 5. decrease moves
            --moves;

            if (moves == 0) {
                System.out.println("Game over, nobody has won.");
                System.out.println("Do you want to play again? 'Y' or 'N':");
                String newGame = scanner.nextLine();
                if (newGame.equals("Y") || newGame.equals("y")) {
                    break;
                }
                if (newGame.equals("N") || newGame.equals("n")) {
                    System.out.println("Thanks for the game!");
                    return;
                }
            }
            // 6. repeat
        } while (true);
    }
}

这是我的董事会成员的代码:

public class Board {

char[][] board = new char[6][7];

int column;

// Fills the empty spaces
public void fillBoard() {
    for (int i = 0; i < 6; i++) {
        for (int j = 0; j < 7; j++) {
            board[i][j] = ' ';
        }
    }
}

// Prints the board
public void presentBoard() {
    for (int i = 0; i < 6; i++) {
        System.out.print("            | ");
        for (int j = 0; j < 7; j++) {
            System.out.print(board[i][j] + " | ");
        }
        System.out.println();
        System.out.print("            -----------------------------");
        System.out.println();
    }
}

// Turn
public void makeTurn(char badge, char Player) {
    Scanner scanner = new Scanner(System.in);
    do {
        // 1. Ask for a column
        System.out.println("Player " + Player + " turn: ");
        column = scanner.nextInt();

        // 2. Check if it's between 0 and 6
        if (column > 6) {
            System.out.println("That is not a valid number. Please enter a number between 0 and 6: ");
            continue;
        }

        // 3. Place a badge
        for (int i = 6 - 1; i >= 0; i--) {
            if (board[i][column] == ' ') {
                board[i][column] = badge;
                return;
            }
        }

        // If column is full
        System.out.println("Column " + column + " is full. Try another column:");

    } while (true);
}

// Check for vertical win
public boolean checkWinVertical() {
            return verticalWin(5, column);
    }

// Check for horizontal win
public boolean checkWinHorizontal() {
    return horizontalWin(5,column);
}

// Conditions for vertical win
private boolean verticalWin(int x, int y) {
    char charToCheck = board[x][y];
    if (board[x-1][y] == charToCheck &&
        board[x-2][y] == charToCheck &&
        board[x-3][y] == charToCheck) {
        return true;
    }

    return false;
    }

// Conditions for horizontal win
private boolean horizontalWin(int x, int y) {
    char charToCheck = board[x][y];
    if (board[x][y+1] == charToCheck &&
            board[x][y+2] == charToCheck &&
            board[x][y+3] == charToCheck) {
        return true;
    }
    return false;
}

我已成功让游戏在阵列的底行水平和垂直识别胜利,但我不知道如何让游戏识别整个阵列。我只关注水平和垂直,因为对角线对我来说太复杂了。我不知道这是正确的做法还是有更好的做法。 谢谢!

3 个答案:

答案 0 :(得分:1)

这是另一个解决方案。它与前面提到的相同的一般概念:循环遍历每一行/列,检查连续4的条纹。也许这个实现将提供一些其他见解。下面,我展示了检查水平条纹的示例方法。对于垂直,您将迭代遍历内部for循环中的行。

public boolean checkWin(char badge) {
    return checkHorizontalStreaks(board, badge)
            || checkVerticalStreaks(board, badge);
}

private boolean checkHorizontalStreaks(char[][] board, char badge) {
    for (int row = 0; row < board.length; row++) {
        // loop throught each row
        int currentStreak = 0;
        for (int col = 0; col < board[row].length; col++) {
            // loop through each column in the row
            if (board[row][col] == badge) {
                // keep the streak of 'badge' going
                currentStreak++;
                if (currentStreak == 4) {
                    // winner
                    return true;
                }
            } else {
                // restart the streak
                currentStreak = 0;
            }
        }
    }
    return false;
}

然后使用

更新您的Main类
        if (board.checkWin(badge)) {
            System.out.println("Player " + Player + " has won!");
            break;
        }

我下注有一种更有效的方法来确定胜利者(可能将网格视为图形并用一些特殊逻辑遍历它)。但是,我怀疑这可能足以满足您的需求。我会为您提供输出,但它适用于几个不同的测试用例。

答案 1 :(得分:0)

可能你可以检查最后一个场地周围的所有相邻场地,所以在用户轮到他之后。因此,为了向上检查,您可以这样做:

    public boolean checkUp(int rowPlayed, int columnPlayed){
        boolean checked = false;
        if(rowplayed + 1 <= maxrows){ //Checks if you didn't hit the top
            if(board[rowPlayed+1][columnPlayed] != null){
                if(board[rowPlayed+1][columnPlayed].getPlayer() == currentPlayer){
                    checked =  true;
                }
            }
        }
        return checked;
    }

并且例如实现如下:

    public void checkWin(int rowPlayed, int columnPlayed){
        boolean checkingWin = true;
        int countWin = 0;
        while(checkingWin){
            if(checkUp(rowPlayed + countWin, columnPlayed)){
                countWin++;
            }
            else{
                checkingWin = false;
            }
            if(countWin == 4){
                checkinWin = false;
                //Insert win confirmation here
            }
        }
    }

它是部分伪代码,因为我不确切知道你如何处理代码中的内容,也不知道这是否是最好的方法。但我希望它对你有帮助。

答案 2 :(得分:0)

这是一个很长的答案,我会绕过房子,所以你可以看到我如何达到我的解决方案(最后也扩展到对角线检查)。

我会使用最后一块作为起点并从那里开始工作,因为检查所有组合是详尽无遗的。

鉴于添加的最后一部分的行和列,我需要决定我需要实现的目标。

我已经知道当前的行和列有我想要的那种颜色,所以我可以忽略它。

对于水平匹配,我想检查一下,我想检查同一行中左右两边的碎片是否有相同的颜色,如果颜色不同或没有碎片则停止。

想象一下下面的棋盘(#=空,R =红棋,Y =黄棋:

6 #  #  #  #  #  #  #  #
5 #  #  #  #  #  #  #  #
4 #  #  #  #  #  #  #  #
3 #  #  #  #  #  #  #  #
2 #  #  #  #  #  #  #  #
1 #  #  #  #  #  #  #  #
0 Y  R  R  R  Y  Y  Y  R
  0  1  2  3  4  5  6  7

最后一步是黄色,第0行,第4列。

所以我想从[0] [4]左右检查,看看颜色的连续部分的总数是3,(不是4),因为我知道[0] [4]是黄色的,可以打折。

基于此,我可以采用递归方法检查相邻的一侧,然后递归地执行相同的操作,只要我保持匹配相同颜色的部分或不遇到空槽。

我开始右边的检查(演示):

private static final int COLS = 7;
private static final int ROWS = 6;
public enum Piece {RED, YELLOW}; // null is empty

private Piece[][] board = new Piece[ROWS][COLS]; // the board

private int checkRight(Piece piece, int row, int col) {
    // assume valid row for now
    col++; // moving col to the right
    if (col >= COLS || board[row][col] != piece) {
       // We're outside the limits of the column or the Piece doesn't match
       return 0; // So return 0, nothing to add
    } else {
        // otherwise return 1 + the result of checkRight for the next col
        return 1 + checkRight(piece, row, col);
    }
}

现在我可以在左边执行相同的操作。

private int checkLeft(Piece piece, int row, int col) {
    // assume valid row for now
    col--; // moving col to the left
    if (col < 0 || board[row][col] != piece) {
       // We're outside the limits of the column or the Piece doesn't match
       return 0; // So return 0, nothing to add
    } else {
        // otherwise return 1 + the result of checkLeft for the next col
        return 1 + checkLeft(piece, row, col);
    }
}

要检查胜利者的水平,我可以这样做:

public boolean checkWinner(Piece piece, int row, int col) {
    // if the sum is 3, we have a winner (horizontal only).
    return checkRight(piece, row, col) + checkLeft(piece, row, col) == 3;
}

呃,那里有很多重复吗?

我们可以通过引入一个新的参数direction将两个方法压缩成一个,如果我们分别通过值1和-1移动col正面或负面,它们可以改变:

private int check(Piece piece, int row, int col, int direction) {
    col += direction; // direction is either 1 (right) or -1 (left)
    if (col < 0 || col >= COLS || board[row][col] != piece) {
        return 0;
    } else {
        return 1 + check(piece, row, col);
    }
}

为此新参数更新checkWinner()

private static final int POSITIVE = 1; // right at the moment
private static final int NEGATIVE = -1; // left at the moment

public boolean checkWinner(Piece piece, int row, int col) {
    // if the sum is 3, we have a winner (horizontal only).
    return check(piece, row, col, POSITIVE) + check(piece, row, col, NEGATIVE) == 3;
}

现在我可以为垂直实现相同类型的逻辑,但是保持相同的col并更改row。我将详细跳过这一部分,并转到包含此和对角线检查的解决方案。

这是使用enum名为CheckType的{​​{1}}存储值完成的,rowcol应更改并由check()方法使用。例如对于HORIZONTAL,列更改为1或-1(取决于调用check()时指定的方向),行仍为0。

public class Board {

    public enum Piece {

        RED, YELLOW
    };

    private enum CheckType {

        HORIZONTAL(0, 1), VERTICAL(1, 0), DIAGNONAL_UP(1, 1), DIAGNONAL_DOWN(-1, 1);

        int row;
        int col;

        CheckType(int row, int col) {
            this.row = row;
            this.col = col;
        }
    }

    private static final int POSITIVE = 1;
    private static final int NEGATIVE = -1;

    private static final int ROWS = 6;
    private static final int COLS = 7;

    private Piece[][] board = new Piece[ROWS][COLS];
    private boolean hasWinner = false;

    public boolean hasWinner() {
        return hasWinner;
    }

    private void checkWinner(Piece piece, int row, int col) {
            // check all values of enum CheckType for a winner
        // so HORIZONTAL, VERTICAL, etc..
        int enumIndex = 0;
        while (!hasWinner && enumIndex < CheckType.values().length) {
            hasWinner = check(piece, row, col, POSITIVE, CheckType.values()[enumIndex])
                    + check(piece, row, col, NEGATIVE, CheckType.values()[enumIndex]) == 3;
            enumIndex++;
        }
    }

    private int check(Piece piece, int row, int col, int direction, CheckType type) {
        row += type.row * direction;
        col += type.col * direction;
        if (row >= ROWS || row < 0 || col >= COLS || col < 0 || board[row][col] != piece) {
            return 0;
        } else {
            return 1 + check(piece, row, col, direction, type);
        }
    }

    // for completeness, adding a Piece    
    public boolean add(Piece piece, int col) {
        int row = 0;
        while (row < ROWS && board[row][col] != null) {
            row++;
        }
        if (row < ROWS) {
            board[row][col] = piece;
            // check for winner after successful add
            checkWinner(piece, row, col);
        }
        return row < ROWS;
    }

}

希望这有帮助。