def establece_mochila(self, cantidad): """Establece los zumbadores en la mochila de karel a cierta cantidad""" if cantidad == 'inf' or cantidad == '-1' or cantidad == -1: self.mundo['karel']['mochila'] = -1 elif type(cantidad) == int: if cantidad >= 0: self.mundo['karel']['mochila'] = cantidad else: raise KarelException( 'Esta no es una cantidad apropiada de zumbadores') else: raise KarelException('Deberías consultar a un psiquiatra')
def carga_archivo(self, archivo): """ Carga el contenido de un archivo con la configuración del mundo. Archivo debe ser una instancia de 'file' o de un objeto con metodo 'read()'""" mundo = json.load(archivo) #Lo cargamos al interior self.mundo_backup = self.mundo try: self.mundo = { 'karel': { 'posicion': tuple(mundo['karel']['posicion']), 'orientacion': mundo['karel']['orientacion'], 'mochila': mundo['karel']['mochila'] #Zumbadores en la mochila }, 'dimensiones': { 'filas': mundo['dimensiones']['filas'], 'columnas': mundo['dimensiones']['columnas'] }, 'casillas': dict() } if not self.carga_casillas(mundo['casillas']): raise KarelException("Se mando un mundo deformado") except KeyError: self.mundo = self.mundo_backup del (self.mundo_backup) return False else: del (self.mundo_backup) return True
def __init__(self, filas=100, columnas=100, karel_pos=(1, 1), orientacion='norte', mochila=0, casillas=dict(), archivo=None): """ Inicializa el mundo, con Karel en la esquina 1,1 del mundo orientado al norte. El mundo es un diccionario con dos llaves: * karel indica mediante una tupla la fila y la columna en la que se encuentra el robot * casillas indica cómo está construido el mundo mediante un diccionario, que tiene por llaves las tuplas con la posicion que representan: (fila, columna) """ self.mundo = { 'karel': { 'posicion': karel_pos, 'orientacion': orientacion, 'mochila': mochila #Zumbadores en la mochila }, 'dimensiones': { 'filas': filas, 'columnas': columnas }, 'casillas': casillas } if archivo is not None and isinstance(archivo, file): if not self.carga_archivo(archivo): raise KarelException( "El archivo de mundo que me diste esta dañado!")
def bloque(self, cola, diccionario_variables): """ Ejecuta una cola de instrucciones dentro de una estructura mayor """ for instruccion in cola: if type(instruccion) == dict: #Se trata de una estructura de control o una funcion definida if instruccion['estructura'] == 'si': if self.termino_logico(instruccion['argumento']['o'], diccionario_variables): self.bloque(instruccion['cola'], diccionario_variables) elif instruccion.has_key('sino-cola'): self.bloque(instruccion['sino-cola'], diccionario_variables) if not self.corriendo or self.sal_de_instruccion or self.sal_de_bucle: return elif instruccion['estructura'] == 'repite': contador = 0 for i in xrange( self.expresion_entera(instruccion['argumento'], diccionario_variables)): self.bloque(instruccion['cola'], diccionario_variables) if not self.corriendo or self.sal_de_instruccion or self.sal_de_bucle: self.sal_de_bucle = False return contador += 1 if not contador < self.limite_iteracion: raise KarelException( u"LongIteration! algun bucle se ha ciclado") elif instruccion['estructura'] == 'mientras': contador = 0 while self.termino_logico(instruccion['argumento']['o'], diccionario_variables): self.bloque(instruccion['cola'], diccionario_variables) if not self.corriendo or self.sal_de_instruccion or self.sal_de_bucle: self.sal_de_bucle = False return contador += 1 if not contador < self.limite_iteracion: raise KarelException( u"LongIteration! algun bucle se ha ciclado") else: #Se trata de una función if self.profundidad == self.limite_recursion: raise KarelException( u"StackOverflow! Se ha alcanzado el límite de una recursion" ) self.profundidad += 1 self.bloque( self.arbol['funciones'][instruccion['nombre']]['cola'], merge( self.arbol['funciones'][instruccion['nombre']] ['params'], instruccion['argumento'])) self.profundidad -= 1 if self.sal_de_instruccion: self.sal_de_instruccion = False else: #Es una instruccion predefinida de Karel if instruccion == 'avanza': if not self.mundo.avanza(): raise KarelException( 'Karel se ha estrellado con una pared!') elif instruccion == 'gira-izquierda': self.mundo.gira_izquierda() elif instruccion == 'coge-zumbador': if not self.mundo.coge_zumbador(): raise KarelException( 'Karel quizo coger un zumbador pero no habia en su posicion' ) elif instruccion == 'deja-zumbador': if not self.mundo.deja_zumbador(): raise KarelException( 'Karel quizo dejar un zumbador pero su mochila estaba vacia' ) elif instruccion == 'apagate': self.corriendo = False return elif instruccion == 'sal-de-instruccion': self.sal_de_instruccion = True return elif instruccion == 'sal-de-bucle': self.sal_de_bucle = True return
def lee_token(self): """Lee un token del archivo""" while True: self.columna += 1 if not self.caracter_actual: break if self.estado == self.ESTADO_COMENTARIO: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado comentario" if self.caracter_actual in self.simbolos: #Lo que puede pasar es que sea basura o termine el comentario if self.caracter_actual == ')' and self.abrir_comentario == '(*' and self.ultimo_caracter == '*': self.estado = self.ESTADO_ESPACIO if self.caracter_actual == '}' and self.abrir_comentario == '{': self.estado = self.ESTADO_ESPACIO if self.caracter_actual == '/' and self.abrir_comentario == '/*' and self.ultimo_caracter == '*': self.estado = self.ESTADO_ESPACIO if self.caracter_actual == '\n': #LINEA self.cambio_de_linea() elif self.estado == self.ESTADO_ESPACIO: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado espacio" if self.caracter_actual not in self.caracteres: raise KarelException( "Caracter desconocido en la linea %d columna %d" % (self.linea, self.columna)) if self.caracter_actual in self.numeros: self.token += self.caracter_actual self.estado = self.ESTADO_NUMERO elif self.caracter_actual in self.palabras: self.token += self.caracter_actual self.estado = self.ESTADO_PALABRA elif self.caracter_actual in self.simbolos: self.estado = self.ESTADO_SIMBOLO continue elif self.caracter_actual == '\n': #LINEA self.cambio_de_linea() elif self.estado == self.ESTADO_NUMERO: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado número" if self.caracter_actual not in self.caracteres: raise KarelException( "Caracter desconocido en la linea %d columna %d" % (self.linea, self.columna)) if self.caracter_actual in self.numeros: self.token += self.caracter_actual elif self.caracter_actual in self.palabras: #Encontramos una letra en el estado numero, incorrecto raise KarelException( "Este token no parece valido, linea %d columna %d" % (self.linea, self.columna)) elif self.caracter_actual in self.simbolos: self.estado = self.ESTADO_SIMBOLO break elif self.caracter_actual in self.espacios: self.estado = self.ESTADO_ESPACIO break #Terminamos este token elif self.estado == self.ESTADO_PALABRA: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado palabra" if self.caracter_actual not in self.caracteres: raise KarelException( "Caracter desconocido en la linea %d columna %d" % (self.linea, self.columna)) if self.caracter_actual in self.palabras + self.numeros: self.token += self.caracter_actual elif self.caracter_actual in self.simbolos: self.estado = self.ESTADO_SIMBOLO break elif self.caracter_actual in self.espacios: self.estado = self.ESTADO_ESPACIO break #Terminamos este token elif self.estado == self.ESTADO_SIMBOLO: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado símbolo" if self.caracter_actual not in self.caracteres: raise KarelException( "Caracter desconocido en la linea %d columna %d" % (self.linea, self.columna)) if self.caracter_actual == '{' and self.sintaxis == 'pascal': self.abrir_comentario = '{' self.estado = self.ESTADO_COMENTARIO if self.token: break elif self.caracter_actual == '#': self.estado = self.ESTADO_ESPACIO self.archivo.readline() #LINEA self.cambio_de_linea() if self.token: break elif self.caracter_actual in self.numeros: self.estado = self.ESTADO_NUMERO if self.token: break elif self.caracter_actual in self.palabras: self.estado = self.ESTADO_PALABRA if self.token: break elif self.caracter_actual in self.simbolos: #Encontramos un símbolo en estado símbolo if self.caracter_actual == '/' and self.ultimo_caracter == '/': self.archivo.readline() #LINEA self.cambio_de_linea() self.estado = self.ESTADO_ESPACIO if self.token.endswith('/'): self.token = self.token[:-1] if self.token: self.caracter_actual = self.lee_caracter() break elif self.caracter_actual == '*' and self.ultimo_caracter == '/' and self.sintaxis == 'java': self.estado = self.ESTADO_COMENTARIO self.abrir_comentario = '/*' if self.token.endswith('/'): self.token = self.token[:-1] if self.token: self.caracter_actual = self.lee_caracter() break elif self.caracter_actual == '*' and self.ultimo_caracter == '(' and self.sintaxis == 'pascal': self.estado = self.ESTADO_COMENTARIO self.abrir_comentario = '(*' if self.token.endswith('('): self.token = self.token[:-1] if self.token: self.caracter_actual = self.lee_caracter() break elif self.caracter_actual in self.lonely_chars: #Caracteres que viven solos self.estado = self.ESTADO_ESPACIO if self.token: break self.token += self.caracter_actual self.caracter_actual = self.lee_caracter() break else: self.token += self.caracter_actual elif self.caracter_actual in self.espacios: self.estado = self.ESTADO_ESPACIO if self.token: break else: raise KarelException( "Caracter desconocido en la linea %d columna %d" % (self.linea, self.columna)) self.caracter_actual = self.lee_caracter() token = self.token self.token = '' obj_token = ktoken(token, self.es_primer_token) self.es_primer_token = False return obj_token
def step(self): """Da un paso en la cinta de ejecución de Karel""" try: if self.corriendo: if self.ejecucion >= self.limite_ejecucion: raise KarelException( u"HanoiTowerException: Tu programa nunca termina ¿Usaste 'apagate'?" ) #Hay que ejecutar la función en turno en el índice actual instruccion = self.ejecutable['lista'][self.indice] if type(instruccion) == dict: #Se trata de una estructura de control o una funcion definida if instruccion.has_key('si'): if self.debug: print 'si' if self.termino_logico( instruccion['si']['argumento']['o'], self.diccionario_variables): self.indice += 1 #Avanzamos a la siguiente posicion en la cinta else: #nos saltamos el si, vamos a la siguiente casilla, que debe ser un sino o la siguiente instruccion self.indice = instruccion['si']['fin'] + 1 self.ejecucion += 1 elif instruccion.has_key( 'sino' ): #Llegamos a un sino, procedemos, no hay de otra if self.debug: print 'sino' self.indice += 1 self.ejecucion += 1 elif instruccion.has_key('repite'): if self.debug: print 'repite', instruccion['repite']['argumento'] if not self.pila.en_tope(instruccion['repite']['id']): argumento = self.expresion_entera( instruccion['repite']['argumento'], self.diccionario_variables) if argumento < 0: raise KarelException( u"WeirdNumberException: Estás intentando que karel repita un número negativo de veces" ) self.pila.append({ 'id': instruccion['repite']['id'], 'cuenta': 0, 'argumento': argumento, 'fin': instruccion['repite']['fin'] }) #Cuenta las ejecuciones para este bucle if self.pila.top()['argumento'] > 0: if self.pila.top( )['cuenta'] == self.limite_iteracion: raise KarelException( 'LoopLimitExceded: hay un bucle que se cicla' ) self.indice += 1 self.pila.top()['argumento'] -= 1 self.pila.top()['cuenta'] += 1 else: #nos vamos al final y extraemos el repite de la pila self.indice = instruccion['repite']['fin'] + 1 self.pila.pop() self.ejecucion += 1 elif instruccion.has_key('mientras'): if self.debug: print 'mientras' if not self.pila.en_tope( instruccion['mientras']['id']): self.pila.append({ 'id': instruccion['mientras']['id'], 'cuenta': 0, 'fin': instruccion['mientras']['fin'] }) #Cuenta las ejecuciones para este bucle if self.termino_logico( instruccion['mientras']['argumento']['o'], self.diccionario_variables ): #Se cumple la condición del mientras if self.pila.top( )['cuenta'] == self.limite_iteracion: raise KarelException( 'LoopLimitExceded: hay un bucle que se cicla' ) self.indice += 1 self.pila.top()['cuenta'] += 1 else: #nos vamos al final self.indice = instruccion['mientras']['fin'] + 1 self.pila.pop() self.ejecucion += 1 elif instruccion.has_key('fin'): #Algo termina aqui if self.debug: print 'fin', instruccion['fin']['estructura'] if instruccion['fin']['estructura'] in [ 'mientras', 'repite' ]: self.indice = instruccion['fin']['inicio'] elif instruccion['fin']['estructura'] == 'si': self.indice = instruccion['fin']['fin'] elif instruccion['fin']['estructura'] == 'sino': self.indice += 1 else: #fin de una funcion nota = self.pila.pop( ) #Obtenemos la nota de donde nos hemos quedado self.indice = nota['posicion'] + 1 self.diccionario_variables = nota[ 'diccionario_variables'] self.profundidad -= 1 else: #Se trata la llamada a una función if self.debug: print instruccion['instruccion']['nombre'] if self.profundidad == self.limite_recursion: raise KarelException( 'StackOverflow: Karel ha excedido el límite de recursión' ) #Hay que guardar la posición actual y el diccionario de variables en uso self.pila.append({ 'posicion': self.indice, 'diccionario_variables': self.diccionario_variables }) self.profundidad += 1 # Lo que prosigue es ir a la definición de la función self.indice = self.ejecutable['indice_funciones'][ instruccion['instruccion']['nombre']] + 1 # recalcular el diccionario de variables valores = [] for i in instruccion['instruccion']['argumento']: valores.append( self.expresion_entera( i, self.diccionario_variables)) self.diccionario_variables = merge( self.ejecutable['lista'][self.indice - 1] [instruccion['instruccion']['nombre']]['params'], valores) self.ejecucion += 1 else: #Es una instruccion predefinida de Karel if self.debug: print instruccion if instruccion == 'avanza': if not self.mundo.avanza(): raise KarelException( 'Karel se ha estrellado con una pared!') self.indice += 1 elif instruccion == 'gira-izquierda': self.mundo.gira_izquierda() self.indice += 1 elif instruccion == 'coge-zumbador': if not self.mundo.coge_zumbador(): raise KarelException( 'Karel quizo coger un zumbador pero no habia en su posicion' ) self.indice += 1 elif instruccion == 'deja-zumbador': if not self.mundo.deja_zumbador(): raise KarelException( 'Karel quizo dejar un zumbador pero su mochila estaba vacia' ) self.indice += 1 elif instruccion == 'apagate': self.corriendo = False #Fin de la ejecución self.estado = 'OK' self.mensaje = 'Ejecucion terminada' return 'TERMINADO' elif instruccion == 'sal-de-instruccion': while self.pila.top().has_key('id'): self.pila.pop() #Sacamos todos los bucles nota = self.pila.pop( ) #Obtenemos la nota de donde nos hemos quedado self.indice = nota['posicion'] + 1 self.diccionario_variables = nota[ 'diccionario_variables'] elif instruccion == 'sal-de-bucle': bucle = self.pila.pop() self.indice = bucle['fin'] + 1 elif instruccion == 'continua-bucle': bucle = self.pila.top() self.indice = bucle['fin'] else: #FIN raise KarelException( u"HanoiTowerException: Tu programa excede el límite de ejecución ¿Usaste 'apagate'?" ) self.ejecucion += 1 else: self.estado = 'OK' self.mensaje = 'Ejecucion terminada' self.corriendo = False return 'TERMINADO' except KarelException, kre: self.estado = 'ERROR' self.mensaje = kre.args[0] self.corriendo = False return 'ERROR'
def lee_token(self): """Lee un token del archivo""" while True: self.caracter_actual = self.lee_caracter() self.columna += 1 if not self.caracter_actual: break if self.tiene_cambio_de_linea: self.linea += 1 self.tiene_cambio_de_linea = False if self.estado == self.ESTADO_COMENTARIO: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado comentario" if self.caracter_actual in self.simbolos: #Lo que puede pasar es que sea basura o termine el comentario if self.caracter_actual == ')' and self.abrir_comentario == '(*' and self.ultimo_caracter == '*': self.estado = self.ESTADO_ESPACIO if self.caracter_actual == '}' and self.abrir_comentario == '{': self.estado = self.ESTADO_ESPACIO elif self.caracter_actual == '\n': self.tiene_cambio_de_linea = True self.columna = 0 elif self.estado == self.ESTADO_ESPACIO: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado espacio" if self.caracter_actual not in self.caracteres: raise KarelException( "Caracter desconocido en la linea %d columna %d" % (self.linea, self.columna)) if self.caracter_actual in self.numeros: self.token += self.caracter_actual self.estado = self.ESTADO_NUMERO elif self.caracter_actual in self.palabras: self.token += self.caracter_actual self.estado = self.ESTADO_PALABRA elif self.caracter_actual in self.simbolos: self.push_char(self.caracter_actual ) #Podria ser algo valido como ();, self.estado = self.ESTADO_SIMBOLO elif self.caracter_actual == '\n': self.tiene_cambio_de_linea = True self.columna = 0 elif self.estado == self.ESTADO_NUMERO: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado número" if self.caracter_actual not in self.caracteres: raise KarelException( "Caracter desconocido en la linea %d columna %d" % (self.linea, self.columna)) if self.caracter_actual in self.numeros: self.token += self.caracter_actual elif self.caracter_actual in self.palabras: #Encontramos una letra en el estado numero, incorrecto raise KarelException( "Este token no parece valido, linea %d columna %d" % (self.linea, self.columna)) elif self.caracter_actual in self.simbolos: self.estado = self.ESTADO_SIMBOLO self.push_char(self.caracter_actual) break elif self.caracter_actual in self.espacios: if self.caracter_actual == '\n': self.tiene_cambio_de_linea = True self.columna = 0 self.estado = self.ESTADO_ESPACIO break #Terminamos este token elif self.estado == self.ESTADO_PALABRA: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado palabra" if self.caracter_actual not in self.caracteres: raise KarelException( "Caracter desconocido en la linea %d columna %d" % (self.linea, self.columna)) if self.caracter_actual in self.palabras + self.numeros: self.token += self.caracter_actual elif self.caracter_actual in self.simbolos: self.estado = self.ESTADO_SIMBOLO self.push_char(self.caracter_actual) break elif self.caracter_actual in self.espacios: if self.caracter_actual == '\n': self.tiene_cambio_de_linea = True self.columna = 0 self.estado = self.ESTADO_ESPACIO break #Terminamos este token elif self.estado == self.ESTADO_SIMBOLO: if self.debug: print "Encontré", repr( self.caracter_actual), "en estado símbolo" if self.caracter_actual not in self.caracteres: raise KarelException( "Caracter desconocido en la linea %d columna %d" % (self.linea, self.columna)) if self.caracter_actual == '{': self.abrir_comentario = '{' self.estado = self.ESTADO_COMENTARIO elif self.caracter_actual in self.numeros: self.estado = self.ESTADO_NUMERO self.push_char(self.caracter_actual) break elif self.caracter_actual in self.palabras: self.estado = self.ESTADO_PALABRA self.push_char(self.caracter_actual) if self.token: break elif self.caracter_actual in self.simbolos: if self.ultimo_caracter == "(" and self.caracter_actual == '*': self.token = '' self.estado = self.ESTADO_COMENTARIO self.abrir_comentario = '(*' elif self.caracter_actual != '(': #el único símbolo con continuación self.token += self.caracter_actual # self.push_char(self.caracter_actual) break else: self.token += self.caracter_actual elif self.caracter_actual in self.espacios: if self.caracter_actual == '\n': self.tiene_cambio_de_linea = True self.columna = 0 self.estado = self.ESTADO_ESPACIO #break #Terminamos este token token = self.token self.token = '' return token