class Simulador(object): """ Motores de simulacion de probabilidades para situaciones aleatorias""" def __init__(self, ultima_simulacion = 0): self.ultima_simulacion = ultima_simulacion self.dado = Dados() def ataque_individual(self, atacante, atacado, minatk = 1, maxdef = 0): """ Recibe la cantidad de ejercitos de cada lado, un minimo de ejercitos a conservar, y la cantidad tolerada de ejercitos enemigos sobrevivientes. Devuelve True si consigue destruir el minimo de ejercitos enemigos o False si no lo logra para cuando le quedan igual o menos ejercitos que el minimo propio. """ if atacado <= maxdef: return True elif atacante <= minatk: return False else: self.dado.lanzar_dados(atacante, atacado) self.ultima_simulacion = self.ataque_individual(atacante - self.dado.ejercitos_perdidos_atacante(), \ atacado - self.dado.ejercitos_perdidos_atacado(), minatk, maxdef) return self.ultima_simulacion def ataque(self, atacante, atacado, minatk = 1, maxdef = 0, precision = 1000): """ Corre mil veces la funcion ataque_individual, y devuelve la probabilidad (estimada) de victoria con esos ejercitos y limites """ ganados = 0 for i in xrange(precision): gane_combate = self.ataque_individual(atacante, atacado, minatk, maxdef) if gane_combate: ganados += 1 return ganados*1.0 / precision def ver_ultima_simulacion(self): """Devuelve el resultado del la ultima simulacion. """ return self.ultima_simulacion
class TEG(object): """Implementa la logica de una partida de TEG.""" def __init__(self): """Constructor de la clase. Inicializa la interfaz grafica y los objetos que va a utilizar durante el juego.""" self.mazo = Mazo(paises.paises_por_tarjeta) self.dados = Dados() self.tablero = Tablero(paises.paises_por_continente, paises.paises_limitrofes) Interfaz.iniciar(paises.coordenadas_de_paises, paises.archivo_tablero, paises.color_tablero) self.jugadores = [] # Eventualmente aca haya falta agregar mas cosas... def configurar_el_juego(self): """Pone a los jugadores en el juego.""" Interfaz.setear_titulo('Configurando el juego') n = Interfaz.elegir('Jugadores', 'Seleccione el numero de jugadores', range(2,7)) nombre_colores = NOMBRE_COLORES.values() for i in range(n): nombre = Interfaz.elegir('Jugador %d' % (i + 1), 'Ingrese el nombre del jugador %d' % (i + 1)) color = Interfaz.elegir('Jugador %d' % (i + 1), 'Ingrese el color del jugador %d' % (i + 1), nombre_colores) nombre_colores.remove(color) c = NOMBRE_COLORES.keys()[NOMBRE_COLORES.values().index(color)] self.jugadores.append(Jugador(c, nombre)) def repartir_paises(self): """Reparte en ronda las tarjetas de paises y pone un ejercito en cada uno de los paises.""" Interfaz.setear_titulo('Repartiendo paises iniciales') ntarjetas = self.mazo.cantidad_tarjetas() njugadores = len(self.jugadores) for jugador in \ self.jugadores * (ntarjetas / njugadores) + \ random.sample(self.jugadores, ntarjetas % njugadores): t = self.mazo.sacar_tarjeta() self.tablero.ocupar_pais(t.pais, jugador.color, 1) self.mazo.devolver_tarjeta(t) def agregar_ejercitos_inicial(self, inicia_ronda): """Realiza la primer fase de colocacion de ejercitos.""" Interfaz.setear_titulo('Incorporando ejercitos') ejercitos_primera = int(math.ceil(self.tablero.cantidad_paises() / 10.0)) ejercitos_segunda = int(math.ceil(self.tablero.cantidad_paises() / 20.0)) for cantidad in (ejercitos_primera, ejercitos_segunda): for i in range(len(self.jugadores)): jugador = self.jugadores[(inicia_ronda + i) % len(self.jugadores)] Interfaz.alertar(jugador, '%s pone ejercitos' % jugador) # cantidad de ejercitos #en cualquier continente ejercitos = jugador.agregar_ejercitos(self.tablero, {"": cantidad}) assert(sum(ejercitos.values()) == cantidad) for pais in ejercitos: assert(self.tablero.color_pais(pais) == jugador.color) self.tablero.asignar_ejercitos(pais, ejercitos[pais]) self.tablero.actualizar_interfaz() def realizar_fase_ataque(self, jugador): """Implementa la fase de ataque de un jugador. Sucesivamente hace combatir a los paises seleccionados. Devuelve el numero de paises conquistados.""" Interfaz.setear_titulo('%s ataca' % jugador) Interfaz.alertar(jugador, '%s ataca' % jugador) paises_ganados = 0 while True: ataque = jugador.atacar(self.tablero) if not ataque: break atacante, atacado = ataque assert(self.tablero.es_limitrofe(atacante, atacado)) assert(self.tablero.ejercitos_pais(atacante) > 1) self.dados.lanzar_dados(self.tablero.ejercitos_pais(atacante), self.tablero.ejercitos_pais(atacado)) self.tablero.asignar_ejercitos(atacante, -self.dados.ejercitos_perdidos_atacante()) self.tablero.asignar_ejercitos(atacado, -self.dados.ejercitos_perdidos_atacado()) Interfaz.setear_titulo('%s: -%d, %s: -%d %s' % (atacante, self.dados.ejercitos_perdidos_atacante(), atacado, self.dados.ejercitos_perdidos_atacado(), self.dados)) if self.tablero.ejercitos_pais(atacado) == 0: paises_ganados += 1 mover = Interfaz.elegir(jugador, 'Cuantos ejercitos se desplazan a %s?' % atacado, range(1, min(self.tablero.ejercitos_pais(atacante) - 1, 3) + 1)) self.tablero.asignar_ejercitos(atacante, -mover) self.tablero.ocupar_pais(atacado, jugador.color, mover) self.tablero.actualizar_interfaz() else: self.tablero.actualizar_interfaz() time.sleep(1) return paises_ganados def realizar_fase_reagrupamiento(self, jugador): """ Realiza el reagrupamiento de ejercitos. """ Interfaz.setear_titulo('%s reagrupa' % jugador) Interfaz.alertar(jugador, '%s reagrupa' % jugador) lista = jugador.reagrupar(self.tablero) # Se fija que el reagrupamiento sea consistente: salientes = {} for origen, destino, cantidad in lista: assert(self.tablero.es_limitrofe(origen, destino)) assert(self.tablero.color_pais(origen) == jugador.color) assert(self.tablero.color_pais(destino) == jugador.color) salientes[origen] = salientes.get(origen, 0) + cantidad for pais in salientes: assert(self.tablero.ejercitos_pais(pais) > salientes[pais]) # Aplica la lista de cambios: for origen, destino, cantidad in lista: self.tablero.asignar_ejercitos(origen, -cantidad) self.tablero.asignar_ejercitos(destino, cantidad) def manejar_tarjetas(self, jugador, paises_ganados): """ Realiza la fase de obtencion de tarjetas de pais. 1) Si el jugador gano un pais del cual no habia usado una tarjeta que posee, se colocan 2 ejercitos en ese pais. 2) Si el jugador realizo menos de 3 canjes y gano al menos un pais o si realizo 3 o mas cajes y gano al menos dos paises, recibe una nueva tarjeta de pais. 3) Si recibio tarjeta de pais y posee ese pais, recibe 2 ejercitos adicionales en el mismo. """ raise NotImplementedError() def agregar_ejercitos(self, inicia_ronda): """Realiza la fase general de colocacion de ejercitos. La cantidad de ejercitos a agregar son: 1) Si el jugador tiene tres tarjetas con el mismo simbolo o si tiene tres tarjetas con distinto simbolo, entonces se realizara el canje. Cuando se realiza el canje, las tarjetas del jugador se devuelven al mazo. El primer canje otorgara 4 ejercitos adicionales para ser colocados en cualquier pais, el segundo 7, el tercero 10 y a partir de ahi 15, 20, 25, etc. 2) El jugador agregara tantos ejercitos como paises / 2 posea (division entera, truncando) en cualquiera de sus paises. 3) Si el jugador poseyera continentes completos agregara el adicional que indica ejercitos_por_continente obligatoriamente en dicho continente.""" raise NotImplementedError def jugador_es_ganador(self, jugador): """Verifica si el jugador gano el juego. Un jugador gana el juego si conquista el 100% de los paises.""" raise NotImplementedError def jugador_esta_vivo(self, jugador): """Verifica si un jugador sigue en carrera. Un jugador muere cuando se queda sin paises.""" raise NotImplementedError def jugar(self): Interfaz.setear_titulo('Trabajo de Entrega Grupal') Interfaz.alertar('Bienvenido!', 'Bienvenido al Trabajo de Entrega Grupal') # Se selecciona el numero de jugadores y se crean los mismos: self.configurar_el_juego() # Se reparten los paises iniciales: self.repartir_paises() self.tablero.actualizar_interfaz() # Se sortea que jugador iniciara el juego: inicia_ronda = random.randrange(len(self.jugadores)) Interfaz.setear_texto("Ronda: %s" % self.texto_ronda(inicia_ronda)) # Primer refuerzo de ejercitos: self.agregar_ejercitos_inicial(inicia_ronda) # Bucle principal del juego: while Interfaz.esta_corriendo(): # Para cada jugador en la ronda: for i in range(len(self.jugadores)): jugador = self.jugadores[(inicia_ronda + i) % len(self.jugadores)] # El jugador puede haber muerto durante esta ronda: if not self.jugador_esta_vivo(jugador): continue # El jugador juega su fase de ataques: paises_ganados = self.realizar_fase_ataque(jugador) # Se verifica si gano el juego: if self.jugador_es_ganador(jugador): Interfaz.alertar('Hay ganador!', 'El jugador %s ha ganado el juego' % jugador) return # El jugador realiza sus reagrupamientos: self.realizar_fase_reagrupamiento(jugador) # Se entrega la tarjeta y se verifica si ocupa # algun pais del cual posee tarjeta. self.manejar_tarjetas(jugador, paises_ganados) # Si algun jugador hubiera perdido durante la ronda # anterior se lo saca del juego: for i in range(len(self.jugadores) - 1, -1, -1): if not self.jugador_esta_vivo(self.jugadores[i]): Interfaz.alertar('Uno menos!', 'El jugador %s ha quedado eliminado' % jugador) self.jugadores.pop(i) if inicia_ronda >= i: inicia_ronda -= 1 # La siguiente ronda es iniciada por el siguiente jugador: inicia_ronda = (inicia_ronda + 1) % len(self.jugadores) Interfaz.setear_texto("Ronda: %s" % self.texto_ronda(inicia_ronda)) # Los jugadores refuerzan sus ejercitos: self.agregar_ejercitos(inicia_ronda) def texto_ronda(self, inicia_ronda): """Magia negra de Python. (Devuelve el nombre de los jugadores en el orden de la ronda.)""" return ', '.join([str(x) for x in self.jugadores[inicia_ronda:] + self.jugadores[:inicia_ronda]])