Created
February 10, 2022 01:11
-
-
Save ZaidaZadkiel/4923f64487b6a8eca7debe0caa649d75 to your computer and use it in GitHub Desktop.
Serpientes y Escaleras en modo consola en C con sonido portable
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<stdio.h> | |
#include<stdlib.h> | |
#include<stdio.h> | |
#include<math.h> | |
#include<string.h> | |
#include <time.h> | |
/* https://github.com/vareille/toot | |
requerido para hacer sonido | |
*/ | |
#include "toot.h" | |
//el nombre del jugador, este va a ser cambiado por entrada de usuario | |
char JUGADOR1[50]; | |
char JUGADOR2[50]; | |
//la posicion de la ficha del jugador 1 | |
int posicion1=1; | |
int posicion2=1; | |
//el modo de juego establecido por el usuario | |
int modoJuego=0; | |
// arreglos de dos dimensiones | |
// la primer dimension es el numero de la casilla que se va a checar | |
// la segunda dimension es el numero a la que se mueve la ficha | |
// las casillas que llevan escaleras | |
int escaleras[][2]={ | |
{ 6,16}, | |
{58,80}, | |
{20,31}, | |
{40,57} | |
}; | |
//las casillas que llevan serpientes | |
int serpientes[][2]={ | |
{99,75}, | |
{70,63}, | |
{55, 3}, | |
{40,33} | |
}; | |
//elimina todo lo que hay en pantalla | |
void limpiaPantalla(){ | |
system("clear"); | |
} | |
//la libreria toot.h proviene de https://github.com/vareille/toot y fue creada por Guillaume Vareille en 2017 | |
// esta libreria es multiplataforma y no requiere dependencias de archivos de sonido ni librerias adicionales | |
//funciona igual en windows, linux, mac, etc | |
//funcion de reproducir sonidos | |
//determina que sonido tocar segun el parametro "cual" | |
// los bucles bloquean mientras el sonido esta reproduciendose, regresando el control al final del sonido | |
// cada llamada a toot() hace un sonido sinusoidal con parametro de frecuencia de sonido y duracion | |
// la frecuencia determina que tan agudo o tan grave suena, y la duracion por cuanto tiempo se mantiene ese sonido | |
// toot( 1000, 500); por ejemplo, reproduce un sonido de frecuencia 1000 hz que se mantiene por exactamente medio segundo | |
// para generar variacion de sonido, se reproducen varias frecuencias una tras de la siguiente variando su agudo | |
// asi se produce variacion en el audio generandolo en tiempo de ejecucion en lugar de ser grabado anteriormente | |
// en general esto permite variaciones mas dinamicas, en menos espacio del archivo, y con menos archivos de dependencia | |
// de modo que usando solamente el binario (o codigo fuente) se puede reproducir el audio de la misma forma siempre | |
// para cambiar el sonido, por ejemplo, solo basta cambiar el bucle que indica cuales frecuencias se reproducen | |
void musica(int cual){ | |
char* titulo = "S E R P I E N T E S Y E S C A L E R A S"; | |
int len = strlen(titulo); | |
switch(cual){ | |
case 1: | |
// sonido de inicio con una animacion de titulo | |
limpiaPantalla(); //limpia la pantalla | |
printf(" "); //espacio para centrar el titulo | |
for (int i = 0; i != len; i++){ //len es la longitud del texto del titulo | |
toot( 200+(i*48), 7); //la frecuencia base es 200 hz, para cada pulso se le agrega 48hz haciendo un efecto ascendente | |
printf("%c", titulo[i]); //dibuja una letra | |
fflush(stdout); //fflush obliga a la pantalla a dibujar la letra anterior | |
} | |
printf("\n "); //espacio para centrar la segunda linea | |
for (int i = len; i >= 0; i--){ | |
toot( 200+(i*48), 7); //es la misma escala pero descendente, | |
printf("%c", titulo[i]); //dibuja el titulo pero invertido | |
fflush(stdout); | |
} | |
//melodia de inicio nota por nota | |
toot(600, 200); | |
toot(600, 200); | |
toot(750, 200); | |
toot(750, 200); | |
toot(950, 200); | |
toot(950, 200); | |
toot(1100, 400); | |
printf("\n\n\n"); | |
break; //regresa el control al final de la funcion | |
case 2: | |
// tirar dado | |
// 10 pulsos de duracion 7 ms con una frecuencia base de 400hz a la cual se le agregan 45hz por cada iteracion | |
// con un "silencio" de 7 ms entre pulso y pulso, para dar un efecto como reverberacion | |
for (int i = 10; i != 0; i--){ | |
toot( 400+(i*45), 7); | |
toot( 1, 7); // frecuencia 1hz = silencio | |
} | |
break; | |
case 3: // ganamos | |
// 6 notas rapidas ascendentes | |
for(int o=0; o!=6; o++){ | |
toot(200+(o*50), 150); | |
} | |
// 3 notas con un silencio | |
for(int o=0; o!=3; o++){ | |
toot(600,200); | |
toot(1,100); | |
} | |
//esta seccion reproduce una melodia nota por nota | |
//basicamente es lo que hace los bucles excepto que la frecuencia de la nota esta definida a mano | |
toot(800,200); | |
toot(1,100); | |
toot(700,200); | |
toot(1,100); | |
toot(650,200); | |
toot(1,100); | |
toot(600,200); | |
toot(1,100); | |
toot(800,200); | |
toot(1,100); | |
break; | |
case 4: // serpiente | |
// ese un sonido donde cada nota es descendiente en forma de "sierra" | |
for (int i = 5; i != 0; i--){ //genera 5 veces | |
for(int o=5; o!= 0; o--) //5 notas | |
toot( (500*o) + (i*200), 7);//que suben rapidamente y regresan, con duracion de 7 ms | |
} | |
break; | |
case 5: // escalera | |
// es el mismo sonido de serpiente pero invertido | |
for (int i = 0; i != 5; i++){ | |
for(int o=0; o!= 5; o++) | |
toot( (500*o) + (i*200), 7); | |
} | |
break; | |
} | |
} | |
//checa si la casilla tiene serpiente | |
//si tiene serpiente devuelve la casilla a la que mueve | |
//si no tiene serpiente devuelve -1 | |
int tieneSerpiente(int casilla){ | |
//obtiene el tamaño del arreglo de serpientes | |
int t_serp = sizeof serpientes / sizeof serpientes[0]; | |
//bucle | |
for(int i = 0; i!=t_serp; i++ ) | |
{ | |
//si el primer elemento del arreglo es el numero de la casilla | |
//devuelve el valor del segundo elemento | |
if(serpientes[i][0] == casilla) return serpientes[i][1]; | |
} | |
//si no se encontro la casilla devuelve un valor conocido (-1) | |
return -1; | |
} | |
//casilla contiene escalera | |
//si tiene escalera, devuelve la casilla que corresponde | |
int tieneEscalera(int casilla){ | |
//el tamaño del arregki de escaleras | |
int t_esca = sizeof escaleras / sizeof escaleras[0]; | |
for(int i = 0; i!=t_esca; i++ ) | |
{ | |
//checa si el primer elemento corresponde al numero de la casilla | |
//y si es true, devuelve el valor del segundo elemento | |
if(escaleras[i][0] == casilla) return escaleras[i][1]; | |
} | |
//valor si no encuentra nada | |
return -1; //no tiene escalera | |
} | |
//escribe en la pantalla E para escalera o S para serpiente | |
//y pone el numero al que va a mover la ficha | |
void dibujaSerpienteOEscalera(int casilla){ | |
int serpiente = tieneSerpiente(casilla); //llamada a funcion | |
if(serpiente != -1) { //si regresa el numero conocido -1 entonces no hace nada | |
printf(" S"); //dibuja la serpiente | |
if(serpiente<10) printf(" "); //si el numero de la casilla es entre 1 y 9 pone un espacio para ajustar | |
printf("%d", serpiente); // pone el numero de la serpiente | |
return; //sale de la funcion | |
} | |
//si no encontro serpiente entonces buscamos por escalera | |
int escalera = tieneEscalera(casilla); | |
if(escalera != -1) { //si el valor no es -1 entonces ejecutamos | |
printf(" E%d", escalera); // dibuja la Escalera | |
return; //como no tenemos casillas menores de 10 (de un solo digito) terminamos | |
} | |
//si no encuentra serpiente ni escalera dibuja el espacio para encuadrar las demas casillas | |
printf(" "); | |
} | |
//funcion para hacer la casilla con el marco, | |
//E para serpiente, S para escalera | |
//X para la ficha y el numero de la casilla | |
void dibujaCasilla(int numero){ | |
printf("%s", "["); //lado izquierdo | |
if(numero < 10){ | |
printf("%s", " "); //encuadra numeros de un digito | |
} | |
printf("%d",numero); //numero de casilla | |
dibujaSerpienteOEscalera(numero); //dibuja E o S | |
//si el jugador esta en la casilla "numero" | |
if(posicion1 == numero){ | |
printf("%s", "X"); //dibuja la ficha | |
} else { | |
printf("%s"," "); // caso contrario deja espacio para encuadrar | |
} | |
//si el jugador esta en la casilla "numero" | |
if(posicion2 == numero){ | |
printf("%s", "O"); //dibuja la ficha | |
} else { | |
printf("%s"," "); // caso contrario deja espacio para encuadrar | |
} | |
printf("] "); //lado derecho | |
} | |
//dibuja el mapa en cuadricula normal | |
void ponerMapa(){ | |
//para cada linea de casillas | |
for(int y = 90; y>=0; y=y-10){ | |
// dibuja la casilla una junto a la otra | |
for(int x=1; x<=10;x++){ | |
dibujaCasilla(y+x); | |
} | |
printf("\n"); | |
} | |
} | |
//devuelve un numero aleatorio entre 1 y 6 | |
int tirarDado(){ | |
return (rand()%6)+1; | |
} | |
//revisa si la casilla tiene serpiente o escalera, en caso de encontrar alguna devuelve la casilla final segun sube o baje | |
int moverSerpienteOEscalera(int casilla){ | |
int serpiente = tieneSerpiente(casilla); //revisa si la casilla tiene serpiente, en caso de que tenga serpiente sera la nueva casilla | |
if(serpiente != -1){ // -1 es el numero conocido para saber que no tiene serpiente, si no es -1 entonces sera la casilla a la que se mueve | |
printf("Salio serpiente, baja a la casilla %d\n\n",serpiente); //escribe el resultado del movimiento | |
ponerMapa(); | |
musica(4); //toca el sonido de serpiente | |
limpiaPantalla(); | |
printf("\n\n"); | |
return serpiente; // regresa la casilla a la que apunta la serpiente y termina funcion | |
} | |
//si se encontro serpiente en la seccion anterior esto no se ejecuta | |
//si no se encontro, entonces buscamos si tiene escalera | |
int escalera = tieneEscalera(casilla); //escalera contiene -1 si no hay o la casilla a la que sube | |
if(escalera != -1) { | |
printf("Salio escalera, sube a la casilla %d\n\n", escalera); //informa el movimiento | |
ponerMapa(); | |
musica(5); //toca el sonido de escalera | |
limpiaPantalla(); | |
printf("\n\n"); | |
return escalera; // regresa la casilla a la que apunta la escalera y termina funcion | |
} | |
//si no se encontro serpiente ni escalera entonces solamente avanza | |
printf("a la numero %d", casilla); | |
//si la casilla a la que avanzamos es mayor de 100 se informa que se ha ganado | |
if(casilla>=100) { | |
printf("%s\n\n", " ¡HA GANADO!"); | |
return 100; | |
} | |
//deja dos lineas en blanco para encuadrar el mapa | |
printf("\n\n"); | |
return casilla; //regresa la misma casilla | |
} | |
//tira el dado y mueve la ficha | |
// jugador es el nombre del jugador en turno | |
// posicion es la casilla en la que la ficha esta al inicio del turno | |
int moverFicha(char *jugador, int posicion){ | |
//pone el texto arriba del mapa y luego espera que el usuario presione enter | |
limpiaPantalla(); | |
ponerMapa(); | |
//limpia la pantalla, toca la musica y pone suspenso al tirar el dado | |
limpiaPantalla(); | |
int dado = tirarDado(); | |
printf("%s tira el dado...\n\n", jugador); | |
ponerMapa(); | |
musica(2); //reproduce el sonido del dado | |
//despues del sonido del dado limpia la pantalla y pone el resultado | |
limpiaPantalla(); | |
printf("El dado sale en: %d....", dado); | |
printf(" %s avanza %d casillas...", jugador, dado); | |
//verifica si cae en casilla normal o tiene serpiente o escalera | |
int posicion_nueva = moverSerpienteOEscalera(posicion + dado); | |
return posicion_nueva; | |
} | |
//funcion para validar el resultado del menu | |
//regresa el valor int segun el parametro tipo caracter | |
// en caso de que no este en la lista de opciones, regresa -1 e imprime texto | |
int validarMenu(char opcion){ | |
if(opcion == '0') {modoJuego = 0; return 0;} | |
if(opcion == '1') {modoJuego = 1; return 1;} | |
if(opcion == '2') {modoJuego = 2; return 2;} | |
if(opcion == '3') {modoJuego = 3; return 3;} | |
printf("Opcion No Valida\n"); | |
return -1; | |
} | |
int menuJugadores(){ | |
limpiaPantalla(); | |
musica(1); | |
printf("%s", "Serpientes y Escaleras\n\n"); | |
//texto de opcion con un espacio adicional (numero, \n, \0) | |
char opcion[3]; | |
do{ | |
printf("Que modo de juego desea?\n"); | |
printf("1: Jugador contra Jugador\n"); | |
printf("2: Jugador contra computadora\n"); | |
printf("3: Jugador solo\n"); | |
printf("0: Salir\n\n"); | |
printf("Escriba su opcion [1 2 3 0]: "); | |
//bug: si se pone un texto largo el bucle se ejecutara varias veces hasta procesar todo el texto | |
fgets(opcion, 3, stdin); | |
} while(validarMenu(opcion[0]) == -1); //valida despues de ejecutar al menos una vez el codigo anterior | |
//si selecciono 0 entonces se termina el juego | |
if(modoJuego == 0) { | |
printf("Gracias por jugar!\n\n"); | |
return 0; | |
} | |
//el jugador 1 siempre va a estar disponible | |
printf("%s", "Nombre del jugador 1: \n"); | |
//funcion fgets captura un texto de teclado con longitud de 50 caracteres como maximo | |
// stdin es el identificador de entrada desde linea de comandos (teclado) | |
if(fgets(JUGADOR1, 50, stdin)){ | |
//fgets deja el caracter de <enter> al final del texto, con esto lo eliminamos | |
//strlen - 1 es el ultimo caracter antes del final de la cadena de texto, que corresponde a <enter> o \n | |
//lo sustituimos por 0 para marcar que es el nuevo final del texto | |
JUGADOR1[strlen(JUGADOR1)-1] = 0; | |
} | |
//si el modo es de dos jugadores, recibe el nombre del segundo jugador | |
if(modoJuego == 1){ | |
printf("Nombre del jugador 2: \n"); | |
if(fgets(JUGADOR2, 50, stdin)){ | |
JUGADOR2[strlen(JUGADOR2)-1] = 0; | |
} | |
} | |
//si el modo es de jugador vs computadora entonces copiamos "computadora" al texto de nombre del jugador 2 | |
if(modoJuego == 2){ | |
strcpy(JUGADOR2, "COMPUTADORA"); | |
} | |
} | |
int main(){ | |
//inicializa el dado | |
srand((unsigned) time(0)); | |
if(menuJugadores() == 0) return 0; // si el modo de juego es 0 salimos, no hay jugadores | |
//bucle principal | |
// while 1 sera un bucle infinito hasta que se salga usando "break;" | |
while(1) | |
{ | |
//para el jugador 1 se calcula la nueva posicion de la ficha | |
posicion1 = moverFicha(JUGADOR1, posicion1); | |
ponerMapa(); //dibujamos el mapa | |
if(posicion1>=100) break; //si el jugador 1 gano, terminamos el bucle while | |
// esperamos que el siguiente jugador presione enter para iniciar su turno | |
printf("persiona enter para el siguiente turno"); | |
getchar(); | |
if(modoJuego == 3) continue; //si es jugador solo, volvemos al inicio del bucle | |
//si estamos en modo de jugador contra computadora esto se ejecuta automatico | |
//para el jugador 2 se caulcula la nueva posicion de la ficha | |
posicion2 = moverFicha(JUGADOR2, posicion2); | |
ponerMapa(); | |
if(posicion2>=100) break; //si el jugador 2 gano, terminamos el bucle whle | |
//esperamos que el primer jugador presione enter para iniciar su turno | |
printf("persiona enter para el siguiente turno"); | |
getchar(); | |
} | |
//al llegar aqui la partida ha terminado, escribimos quien gano y tocamos la musica de victoria | |
musica(3); | |
if(posicion1 >= 100) printf("Gano la partida: %s", JUGADOR1); | |
if(posicion2 >= 100) printf("Gano la partida: %s", JUGADOR2); | |
printf("\n\n"); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment