Hola, me llamo Desirée y estoy haciendo el juego Torres de Hanói
y pretendo hacer un tutorial una vez esté completo. Pero estoy teniendo dificultades para hacer que funcione el arrastrar y soltar los discos. Utilizo el método aprender y pilas.habilidades.Arrastrable para poder mover los discos, pero necesito de alguna forma que al soltar el disco se ejecute una función, la cual debe encargarse de detectar si hay contacto (colisión) con uno de los postes y de ser así registrar el moviento. En concreto tengo dos problemas:
- Detectar cuando se suelta un disco
- Detectar la colisión entre la pieza soltada y los 3 posibles postes
Paso el código que tengo funcionando hasta ahora ( con solución automática incluída ), para realizar movimientos manuales por ahora hay que llamar a la función realizar_movimiento(origen,destino), la cuál solo realiza el movimiento si éste es válido.
# coding: utf-8
import pilasengine
pilas = pilasengine.iniciar()
# Número de discos del juego
numero_discos = 5
# Estado del juego
#############
# El estado del juego se guarda en una lista de tres componentes,
# donde cada una corresponde a cada uno de los postes y cuyo valor
# es a su vez tambien una lista, que contiene los numeros de los
# discos que se encuentran en ese poste. Los discos se numeran de
# 0 a numero_discos desde el mas grande hasta el mas pequeño.
#
# Ejemplo con 5 discos: [[0,1,2],[4],[3]]
# en este ejemplo en el poste 1 (inicial) se encuentran los tres discos
# mas grandes, en el segundo se encuentra el mas pequeño y en el
# tercero se encuentra el restante.
#
# De esta forma el estado del juego es valido siempre que las listas
# de los discos de cada poste se encuentren ordenadas de manera
# ascendente
# Estado inicial del juego
juego = [range(numero_discos),[],[]]
# Número de movimientos realizados
movimientos = 0
ancho_max = 200
ancho_min = 50
alto = 20
delta = (ancho_max - ancho_min)/(numero_discos-1)
separacion_postes = 200
alto_postes = alto*(numero_discos+1)
def crear_rectangulo(ancho,alto,color,id=("tipo",0),colortexto=pilas.colores.negro):
superficie = pilas.imagenes.cargar_superficie(ancho,alto)
superficie.rectangulo(0,0,ancho,alto,color=color, relleno=True)
superficie.rectangulo(0,0,ancho,alto,color=pilas.colores.negro, relleno=False,grosor=4)
superficie.texto(str(id[1]), magnitud=12, color=colortexto,x=ancho/2-5)
actor = pilas.actores.Actor(imagen=superficie)
actor.crear_figura_de_colision_rectangular(0,0,ancho,alto)
actor.id = id
return actor
# Crear los postes y base
postes = [ crear_rectangulo(14,alto_postes,pilas.colores.negro,("poste",i),pilas.colores.blanco) for i in range (3) ]
for i in range(3):
postes[i].x = separacion_postes*(i-1)
postes[i].y = alto_postes/2-alto/2
base = crear_rectangulo(2*separacion_postes+ancho_max,alto,pilas.colores.negro)
base.y = -alto
# Crear los discos
discos = [ crear_rectangulo(ancho_max-delta*i,alto,pilas.colores.blanco,("disco",i)) for i in range(numero_discos)]
discos[-1].aprender(pilas.habilidades.Arrastrable)
for i in range(len(discos)):
discos[i].y = alto*i
discos[i].x = -separacion_postes
################################################################################
# #
# Lógica del juego #
# #
################################################################################
#
# Validar movimiento
#
# Esta funcion toma como entrada dos valores, el numero de poste
# desde el cual se saca
#
def validar_movimiento(origen,destino):
if origen == destino:
return False
if len(juego[origen]) > 0:
if len(juego[destino]) > 0:
return juego[origen][-1] > juego[destino][-1]
else:
return True
else:
return False
#
# Realizar movimiento
#
ultimo_movimiento = "ninguno"
tiempo_movimiento = 0.6;
def realizar_movimiento(origen,destino):
#realizar_movimiento_logico(origen,destino)
#realizar_movimiento_grafico(origen,destino)
if validar_movimiento(origen,destino):
# realizar animacion
x_inicial = separacion_postes*(origen-1)
x_final = separacion_postes*(destino-1)
y_inicial = alto*len(juego[origen])
y_final = alto*len(juego[destino])
discos[juego[origen][-1]].x = [x_inicial,x_final,x_final] , tiempo_movimiento/3
discos[juego[origen][-1]].y = [alto_postes+30,alto_postes+30,y_final] , tiempo_movimiento/3
global movimientos
movimientos = movimientos + 1
# actualizar habilidades
if len(juego[origen]) > 1:
discos[juego[origen][-2]].aprender(pilas.habilidades.Arrastrable)
if len(juego[destino]) > 0:
discos[juego[destino][-1]].eliminar_habilidades()
# actualizar el estado del juego
juego[destino].append(juego[origen].pop())
global ultimo_movimiento
ultimo_movimiento = (origen,destino)
# mostrar el estado del juego
global texto3
texto3.texto = str(movimientos)
pilas.avisar(str(juego))
verificar_fin_de_juego()
else:
print("Movimiento inválido")
def verificar_fin_de_juego():
for poste in juego[1:]: # todos los postes menos en el inicial (0)
if len(poste) == numero_discos:
# todos los discos están en este poste, si todos
# los movimientos fueron válidos entonces la
# torre debe estar completa y el juego ha sido
# resuelto, no obstante vamos a verificar que los
# discos estén en el orden correcto.
for i in range(1,numero_discos):
if poste[i]<poste[i-1]:
return False
#pilas.actores.Texto("JUEGO RESUELTO!",y=200)
#pilas.actores.Texto("numero de movimientos: "+str(movimientos),y=170)
texto1.y = [200]
#texto2.y = [170]
#texto2.texto = "numero de movimientos: "+str(movimientos)
pilas.avisar("Juego Resuelto! numero de movimientos: " + str(movimientos))
return True
elif len(poste) != 0:
# los discos no están todos en el mismo poste
return False
return False
def reiniciar():
global juego,movimientos,ultimo_movimiento
juego = [range(numero_discos),[],[]]
movimientos = 0
ultimo_movimiento = (0,0)
texto1.y=1200
actualizar_posiciones()
def actualizar_posiciones():
for p in range(len(juego)):
for d in range(len(juego[p])):
discos[juego[p][d]].x = [separacion_postes*(p-1)]
discos[juego[p][d]].y = [alto*d]
resolviendo = False
def click_resolver():
global resolviendo
if not resolviendo:
resolviendo = True
resolver()
def resolver():
global resolviendo
if not verificar_fin_de_juego():
paso_resolver()
pilas.tareas.agregar(tiempo_movimiento,resolver)
else:
resolviendo = False
def paso_resolver():
if not verificar_fin_de_juego():
for i in range(1,3):
if len(juego[i]) == 0:
realizar_movimiento(0,i)
return
todos_los_movimientos = [ (0,1), (0,2), (1,0), (1,2), (2,0), (2,1) ]
movimientos_validos = [ m for m in todos_los_movimientos if validar_movimiento(m[0],m[1]) ]
movimientos_validos = [ m for m in movimientos_validos if (m[1],m[0]) != ultimo_movimiento ]
movimientos_validos = [ m for m in movimientos_validos if len(juego[m[1]]) == 0 or juego[m[0]][-1]%2 != juego[m[1]][-1]%2 ]
print(movimientos_validos)
if len(movimientos_validos) > 1:
print(movimientos_validos)
tmp = [ m for m in movimientos_validos if juego[m[0]][-1] != numero_discos-1 ]
if len(tmp) > 0:
movimientos_validos = tmp
print(movimientos_validos)
if len(movimientos_validos) > 1:
L = [ (len(juego[m[1]]),m) for m in movimientos_validos ]
x = L[0]
for m in L:
if m[0] > x[0]:
x = m
movimientos_validos = [x[1]]
if len(movimientos_validos) == 1 :
m = movimientos_validos[0]
realizar_movimiento(m[0],m[1])
else:
print("Error! No se puede resolver... :(")
texto1 = pilas.actores.Texto("JUEGO RESUELTO!",y=1200)
texto2 = pilas.actores.Texto("numero de movimientos: ",y=-150)
texto3 = pilas.actores.Texto(str(movimientos),x=150,y=-150)
boton_paso_resolver = pilas.interfaz.Boton("Paso")
boton_paso_resolver.conectar(paso_resolver)
boton_paso_resolver.x = 60
boton_paso_resolver.y = -80
boton_resolver = pilas.interfaz.Boton("Resolver")
boton_resolver.conectar(click_resolver)
boton_resolver.x = 150
boton_resolver.y = -80
boton_reiniciar = pilas.interfaz.Boton("Reiniciar")
boton_reiniciar.conectar(reiniciar)
boton_reiniciar.x = 240
boton_reiniciar.y = -80
pilas.avisar(str(juego))
pilas.ejecutar()
Desde ya muchas gracias y felicitaciones por tan interesante proyecto!