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()