Crear un sencillo juego de Tres en Raya en C

CBeginner
Practicar Ahora

Introducción

En este proyecto, aprenderás cómo crear un sencillo juego de Tres en Raya (Tic-Tac-Toe) en C. El juego se jugará entre dos jugadores que se turnan para marcar los espacios en una cuadrícula de 3x3. El primer jugador en tener tres de sus marcas en una fila, columna o diagonal es el ganador. Si todos los espacios están llenos y ningún jugador tiene tres marcas en una fila, el juego termina en empate.

👀 Vista previa

Vista previa del juego de Tres en Raya

🎯 Tareas

En este proyecto, aprenderás:

  • Cómo crear un tablero de juego e inicializarlo con espacios vacíos.
  • Cómo implementar funciones para limpiar la pantalla, mostrar el tablero de juego y comprobar si el juego ha terminado.
  • Cómo determinar el ganador del juego.
  • Cómo implementar el bucle principal del juego para permitir que los jugadores se turnen e interactúen con el juego.

🏆 Logros

Después de completar este proyecto, podrás:

  • Crear y manipular arrays en C.
  • Utilizar bucles y condicionales para implementar la lógica del juego.
  • Interactuar con el usuario a través de la interfaz de línea de comandos.
  • Organizar el código en funciones para una mejor modularidad y legibilidad.

Crear los archivos del proyecto

Primero, crea un nuevo archivo llamado tictactoe.c y ábrelo en tu editor de código preferido.

cd ~/project
touch tictactoe.c
✨ Revisar Solución y Practicar

Definir constantes

Ahora, necesitamos escribir el código en C. El primer paso es incluir los archivos de cabecera:

#include <stdio.h>
#include <stdbool.h>

Declarar el tamaño del tablero:

char board[3][3];
✨ Revisar Solución y Practicar

Inicializar el tablero de juego

Inicializa el tablero de juego con espacios vacíos.

void initializeBoard() {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            board[i][j] = ' ';
        }
    }
}

El primer for es un bucle exterior que utiliza la variable i para iterar desde 0 hasta 2, representando el número de filas en el tablero de juego. El segundo for es un bucle interior que utiliza la variable j para iterar desde 0 hasta 2, representando el número de columnas en el tablero de juego a su vez.

board[i][j] = ' ' En el bucle interior, establece el contenido de las casillas en la fila i y la columna j del tablero de juego al carácter de espacio (' '). Esto significa que todo el tablero de juego se inicializa en un estado vacío, sin que ningún jugador haya jugado en el tablero.

✨ Revisar Solución y Practicar

Limpiar la pantalla después de cada turno

Implementa una función para limpiar la pantalla después de cada turno.

void clearScreen() {
    printf("\033[H\033[J");
}

La función clearScreen se utiliza principalmente para limpiar el contenido del terminal o de la pantalla de la consola para borrar el estado y la salida del juego previos al final de cada turno. Esto se logra imprimiendo una secuencia de escape especial en una secuencia de salida estándar (por lo general, una ventana de terminal) que borra el contenido de texto de la pantalla.

printf("\033[H\033[J") utiliza secuencias de escape ANSI:

  • \033 es la representación octal del carácter de escape ASCII, que representa el inicio de la secuencia.
  • [H indica mover el cursor a la esquina superior izquierda de la pantalla, equivalente a posicionar el cursor en la primera fila y la primera columna de la pantalla.
  • [J significa limpiar la pantalla. Borrará todo el contenido de texto después de la posición del cursor, incluyendo el estado y la salida del juego previos.

Esto significa que cada vez que se llama a la función clearScreen, borrará el contenido de la pantalla actual del terminal o de la consola para mostrar el nuevo estado del juego antes de la próxima sesión de juego, lo que resulta en una interfaz más limpia.

✨ Revisar Solución y Practicar

Mostrar el tablero de juego

Crea la función printBoard para mostrar visualmente el estado actual del tablero de juego en la pantalla, lo que permite al jugador entender la posición de las fichas en el tablero. Esta es una parte del juego utilizada en los juegos de tres en raya para mostrar el estado del juego.

void printBoard() {
    printf("\n");
    printf("  1   2   3\n");
    printf("1 %c | %c | %c\n", board[0][0], board[0][1], board[0][2]);
    printf("  ---------\n");
    printf("2 %c | %c | %c\n", board[1][0], board[1][1], board[1][2]);
    printf("  ---------\n");
    printf("3 %c | %c | %c\n", board[2][0], board[2][1], board[2][2]);
}
✨ Revisar Solución y Practicar

Verificar si el juego ha terminado

Se implementa una función llamada isGameOver para determinar si el juego de tres en raya ha terminado y devolver un valor booleano (true o false).

bool isGameOver() {
    // Check rows
    for (int i = 0; i < 3; i++) {
        if (board[i][0]!= ' ' && board[i][0] == board[i][1] && board[i][0] == board[i][2]) {
            return true;
        }
    }

    // Check columns
    for (int j = 0; j < 3; j++) {
        if (board[0][j]!= ' ' && board[0][j] == board[1][j] && board[0][j] == board[2][j]) {
            return true;
        }
    }

    // Check diagonals
    if (board[0][0]!= ' ' && board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
        return true;
    }
    if (board[0][2]!= ' ' && board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
        return true;
    }

    // Check for a draw
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (board[i][j] == ' ') {
                return false;
            }
        }
    }

    return true;
}

Comprobar si hay un ganador en una fila: Si las tres celdas de una fila están ocupadas por el mismo jugador, hay un ganador y la función devuelve true.

Comprobar si hay un ganador en una columna: Si las tres celdas de una columna están ocupadas por el mismo jugador, hay un ganador y la función devuelve true.

Comprobar si hay un ganador en la diagonal: Si las tres casillas de cualquier diagonal están ocupadas por el mismo jugador, hay un ganador y la función devuelve true.

Comprobar si hay un empate: Finalmente, la función comprueba si todas las celdas están ocupadas, pero no hay un ganador. Si es así, el juego termina en empate y la función devuelve true.

✨ Revisar Solución y Practicar

Determinar el ganador

Se define una función llamada getWinner cuyo propósito es determinar si hay un ganador en un juego de tres en raya y devolver la marca del ganador (X o O), o un espacio (' ') si no hay ganador.

char getWinner() {
    // Check rows
    for (int i = 0; i < 3; i++) {
        if (board[i][0]!= ' ' && board[i][0] == board[i][1] && board[i][0] == board[i][2]) {
            return board[i][0];
        }
    }

    // Check columns
    for (int j = 0; j < 3; j++) {
        if (board[0][j]!= ' ' && board[0][j] == board[1][j] && board[0][j] == board[2][j]) {
            return board[0][j];
        }
    }

    // Check diagonals
    if (board[0][0]!= ' ' && board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
        return board[0][0];
    }
    if (board[0][2]!= ' ' && board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
        return board[0][2];
    }

    return ' '; // No winner
}
✨ Revisar Solución y Practicar

Implementar el bucle principal del juego

Escribe el bucle principal del juego para permitir a los jugadores tomar turnos e interactuar con el juego.

int main() {
    initializeBoard();
    int currentPlayer = 1;

    while (1) {
        clearScreen();
        printf("Current board state:\n");
        printBoard();

        int row, col;
        printf("Player %d, please enter a row and column (e.g., 1 2):", currentPlayer);

        while (scanf("%d %d", &row, &col)!= 2) {
            printf("Invalid input, please try again: ");
            while (getchar()!= '\n');
        }

        if (row < 1 || row > 3 || col < 1 || col > 3 || board[row - 1][col - 1]!= ' ') {
            printf("Invalid move, please try again.\n");
        } else {
            if (currentPlayer == 1) {
                board[row - 1][col - 1] = 'X';
                currentPlayer = 2;
            } else {
                board[row - 1][col - 1] = 'O';
                currentPlayer = 1;
            }
        }

        if (isGameOver()) {
            clearScreen();
            printf("Game over!\n");
            printBoard();
            char winner = getWinner();
            if (winner!= ' ') {
                printf("Player %c wins!\n", winner);
            } else {
                printf("It's a draw!\n");
            }
            break;
        }
    }

    return 0;
}

Llama a la función initializeBoard para inicializar el tablero de juego, estableciendo todas las casillas en espacios.

Crea una variable entera currentPlayer para llevar un registro de de quién es el turno. La configuración inicial es 1, lo que indica el jugador 1.

En el bucle principal while (1):

  • Llama a la función clearScreen para limpiar la pantalla, de modo que la pantalla se actualice después de cada turno.
  • Llama a la función printBoard para imprimir el tablero de juego actual.

Entrada del jugador: Solicita al jugador actual que ingrese las coordenadas de fila y columna a través de la función scanf, por ejemplo, Player 1, please enter a row and column (e.g., 1 2):. Si la entrada es inválida (no son dos enteros), se muestra el mensaje Invalid input, please try again: y se limpia el buffer de entrada hasta obtener una entrada válida.

Validación de entrada: Luego, se comprueba que las coordenadas de fila y columna ingresadas sean válidas (en un rango de 1 a 3) y que la posición seleccionada sea un espacio. Si la entrada es inválida o la ubicación seleccionada ya está ocupada, se muestra el mensaje Invalid move, please try again. y se pide al jugador que ingrese de nuevo.

Colocar ficha: Si la entrada es válida, el código coloca una X o una O en la posición correspondiente del tablero de juego según el jugador actual (1 o 2).

Detección del fin del juego: Luego, el código llama a la función isGameOver() para comprobar si el juego ha terminado. Si el juego termina, se limpia la pantalla y se muestra un mensaje de que el juego ha terminado, incluyendo el ganador (si lo hay) o un empate.

Resultado del juego: Si hay un ganador, el código mostrará Player X wins! o Player O wins!, dependiendo de qué jugador sea el ganador. Si no hay ganador, el código mostrará It's a draw! para indicar un empate.

✨ Revisar Solución y Practicar

Compilar y ejecutar el proyecto

Ejecuta el comando gcc para compilar:

cd ~/project
gcc -o tictactoe tictactoe.c
./tictactoe
Tic Tac Toe game demo
✨ Revisar Solución y Practicar

Resumen

¡Felicidades! Has creado con éxito un sencillo juego de Tres en Raya (Tic-Tac-Toe) en C. Los jugadores pueden tomar turnos y marcar sus posiciones en una cuadrícula de 3x3. El juego comprueba si hay un ganador o un empate después de cada turno y muestra el resultado en consecuencia. Este sencillo proyecto demuestra los conceptos básicos de la programación en C y puede servir como punto de partida para el desarrollo de juegos más complejos.