24 octubre 2023

Generando números al azar en Python

Por lo menos en la programación, dejamos algunas cosas al azar. Es muy importante generar números al azar para diferentes tipos de aplicaciones, desde juegos, simulaciones y análisis de datos hasta ciberseguridad y mil aplicaciones más.

Para facilitarnos la vida, Python tiene un módulo, llamado random, que nos ayuda a generarlos. En este post te voy a mostrar cómo usarlo.

Antes de empezar...

Antes de poder empezar a generar números aleatorios, debes importar el módulo random. Puedes hacerlo con una simple declaración import al principio de tu programa:

import random

Con esto tu programa ya tiene acceso a varias funciones y clases para generar datos aleatorios, algunos de los cuales vamos a hablar más adelante.

Generando números enteros aleatorios

El módulo random proporciona la función randint(a, b) para generar un número entero aleatorio entre a y b, incluyendo ambos valores. Así es cómo puedes utilizarlo:

1 2 3 4
import random

entero_aleatorio = random.randint(1, 10)
print("Entero Aleatorio:", entero_aleatorio)

En este ejemplo, random.randint(1, 10) genera un número entero aleatorio entre 1 y 10, y el resultado se almacena en la variable entero_aleatorio. Puedes ajustar el rango para adaptarlo a tus necesidades específicas.

Generando números con decimales

No es tan común, pero a veces necesitas generar números que tengan decimales de forma aleatoria. Para esto puedes utilizar la función random.uniform(a, b). Genera un número de punto flotante aleatorio entre a y b. Aquí tienes un ejemplo:

1 2 3 4
import random

flotante_aleatorio = random.uniform(0.0, 1.0)
print("Número de Punto Flotante Aleatorio:", flotante_aleatorio)
Para terminar, les muestro el ejemplo de un programa que genera 10 números aleatorios enteros entre 5 y 30:
 
1 2 3 4 5 6 7 8 9 10 11 12
# Genero números al azar
# Este import me deja usar el objeto random
import random

print('10 números al azar entre 5 y 30...')
i = 0
while i < 10:
    # random.randint de devuelve un número al azar entre...
    # ...los números que le diga, en este caso, entre 5 y 30.
    print(random.randint(5,30))
    i = i + 1
input('Fin del programa, presione ENTER para salir');
random tiene muchas otras funciones en los que no me voy a meter pero que estos son los principales o más usuales. Espero que les haya sido de utilidad. ¡Hasta la próxima!

09 octubre 2023

Revolviendo vectores

El otro día estaba tratando de hacer un programa que te permite jugar 21 (Blackjack), aunque no fuera de forma "completa", más bien como un ejercicio del uso de vectores, clases y objetos en C++.

Uno de los problemas era revolver una baraja. Como ya he hablado de cómo generar números aleatorios en C++, pensé una forma de generar números al azar e irlos cambiando con los que están, pero supuse que debía haber una mejor manera, algo más sencillo. Y sabía que en Java había forma de trabajar con ArrayLists, así que me puse a buscar cómo se puede hacer en C++. Y sí, hay una función que me puede "mezclar" al azar (o pseudoazar, como hemos dicho cuando hablé de números aleatorios), e incluso escribí brevemente sobre cómo usarlo, pero aquí te explico cómo usarlo con un ejemplo más completo.

El método en cuestión es el random_shuffle y para poderlo usar, tienes que incluir la librería <algorithm>. Y necesita el uso de números aleatorios (si no sabes cómo funcionan, lee primero este post de mi blog), así que incluimos la librería <cstdlib> para usar el srand y el rand, y la librería <ctime> para obtener la hora del sistema para inicializar el generador de números pseudoaleatorios. Así que la pura parte de la declaración, quedaría así:

1 2 3 4 5
#include <iostream>			// cout, cin
#include <vector>			// vector
#include <algorithm>		// random_shuffle
#include <ctime>			// Para usar time() - inicializar números aleatorios
#include <cstdlib>			// srand, rand
Después de esto, en el main() antes en hacer cualquier otra cosa, inicializo el generador de números aleatorios con el reloj del sistema, como se ve aquí:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
Esto va al principio del main():

    srand(time(NULL));
	baraja.Barajear();

En la clase Baraja viene estos métodos:

// Genera números aleatorios (para uso con random_shuffle)
int myrandom (int i) { return rand()%i;}

// Barajear: barajea toda la baraja
void Baraja::Barajear() {
	random_shuffle(cartas.begin(),cartas.end(),myrandom);
}
Aquí viene una parte que va en el main() y también estoy mostrando el método de la clase Baraja (al rato pongo todo el código) que barajea (revuelve) los elementos del vector. También agrego una función, llamado myrandom, que no pertenece a ninguna clase, que genera los números aleatorios para ser usados en el método random_shuffle.

Aquí pongo el código completo. El archivo tiene una clase Carta que guarda el palo (corazones, trébol, etc.), el valor o rango (As, 2, 3, etc) y si está visible o no. Tiene un constructor que recibe dos cadenas (palo y rango) y métodos para voltear una carta, devolver los datos de una carta, saber si está visible o no y para devolver el valor (rango).

Luego tiene una clase Baraja que tiene un vector de objetos Carta, un constructor que inicializa el vector con todas las cartas de una baraja inglesa (para eso hay un par de arreglos para ayudar a inicializar) y métodos que te devuelve una carta (y lo quita del vector), para barajear la carta (lo que mostré en el código anterior), para imprimir todas las cartas en la baraja, y una que nos indica si la baraja está vacía o no.

También hay una clase Jugador que tiene las manos de cada jugador: guarda un vector de tipo Carta y una cadena con el nombre del jugador. No tiene constructor y tiene métodos para Agregar una carta al vector del jugador, devolver el número de cartas que tiene, mostrar sus cartas, asignar un nombre al jugador y para mostrar el nombre del jugador.

El main() declara una Baraja y un vector de Jugador, inicializa la baraja (con un código que mostré con anterioridad), pide número de jugadores, pide las cartas para cada jugador, revisa si alguien ganó justo después de repartir las cartas (poco probable, pero hay que revisar) e inicia un ciclo donde muestra cartas del jugador y le pregunta si desea otra carta, revisa si perdió o si ganó. Si nadie ha ganado, al final determina el ganador (el que más cera esté de sumar 21).

Con esa explicación, ahora sí les dejo el código completo del programa, esperando que les sea de utilidad. ¡Saludos!

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
/* ****
 * Juego de 21
 * ****/

#include <iostream>			// cout, cin
#include <vector>			// vector
#include <string>			// uso strings
#include <algorithm>		// random_shuffle
#include <ctime>			// Para usar time() - inicializar números aleatorios
#include <cstdlib>			// srand, rand

using namespace std;

/* ***
 * CLASE Carta 
 * *** */
class Carta {
	// Campos privados
	string palo,rango;
	bool visible;
	
	// Constructor
	public:
	    Carta(string,string);
	
	// Métodos
		void Voltear() {
			visible = !visible;
		}
		string Imprimir();
	    bool Visible() {
	    	return visible;
		}
		string Rango() {
			return rango;
		}
};

// Constructor
Carta::Carta(string palo,string rango) {
	this->palo = palo;
	this->rango = rango;
	visible = false;
}

// Imprimir
string Carta::Imprimir() {
	string x;
	x.append(rango).append(" de ").append(palo);
	return x;
}

/* ***
 * CLASE Baraja
 * ***/
class Baraja {
	// Campos
	private:
		vector <Carta> cartas;
	
	// Constructor
	public:
		Baraja();
		
	// Métodos
		Carta TomaCarta();
		void Barajear();
		void Imprimir();
		//void Partir(int);
		bool Vacia() {
			return cartas.empty();
		}
};

// Declaro arreglos útiles para inicializar
string rangos[] = {"As","2","3","4","5","6","7","8","9","10","Joto","Reina","Rey"};
string palos[] = {"Corazones","Diamantes","Treboles","Picas"};

// Constructor: llena la baraja con 52 cartas
Baraja::Baraja() {
	int i,j;
	
	for (i=0;i<4;i++) {
		for (j=0;j<13;j++) {
			Carta temp(palos[i],rangos[j]);
			cartas.push_back(temp);
		}
	}
}

// Imprimir: Imprime todas las cartas de la baraja
void Baraja::Imprimir() {
	int i;
	
	for (i=0;i<cartas.size();i++) {
		cout << cartas[i].Imprimir() << endl;
	}
}

// Genera números aleatorios (para uso con random_shuffle)
int myrandom (int i) { return rand()%i;}

// Barajear: barajea toda la baraja
void Baraja::Barajear() {
	random_shuffle(cartas.begin(),cartas.end(),myrandom);
}

// TomaCarta: Devuelve la última carta de la baraja
Carta Baraja::TomaCarta() {
	Carta x = cartas[cartas.size()-1];  		// x = la última carta
	cartas.pop_back();							// Elimino la última carta de la baraja
	return x;									// Devuelvo x
}

/* ***
 * CLASE: Jugador
 * ***/
class Jugador {
	// Campos
	private:
		vector<Carta> cartas;
		string nombre;
	
	// Métodos
	public:
		void AgregarCarta(Carta);
		// Devuelve el número de cartas que tengo en las manos
		int NumCartas() {
			return cartas.size();
		}
		int SumaCartas();
		string MuestraCartas();
		void AsignaNombre(string nombre) {
			this->nombre = nombre;
		}
		string MuestraNombre() {
			return nombre;
		}
};

// Agrega una carta a las que tengo en mis manos
void Jugador::AgregarCarta(Carta c) {
	cartas.push_back(c);
}

// Devuelve la suma de las cartas
int Jugador::SumaCartas() {
	int i,suma=0,temp;
	string r;
	
	for(i=0;i<cartas.size();i++) {
		r = cartas[i].Rango();
		if (r.compare("As")==0) {
			suma += 11;
		} else if (r.compare("Joto")==0 || r.compare("Reina")==0 || r.compare("Rey")==0) {
			suma += 10;
		} else {
			temp = stoi(r);		// Obtiene el entero que hay en la cadena del rango
			suma += temp;
		}
	}
	
	// Si me pasé de 21, veo si hubo As. Si hay, le resto 10
	if (suma > 21) {
		for(i=0;i<cartas.size();i++) {
			if (cartas[i].Rango().compare("As")==0) {
				suma -= 10;
			}
		}
	}
	
	return suma;
}

// Devuelve una cadena con las cartas del jugador
string Jugador::MuestraCartas() {
	string temp;
	int i;
	
	for (i=0;i<cartas.size();i++) {
		temp.append(cartas[i].Imprimir()).append("\n");
	}
	return temp;
}

int main() {
	// Declaro variables y objetos
	Baraja baraja;
	int i,j,noJugadores = 0;
	vector <Jugador> jugadores;
	string siono;
	
	// Preparo la baraja
	srand(time(NULL));
	baraja.Barajear();
	
	// Preguntar número de jugadores
	while (noJugadores < 2 || noJugadores > 4) {
		cout << "Numero de jugadores: ";
		cin >> noJugadores;
	}
	getline(cin,siono);
	
	// Pedir cartas
	Jugador x;
	for (i=0;i<noJugadores;i++) {		// Creo un vector de jugadores del tamaño adecuado
		cout << "Nombre: ";
		getline(cin,siono);
		x.AsignaNombre(siono);
		jugadores.push_back(x);
	}
	for (i=0;i<2;i++) {					// Se reparten 2 cartas a cada jugador
		for (j=0;j<noJugadores;j++) {	// Se reparten a todos los jugadores
			jugadores[j].AgregarCarta(baraja.TomaCarta());
		}
	}
	
	// Si alguien tiene 21 (ya ganó desde el inicio)
	for (i=0;i<noJugadores;i++) {
		if (jugadores[i].SumaCartas() == 21) {
			cout << "¡Ganó el jugador " << jugadores[i].MuestraNombre() 
				<< "! Sus cartas fueron:\n" << jugadores[i].MuestraCartas();
			return 1;
		}
	}
	
	// Ciclo de pedir cartas
	for (i=0;i<noJugadores;i++) {
		do {
			// Muestro las cartas del jugador y le pregunto si quiere otra
			cout << jugadores[i].MuestraNombre() << ", tus cartas son:\n";
			cout << jugadores[i].MuestraCartas() << endl;
			cout << "Jugador " << jugadores[i].MuestraNombre() <<
				", ¿Otra carta (S/N)? ";
			getline(cin,siono);
			if (siono[0] == 'S' || siono[0] == 's') {
				jugadores[i].AgregarCarta(baraja.TomaCarta());
				// Si perdió, elimino al jugador y decremento noJugadores
				if (jugadores[i].SumaCartas() > 21) {
					cout << "Jugador " << jugadores[i].MuestraNombre()
						<< " perdió. Sus cartas suman " << 
						jugadores[i].SumaCartas() << "\nY sus cartas son\n"
						<< jugadores[i].MuestraCartas() << endl;
					jugadores.erase(jugadores.begin()+i);
					noJugadores --;
				} else if (jugadores[i].NumCartas() == 5) {	// Si llega a tener 5 cartas y no se pasa, gana
					cout << jugadores[i].MuestraNombre() 
						<< ", ¡ganaste! Tienes 5 cartas y no te pasaste de 21. "
						<< "Tus cartas fueron:\n" << jugadores[i].MuestraCartas() << endl;
					return 1;
				} else if (jugadores[i].SumaCartas() == 21) {	// Si sus cartas suman 21, gana
					cout << jugadores[i].MuestraNombre() 
						<< ", ¡ganaste! Tus cartas suman 21. "
						<< "Tus cartas fueron:\n" << jugadores[i].MuestraCartas() << endl;
					return 1;
				}
			}
		} while (siono[0] != 'N' && siono[0] != 'n');
	}
	
	// Ver quien ganó (de los que quedan)
	j = 0;				// En j guardo el índice de quien ganó
	if (!jugadores.empty()) {
		for (i=1;i<noJugadores;i++) {
			if (jugadores[i].SumaCartas() > jugadores[j].SumaCartas()) {
				j = i;
			}
		}
		cout << "El ganador es " << jugadores[j].MuestraNombre() << 
			" y sus cartas fueron:\n" << jugadores[j].MuestraCartas() << endl;
	} else {
		cout << "Todos perdieron\n";
	}
}

El Tony y sus ondas...

Related Posts Plugin for WordPress, Blogger...