En este post te mostraré el juego Conecta 4 programado en C por consola. Se trata del juego que lleva el mismo nombre en donde se deben conectar cuatro fichas del mismo color de manera que formen una línea, ya sea horizontal, vertical o diagonal.
Las características del mismo son:
A lo largo del post te mostraré cómo es que programé el juego, dónde se puede probar, descargar, etcétera.
Nota: mira este juego portado para JavaScript, es decir, en su versión web.
He definido el encabezado de todo el juego con el prototipo de las funciones así como con las constantes que ajustan el juego.
Lo que se puede cambiar (lo demás no lo recomiendo si no lo entiendes) es el número de filas y columnas para cambiar el tamaño del tablero de juego. Debido a que no he implementado un color para cada jugador, un color es la letra o y el otro color es la letra x.
Finalmente la constante de CONECTA
indica cuántas piezas se deben conectar para ganar. Justo aquí se puede modificar para que se juegue a conecta 3, por ejemplo.
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me). Este encabezado debe mantenerse intacto,
excepto si este es un proyecto de un estudiante.
*/#define FILAS 6
#define COLUMNAS 7
#define TAMANIO_MATRIZ sizeof(char)*FILAS*COLUMNAS
#define JUGADOR_1 'o'
#define JUGADOR_2 'x'
#define JUGADOR_CPU_1 JUGADOR_1
#define JUGADOR_CPU_2 JUGADOR_2
#define ESPACIO_VACIO ' '
#define FILA_NO_ENCONTRADA -1
#define ERROR_COLUMNA_LLENA 2
#define ERROR_FILA_INVALIDA 4
#define ERROR_NINGUNO 3
#define CONECTA 4
#define CONECTA_ARRIBA 1
#define CONECTA_DERECHA 2
#define CONECTA_ABAJO_DERECHA 3
#define CONECTA_ARRIBA_DERECHA 4
#define NO_CONECTA 0
#define COLUMNA_GANADORA_NO_ENCONTRADA -1
#define MODO_HUMANO_CONTRA_HUMANO 1
#define MODO_HUMANO_CONTRA_CPU 2
#define MODO_CPU_CONTRA_CPU 3
int contarArriba(int x, int y, char jugador, char tablero[FILAS][COLUMNAS]);
int contarDerecha(int x, int y, char jugador, char tablero[FILAS][COLUMNAS]);
int contarArribaDerecha(int x, int y, char jugador, char tablero[FILAS][COLUMNAS]);
int contarAbajoDerecha(int x, int y, char jugador, char tablero[FILAS][COLUMNAS]);
int obtenerFilaDesocupada(int columna, char tablero[FILAS][COLUMNAS]);
int colocarPieza(char jugador, int columna, char tablero[FILAS][COLUMNAS]);
void limpiarTablero(char tablero[FILAS][COLUMNAS]);
void dibujarEncabezado(int columnas);
int dibujarTablero(char tablero[FILAS][COLUMNAS]);
int esEmpate(char tablero[FILAS][COLUMNAS]);
char obtenerOponente(char jugador);
void clonarMatriz(char tableroOriginal[FILAS][COLUMNAS], char destino[FILAS][COLUMNAS]);
int obtenerColumnaGanadora(char jugador, char tableroOriginal[FILAS][COLUMNAS]);
int obtenerPrimeraFilaLlena(int columna, char tablero[FILAS][COLUMNAS]);
void obtenerColumnaEnLaQueSeObtieneMayorPuntaje(char jugador, char tableroOriginal[FILAS][COLUMNAS], int *conteo,
int *indice);
int aleatorio_en_rango(int minimo, int maximo);
int obtenerColumnaAleatoria(char jugador, char tableroOriginal[FILAS][COLUMNAS]);
int obtenerColumnaCentral(char jugador, char tableroOriginal[FILAS][COLUMNAS]);
int elegirColumnaCpu(char jugador, char tablero[FILAS][COLUMNAS]);
int ganador(char jugador, char tablero[FILAS][COLUMNAS]);
char elegirJugadorAlAzar();
int solicitarColumnaAJugador();
void jugar(int modo);
Además de los ajustes, se pueden ver todas las funciones del programa. A continuación iré explicando a las mismas.
Para mostrar el tablero de juego de Conecta 4 en C he decidido por usar una matriz de tipo char
. Cada campo de la matriz tiene tres estados:
Recuerda que igualmente la CPU se toma como el jugador 1, y la CPU 2 como el jugador 2. Al inicio del juego se debe limpiar el tablero, colocando los espacios en vacíos.
También tenemos otras funciones como colocarPieza que coloca la pieza en determinada columna y verifica que sea posible además de que sobre espacio.
Otra función interesante es obtenerFilaDesocupada que devuelve la fila en donde se debería colocar la pieza, normalmente debe ser en la primera desocupada de arriba hacia abajo, pero esta función también valida que haya espacio disponible.
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me). Este encabezado debe mantenerse intacto,
excepto si este es un proyecto de un estudiante.
*/#include "conecta4.h"
#include <stdio.h>
int obtenerFilaDesocupada(int columna, char tablero[FILAS][COLUMNAS]) {
int i;
for (i = FILAS - 1; i >= 0; i--) {
if (tablero[i][columna] == ESPACIO_VACIO) {
return i;
}
}
return FILA_NO_ENCONTRADA;
}
int colocarPieza(char jugador, int columna, char tablero[FILAS][COLUMNAS]) {
if (columna < 0 || columna >= COLUMNAS) {
return ERROR_FILA_INVALIDA;
}
int fila = obtenerFilaDesocupada(columna, tablero);
if (fila == FILA_NO_ENCONTRADA) {
return ERROR_COLUMNA_LLENA;
}
tablero[fila][columna] = jugador;
return ERROR_NINGUNO;
}
void limpiarTablero(char tablero[FILAS][COLUMNAS]) {
int i;
for (i = 0; i < FILAS; ++i) {
int j;
for (j = 0; j < COLUMNAS; ++j) {
tablero[i][j] = ESPACIO_VACIO;
}
}
}
void dibujarEncabezado(int columnas) {
printf("\n");
int i;
for (i = 0; i < columnas; ++i) {
printf("|%d", i + 1);
if (i + 1 >= columnas) {
printf("|");
}
}
}
int dibujarTablero(char tablero[FILAS][COLUMNAS]) {
dibujarEncabezado(COLUMNAS);
printf("\n");
int i;
for (i = 0; i < FILAS; ++i) {
int j;
for (j = 0; j < COLUMNAS; ++j) {
printf("|%c", tablero[i][j]);
if (j + 1 >= COLUMNAS) {
printf("|");
}
}
printf("\n");
}
return 0;
}
int esEmpate(char tablero[FILAS][COLUMNAS]) {
int i;
for (i = 0; i < COLUMNAS; ++i) {
int resultado = obtenerFilaDesocupada(i, tablero);
if (resultado != FILA_NO_ENCONTRADA) {
return 0;
}
}
return 1;
}
Finalmente contamos con la función esEmpate
que devuelve un booleano si ya no quedan espacios vacíos en el tablero.
En este juego de conecta 4 necesitamos contar cuántas piezas del mismo color hay en línea, y justo así se detecta si existe un ganador. Para ello simplemente hacemos ciclos y tomamos en cuenta las siguientes ubicaciones:
Esto es debido a que las otras ubicaciones ya son tomadas en cuenta con las anteriores. Por ejemplo, para saber si conecta hacia abajo, es lo mismo que conectar hacia arriba pero desde la fila inferior. Lo mismo para las demás.
Sé que debe existir una función que permita navegar de un punto a otro, de manera que elimine el código repetido, pero no he investigado.
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me). Este encabezado debe mantenerse intacto,
excepto si este es un proyecto de un estudiante.
*/#include "conecta4.h"
int contarArriba(int x, int y, char jugador, char tablero[FILAS][COLUMNAS]) {
int yInicio = (y - CONECTA >= 0) ? y - CONECTA + 1 : 0;
int contador = 0;
for (; yInicio <= y; yInicio++) {
if (tablero[yInicio][x] == jugador) {
contador++;
} else {
contador = 0;
}
}
return contador;
}
int contarDerecha(int x, int y, char jugador, char tablero[FILAS][COLUMNAS]) {
int xFin = (x + CONECTA < COLUMNAS) ? x + CONECTA - 1 : COLUMNAS - 1;
int contador = 0;
for (; x <= xFin; x++) {
if (tablero[y][x] == jugador) {
contador++;
} else {
contador = 0;
}
}
return contador;
}
int contarArribaDerecha(int x, int y, char jugador, char tablero[FILAS][COLUMNAS]) {
int xFin = (x + CONECTA < COLUMNAS) ? x + CONECTA - 1 : COLUMNAS - 1;
int yInicio = (y - CONECTA >= 0) ? y - CONECTA + 1 : 0;
int contador = 0;
while (x <= xFin && yInicio <= y) {
if (tablero[y][x] == jugador) {
contador++;
} else {
contador = 0;
}
x++;
y--;
}
return contador;
}
int contarAbajoDerecha(int x, int y, char jugador, char tablero[FILAS][COLUMNAS]) {
int xFin = (x + CONECTA < COLUMNAS) ? x + CONECTA - 1 : COLUMNAS - 1;
int yFin = (y + CONECTA < FILAS) ? y + CONECTA - 1 : FILAS - 1;
int contador = 0;
while (x <= xFin && y <= yFin) {
if (tablero[y][x] == jugador) {
contador++;
} else {
contador = 0;
}
x++;
y++;
}
return contador;
}
int ganador(char jugador, char tablero[FILAS][COLUMNAS]) {
/*
* Solo necesitamos
* Arriba
* Derecha
* Arriba derecha
* Abajo derecha
*
* */ int y;
for (y = 0; y < FILAS; y++) {
int x;
for (x = 0; x < COLUMNAS; x++) {
int conteoArriba = contarArriba(x, y, jugador, tablero);
if (conteoArriba >= CONECTA) {
return CONECTA_ARRIBA;
}
if (contarDerecha(x, y, jugador, tablero) >= CONECTA) {
return CONECTA_DERECHA;
}
if (contarArribaDerecha(x, y, jugador, tablero) >= CONECTA) {
return CONECTA_ARRIBA_DERECHA;
}
if (contarAbajoDerecha(x, y, jugador, tablero) >= CONECTA) {
return CONECTA_ABAJO_DERECHA;
}
}
}
return NO_CONECTA;
}
Por cierto la función que cuenta regresa varios estados para saber si se conecta hacia determinado lugar (y así determinar el ganador).
Ahora veamos el montón de if’s que hacen que la CPU piense. Ya expliqué anteriormente el algoritmo, ahora vengo a mostrarlo convertido en código. Queda así:
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me). Este encabezado debe mantenerse intacto,
excepto si este es un proyecto de un estudiante.
*/#include "conecta4.h"
#include <string.h>
#include <stdio.h>
void clonarMatriz(char tableroOriginal[FILAS][COLUMNAS], char destino[FILAS][COLUMNAS]) {
memcpy(destino, tableroOriginal, TAMANIO_MATRIZ);
}
int obtenerColumnaGanadora(char jugador, char tableroOriginal[FILAS][COLUMNAS]) {
char tablero[FILAS][COLUMNAS];
int i;
for (i = 0; i < COLUMNAS; i++) {
clonarMatriz(tableroOriginal, tablero);
int resultado = colocarPieza(jugador, i, tablero);
if (resultado == ERROR_NINGUNO) {
int gana = ganador(jugador, tablero);
if (gana != NO_CONECTA) {
return i;
}
}
}
return COLUMNA_GANADORA_NO_ENCONTRADA;
}
int obtenerPrimeraFilaLlena(int columna, char tablero[FILAS][COLUMNAS]) {
int i;
for (i = 0; i < FILAS; ++i) {
if (tablero[i][columna] != ESPACIO_VACIO) {
return i;
}
}
return FILA_NO_ENCONTRADA;
}
/*
* Los dos últimos apuntadores son porque no podemos regresar dos variables
* */void obtenerColumnaEnLaQueSeObtieneMayorPuntaje(char jugador, char tableroOriginal[FILAS][COLUMNAS], int *conteo,
int *indice) {
int conteoMayor = 0,
indiceColumnaConConteoMayor = -1;
char tablero[FILAS][COLUMNAS];
int i;
for (i = 0; i < COLUMNAS; ++i) {
clonarMatriz(tableroOriginal, tablero);
int estado = colocarPieza(jugador, i, tablero);
if (estado == ERROR_NINGUNO) {
int filaDePiezaRecienColocada = obtenerPrimeraFilaLlena(i, tablero);
if (filaDePiezaRecienColocada != FILA_NO_ENCONTRADA) {
int c = contarArriba(i, filaDePiezaRecienColocada, jugador, tablero);
if (c > conteoMayor) {
conteoMayor = c;
indiceColumnaConConteoMayor = i;
}
c = contarArribaDerecha(i, filaDePiezaRecienColocada, jugador, tablero);
if (c > conteoMayor) {
conteoMayor = c;
indiceColumnaConConteoMayor = i;
}
c = contarDerecha(i, filaDePiezaRecienColocada, jugador, tablero);
if (c > conteoMayor) {
conteoMayor = c;
indiceColumnaConConteoMayor = i;
}
c = contarAbajoDerecha(i, filaDePiezaRecienColocada, jugador, tablero);
if (c > conteoMayor) {
conteoMayor = c;
indiceColumnaConConteoMayor = i;
}
}
}
}
*conteo = conteoMayor;
*indice = indiceColumnaConConteoMayor;
}
int obtenerColumnaAleatoria(char jugador, char tableroOriginal[FILAS][COLUMNAS]) {
while (1) {
char tablero[FILAS][COLUMNAS];
clonarMatriz(tableroOriginal, tablero);
int columna = aleatorio_en_rango(0, COLUMNAS - 1);
int resultado = colocarPieza(jugador, columna, tablero);
if (resultado == ERROR_NINGUNO) {
return columna;
}
}
}
int obtenerColumnaCentral(char jugador, char tableroOriginal[FILAS][COLUMNAS]) {
char tablero[FILAS][COLUMNAS];
clonarMatriz(tableroOriginal, tablero);
int mitad = (COLUMNAS - 1) / 2;
int resultado = colocarPieza(jugador, mitad, tablero);
if (resultado == ERROR_NINGUNO) {
return mitad;
}
return COLUMNA_GANADORA_NO_ENCONTRADA;
}
int elegirColumnaCpu(char jugador, char tablero[FILAS][COLUMNAS]) {
// Voy a comprobar si puedo ganar...
int posibleColumnaGanadora = obtenerColumnaGanadora(jugador, tablero);
if (posibleColumnaGanadora != COLUMNA_GANADORA_NO_ENCONTRADA) {
printf("*elijo ganar*\n");
return posibleColumnaGanadora;
}
// Si no, voy a comprobar si mi oponente gana con el siguiente movimiento, para evitarlo
char oponente = obtenerOponente(jugador);
int posibleColumnaGanadoraDeOponente = obtenerColumnaGanadora(oponente, tablero);
if (posibleColumnaGanadoraDeOponente != COLUMNA_GANADORA_NO_ENCONTRADA) {
printf("*elijo evitar que mi oponente gane*\n");
return posibleColumnaGanadoraDeOponente;
}
// En caso de que nadie pueda ganar en el siguiente movimiento, buscaré en dónde se obtiene el mayor
// puntaje al colocar la pieza
int conteoCpu, columnaCpu;
obtenerColumnaEnLaQueSeObtieneMayorPuntaje(jugador, tablero, &conteoCpu, &columnaCpu);
int conteoOponente, columnaOponente;
obtenerColumnaEnLaQueSeObtieneMayorPuntaje(oponente, tablero, &conteoOponente, &columnaOponente);
if (conteoOponente > conteoCpu) {
printf("*elijo quitarle el puntaje a mi oponente*\n");
return columnaOponente;
} else if (conteoCpu > 1) {
printf("*elijo colocarla en donde obtengo un mayor puntaje*\n");
return columnaCpu;
}
// Si no, regresar la central por si está desocupada
int columnaCentral = obtenerColumnaCentral(jugador, tablero);
if (columnaCentral != COLUMNA_GANADORA_NO_ENCONTRADA) {
printf("*elijo ponerla en el centro*\n");
return columnaCentral;
}
// Finalmente, devolver la primera disponible de manera aleatoria
int columna = obtenerColumnaAleatoria(jugador, tablero);
if (columna != FILA_NO_ENCONTRADA) {
printf("*elijo la primera vacía aleatoria*\n");
return columna;
}
printf("Esto no debería suceder\n");
return 0;
}
Como puedes ver, todo se basa en clonar el tablero original, simular colocar las piezas y elegir el mejor camino además del balance entre la defensa y el ataque.
Tenemos más funciones “misceláneas” por ejemplo para obtener un número aleatorio, solicitar una columna, etcétera.
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me). Este encabezado debe mantenerse intacto,
excepto si este es un proyecto de un estudiante.
*/#include "conecta4.h"
#include <stdlib.h> // rand y RAND_MAX
char obtenerOponente(char jugador) {
if (jugador == JUGADOR_1) {
return JUGADOR_2;
} else {
return JUGADOR_1;
}
}
int aleatorio_en_rango(int minimo, int maximo) {
return minimo + rand() / (RAND_MAX / (maximo - minimo + 1) + 1);
}
char elegirJugadorAlAzar() {
int numero = aleatorio_en_rango(0, 1);
if (numero) {
return JUGADOR_1;
} else {
return JUGADOR_2;
}
}
int solicitarColumnaAJugador() {
int columna = 0;
printf("Escribe la columna en donde colocar la pieza: ");
scanf("%d", &columna);
// Necesitamos índices de arreglos
columna--;
return columna;
}
Otra función interesante es la que devuelve el oponente del jugador actual, y aunque es simple, es muy útil para evitar repetición de código.
Ahora en la función main o principal iniciamos el juego dependiendo de lo que el usuario seleccione:
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me). Este encabezado debe mantenerse intacto,
excepto si este es un proyecto de un estudiante.
*/#include <stdio.h>
#include <stdlib.h> // rand y RAND_MAX
#include <unistd.h> // getpid
#include "conecta4.h"
#include "conteo.c"
#include "tablero.c"
#include "ia.c"
#include "misc.c"
#include "juego.c"
int main() {
// Hay que alimentar a rand, solamente una vez (seed rand)
srand(getpid());
printf("*** Conecta 4 ***\n\nBy Parzibyte\n\t\thttps://parzibyte.me/blog\n");
int modo;
printf("1 => Humano contra Humano\n"
"2 => Humano contra CPU\n"
"3 => CPU contra CPU\n"
"4 => Salir\n"
"Seleccione una opción: ");
scanf("%d", &modo);
if (modo <= 0 || modo > 3) {
return 0;
}
jugar(modo);
return 0;
}
La función de juego simplemente recibe el modo de juego que puede ser humano contra humano, humano contra CPU, CPU contra CPU. Se ve así:
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me). Este encabezado debe mantenerse intacto,
excepto si este es un proyecto de un estudiante.
*/#include "conecta4.h"
void jugar(int modo) {
char tablero[FILAS][COLUMNAS];
limpiarTablero(tablero);
char jugadorActual = elegirJugadorAlAzar();
printf("Comienza el jugador %c\n", jugadorActual);
while (1) {
int columna = 0;
printf("\nTurno del jugador %c\n", jugadorActual);
dibujarTablero(tablero);
if (modo == MODO_HUMANO_CONTRA_CPU) {
if (jugadorActual == JUGADOR_CPU_2) {
printf("CPU 2 pensando...");
columna = elegirColumnaCpu(jugadorActual, tablero);
} else {
columna = solicitarColumnaAJugador();
}
} else if (modo == MODO_CPU_CONTRA_CPU) {
printf("CPU %d pensando...", jugadorActual == JUGADOR_CPU_1 ? 1 : 2);
columna = elegirColumnaCpu(jugadorActual, tablero);
} else if (modo == MODO_HUMANO_CONTRA_HUMANO) {
columna = solicitarColumnaAJugador();
}
int estado = colocarPieza(jugadorActual, columna, tablero);
if (estado == ERROR_COLUMNA_LLENA) {
printf("Error: columna llena");
} else if (estado == ERROR_FILA_INVALIDA) {
printf("Fila no correcta");
} else if (estado == ERROR_NINGUNO) {
int g = ganador(jugadorActual, tablero);
if (g != NO_CONECTA) {
dibujarTablero(tablero);
printf("Gana el jugador %c.", jugadorActual);
break;
} else if (esEmpate(tablero)) {
dibujarTablero(tablero);
printf("Empate");
break;
}
}
jugadorActual = obtenerOponente(jugadorActual);
}
}
De este modo termina todo el código de este maravilloso juego.
Ahora viene la parte interesante. Puedes descargar el código desde mi repositorio de GitHub (sígueme y déjale una estrella si quieres). Si te fijas, son varios archivos, pues he separado conceptos.
Yo recomiendo usar MinGW en Windows.
En la carpeta que lo has descargado ejecuta simplemente con gcc:
gcc main.c -o conecta4.exe
Y luego puedes ejecutar el archivo conecta4.exe
. Si estás en Linux (Ubuntu en este caso) ejecuta:
gcc main.c -o conecta4
Después puedes ejecutar ./conecta4
También debería compilar como un encanto en otros compiladores decentes. Yo lo he probado en la nube con replit (que usa clang) y en local (con gcc); todo funciona de maravilla. Por cierto, si en tu caso quieres todo el código en un mismo archivo, mira el ejemplo en línea.
He grabado un vídeo en donde explico igualmente las funciones del juego conecta 4 en C además de hacer una pequeña demostración.
Muy pronto traeré este juego portado a otro lenguaje y con interfaz gráfica.
Como siempre lo digo, escribo el código en C para que pueda portarlo a otros lenguajes de manera fácil, pues no hay algo en C que no exista en otros lenguajes (sin contar los macros o apuntadores, de los cuales solo usamos los primeros pero se pueden remplazar por constantes).
Por cierto, este no es el único videojuego que he creado. Aquí hay más.
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…
Esta web usa cookies.