jueves, 6 de febrero de 2014

Juegos de texto sencillos: las torres de Hanoi

He desarrollado una versión en modo texto del juego de las torres de Hanoi, que consiste en mover discos de distintos tamaños desde una torre a otra.  La ventaja de desarrollar juegos en modo texto cuando e está aprendiendo a programar es que se utilizan sólo las instrucciones básicas como print y raw_input (Python 2.*) que se enseñan en las primeras lecciones. Utilizar gráficos y no texto supone el manejo de herramientas y librerías que son algo más complicadas para un novato (por ejemplo, PyGame).  Fuera de las razones pedagógicas para comenzar a enseñar la creación de video juegos a novatos usando como ejemplos de clase juegos de texto, están las razones "nostálgicas"- cuando yo aprendí a programar en BASIC, los primeros video juegos que uno hacia eran juegos en modo texto. Creo que aún hay mucho por explotar en cuanto a las herramientas de manejo de texto en lo que respecta a sus potencialidades para crear video juegos. En esta y en sucesivas entradas trataré de publicar video juegos en modo texto que puedan ser utilizados para las primeras lecciones de un curso de programación en Python.

El juego que les presento a continuación tiene todos los elementos de un video juego más complejo:. Hay un "mundo", que en este caso es la posición que ocupan los tres discos de distintos tamaños. Como programador, uno tiene que vérselas con el problema de encontrar la representación más adecuada (en términos de estructuras de datos) para el "mundo". Para este programa, yo escogí representar al mundo como una matriz de 4 filas y 3 columnas. Las columnas son las torres y en cada torre hay espacio hasta para 4 discos montados uno sobre otro. Como en este juego solo hay 3 discos, el último espacio de cada torre siempre estará vacio. En esta matriz, he escogido representar el lugar vacio como "0", y los discos de distintos tamaños como los números 1,2 y 3 (el 1 es el disco más pequeño y el 3 el más grande). La matriz en sí se representa en Python como una lista de listas (ver código).



Otro elemento importante de un video juego es visualizar el mundo en la pantalla, para que el jugador lo pueda ver.  En este caso yo imprimo las 3 torres y los discos mediante instrucciones print (ver las funciones dibuja_celda y dibujar_torres en el código fuente).  Y también está presente el solicitar al jugador cuál será su jugada en cada turno. Se verifica si esa jugada es válida y se realiza la jugada, lo cual cambia la posición de los discos. Este ciclo se repite hasta que el usuario haya puesto todos los discos en la posición final requerida.

A continuación el código:


# -*- coding: utf-8 -*-
#juego de las TORRES DE HANOI
#Autor: José Romero, 29/1/2014 a las 11:50pm

def dibuja_celda(disco):
 if disco==0:
  print "     |     ",
 elif disco==1:
  print "    OOO    ",
 elif disco==2:
  print "   OOOOO   ",
 elif disco==3:
  print "  OOOOOOO  ",

def dibujar_torres():
#esta función dibuja las torres (mundo)
 #primero, borra la pantalla introduciendo varias líneas en blanco
 print "\n"*40
 #luego, dibuja el "mundo"
 for fila in mundo:
  for columna in fila:
   dibuja_celda(columna)
  print
 print "************"*3
 print "     1     ","     2     ","     3     "

def encuentra_disco_de_arriba(col):
#esta función retorna el disco (1-3) en la columna indicada.
#si la columna está vacia, retorna un 0
 fila=0
 while fila<=3 and mundo[fila][col]==0:
  fila+=1
 if fila<=3:
  return mundo[fila][col]
 else:
  return 0

def encuentra_proximo_espacio_en_blanco(col):
#esta función indica el número de la fila (1-3) del lugar vacio
#en la columna debajo del cual hay un disco
 fila=0
 while fila<=3 and mundo[fila][col]==0:
  fila+=1
 return fila-1

def elimina_disco_superior(col):
#Esta función quita el disco superior en una columna
 fila=0
 while fila<=3 and mundo[fila][col]==0:
  fila+=1
 mundo[fila][col]=0


def verifica_si_termino():
#verifca si los discos estan todos en su posición final
 return mundo==objetivo

mundo = [[0,0,0],[1,0,0],[2,0,0],[3,0,0]]
objetivo = [[0,0,0],[0,0,1],[0,0,2],[0,0,3]]

movimientos=0
while not(verifica_si_termino()):
 #dibuja el mundo en la pantalla
 dibujar_torres()
 #solicita la jugada 
 c0=raw_input("Mover disco desde la torre # : ")
 c0=int(c0)-1
 c1=raw_input("Mover disco a la torre #     : ")
 c1=int(c1)-1
 #validar la jugada
 hayerror=False
 if (c0<0 data-blogger-escaped-c0="" data-blogger-escaped-or="">2):
  print "Torre 'desde' inválida"
  hayerror=True
 elif (c1<0 data-blogger-escaped-c1="" data-blogger-escaped-or="">2):
  print "Torre 'hasta' inválida"
  hayerror=True
 elif encuentra_disco_de_arriba(c0)==0:
  print "No hay discos en la torre #",c0+1
  hayerror=True
 elif encuentra_disco_de_arriba(c1)>0 and encuentra_disco_de_arriba(c0)>encuentra_disco_de_arriba(c1):
  print "Intenta colocar un disco más grande sobre uno más pequeño"
  hayerror=True
 #Si la jugada es válida, efectuar la jugada
 if not(hayerror):
  disco1=encuentra_disco_de_arriba(c0)
  elimina_disco_superior(c0)
  mundo[encuentra_proximo_espacio_en_blanco(c1)][c1]=disco1
  movimientos+=1
 else:
  raw_input("Preione [ENTER] para continuar")

dibujar_torres()
print "Felicitaciones! Ha terminado en",movimientos,"movimientos."


¡Disfruten!