2010-02-05 16 views
8

Estoy jugando con la escritura de una aventura de MUD/texto (por favor no te rías) en Ruby. ¿Alguien puede darme algún consejo sobre una solución elegante y basada en oops para analizar el texto de entrada?Elegante análisis de comandos en un juego de texto basado en OOP

Estamos hablando de nada más complejo que "poner la varita en la mesa", aquí. Pero todo debe ser suave; Quiero extender el comando establecido sin dolor, más tarde.

Mis pensamientos actuales, ligeramente simplificada:

  1. Cada clase de elemento (caja, de mesa, sala, jugador) sabe cómo reconocer un comando que 'pertenece' a la misma.

  2. La clase de juego comprende una especie de un lenguaje de dominio específico que implica acciones como "objeto movimiento X dentro objeto Y", "mostrar descripción de objeto X", etc.

  3. La clase de juego de cada pregunta elemento en la sala si reconoce el comando de entrada. Primero, decir que sí gana.

  4. Pasa el control a un método en la clase de elemento que maneja el comando. Este método reformula el comando en el DSL, lo pasa de vuelta al objeto del juego para que suceda.

Debe haber formas bien gastadas y elegantes de hacer esto. Sin embargo, parece que no puede googlear nada.

+0

Como una nota al pie, el poco pelos con mi plan actual es la implementación de acciones que involucran a dos objetos. – Shadowfirebird

+1

Puede comenzar con http://stackoverflow.com/questions/tagged/natural-language y ver a dónde lo lleva. – dmckee

+0

Ta! Acabo de agregar esa etiqueta a la pregunta. – Shadowfirebird

Respuesta

3

El Interpreter design pattern es el orientado a objetos enfoque más a analizar que yo sepa, pero estoy seguro de expertos compilador señalarán algoritmos que son más potentes.

+0

Soy basura en los patrones de diseño, y mi Google no había podido ver este. Ciertamente echaré un vistazo a esto, ta. – Shadowfirebird

+0

De hecho, ¡el patrón del intérprete parece un árbol de expresiones en un proceso de compilación! bonito. Parece una implementación directa para un compilador. (después del análisis del token de cadena) –

+0

Todavía estoy luchando por aplicar este patrón a mi proyecto, pero parece más bien como si fuera la idea a la que estaba buscando. Lo que no se dice, sin embargo, es cómo se analiza la cadena de comandos. – Shadowfirebird

0

dividirlo en fichas como el formato será siempre:
[comando] [objeto1] ([refering] [objeto2])

Usted puede llamar al método [comando] en la [objeto1] en su habitación y páselo [object2] si corresponde.

+0

Eso es muy tentador. Pero, "enciende la luz". O, para el caso, sería realmente agradable poder aceptar "encender la luz". – Shadowfirebird

+1

Puede hacer eso simplemente borrando lo que se suele llamar "palabras de parada" de la cadena. Palabras como "the", "an", "on". En ese caso, todo lo que queda de la frase "ahora enciende esa luz allí" sería "encenderse". Por supuesto, eso podría ser * demasiado * demasiado, pero en este caso específico la * ausencia * de la palabra "apagado" le dice todo lo que necesita saber. –

+0

@Jorg: En realidad, eso es más o menos lo que hace mi enfoque actual, excepto que detecta "palabras de inicio" en su lugar. Entonces (para simplificar algo) la clase de luz busca /light.*(on|off)/. Quizás lo tengas bien, y yo no. – Shadowfirebird

1

Para los intérpretes de comandos, soy bastante aficionado a este patrón simple, no tan elegante. Los patrones en lenguajes dinámicos tienden a involucrar menos cajas y líneas que los patrones GOF.

class Thing 

    # Handle a command by calling the method "cmd_" + command. 
    # Raise BadCommand exception if there is no method for that command. 

    def handle_command(command, args) 
    method_name = "cmd_#{command}" 
    raise BadCommand, command unless respond_to?(method_name) 
    send(method_name, args) 
    end 

    def cmd_quit(args) 
    # the code for command "quit" 
    end 

    def cmd_list(args) 
    # the code for command "list" 
    end 

    ... 

end 

De esta manera, agregar un nuevo comando es simplemente agregar un nuevo método. No es necesario ajustar tablas ni declaraciones de casos.

+2

Esto se ve en un primer momento como un estrabismo de tres vías entre el extraño visitante, Estrategia y Comando, pero como usted ha dicho: en un lenguaje expresivo (no compro la parte "dinámica" * que * tanto, que probablemente se vería igual de elegante en Scala, F # o Haskell) simplemente no es tan importante. Recuerde: un Patrón no es más que un Programa que desea escribir, pero su lenguaje no le permite. Bueno, Ruby * no * te deja. –

+0

@Jorg, Bien dicho. Excavo esa definición de un patrón. ¿Es tuyo? –

+3

No lo creo. Esa frase * precisa * podría ser mía, pero la idea es general. De hecho, si abres tu copia del GoF a la página 4 y lees el último párrafo de la sección 1.1, en realidad está escrito allí. La diatriba clásica sobre este tema es http://blog.plover.com/prog/design-patterns.html con esta respuesta http://www.cincomsmalltalk.com/userblogs/ralph/blogView?entry=3335803396 y entonces este http: //blog.plover.com/prog/johnson.html. Y, por supuesto, la famosa presentación de Norvig: http://norvig.com/design-patterns/ –

0

Ok. ¿Entonces necesitas una semántica? (turn es una acción, ilumina un objeto, en un argumento ... (me relaciono con tu comentario a dbemerlin)).

¿Por qué no definir una gramática? Humm ... Supongo que Lex y Yacc no son una opción? (dado que no es OOP en absoluto, pero lo que quiere hacer es "compilar" la entrada del usuario para producir algo - ejecutar algún código que cambie los datos de la sala, y dar salida a un resultado)

Puede tener un POO diseño para su objeto y su acción (como, todos los objetos tienen un método .describeMe() ..), y al lado de eso, un compilador de entrada + compilador.

¿Estoy completamente fuera del tema?

Editar: después de mirar al patrón intérprete señalado por Marc Seeman, que parece ser el camino a seguir en el que desea que en la programación orientada a objetos. (Pero tendrá un poco de reinventar la rueda)

+0

Miré lex y yacc. Pero me hacen doler la cabeza, y se supone que es un proyecto divertido.Además, si entiendo correctamente, me atan a una gramática mucho más estricta que la que realmente tiene el inglés. Supongo que mi objetivo de oro es que el usuario pueda escribir "en la mesa poner varita" y que se entienda ... o al menos que el juego intente poner la mesa en la varita mágica;) – Shadowfirebird

2

Suena como que necesita un analizador.

Dividir la cadena de entrada en tokens (palabras). Luego alimente los tokens, uno a la vez, a una máquina de estado. Encuentro que el autómata push-down es una forma bastante intuitiva y poderosa de escribir tal stm.

+0

Cualquier sugerencia sobre cómo Comienzo a estudiar el concepto de máquinas de estado? La entrada de Wikipedia es un hecho, por supuesto. – Shadowfirebird

+1

Tomo el comentario de wikipedia. La página sobre autómatas pushdown parece fascinante, pero está escrita en matemáticas avanzadas. – Shadowfirebird

+1

@ Shadow: http://stackoverflow.com/questions/1669/learning-to-write-a-compiler es la página canónica para los recursos del compilador en SO. Pero lo que necesita es especialidad y puede no ser bien tratado. Esta respuesta es técnicamente correcta, pero no muy útil porque el procesamiento del lenguaje natural es notoriamente difícil y tiene su propia cultura e idioma. – dmckee

Cuestiones relacionadas