(Java) Jeu Tic-Tac-Toe utilisant un tableau à 2 dimensions


En classe, notre mission est de créer un tableau bidimensionnel et de créer un jeu de tic-tac-toe autour de lui. J'ai tout fait sauf l'affichage lorsque tout le plateau est plein et que le jeu est un match nul. J'ai essayé quelques petites choses mais je n'ai pas trouvé la solution et j'ai besoin d'aide... Voici mon code:

import java.util.Scanner;

public class TicTacToe {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int row, column;
        char player = 'X';

        //create 2 dimensional array for tic tac toe board
        char[][] board = new char[3][3];
        char ch = '1';
        for (int i = 0; i < 3; i++){
            for (int j = 0; j < 3; j++) {
                board[i][j] = ch++;
            }
        }
        displayBoard(board);
        while(!winner(board) == true){

            //get input for row/column
            System.out.println("Enter a row and column (0, 1, or 2); for player " + player + ":");
            row = in.nextInt();
            column = in.nextInt();

            //occupied
            while (board[row][column] == 'X' || board[row][column] == 'O') {
                System.out.println("This spot is occupied. Please try again");
            }
            //place the X
            board[row][column] = player;
            displayBoard(board);

            if (winner(board)){
                System.out.println("Player " + player + " is the winner!");
            }

            //time to swap players after each go.
            if (player == 'O') {
                player = 'X';

            }
            else {
                player = 'O';
            }
            if (winner(board) == false) {
            System.out.println("The game is a draw. Please try again.");

        }

    }

    private static void displayBoard(char[][] board) {
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                if (j == board[i].length - 1) System.out.print(board[i][j]);
                else System.out.print( board[i][j] + " | ");
            }
            System.out.println();
        }


    }
    //method to determine whether there is an x or an o in the spot
    public static Boolean winner(char[][] board){
        for (int i = 0; i< board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == 'O' || board[i][j] == 'X') {
                    return false;
                }
            }
        }

        return (board[0][0] == board [0][1] && board[0][0] == board [0][2]) ||
            (board[0][0] == board [1][1] && board[0][0] == board [2][2]) ||
            (board[0][0] == board [1][0] && board[0][0] == board [2][0]) ||
            (board[2][0] == board [2][1] && board[2][0] == board [2][2]) ||
            (board[2][0] == board [1][1] && board[0][0] == board [0][2]) ||
            (board[0][2] == board [1][2] && board[0][2] == board [2][2]) ||
            (board[0][1] == board [1][1] && board[0][1] == board [2][1]) ||
            (board[1][0] == board [1][1] && board[1][0] == board [1][2]);
    }
}

Je veux une sortie disant que le tableau est plein quand il est plein mais je ne reçois rien. C'est la dernière ligne de ma sortie et comme vous pouvez le voir, ma stratégie actuelle ne fonctionne pas comme il continue de demander des commentaires. -->

Entrez une ligne et une colonne (0, 1 ou 2); pour le lecteur X: 2 0 X / O / X O / O / X X / X / O Entrez une ligne et une colonne (0, 1 ou 2); pour le joueur O:

Author: Dracose, 2016-10-09

5 answers

Tout d'Abord:

 while (board[row][column] == 'X' || board[row][column] == 'O') {
            System.out.println("This spot is occupied. Please try again");
        }

Cela créera une boucle infinie car row et column ne devraient pas changer vous devriez demander une nouvelle entrée!

Aussi

public static Boolean winner(char[][] board){
    for (int i = 0; i< board.length; i++) {
        for (int j = 0; j < board[0].length; j++) {
            if (board[i][j] == 'O' || board[i][j] == 'X') {
                return false;
            }
        }
    }

Dès que vous appuyez sur ' O ' ou 'X', vous quitterez la méthode avec un false (pas de gagnant)

Ce que vous voulez probablement vérifier, c'est si chaque place est occupée

public static Boolean winner(char[][] board){
   //Boolean which is true until there is a empty spot
   boolean occupied = true;
   //loop and check if there is empty space or if its a draw
    for (int i = 0; i< board.length; i++) {
        for (int j = 0; j < board[0].length; j++) {
            //Check if spot is not 'O' or not 'X' => empty 
            if (board[i][j] != 'O' || board[i][j] != 'X') {
                occupied = false;
            }
        }
    }
    if(occupied)
        return false;
   //Check if someone won
    return (board[0][0] == board [0][1] && board[0][0] == board [0][2]) ||
        (board[0][0] == board [1][1] && board[0][0] == board [2][2]) ||
        (board[0][0] == board [1][0] && board[0][0] == board [2][0]) ||
        (board[2][0] == board [2][1] && board[2][0] == board [2][2]) ||
        (board[2][0] == board [1][1] && board[0][0] == board [0][2]) ||
        (board[0][2] == board [1][2] && board[0][2] == board [2][2]) ||
        (board[0][1] == board [1][1] && board[0][1] == board [2][1]) ||
        (board[1][0] == board [1][1] && board[1][0] == board [1][2]);
}

Cela vérifierait maintenant s'il y a un gagnant ou si c'est une égalité

Occupied == true == tie == return false

Winner == return true

, Mais vous avez trois états:

  • Gagner
  • Cravate
  • Non fini

Avec la méthode modifiée, vous ne finirez PAS le jeu tant que vous n'aurez pas gagné.

Raison:

 while(!winner(board) == true)

Cela fait fonctionner le jeu tant qu'il n'y a PAS de gagnant (gagnant) sera faux car tout est occupé, ou il n'y a pas de gagnant)

while(!false==true) => while(true) 

Vous pouvez écrire une méthode similaire à winner mais elle ne vérifie que si le tableau a des taches vides:

public static Boolean hasEmptySpot(char[][] board){
   //loop and check if there is empty space 
    for (int i = 0; i< board.length; i++) {
        for (int j = 0; j < board[0].length; j++) {
            if (board[i][j] != 'O' && board[i][j] != 'X') {
                return true;
            }
        }
    }
    return false;
}

//New code 
while(hasEmptySpot(board) || !winner(board)){
          //Your code for the game here
     ....
    }

Cela mettrait fin au jeu quand il n'y a plus de place vide Après vous avez terminé le jeu, vous pouvez appeler gagnant (conseil) et il reviendra si vous êtes à égalité ou gagné!

En créant hasEmptySpot(), vous pouvez changer votre méthode winner en

public static Boolean winner(char[][] board){
    return (board[0][0] == board [0][1] && board[0][0] == board [0][2]) ||
        (board[0][0] == board [1][1] && board[0][0] == board [2][2]) ||
        (board[0][0] == board [1][0] && board[0][0] == board [2][0]) ||
        (board[2][0] == board [2][1] && board[2][0] == board [2][2]) ||
        (board[2][0] == board [1][1] && board[0][0] == board [0][2]) ||
        (board[0][2] == board [1][2] && board[0][2] == board [2][2]) ||
        (board[0][1] == board [1][1] && board[0][1] == board [2][1]) ||
        (board[1][0] == board [1][1] && board[1][0] == board [1][2]);
}

Pourquoi? Parce que vous avez terminé le jeu et vous savez qu'il n'y a que deux résultats possibles Victoire ou Égalité.

J'espère que cela vous a un peu aidé.

MODIFIER Avait une erreur de logique moi-même!

Première erreur: vous devez toujours vérifier s'il y a un gagnant pendant que le jeu est en cours d'exécution oublié ce point!

while(hasEmptySpot(board) || !winner(board)){
}

Maintenant, cela quittera la boucle de jeu quand il y a un gagnant ou qu'il ne reste plus de places vides

Deuxième erreur: Dans hasEmptySpot ()

 if (board[i][j] != 'O' && board[i][j] != 'X') {
                return true;

Pas

 if (board[i][j] != 'O' || board[i][j] != 'X') {
                return true;

Fixe dans les exemples supérieurs.

Je suis désolé pour le désagrément!

 2
Author: Nordiii, 2016-10-09 21:06:03

Le moyen le plus efficace de le faire est de garder un nombre en cours d'exécution du nombre d'espaces qui ont été remplis précédemment et d'incrémenter ce nombre à chaque fois qu'un espace est occupé. Le tableau peut être considéré comme complet lorsque ce nombre atteint 9.

Si vous êtes familier avec la programmation orientée objet, je pense que vous trouverez cela plus facile à implémenter si vous enveloppez votre tableau 2D dans une classe Board.

Exemple:

public static class Board {
    private char[][] spaces = new char[3][3];
    private int numMoves = 0;

    public void makeMove(int row, int col, char player) {
        if (spaces[row][col] == 'X' || spaces[row][col] == 'O') {
            System.out.println("This spot is occupied. Please try again");
        } else {
            spaces[row][col] = player;
            numMoves++;
        }
    }

    public boolean isFull() {
        return numMoves == 9;
    }

    public boolean hasWinner() {
        ...
    }

    public void display() {
        ...
    }
}
 1
Author: Pablo Napolitano, 2016-10-09 17:41:27

Vous pouvez essayer d'incorporer une nouvelle méthode telle que la suivante:

public Boolean boardFull()
{
    short count = 0;
    for(short i = 0; i < 3; i++){
        for(short j = 0; j < 3; j++){
            if(board[i][j] == ‘O’ || board[i][j] == ’X’){
                count++;
            } else {
                continue;
            }
        }
    }

    if(count == 9){
        return true;
    } else {
        return false;
    }
}

Vous pouvez utiliser une instruction if pour voir si elle renvoie true, puis imprimer quelque chose si elle ne.

 0
Author: ccless1, 2016-10-09 17:31:01

Solution

Le code qui ne fonctionne pas est votre winner() méthode. Il renvoie toujours false s'il y a au moins une cellule occupée. Vous pouvez procéder en fonction de la dernière partie de Réponse de Nordiii.

Problèmes Supplémentaires

Boucle de vérification de cellules

Votre code pour vérifier si une cellule est occupée va à l'infini. Vous devez utiliser un if au lieu d'un "tout" en boucle:

if(board[row][column] == 'X' || board[row][column] == 'O'){
    System.out.println("This spot is occupied. Please try again");
    continue;
}

Votre ancien code est resté bloqué en vérifiant toujours si 1 cellule était occupée et il retournait toujours true, ce qui maintenait la boucle en vie et inondait votre console. L'instruction continue quittera l'itération actuelle de votre autre boucle "while" et démarrera une nouvelle itération, demandant ainsi une nouvelle entrée.

Exceptions

Mec, c'est beaucoup d'exceptions non attrapées! Si je gâche mon entrée, pow! Le tout échoue. Il suffit de mettre un bloc try pour votre code de vérification d'entrée:

try {
    row = in.nextInt();
    column = in.nextInt();

    // Attempt to place player (an ArrayOutOfBoundsException could be thrown)
    if(board[row][column] == 'X' || board[row][column] == 'O'){
        System.out.println("This spot is occupied. Please try again");
        continue;
    }

    board[row][column] = player;
} catch(Exception e){
    System.out.println("I'm sorry, I didn't get that.");
    continue;
}

Cela tente d'exécuter le code dans l'instruction try, et si quelqu'un entre quelque chose d'incorrect, l'exception est "attrapée" et une nouvelle itération est créée. Génie!

 0
Author: XavCo7, 2017-05-23 12:02:14

Bien qu'il y ait déjà d'excellentes réponses, j'aimerais publier une autre solution plus générique dans sa logique pour déterminer le gagnant. Actuellement, vous avez codé en dur certains des scénarios gagnants possibles lorsque vous pourriez écrire une logique plus générique pour cela.

Comme d'autres réponses ont souligné vous voulez une méthode pour vérifier inoccupé dans le conseil et cela vous dira si il y a égalité. J'ai implémenté une telle méthode dans le code ci-dessous avec le plus générique vainqueur de la logique.

Notez que certaines méthodes sont publiques pour faciliter les tests, elles ne doivent pas nécessairement rester publiques.

import java.util.Scanner;

public class TicTacToe {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int row, column;
        char player = 'X';

        //create 2 dimensional array for tic tac toe board
        char[][] board = new char[3][3];
        char ch = '1';
        for (int i = 0; i < 3; i++){
            for (int j = 0; j < 3; j++) {
                board[i][j] = ch++;
            }
        }
        displayBoard(board);
        while(!winner(board) == true){

            //get input for row/column
            System.out.println("Enter a row and column (0, 1, or 2); for player " + player + ":");
            row = in.nextInt();
            column = in.nextInt();

            //occupied
            while (board[row][column] == 'X' || board[row][column] == 'O') {
                System.out.println("This spot is occupied. Please try again");
            }
            //place the X
            board[row][column] = player;
            displayBoard(board);

            if (winner(board)){
                System.out.println("Player " + player + " is the winner!");
            }

            //time to swap players after each go.
            if (player == 'O') {
                player = 'X';

            }
            else {
                player = 'O';
            }
            if (winner(board) == false && !hasFreeSpace(board)) {
                System.out.println("The game is a draw. Please try again.");
            }
        }

        //Don't forget to close the scanner.
        in.close();

    }

    public static void displayBoard(char[][] board) {
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                if (j == board[i].length - 1) System.out.print(board[i][j]);
                else System.out.print( board[i][j] + " | ");
            }
            System.out.println();
        }
    }

    /**
     * Determines whether the board is completely occupied by X and O characters
     * @param board the board to search through
     * @return true if entire board is populated by X or O, false otherwise.
     */
    public static boolean hasFreeSpace(char[][] board){
        for (int i = 0; i< board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] != 'O' && board[i][j] != 'X') {
                    return true;
                }
            }
        }
        return false;
    }

    //method to determine whether there is a winner
    public static boolean winner(char[][] board){
        return isHorizontalWin(board) || isVerticalWin(board) || isDiagonalWin(board);
    }

    /**
     * Determines if there is a winner by checking each row for consecutive
     * matching tokens.
     * @return true if there is a winner horizontally, false otherwise.
     */
    private static boolean isHorizontalWin(char[][] board) {
        for(int row = 0; row < board.length; row++){
            if(isWin(board[row]))
                return true;
        }
        return false;
    }

    /**
     * Determines whether all of the buttons in the specified array have the 
     * same text and that the text is not empty string.
     * @param lineToProcess an array of buttons representing a line in the grid
     * @return true if all buttons in the array have the same non-empty text, false otherwise.
     */
    private static boolean isWin(char[] lineToProcess) {
        boolean foundWin = true;
        char prevChar = '-';
        for(char character: lineToProcess) {
            if(prevChar == '-')
                prevChar = character;
            if ('O' != character && 'X' != character) {
                foundWin = false;
                break;
            } else if (prevChar != character) {
                foundWin = false;
                break;
            }
        }
        return foundWin;
    }

    /**
     * Determines whether there is a winner by checking column for consecutive
     * matching tokens.
     * @return true if there is a vertical winner, false otherwise.
     */
    private static boolean isVerticalWin(char[][] board) {
        char[] column = null;
      //assuming all rows have same legnth (same number of cols in each row), use first row
        for(int col = 0; col < board[0].length; col++){
            column = new char[board[0].length]; 
            for(int row = 0; row < column.length; row++){
                column[row] = board[row][col];
            }
            if(isWin(column))
                return true;
        }
        return false;
    }

    /**
     * Determines if there is a winner by checking each diagonal for consecutive
     * matching tokens.
     * @return true if a diagonal winner exists, false otherwise.
     */
    private static boolean isDiagonalWin(char[][] board) {

        int row = 0, col = 0;
        int cols = board.length;
        int rows = board[0].length; //assuming all rows are equal length so just use the first one

        //Create a one-dimensional array to represent the diagonal. Use the lesser
        // of the rows or columns to set its size. If the grid is rectangular then
        // a diagonal will always be the size of the lesser of its two dimensions.
        int size = rows < cols ? rows : cols;
        char[] diagonal = new char[size];

        //Since we know the grid is a square we really could just check one of
        // these - either row or col, but I left both in here anyway.
        while (row < rows && col < cols) {
            diagonal[col] = board[row][col];

            row++;
            col++;
        }
        if (isWin(diagonal)) {
            return true;
        }


        row = rows - 1;
        col = 0;
        diagonal = new char[size];
        while (row >=0 && col < cols) {
            diagonal[col] = board[row][col];
            row--;
            col++;
        }
        return isWin(diagonal);

    }
}
 0
Author: D.B., 2016-10-09 17:53:35