Skip to content

Instantly share code, notes, and snippets.

@ZaidaZadkiel
Created February 10, 2022 01:11
Show Gist options
  • Save ZaidaZadkiel/4923f64487b6a8eca7debe0caa649d75 to your computer and use it in GitHub Desktop.
Save ZaidaZadkiel/4923f64487b6a8eca7debe0caa649d75 to your computer and use it in GitHub Desktop.
Serpientes y Escaleras en modo consola en C con sonido portable
#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