Cómo escribir un programa Tic-Tac-Toe en Java

Introducción:

Tic-Tac-Toe es un juego muy común que es bastante fácil de jugar. Las reglas del juego son simples y bien conocidas. Debido a estas cosas, Tic-Tac-Toe es bastante fácil de codificar. En este tutorial, veremos cómo codificar un juego de trabajo de Tic-Tac-Toe en Java. Este tutorial asume que tiene conocimiento de la sintaxis básica de Java y acceso a un compilador de Java en funcionamiento. Este tutorial utilizará el IDE de Eclipse.

Bosquejo general:

Hay muchas formas de implementar un juego de Tic-Tac-Toe en Java, por lo que antes de comenzar a codificar, debemos pensar en cómo implementaremos el juego específicamente. Para este tutorial, codificaremos una versión basada en texto de Tic-Tac-Toe. Nuestro Tic-Tac-Toe comenzará imprimiendo el tablero y luego solicitando la entrada del primer jugador que especificará en qué lugar del tablero colocará la marca de ese jugador. Después de colocar la marca, imprimiremos el estado del tablero nuevamente y luego le pediremos al otro jugador su movimiento. Ese proceso continuará hasta que un jugador gane o el tablero se llene (lo que indica que se produjo un empate). La entrada que se tomará para especificar dónde colocar una marca tendrá el formato de dos enteros, que especifican la fila y la columna donde se colocará la marca. A continuación se muestra una muestra de cómo se jugará un juego.

Paso 1: Creando tu proyecto

¡El primer paso para codificar cualquier cosa es hacer un nuevo proyecto! En su IDE, cree un nuevo proyecto Java llamado TicTacToe. En este Instructable, el paquete predeterminado es el que se utilizará. Dentro de su paquete de proyecto, cree dos clases: Main.java y TTT.java. Main.java alojará el método principal y se usará para ejecutar el código en TTT.java. TTT.java contendrá un objeto Tic-Tac-Toe que contiene el estado del tablero y los métodos para manipular el juego.

Paso 2: iniciar la clase TTT

Antes de que podamos crear código para ejecutar nuestro objeto TTT, necesitamos crear un objeto TTT que funcione. Dado que un objeto TTT es representativo de un juego de Tic-Tac-Toe, debe contener dos variables miembro. A continuación se muestran las variables miembro que se deben colocar en la clase TTT, seguidas de descripciones de por qué son necesarias.

tablero privado [] [];

Esta variable es una matriz 2D de personajes que serán representativos del tablero de tres por tres de un juego de Tic-Tac-Toe. Mantendrá el estado del juego dentro del objeto TTT en cualquier momento dado.

char privado currentPlayerMark;

Esta variable mantendrá una 'x' o una 'o', que representa el turno de cada jugador en un momento dado. Los métodos de la clase TTT usarán esto al marcar el tablero para determinar qué tipo de marca se colocará.

Paso 3: Inicializar prototipos de métodos en la clase TTT

La siguiente es una configuración general del programa. A continuación se muestran todos los encabezados de métodos para los métodos que pertenecen a la clase TTT. Estos métodos actuarán sobre las variables miembro de la clase TTT para hacer que el juego de Tic-Tac-Toe sea mutable. Cada uno tiene una breve descripción de lo que hará el método. Estos comportamientos son necesarios para jugar un juego completo de Tic-Tac-Toe.

TTT público ()

Este es el constructor. Será responsable de garantizar que el tablero se inicialice correctamente y de establecer quién será el primer jugador.

public void initializeBoard ()

Este método inicializará la variable del tablero de modo que todas las ranuras estén vacías.

printBoard vacío público ()

Este método imprimirá la placa Tic-Tac-Toe a la salida estándar.

public boolean isBoardFull ()

Este método verificará si el tablero está lleno o no. Volverá verdadero si el tablero está lleno y un falso de lo contrario.

public boolean checkForWin ()

Este método verificará si un jugador ha ganado, y si es así, volverá verdadero.

checkRowsForWin privado (boolean)

Este método verificará específicamente las filas para una victoria.

privado booleano checkColumnsForWin ()

Este método verificará específicamente las columnas para una victoria.

cheque privado booleanoDiagonalsForWin ()

Este método verificará específicamente las diagonales para una victoria.

checkRowCol booleano privado (char c1, char c2, char c3)

Este método verificará los tres caracteres especificados tomados para ver si los tres son la misma letra 'x' u 'o'. Si es así, volverá verdadero.

Nota : Si codifica stubs de método para todos los encabezados de método en su clase TTT, es probable que su compilador le informe que su código tiene errores. Esto es normal. El compilador simplemente espera que se devuelva un valor para todos los métodos no nulos.

Paso 4: Inicialice el tablero

public void initializeBoard ()

Esto establecerá el tablero en todos los valores vacíos. Dentro de este método, debe crear 2 para bucles uno dentro del otro que recorrerán todas las filas y columnas configurando cada espacio en '-'. Para recorrer las filas, cree un bucle for y un número entero, en este caso llamado i, para representar qué fila estamos observando actualmente.

para (int i = 0; i <3; i ++) {}

Dentro de este bucle for, crearemos un segundo bucle for con un número entero j para representar qué columna estamos observando actualmente.

para (int j = 0; j <3; j ++) {}

Dentro del segundo bucle for, configuramos la ubicación del tablero en '-'. Con ambos bucles completados y anidados correctamente, podemos iterar a través de cada lugar dentro de la matriz 2D del tablero.

tablero [i] [j] = '-';

Adjunto a este paso hay una imagen que muestra una posible implementación del método initializeBoard ().

Paso 5: imprimir la pizarra

El tablero impreso inicial se verá como la primera imagen.

Se manejará en el método public void printBoard (), que se encuentra en la clase TTT. Para imprimir el tablero, debemos acceder a todos los lugares en el tablero llamado matriz 2D en nuestra clase TTT. Debido a que estamos tratando con una matriz 2D, esto se manejará con bucles anidados.

Primero, solo necesitamos imprimir una línea de guiones (13 de ellos en este caso) designando la parte superior del tablero. Debajo de eso, necesitamos un bucle for que recorra cada una de las tres filas. Este bucle contendrá una llamada para imprimir un '|', otro bucle for para recorrer las columnas y una llamada a la función System.out.println () para imprimir una nueva línea y los siguientes 13 guiones en la pantalla.

Nuestro bucle for interno también solo recorrerá tres columnas. Dado que nuestro bucle for externo ya imprimió el primer | carácter de cada fila del tablero, podemos seguir imprimiendo el carácter que pertenece en el cuadro. Para hacer esto, imprimiremos el carácter en esa fila y columna usando el tablero [i] [j] (siendo la variable usada para el bucle externo, que era la fila, y j siendo la variable usada para el bucle interno, que es la columna.) Esta declaración de impresión también contendrá una concatenada | personaje, para separar las cajas.

Lo único que queda es imprimir la última llamada para imprimir la nueva línea para separar cada fila, seguido de los 13 guiones. La segunda imagen adjunta muestra un ejemplo de cómo se vería la función de impresión descrita.

Paso 6: Verificación de un ganador (Parte 1)

Hay tres funciones diferentes para verificar una ganancia: filas, columnas y diagonales. Las computadoras tienen que separarlos en diferentes condiciones porque todos son diferentes en términos de matrices. checkForWin () será nuestra función principal para probar las 3 funciones para cada escenario que la entrada del usuario haya afectado.

Para el método checkForWin (): simplemente necesita una declaración return que invoque las tres funciones diferentes. Si la comprobación de las filas para win no devuelve verdadero, compruebe las columnas para win, etc. Dentro de la declaración de retorno debería verse así: checkRowsForWin () || checkColumnsForWin () || checkDiagonalsForWin ()

Para el método checkRowsForWin (): estamos recorriendo las filas para ver si hay algún ganador. Esto requerirá un bucle for con una declaración if dentro de él. El bucle for se incrementará a través del número entero i para verificar cada fila. for (int i = 0; i <3; i ++) La instrucción if compara cada espacio de la fila entre sí y proporciona un valor 'verdadero' si todos son iguales. Por ejemplo, si la fila tenía tres x en una fila, el método devolvería verdadero. if (checkRowCol (tablero [i] [0], tablero [i] [1], tablero [i] [2]) == verdadero) Entonces, dentro de esta declaración if, debería haber un: return true; Y después del ciclo for, si el método nunca se detuvo, entonces el método debe devolver que esta fila no tenía tres símbolos coincidentes consecutivos. Por lo tanto, justo antes de cerrar el método con su '}' final, escribiremos: return false; Satisfaciendo la necesidad de devolver un booleano.

Para el método checkColumnsForWin (): copie y pegue el contenido del método checkRowsForWin (). El único cambio estará dentro de la declaración if. En lugar de incrementar a través de las filas, incrementaremos a través de las columnas. Entonces, mientras está en checkRowsForWin tiene una instrucción if que dice: if (checkRowCol (board [i] [0], board [i] [1], board [i] [2]) == true) checkColumnsForWin () tendrá un if declaración que dice: if (checkRowCol (board [0] [i], board [1] [i], board [2] [i]) == true) Aparte de eso, todo lo demás en el método permanece igual.

Para el método checkDiagonalsForWin (): todo lo escrito puede estar contenido entre paréntesis de una declaración return (). La primera comprobación que realizaremos estará en la diagonal desde la esquina superior izquierda hasta la esquina inferior derecha. Para hacer esto, verificamos todos los espacios que se incluirían en esta sección. checkRowCol (tablero [0] [0], tablero [1] [1], tablero [2] [2]) == verdadero) Entonces tendremos una declaración más, pero las separaremos con un símbolo OR: ' || ' La segunda declaración verificará desde la esquina superior derecha hasta la esquina inferior izquierda. checkRowCol (tablero [0] [2], tablero [1] [1], tablero [2] [0]) == verdadero) Por lo tanto, su producto final del método checkDiagonalsForWin () debe ser un return (), y dentro de él debe contener la primera declaración O la segunda declaración.

Paso 7: busque un ganador (Parte 2)

Ahora tenemos que asegurarnos de que si un jugador obtiene tres seguidos, él o ella gana. checkRowCol () será una función que comparará las tres letras entre sí y, si coinciden, devolverá verdadero.

Para el método checkRowCol (): Este método es utilizado por los otros métodos para enviar tres valores. Primero verificamos que el primer valor no esté vacío, como '-'. Luego comparamos el primer valor con el segundo, y el segundo con el tercero, y si y solo si los tres valores son iguales Y no son declaraciones vacías, entonces este método devolverá verdadero. Entonces, dentro de una declaración return (), nuestra primera declaración verificará que esto no sea un '-'. (c1! = '-') Separe la primera y la segunda instrucción con un '&&'. La segunda instrucción verá si el primer valor es igual al segundo valor. (c1 == c2) Separe las declaraciones segunda y tercera con un '&&' La tercera declaración verá si el segundo valor es igual al tercero. (c2 == c3) Por lo tanto, su método checkRowCol () final será una devolución () que contiene la primera declaración && la segunda declaración && la tercera declaración.

Paso 8: Cambio entre jugadores (x y O)

public void changePlayer ()

El método changePlayer () cambiará la variable currentPlayerMark entre x y o. Para hacer esto, simplemente verifique qué contiene actualmente la variable. Si la variable contiene una 'x', cámbiela a una 'o'. De lo contrario, cámbielo a una 'x'.

public boolean placeMark (int fila, int col)

El método placeMark () colocará la letra correcta en la fila especificada y col en la variable del tablero (tomada como parámetros). Volverá verdadero si fue una colocación válida. De lo contrario, no se realizará ninguna modificación en la variable del tablero, y el jugador tendrá que intentar colocar su letra en un lugar diferente, ya que se seleccionó un lugar no válido o se seleccionó un lugar donde un jugador ya colocó su letra. Para lograr este comportamiento, se deben verificar algunas cosas. Primero, asegúrese (usando una declaración if) de que el argumento de fila estaba entre 0 y 2. Luego, verifique para asegurarse de que el argumento col estaba entre 0 y 2. Finalmente, verifique para asegurarse de que el punto en cuestión contenga actualmente un '- ', lo que significa que ningún pagador ha marcado ese lugar todavía. Si se cumplen las tres condiciones, coloque una marca (cuyo tipo se especifica mediante la variable de clase currentPlayerMark) en la ubicación especificada por row y col y luego devuelve true. Si alguna de las tres condiciones no se cumple, entonces se debe tener en cuenta y se debe devolver falso.

Adjunto a este paso hay imágenes que muestran posibles implementaciones de los métodos mencionados anteriormente.

Paso 9: entrada del jugador y jugar el juego

Ahora que la clase TTT y todos sus métodos están completos, se debe crear un método principal que se ejecute a través de un juego completo de Tic-Tac-Toe usando el objeto TTT. El método principal debe hacer bastantes cosas para ejecutar un juego completo de Tic-Tac-Toe.

Primero, debe crear un objeto Scanner para recibir información de System.in. Además, debe crear una instancia de un objeto TTT para jugar el juego Tic-Tac-Toe. Después de estas cosas, debe inicializar la placa del objeto TTT llamando a su método initializeBoard ().

Después de completar estos pasos, se debe tener en cuenta el juego real. Para pasar por turnos, se requiere un bucle do while. El ciclo debería estallar cuando el juego termine, es decir, cuando el tablero del objeto TTT esté lleno o tenga un ganador. Dentro del bucle, el estado actual del tablero debe imprimirse antes de cada turno, así que muéstrele al jugador qué espacios están disponibles y qué espacios están ocupados. Luego, se deben tomar dos entradas para indicar la fila y la columna para colocar una marca para el giro. Después de ingresar esta entrada, la marca debe colocarse utilizando el método del objeto TTT, y el jugador también debe cambiarse utilizando el método del objeto TTT.

Debajo del ciclo while que maneja todos los turnos hasta el final del juego, será necesario declarar quién es el ganador del juego (o si el juego fue un empate). Para hacer esto, verifique si el juego fue un empate primero verificando si tanto el tablero estaba lleno como si no había ganador. Si este es el caso, imprime que el juego fue un empate. De lo contrario, imprima quién ganó imprimiendo el opuesto del estado actual de la variable currentPlayerMark del objeto TTT. Esto se puede lograr primero llamando al método changePlayer () del objeto TTT y luego usando el método getCurrentPlayerMark () del objeto TTT para obtener el estado de la variable currentPlayerMark. También puede ser bueno imprimir el tablero una vez más para mostrar el estado final del tablero.

Se ha adjuntado un ejemplo de método principal como imagen.

Paso 10: use Class, Compile y Run

Una vez que haya llegado a este punto, su proyecto debería estar lo suficientemente completo como para ejecutarse. Si hay errores o faltan paréntesis o punto y coma, ahora sería el momento de encontrarlos y corregirlos. Si está perdido en cuanto a cómo debería verse su proyecto, hemos incluido un archivo descargable para que pueda comparar su código con un producto final que funcione. Anímate y compila tu proyecto. En Eclipse hay un botón de reproducción que se parece a la imagen adjunta a este paso.

Archivos adjuntos

  • Working Final Product.zip Descargar

Artículos Relacionados