Skip to content

Commit 0d9b8be

Browse files
authored
Merge pull request mouredev#6106 from avcenal/main
mouredev#33 mouredev#34 mouredev#35 - Python
2 parents 6714677 + 08dd85c commit 0d9b8be

File tree

3 files changed

+783
-0
lines changed
  • Roadmap
    • 33 - RESCATANDO A MICKEY/python
    • 34 - ÁRBOL GENEALÓGICO LA CASA DEL DRAGÓN/python
    • 35 - REPARTIENDO LOS ANILLOS DE PODER/python

3 files changed

+783
-0
lines changed
Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
"""
2+
* EJERCICIO:
3+
* ¡Disney ha presentado un montón de novedades en su D23!
4+
* Pero... ¿Dónde está Mickey?
5+
* Mickey Mouse ha quedado atrapado en un laberinto mágico
6+
* creado por Maléfica.
7+
* Desarrolla un programa para ayudarlo a escapar.
8+
* Requisitos:
9+
* 1. El laberinto está formado por un cuadrado de 6x6 celdas.
10+
* 2. Los valores de las celdas serán:
11+
* - ⬜️ Vacío
12+
* - ⬛️ Obstáculo
13+
* - 🐭 Mickey
14+
* - 🚪 Salida
15+
* Acciones:
16+
* 1. Crea una matriz que represente el laberinto (no hace falta
17+
* que se genere de manera automática).
18+
* 2. Interactúa con el usuario por consola para preguntarle hacia
19+
* donde se tiene que desplazar (arriba, abajo, izquierda o derecha).
20+
* 3. Muestra la actualización del laberinto tras cada desplazamiento.
21+
* 4. Valida todos los movimientos, teniendo en cuenta los límites
22+
* del laberinto y los obtáculos. Notifica al usuario.
23+
* 5. Finaliza el programa cuando Mickey llegue a la salida.
24+
"""
25+
#A pesar de que en el ejercicio no se pide, el programa genera el laberinto de manera automática
26+
#Esto tiene varias limitaciones a nivel de cuántos obstáculos se pueden colocar para que el juego tenga solución
27+
28+
from abc import ABC,abstractmethod
29+
from random import randint,shuffle
30+
from math import ceil
31+
32+
#Clases Abstractas
33+
class AbstractBoardGenerator(ABC):
34+
@abstractmethod
35+
def create_board(self):
36+
pass
37+
38+
class AbstractPlaceMickeyAndExit(ABC):
39+
@abstractmethod
40+
def place_mickey_and_exit(self,board:AbstractBoardGenerator):
41+
pass
42+
43+
class AbstractObstaclesGenerator(ABC):
44+
@abstractmethod
45+
def place_obstacles(self,board:AbstractBoardGenerator):
46+
pass
47+
48+
class AbstractBoardChecker(ABC):
49+
@abstractmethod
50+
def confirm_board(self,board:AbstractBoardGenerator):
51+
pass
52+
53+
class AbstractBoardPrinter(ABC):
54+
@abstractmethod
55+
def print_board(self,board:AbstractBoardGenerator):
56+
pass
57+
58+
class AbstractMickeyMove(ABC):
59+
@abstractmethod
60+
def __init__(self):
61+
pass
62+
63+
@abstractmethod
64+
def move_up(self):
65+
pass
66+
67+
@abstractmethod
68+
def move_down(self):
69+
pass
70+
71+
@abstractmethod
72+
def move_left(self):
73+
pass
74+
75+
@abstractmethod
76+
def move_right(self):
77+
pass
78+
79+
class AbstractMoveChecker(ABC):
80+
@abstractmethod
81+
def check_move(self,board:AbstractBoardGenerator):
82+
pass
83+
84+
#Clases del programa que implementan las abstractas
85+
86+
#Clase que se ocupa de colocar a Mickey y la Salida
87+
class PlaceMickeyAndExit(AbstractPlaceMickeyAndExit):
88+
def place_mickey_and_exit(self,board:AbstractBoardGenerator):
89+
while True:
90+
mickey_row = randint(0,board.number_of_rows-1)
91+
mickey_column = randint(0,board.number_of_columns-1)
92+
if mickey_row == 0:
93+
out_row = 5
94+
out_column = randint(0,board.number_of_columns-1)
95+
break
96+
elif mickey_row == 5:
97+
out_row = 0
98+
out_column = randint(0,board.number_of_columns-1)
99+
break
100+
else:
101+
if mickey_column == 0:
102+
out_column = board.number_of_columns-1
103+
out_row = randint(0,board.number_of_rows-1)
104+
break
105+
elif mickey_column == board.number_of_columns-1:
106+
out_column = 0
107+
out_row = randint(0,board.number_of_rows-1)
108+
break
109+
110+
board.board[mickey_row][mickey_column] = "🐭"
111+
board.board[out_row][out_column] = "🚪"
112+
return mickey_row,mickey_column,out_row,out_column
113+
114+
class ObstaclesGenerator(AbstractObstaclesGenerator):
115+
#Método privado que genera 2 obstáculos por cuadrante de manera aleatoria
116+
def __set_obstacles_in_cuadrant(self,board:AbstractBoardGenerator,rows_start:int,rows_limit:int,columns_start:int,columns_limit:int,number_of_obstacles:int):
117+
index = 0
118+
positions = [(row, col) for row in range(rows_start, rows_limit + 1) for col in range(columns_start, columns_limit + 1)]
119+
shuffle(positions) # Mezclar posiciones para seleccionar aleatoriamente
120+
while index < number_of_obstacles:
121+
row, column = positions.pop()
122+
if board.board[row][column] == "⬜️":
123+
board.board[row][column] = "⬛️"
124+
index +=1
125+
#método que calcula cuántos obstáculos se han de colocar por cuadrante según el tamaño del tablero (2 en este ejercicio) y usa __set_obstacles_in_cuadrant para generarlos
126+
def place_obstacles(self,board:AbstractBoardGenerator):
127+
NUMBER_OF_OBSTACLES = ceil((board.number_of_rows*board.number_of_columns)*2/9/4) #la proporcion es 9/2, por cada 9 casillas se ponen un máximo de 2 obstáculos para que el laberinto tenga solución. El resultado se divide entre 4 cuadrantes
128+
#primer cuadrante
129+
rows_start = 0
130+
rows_limit = int(board.number_of_rows/2-1)
131+
colunms_start = 0
132+
columns_limit = int(board.number_of_columns/2-1)
133+
self.__set_obstacles_in_cuadrant(board,rows_start,rows_limit,colunms_start,columns_limit,NUMBER_OF_OBSTACLES)
134+
#segundo cuadrante
135+
rows_start = int(board.number_of_rows/2)
136+
rows_limit = board.number_of_rows-1
137+
colunms_start = 0
138+
columns_limit = int(board.number_of_columns/2-1)
139+
self.__set_obstacles_in_cuadrant(board,rows_start,rows_limit,colunms_start,columns_limit,NUMBER_OF_OBSTACLES)
140+
#tercer cuadrante
141+
rows_start = 0
142+
rows_limit = int(board.number_of_rows/2-1)
143+
colunms_start = int(board.number_of_columns/2)
144+
columns_limit = board.number_of_columns-1
145+
self.__set_obstacles_in_cuadrant(board,rows_start,rows_limit,colunms_start,columns_limit,NUMBER_OF_OBSTACLES)
146+
#cuarto cuadrante
147+
rows_start = int(board.number_of_rows/2)
148+
rows_limit = board.number_of_rows-1
149+
colunms_start = int(board.number_of_columns/2)
150+
columns_limit = board.number_of_columns-1
151+
self.__set_obstacles_in_cuadrant(board,rows_start,rows_limit,colunms_start,columns_limit,NUMBER_OF_OBSTACLES)
152+
153+
class BoardChecker(AbstractBoardChecker): #comprueba que ni Mickey ni la salida están bloqueados por obstáculos
154+
def __check_position(self,board:AbstractBoardGenerator,row:int,column:int): #este método privado revisa que Mickey o la Salida no estén rodeados por obstáculos devolviendo un boolean
155+
valid_position = True
156+
if row == 5:
157+
if board.board[row-1][column] == "⬛️" and board.board[row][column-1] == "⬛️" and board.board[row][column+1] == "⬛️":
158+
valid_position = False
159+
elif column == 5:
160+
if board.board[row-1][column] == "⬛️" and board.board[row+1][column] == "⬛️" and board.board[row][column-1] == "⬛️":
161+
valid_position = False
162+
elif row == 0:
163+
if board.board[row][column+1] == "⬛️" and board.board[row+1][column] == "⬛️" and board.board[row][column-1] == "⬛️":
164+
valid_position = False
165+
elif column == 0:
166+
if board.board[row-1][column] == "⬛️" and board.board[row+1][column] == "⬛️" and board.board[row][column+1] == "⬛️":
167+
valid_position = False
168+
elif row == 0 and column == 0:
169+
if board.board[row+1][column] == "⬛️" and board.board[row][column+1] == "⬛️":
170+
valid_position = False
171+
elif row == 5 and column == 5:
172+
if board.board[row-1][column] == "⬛️" and board.board[row][column-1] == "⬛️":
173+
valid_position = False
174+
elif row == 0 and column == 5:
175+
if board.board[row+1][column] == "⬛️" and board.board[row][column-1] == "⬛️":
176+
valid_position = False
177+
elif row == 5 and column == 0:
178+
if board.board[row-1][column] == "⬛️" and board.board[row][column+1] == "⬛️":
179+
valid_position = False
180+
else:
181+
if board.board[row-1][column] == "⬛️" and board.board[row+1][column] == "⬛️" and board.board[row][column-1] == "⬛️" and board.board[row][column+1] == "⬛️":
182+
valid_position = False
183+
184+
return valid_position
185+
186+
#Este método confirma el tablero apoyándose en __check_position. Si Mickey o la salida están rodeados, genera un nuevo tablero y lo comprueba de manera recursiva
187+
def confirm_board(self, board: AbstractBoardGenerator,place_mickey_and_exit:AbstractPlaceMickeyAndExit,obstacle_generator:AbstractObstaclesGenerator):
188+
if not self.__check_position(board,board.mickey_row,board.mickey_column) or not self.__check_position(board,board.out_row,board.out_column):
189+
board.create_blank_board()
190+
board.mickey_row,board.mickey_column,board.out_row,board.out_column = place_mickey_and_exit.place_mickey_and_exit(board)
191+
obstacle_generator.place_obstacles(board)
192+
self.confirm_board(board,place_mickey_and_exit,obstacle_generator)
193+
else:
194+
pass
195+
196+
class BoardPrinter(AbstractBoardPrinter): #imprime el tablero por consola
197+
def print_board(self,board:AbstractBoardGenerator):
198+
row_printed = ""
199+
index = 0
200+
for row in board.board:
201+
for index,column in enumerate(row):
202+
if index == len(row)-1:
203+
row_printed += f"{row[index]}\n"
204+
else:
205+
row_printed += f"{row[index]} "
206+
print (row_printed)
207+
row_printed = ""
208+
209+
class BoardGenerator(AbstractBoardGenerator): #genera el tablero en blanco y usa el resto de métodos para generar los obstáculos y colocar a Mickey y la salida
210+
def create_blank_board(self):
211+
for i in range (0,self.number_of_rows):
212+
row = []
213+
for index in range(0,self.number_of_columns):
214+
row.append("⬜️")
215+
self.board.append(row)
216+
217+
def create_board(self,number_of_rows:int,number_of_columns:int,place_mickey_and_exit:AbstractPlaceMickeyAndExit,place_obstacles:AbstractObstaclesGenerator,confirm_board:AbstractBoardChecker):
218+
self.number_of_rows:int = number_of_rows
219+
self.number_of_columns:int = number_of_columns
220+
self.board:list = []
221+
self.create_blank_board()
222+
self.mickey_row,self.mickey_column,self.out_row,self.out_column = place_mickey_and_exit.place_mickey_and_exit(self)
223+
place_obstacles.place_obstacles(self)
224+
confirm_board.confirm_board(self,place_mickey_and_exit,place_obstacles)
225+
return self.mickey_row,self.mickey_column,self.out_row,self.out_column
226+
227+
class MoveChecker(AbstractMoveChecker): #con este método comprueba que el movimiento es válido y si ha llegado a la salida o no.
228+
def check_move(self,board:AbstractBoardGenerator,move:AbstractMickeyMove):
229+
exit = False
230+
if move.up:
231+
if board.mickey_row == 0:
232+
print("Mickey no puede avanzar en esa dirección, se chocaría con la pared del laberinto\n")
233+
move.up = False
234+
else:
235+
row = board.mickey_row
236+
board.mickey_row -= 1
237+
if board.board[board.mickey_row][board.mickey_column] == "🚪":
238+
board.board[row][board.mickey_column] ="⬜️"
239+
print("¡Mickey ha conseguido salir del laberinto!\n")
240+
exit = True
241+
elif board.board[board.mickey_row][board.mickey_column] != "⬛️":
242+
board.board[board.mickey_row][board.mickey_column] = "🐭"
243+
board.board[row][board.mickey_column] ="⬜️"
244+
move.up = False
245+
else:
246+
print("Mickey no se puede mover ahi, hay un obstáculo en el camino\n")
247+
board.mickey_row = row
248+
move.up = False
249+
elif move.down:
250+
row = board.mickey_row
251+
try:
252+
board.mickey_row +=1
253+
if board.board[board.mickey_row][board.mickey_column] == "🚪":
254+
board.board[row][board.mickey_column] ="⬜️"
255+
print("¡Mickey ha conseguido salir del laberinto!\n")
256+
exit = True
257+
elif board.board[board.mickey_row][board.mickey_column] != "⬛️":
258+
board.board[board.mickey_row][board.mickey_column] = "🐭"
259+
board.board[row][board.mickey_column] ="⬜️"
260+
move.down = False
261+
else:
262+
print("Mickey no se puede mover ahi, hay un obstáculo en el camino\n")
263+
board.mickey_row = row
264+
move.down = False
265+
except IndexError:
266+
print("Mickey no puede avanzar en esa dirección, se chocaría con la pared del laberinto\n")
267+
move.down = False
268+
elif move.left:
269+
if board.mickey_column == 0:
270+
print("Mickey no puede avanzar en esa dirección, se chocaría con la pared del laberinto\n")
271+
move.left = False
272+
else:
273+
column = board.mickey_column
274+
board.mickey_column -= 1
275+
if board.board[board.mickey_row][board.mickey_column] == "🚪":
276+
board.board[board.mickey_row][column] ="⬜️"
277+
print("¡Mickey ha conseguido salir del laberinto!\n")
278+
exit = True
279+
elif board.board[board.mickey_row][board.mickey_column] != "⬛️":
280+
board.board[board.mickey_row][board.mickey_column] = "🐭"
281+
board.board[board.mickey_row][column] ="⬜️"
282+
move.left = False
283+
else:
284+
print("Mickey no se puede mover ahi, hay un obstáculo en el camino\n")
285+
board.mickey_column = column
286+
move.left = False
287+
elif move.right:
288+
column = board.mickey_column
289+
try:
290+
board.mickey_column += 1
291+
if board.board[board.mickey_row][board.mickey_column] == "🚪":
292+
board.board[board.mickey_row][column] ="⬜️"
293+
print("¡Mickey ha conseguido salir del laberinto!\n")
294+
exit = True
295+
elif board.board[board.mickey_row][board.mickey_column] != "⬛️":
296+
board.board[board.mickey_row][board.mickey_column] = "🐭"
297+
board.board[board.mickey_row][column] ="⬜️"
298+
move.right = False
299+
else:
300+
print("Mickey no se puede mover ahi, hay un obstáculo en el camino\n")
301+
board.mickey_column = column
302+
move.right = False
303+
except IndexError:
304+
print("Mickey no puede avanzar en esa dirección, se chocaría con la pared del laberinto\n")
305+
move.right = False
306+
return exit
307+
308+
class MickeyMove(AbstractMickeyMove): #clase para el movimiento de Mickey
309+
def __init__(self):
310+
self.up:bool = False
311+
self.down:bool = False
312+
self.right:bool = False
313+
self.left:bool = False
314+
315+
def move_up(self):
316+
self.up = True
317+
return self
318+
319+
def move_down(self):
320+
self.down = True
321+
return self
322+
323+
def move_left(self):
324+
self.left = True
325+
return self
326+
327+
def move_right(self):
328+
self.right = True
329+
return self
330+
331+
exit = False
332+
NUMBER_OF_ROWS = 6 #se podría solicitar el tamaño del tablero por consola.
333+
NUMBER_OF_COLUMNS = 6
334+
board = BoardGenerator()
335+
mickey_row,mickey_column,out_row,out_column = board.create_board(NUMBER_OF_ROWS,NUMBER_OF_COLUMNS,PlaceMickeyAndExit(),ObstaclesGenerator(),BoardChecker())
336+
board_printer = BoardPrinter()
337+
print("Te doy la bienvenida al Laberinto del D23 en el que tendrás que ayudar a Mickey a escapar\n")
338+
board_printer.print_board(board)
339+
print("\n")
340+
mickey_move = MickeyMove()
341+
move_checker = MoveChecker()
342+
while not exit:
343+
input_move = input("¿Hacia donde quieres mover a Mickey?\n- Arriba (U)\n- Abajo (D)\n- Izquierda (L)\n- Derecha (R)\n Introduce el movimiento por favor: ").upper()
344+
if input_move == "U":
345+
move = mickey_move.move_up()
346+
elif input_move == "D":
347+
move = mickey_move.move_down()
348+
elif input_move == "L":
349+
move = mickey_move.move_left()
350+
elif input_move == "R":
351+
move = mickey_move.move_right()
352+
else:
353+
print("Vaya, parece que Mickey no puede hacer ese movimiento, probemos de nuevo...")
354+
exit = move_checker.check_move(board,move)
355+
board_printer.print_board(board)
356+
print("\n")
357+
358+
print("Enhorabuena y gracias por ayudar a Mickey a salir del laberinto. Hasta pronto.")

0 commit comments

Comments
 (0)