179 lines
6.6 KiB
Python
179 lines
6.6 KiB
Python
|
import random
|
|||
|
import re
|
|||
|
import os
|
|||
|
|
|||
|
|
|||
|
# Limpiar Pantalla
|
|||
|
cl = lambda: os.system('clear') if os.name == 'posix' else os.system('cls')
|
|||
|
|
|||
|
class Tablero:
|
|||
|
"""
|
|||
|
Creación de objeto tablero que representa al juego 'BuscaMinas'
|
|||
|
"""
|
|||
|
|
|||
|
def __init__(self, dim_size, num_bombs):
|
|||
|
self.dim_size = dim_size
|
|||
|
self.num_bombs = num_bombs
|
|||
|
|
|||
|
# Crear tablero (helper function?)
|
|||
|
self.tablero = self.hacer_nuevo_tablero() # Plantar bombas
|
|||
|
self.asignar_valores_a_tablero()
|
|||
|
|
|||
|
# Inicializar un set() para hacer seguimiento de las locaciones descubiertas
|
|||
|
# se almacenan tuplas (fila, columna) en este set
|
|||
|
self.excavado = set()
|
|||
|
|
|||
|
def hacer_nuevo_tablero(self):
|
|||
|
"""
|
|||
|
Cronstruye un nuevo tablero según dim_size y num_bombs.
|
|||
|
Basado en una lista de listas (represantación 2-D)
|
|||
|
"""
|
|||
|
# generar nuevo tablero
|
|||
|
tablero = [[None for _ in range(self.dim_size)] for _ in range(self.dim_size)]
|
|||
|
# Contruye algo como esto:
|
|||
|
# [ [None, None, .., None],
|
|||
|
# [None, None, .., None],
|
|||
|
# [... ...],
|
|||
|
# [None, None, .., None] ]
|
|||
|
|
|||
|
# Plantar bombas
|
|||
|
bombas_plantadas = 0
|
|||
|
while bombas_plantadas < self.num_bombs:
|
|||
|
loc = random.randint(0, self.dim_size ** 2 - 1)
|
|||
|
fil = loc // self.dim_size
|
|||
|
col = loc % self.dim_size
|
|||
|
|
|||
|
if tablero[fil][col] == '💥️':
|
|||
|
continue # ignorar
|
|||
|
tablero[fil][col] = '💥️' # plantar bomba
|
|||
|
bombas_plantadas += 1
|
|||
|
return tablero
|
|||
|
|
|||
|
def asignar_valores_a_tablero(self):
|
|||
|
"""
|
|||
|
Asigna números enteros de 0 a 8 a cada espacio vacío, según
|
|||
|
cuantas bombas existan al rededor
|
|||
|
"""
|
|||
|
for f in range(self.dim_size):
|
|||
|
for c in range(self.dim_size):
|
|||
|
if self.tablero[f][c] == '💥️':
|
|||
|
continue # si ya es una bomba
|
|||
|
self.tablero[f][c] = self.get_num_bombs_cercanas(f, c)
|
|||
|
|
|||
|
def get_num_bombs_cercanas(self, fil, col):
|
|||
|
"""
|
|||
|
Itera cada cuadrante cercano y suma el número de bombas
|
|||
|
'top left: (fil-1, col-1) top middle: (fil-1, col) top right: (fil-1, col+1)'
|
|||
|
' left: ( fil, col-1) right : ( fil, col+1)'
|
|||
|
'bot left: (fil+1, col-1) bot middle: (fil+1, col) bot right: (fil+1, col+1)'
|
|||
|
"""
|
|||
|
num_bombs_cerca = 0
|
|||
|
for f in range( max(0, fil-1), min(self.dim_size-1, fil+1) +1):
|
|||
|
for c in range( max(0, col-1), min(self.dim_size-1, col+1) +1):
|
|||
|
if f == fil and c == col:
|
|||
|
continue # posicion original, no checkear
|
|||
|
if self.tablero[f][c] == '💥️':
|
|||
|
num_bombs_cerca += 1
|
|||
|
return num_bombs_cerca
|
|||
|
|
|||
|
def excavar(self, fil, col):
|
|||
|
"""
|
|||
|
Busca minas en la posicion, retorna True si tiene exito
|
|||
|
False si es una bomba (gameover), si no hay bombas cercanas
|
|||
|
la busqueda sigue recursivamente
|
|||
|
"""
|
|||
|
self.excavado.add((fil, col)) # seguimiento de locaciones 'excavadas'
|
|||
|
if self.tablero[fil][col] == '💥️':
|
|||
|
return False
|
|||
|
elif self.tablero[fil][col] > 0:
|
|||
|
return True
|
|||
|
|
|||
|
# self.tablero[fil][col] == 0
|
|||
|
for f in range( max(0, fil-1), min(self.dim_size-1, fil+1) +1):
|
|||
|
for c in range( max(0, col-1), min(self.dim_size-1, col+1) +1):
|
|||
|
if (f, c) in self.excavado:
|
|||
|
continue # no 'excava' donde ya se ha 'excavado'
|
|||
|
self.excavar(f, c)
|
|||
|
return True
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
"""
|
|||
|
Retorna un string con la represantación del tablero de juego
|
|||
|
"""
|
|||
|
tablero_visible = [[None for _ in range(self.dim_size) ] for _ in range(self.dim_size)]
|
|||
|
for fil in range(self.dim_size):
|
|||
|
for col in range(self.dim_size):
|
|||
|
if (fil, col) in self.excavado:
|
|||
|
tablero_visible[fil][col] = str(self.tablero[fil][col])
|
|||
|
else:
|
|||
|
tablero_visible[fil][col] = ' '
|
|||
|
# Formato de string para represantación de tablero
|
|||
|
string_rep = ''
|
|||
|
anchos = [] # anchos maximo de columna para print
|
|||
|
for idx in range(self.dim_size):
|
|||
|
columnas = map(lambda x: x[idx], tablero_visible)
|
|||
|
anchos.append(len(max(columnas, key = len)))
|
|||
|
|
|||
|
# print the csv strings
|
|||
|
indices = [i for i in range(self.dim_size)]
|
|||
|
indices_fil = ' '
|
|||
|
cells = []
|
|||
|
for idx, col in enumerate(indices):
|
|||
|
format = '%-' + str(anchos[idx]) + "s"
|
|||
|
cells.append(format % (col))
|
|||
|
indices_fil += ' '.join(cells)
|
|||
|
indices_fil += ' \n'
|
|||
|
|
|||
|
for i in range(len(tablero_visible)):
|
|||
|
fila = tablero_visible[i]
|
|||
|
string_rep += f'{i} |'
|
|||
|
cells = []
|
|||
|
for idx, col in enumerate(fila):
|
|||
|
format = '%-' + str(anchos[idx]) + "s"
|
|||
|
cells.append(format % (col))
|
|||
|
string_rep += ' |'.join(cells)
|
|||
|
string_rep += ' |\n'
|
|||
|
|
|||
|
str_len = int(len(string_rep) / self.dim_size)
|
|||
|
string_rep = indices_fil + '-'*str_len + '\n' + string_rep + '-'*str_len
|
|||
|
|
|||
|
return string_rep
|
|||
|
|
|||
|
def jugar(dim_size = 10, num_bombs = 10):
|
|||
|
"""
|
|||
|
Comenzar juego
|
|||
|
Paso 1 : Crear tablero y plantar bombas
|
|||
|
Paso 2 : Mostrar tablero y preguntar donde excavar
|
|||
|
Paso 3a: Si se elige el lugar donde hay una bomba, muestra Game Over
|
|||
|
Paso 3b: Si el cuadrante no es una bomba, excava recursivamente hasta un cuadrante
|
|||
|
cercano a una bomba.
|
|||
|
Paso 4 : Repetir pasos 2 y 3 hasta que no queden espacios para excavar -> Victoria!
|
|||
|
"""
|
|||
|
# Paso 1
|
|||
|
safe = True
|
|||
|
tablero = Tablero(dim_size ,num_bombs)
|
|||
|
# Paso 2
|
|||
|
while len(tablero.excavado) < tablero.dim_size ** 2 - num_bombs:
|
|||
|
cl()
|
|||
|
print(tablero)
|
|||
|
# 3, 4 o 3, 4 o 3, 4
|
|||
|
user_input = re.split(',(\\s)*', input("Ingresa coordenada para buscar\n-> fila, columna : "))
|
|||
|
fil, col = int(user_input[0]), int(user_input[-1])
|
|||
|
if fil < 0 or fil >= tablero.dim_size or col < 0 or col >= dim_size:
|
|||
|
print("Posición invalida, prueba otra.")
|
|||
|
continue
|
|||
|
# si es valida
|
|||
|
safe = tablero.excavar(fil, col)
|
|||
|
if not safe:
|
|||
|
break # game over
|
|||
|
if safe:
|
|||
|
print("\n 🎉️FELICITACIONES!!🎊️ Ganaste 😎️ ")
|
|||
|
else:
|
|||
|
cl()
|
|||
|
tablero.excavado = [(f, c) for f in range(tablero.dim_size) for c in range(tablero.dim_size)]
|
|||
|
print(tablero)
|
|||
|
print("\n Perdiste! 👻️ \n")
|
|||
|
|
|||
|
if __name__ == '__main__':
|
|||
|
jugar()
|