Hola a todos, hoy os voy a explicar como podemos crear el juego del 3 en raya en Java.
El juego del 3 en raya o Tic Tac Toe es un juego mas que conocidos por todos, pues vamos a ver como podemos hacerlo en Java con programación orientada a objetos.
Tendremos como atributos una matriz de char donde contendrán X, O o – (vacio), otro atributo para saber cual es el turno actual y contantes para de los valores posibles.
public class TicTacToe { //Reprentaciones de los jugadores y del simbolo vacio private final char J1 = 'X'; private final char J2 = 'O'; private final char VACIO = '-'; //turno actual //true = J1, false = J2 private boolean turno; //tablero donde vamos a jugar private char tablero[][]; }
Tenemos que inicializar el tablero de primeras, poniendo todo a vacio:
/** * Inicializa el tablero con el simbolo VACIO */ private void inicializarTablero() { for (int i = 0; i < tablero.length; i++) { for (int j = 0; j < tablero.length; j++) { tablero[i][j] = VACIO; } } }
El constructor seria así:
public TicTacToe() { this.turno = true; this.tablero = new char[3][3]; this.inicializarTablero(); }
Necesitamos mostrar el tablero en algún momento:
/** * Muestra la matriz * */ public void mostrarTablero() { for (int i = 0; i < this.tablero.length; i++) { for (int j = 0; j < this.tablero[0].length; j++) { System.out.print(this.tablero[i][j] + " "); } System.out.println(""); } }
Para el tema del turno, debemos saber cual es el actual y como cambiarlo:
/** * Mostramos el turno actual */ public void mostrarTurnoActual() { if (turno) { System.out.println("Le toca al jugador 1"); } else { System.out.println("Le toca al jugador 2"); } } /** * Cambia el turno */ public void cambiaTurno() { this.turno = !this.turno; }
Para insertar un elemento en la matriz, usaremos este método:
/** * Insertamos en una posicion de una matriz un simbolo en concreto * * @param fila * @param columna */ public void insertarEn(int fila, int columna) { if (turno) { this.tablero[fila][columna] = J1; } else { this.tablero[fila][columna] = J2; } }
Para usar el método anterior, recomiendo antes validar la posición que se va a insertar:
/** * Validamos la posicion que nos insertan * * @param fila * @param columna * @return */ public boolean validarPosicion(int fila, int columna) { if (fila >= 0 && fila < tablero.length && columna >= 0 && columna < tablero.length) { return true; } return false; } /** * Indicamos si en una posicion hay una marca * * @param fila * @param columna * @return */ public boolean hayValorPosicion(int fila, int columna) { if (this.tablero[fila][columna] != VACIO) { return true; } return false; }
Hacemos otro método para saber si el tablero esta lleno o no:
/** * Indica si el tablero esta llena cuando el simbolo por defecto aparezca, * no esta llena * * @return talero vacio o no */ public boolean tableroLleno() { for (int i = 0; i < tablero.length; i++) { for (int j = 0; j < tablero[0].length; j++) { if (tablero[i][j] == VACIO) { return false; } } } return true; }
Para saber si alguno de los jugadores han ganado, debemos comprobar tanto lineas, columnas y diagonales, entonces, lo hacemos cada uno en diferentes métodos.
La idea en general, es coger el primer elemento y ver si el resto de la linea, columna o diagonal coincide con ese elemento. En el caso de que no, devolvemos el elemento vacio (-).
Para comprobar las lineas:
/** * Indica si hay un ganador en una linea * * @return Simbolo del ganador, VACIO sino hay ganador */ private char coincidenciaLinea() { char simbolo; boolean coincidencia; for (int i = 0; i < tablero.length; i++) { //Reiniciamos la coincidencia coincidencia = true; //Cogemos el simbolo de la fila simbolo = tablero[i][0]; if (simbolo != VACIO) { for (int j = 1; j < tablero[0].length; j++) { //sino coincide ya no habra ganadro en esta fila if (simbolo != tablero[i][j]) { coincidencia = false; } } //Si no se mete en el if, devuelvo el simbolo ganador if (coincidencia) { return simbolo; } } } //Si no hay ganador, devuelvo el simbolo por defecto return VACIO; }
Para comprobar las columnas:
/** * Indica si hay un ganador en una columna * * @return Simbolo del ganador, VACIO sino hay ganador */ private char coincidenciaColumna() { char simbolo; boolean coincidencia; for (int j = 0; j < tablero.length; j++) { //Reiniciamos la coincidencia coincidencia = true; //Cogemos el simbolo de la columna simbolo = tablero[0][j]; if (simbolo != VACIO) { for (int i = 1; i < tablero[0].length; i++) { //sino coincide ya no habra ganadro en esta fila if (simbolo != tablero[i][j]) { coincidencia = false; } } //Si no se mete en el if, devuelvo el simbolo ganador if (coincidencia) { return simbolo; } } } //Si no hay ganador, devuelvo el simbolo por defecto return VACIO; }
Para comprobar las diagonales:
/** * Comprueba las diagonales * * @return Simbolo del ganador, VACIO sino hay ganador */ private char coincidenciaDiagonal() { char simbolo; boolean coincidencia = true; //Diagonal principal simbolo = tablero[0][0]; if (simbolo != VACIO) { for (int i = 1; i < tablero.length; i++) { //sino coincide ya no habra ganadro en esta fila if (simbolo != tablero[i][i]) { coincidencia = false; } } //Si no se mete en el if, devuelvo el simbolo ganador if (coincidencia) { return simbolo; } } coincidencia = true; //Diagonal inversa simbolo = tablero[0][2]; if (simbolo != VACIO) { for (int i = 1, j = 1; i < tablero.length; i++, j--) { //sino coincide ya no habra ganadro en esta fila if (simbolo != tablero[i][j]) { coincidencia = false; } } //Si no se mete en el if, devuelvo el simbolo ganador if (coincidencia) { return simbolo; } } //Si no hay ganador, devuelvo el simbolo por defecto return VACIO; }
Ya teniendo estos métodos, podemos saber cuando se acaba la partida:
/** * Indica si es el fin de la partida, acaba cuando hay un ganador o el tablero esta lleno * @return fin de partida */ public boolean finPartida() { if (tableroLleno() || coincidenciaLinea() != VACIO || coincidenciaColumna() != VACIO || coincidenciaDiagonal() != VACIO) { return true; } return false; }
Cuando se acabe el juego, tendremos que mostrar el ganador:
/** * Muestra el ganador de la partida */ public void mostrarGanador() { char simbolo = coincidenciaLinea(); if (simbolo != VACIO) { ganador(simbolo, 1); return; } simbolo = coincidenciaColumna(); if (simbolo != VACIO) { ganador(simbolo, 2); return; } simbolo = coincidenciaDiagonal(); if (simbolo != VACIO) { ganador(simbolo, 3); return; } System.out.println("Hay empate"); } /** * Funcion auxiliar de la anterior funcion * * @param simbolo * @param tipo */ private void ganador(char simbolo, int tipo) { switch (tipo) { case 1: if (simbolo == J1) { System.out.println("Ha ganado el Jugador 1 por linea"); } else { System.out.println("Ha ganado el Jugador 2 por linea"); } break; case 2: if (simbolo == J1) { System.out.println("Ha ganado el Jugador 1 por columna"); } else { System.out.println("Ha ganado el Jugador 2 por columna"); } break; case 3: if (simbolo == J1) { System.out.println("Ha ganado el Jugador 1 por diagonal"); } else { System.out.println("Ha ganado el Jugador 2 por diagonal"); } break; } }
Os dejo la clase completa:
public class TicTacToe { //Reprentaciones de los jugadores y del simbolo vacio private final char J1 = 'X'; private final char J2 = 'O'; private final char VACIO = '-'; //turno actual //true = J1, false = J2 private boolean turno; //tablero donde vamos a jugar private char tablero[][]; public TicTacToe() { this.turno = true; this.tablero = new char[3][3]; this.inicializarTablero(); } /** * Inicializa el tablero con el simbolo VACIO */ private void inicializarTablero() { for (int i = 0; i < tablero.length; i++) { for (int j = 0; j < tablero.length; j++) { tablero[i][j] = VACIO; } } } /** * Indica si es el fin de la partida, acaba cuando hay un ganador o el * tablero esta lleno * * @return fin de partida */ public boolean finPartida() { if (tableroLleno() || coincidenciaLinea() != VACIO || coincidenciaColumna() != VACIO || coincidenciaDiagonal() != VACIO) { return true; } return false; } /** * Indica si el tablero esta llena cuando el simbolo por defecto aparezca, * no esta llena * * @return talero vacio o no */ public boolean tableroLleno() { for (int i = 0; i < tablero.length; i++) { for (int j = 0; j < tablero[0].length; j++) { if (tablero[i][j] == VACIO) { return false; } } } return true; } /** * Indica si hay un ganador en una linea * * @return Simbolo del ganador, VACIO sino hay ganador */ private char coincidenciaLinea() { char simbolo; boolean coincidencia; for (int i = 0; i < tablero.length; i++) { //Reiniciamos la coincidencia coincidencia = true; //Cogemos el simbolo de la fila simbolo = tablero[i][0]; if (simbolo != VACIO) { for (int j = 1; j < tablero[0].length; j++) { //sino coincide ya no habra ganadro en esta fila if (simbolo != tablero[i][j]) { coincidencia = false; } } //Si no se mete en el if, devuelvo el simbolo ganador if (coincidencia) { return simbolo; } } } //Si no hay ganador, devuelvo el simbolo por defecto return VACIO; } /** * Indica si hay un ganador en una columna * * @return Simbolo del ganador, VACIO sino hay ganador */ private char coincidenciaColumna() { char simbolo; boolean coincidencia; for (int j = 0; j < tablero.length; j++) { //Reiniciamos la coincidencia coincidencia = true; //Cogemos el simbolo de la columna simbolo = tablero[0][j]; if (simbolo != VACIO) { for (int i = 1; i < tablero[0].length; i++) { //sino coincide ya no habra ganadro en esta fila if (simbolo != tablero[i][j]) { coincidencia = false; } } //Si no se mete en el if, devuelvo el simbolo ganador if (coincidencia) { return simbolo; } } } //Si no hay ganador, devuelvo el simbolo por defecto return VACIO; } /** * Comprueba las diagonales * * @return Simbolo del ganador, VACIO sino hay ganador */ private char coincidenciaDiagonal() { char simbolo; boolean coincidencia = true; //Diagonal principal simbolo = tablero[0][0]; if (simbolo != VACIO) { for (int i = 1; i < tablero.length; i++) { //sino coincide ya no habra ganadro en esta fila if (simbolo != tablero[i][i]) { coincidencia = false; } } //Si no se mete en el if, devuelvo el simbolo ganador if (coincidencia) { return simbolo; } } coincidencia = true; //Diagonal inversa simbolo = tablero[0][2]; if (simbolo != VACIO) { for (int i = 1, j = 1; i < tablero.length; i++, j--) { //sino coincide ya no habra ganadro en esta fila if (simbolo != tablero[i][j]) { coincidencia = false; } } //Si no se mete en el if, devuelvo el simbolo ganador if (coincidencia) { return simbolo; } } //Si no hay ganador, devuelvo el simbolo por defecto return VACIO; } /** * Muestra el ganador de la partida */ public void mostrarGanador() { char simbolo = coincidenciaLinea(); if (simbolo != VACIO) { ganador(simbolo, 1); return; } simbolo = coincidenciaColumna(); if (simbolo != VACIO) { ganador(simbolo, 2); return; } simbolo = coincidenciaDiagonal(); if (simbolo != VACIO) { ganador(simbolo, 3); return; } System.out.println("Hay empate"); } /** * Funcion auxiliar de la anterior funcion * * @param simbolo * @param tipo */ private void ganador(char simbolo, int tipo) { switch (tipo) { case 1: if (simbolo == J1) { System.out.println("Ha ganado el Jugador 1 por linea"); } else { System.out.println("Ha ganado el Jugador 2 por linea"); } break; case 2: if (simbolo == J1) { System.out.println("Ha ganado el Jugador 1 por columna"); } else { System.out.println("Ha ganado el Jugador 2 por columna"); } break; case 3: if (simbolo == J1) { System.out.println("Ha ganado el Jugador 1 por diagonal"); } else { System.out.println("Ha ganado el Jugador 2 por diagonal"); } break; } } /** * Insertamos en una posicion de una matriz un simbolo en concreto * * @param fila * @param columna */ public void insertarEn(int fila, int columna) { if (turno) { this.tablero[fila][columna] = J1; } else { this.tablero[fila][columna] = J2; } } /** * Muestra la matriz * */ public void mostrarTablero() { for (int i = 0; i < this.tablero.length; i++) { for (int j = 0; j < this.tablero[0].length; j++) { System.out.print(this.tablero[i][j] + " "); } System.out.println(""); } } /** * Mostramos el turno actual */ public void mostrarTurnoActual() { if (turno) { System.out.println("Le toca al jugador 1"); } else { System.out.println("Le toca al jugador 2"); } } /** * Cambia el turno */ public void cambiaTurno() { this.turno = !this.turno; } /** * Validamos la posicion que nos insertan * * @param fila * @param columna * @return */ public boolean validarPosicion(int fila, int columna) { if (fila >= 0 && fila < tablero.length && columna >= 0 && columna < tablero.length) { return true; } return false; } /** * Indicamos si en una posicion hay una marca * * @param fila * @param columna * @return */ public boolean hayValorPosicion(int fila, int columna) { if (this.tablero[fila][columna] != VACIO) { return true; } return false; } }
También os dejo un pequeño ejemplo:
import java.util.Scanner; public class Ejercicio_POO_DDR_23 { static Scanner teclado = new Scanner(System.in); public static void main(String[] args) { TicTacToe ttt = new TicTacToe(); int fila, columna; boolean posValida, correcto; //No salimos hasta que uno gane o no haya mas posibilidades while (!ttt.finPartida()) { do { //mostramos el jugador al que le toca ttt.mostrarTurnoActual(); //muestro el tablero ttt.mostrarTablero(); correcto = false; fila = pedirInteger("Dame la fila"); columna = pedirInteger("Dame la columna"); //Validamos la posicion posValida = ttt.validarPosicion(fila, columna); //Si es valido, comprobamos que no haya ninguna marca if (posValida) { //Si no hay marca, significa que es correcto if (!ttt.hayValorPosicion(fila, columna)) { correcto = true; } else { System.out.println("Ya hay una marca en esa posicion"); } } else { System.out.println("La posicion no es valida"); } //Mientras no sea correcto, no salgo } while (!correcto); //depende del turno, inserta un simbolo u otro ttt.insertarEn(fila, columna); ttt.cambiaTurno(); } //Muestra el tablero ttt.mostrarTablero(); //Mostramos el ganador ttt.mostrarGanador(); } /** * Pedimos un numero y lo devolvemos * * @param mensaje * @return */ public static int pedirInteger(String mensaje) { System.out.println(mensaje); int numero = teclado.nextInt(); return numero; } }
También te dejo un par de videos:
Espero que os sea de ayuda. Si tenéis dudas, preguntad. Estamos para ayudarte.
Buenas, no se me coloca la matriz en consola, se imprime de 3 en 3 hacia abajo, sabes que puede suceder o que puedo hacer para que esto no ocurra?