¿Cómo debería analizar la entrada del usuario en un juego de aventura de texto?

16

Analizar los comandos del usuario en una aventura de texto es un espectro desde el simple "ir al norte" de Adventure hasta algunos alucinantes e inteligentes en hhgttg .

Me parece recordar haber leído buenos tutoriales en revistas de informática en los años 80, pero ahora no encuentro casi nada en la red excepto una breve referencia de Wikipedia .

¿Cómo se haría?


Actualización : Fui con el enfoque más simple posible en mi entrada Ludum Dare .

Será
fuente
3
¿Hay algún problema particular que intentes resolver?
Trevor Powell el
@TrevorPowell considerando embarcarse en hacer un poco de aventura de texto por diversión, y sólo quiero familiarizarme del 'estado del arte' en lugar de buceo en la solución y que mi camino es todo
Will
1
Use Inform ; esa es la mejor estrategia que podrías usar. Prácticamente no hay razón para codificar manualmente una aventura de texto en estos días.
Nicol Bolas
@NicolBolas a menos que se acerque Ludum Dare? ;)
Será el
1
No es tanto derrotista como pragmático. Entrar en todas las técnicas de análisis de texto avanzado (más allá de las cosas obvias que cualquiera puede encontrar) probablemente esté fuera del alcance de una sola respuesta aquí.
Tetrad

Respuestas:

10

¿Buscaste en la comunidad de ficción interactiva? Todavía escriben analizadores y algunos intentan superar los límites mediante la implementación de nuevas técnicas, como el procesamiento del lenguaje natural.

Vea, por ejemplo, este enlace para artículos que describen los enfoques utilizados:

http://ifwiki.org/index.php/Past_raif_topics:_Development:_part_2#Parsing

krolth
fuente
44
¡Ajá, la "aventura de texto" se convierte en "ficción interactiva" y de repente es mucho más fácil de buscar! ¿Quién hubiera pensado que incluso cambiaría de nombre desde que lo jugué? :) Aún así, mirando esas pistas, y en realidad no mucho se explica tristemente
Will
9

El término que desea es 'procesamiento de lenguaje natural' o PNL. Sin embargo, tenga en cuenta que los métodos formales están diseñados para tratar de comprender textos del mundo real, mientras que generalmente solo necesita algo que funcione para un subconjunto limitado de su lenguaje natural.

Por lo general, puede comenzar con una gramática y vocabulario simples, y luego escribir un analizador para ello. Una gramática podría ser algo simple como esto:

sentence = verb [preposition] object
verb = "get" | "go" | "look" | "examine"
preposition = "above" | "below"
object = ["the"] [adjective] noun
adjective = "big" | "green"
noun = "north" | "south" | "east" | "west" | "house" | "dog"

Lo anterior es una variante de la forma Backus-Naur, la forma estándar de representar gramáticas. De todos modos, puede usar un generador de analizador para generar código para analizar esta gramática, o escribir el suyo con bastante facilidad si su idioma tiene un manejo de cadena decente. (Busque 'analizadores de descenso recursivo', que usan una función para cada línea de la gramática).

Una vez analizado, puede averiguar si la oración tiene sentido: "ir al norte" puede tener sentido, pero "obtener el norte verde" no. Puedes resolver esto de 2 maneras; hacer que la gramática sea más formal (por ejemplo, tener diferentes tipos de verbos solo válidos con ciertos tipos de sustantivo) o verificar los sustantivos con el verbo posterior. La primera forma puede ayudarlo a dar mejores mensajes de error al jugador, pero siempre debe hacer la segunda en algún grado, ya que siempre debe verificar el contexto, por ejemplo. "tomar la tecla verde" es gramaticalmente correcto y sintácticamente correcto, pero aún debe verificar que la tecla verde esté presente.

Finalmente, su programa termina con un comando validado con todas las diversas partes marcadas; entonces es solo un caso de llamar a la función correcta con los argumentos para realizar la acción.

Kylotan
fuente
6

El estado del arte para hacer aventuras de texto hoy en día está utilizando Inform 7 . La fuente de Inform 7 dice "me gusta el inglés", de la misma manera que los juegos basados ​​en Inform le permiten "escribir en inglés". Por ejemplo, de Emily Short's Bronze :

Una cosa tiene un texto llamado aroma. El aroma de una cosa suele ser "nada".
La regla de olor a bloque no figura en ningún libro de reglas.
Oler algo:
    di "De [el sustantivo] hueles [aroma del sustantivo]".
En lugar de oler una habitación:
    si el jugador puede tocar algo perfumado, diga "Hueles [la lista de cosas perfumadas que puede tocar el jugador]";
    de lo contrario diga "El lugar es maravillosamente inodoro".

El analizador Inform 7 está estrechamente integrado con el IDE Inform 7, y el código fuente completo aún no está disponible para su estudio:


fuente
5

Las dos mejores fuentes actuales para aprender a crear un analizador de aventura de texto son (como se mencionó) la comunidad IF y la comunidad de barro. Si busca en los foros principales (Intfiction.org/forum, el grupo de noticias rec.arts.int-fiction, Mud Connector, Mudbytes, Mudlab, Top Mud Sites) encontrará algunas respuestas, pero si solo está buscando para los artículos, recomendaría la explicación de Richard Bartle del analizador en MUD II:

http://www.mud.co.uk/richard/commpars.htm

Y esta explicación en rec.arts.int-fiction:

http://groups.google.com/group/rec.arts.int-fiction/msg/f545963efb72ec7b?dmode=source

Sin faltar el respeto a las otras respuestas, pero crear una gramática CF o usar BNF no es la solución para este problema. Eso no quiere decir que no podría ser una solución para un problema diferente, es decir, crear un analizador de lenguaje natural más avanzado, pero ese es el tema de una investigación considerable y no de la OMI en el ámbito de una aventura de texto.

georgek
fuente
4

En mi primer año en la universidad, hicimos un juego de aventuras en Prolog, y para la entrada del usuario tuvimos que usar la gramática de cláusula definida o DCG. Consulte http://www.amzi.com/manuals/amzi/pro/ref_dcg.htm#DCGCommandLanguage para ver un ejemplo de su uso como lenguaje de comandos. Parecía un enfoque basado en principios (era único después de todo) y flexible en ese momento.

Eric
fuente
1

Debes definir un lenguaje específico de dominio que contenga todas las oraciones correctas en tu juego. Para ello, debe definir una gramática para su idioma (vocabulario y sintaxis). El tipo de gramática que necesita es una gramática libre de contexto y existen herramientas que generan automáticamente un analizador sintáctico a partir de una descripción sintética de la gramática, como ANTLR (www.antlr.org). El analizador solo verifica si una oración es correcta o no y produce un Árbol de sintaxis abstracta (AST) de la oración, que es una representación navegable de la oración en la que cada palabra tiene el rol que especificó en la gramática. Al navegar por el AST, debe agregar el código que evalúa cuál es la semántica que toma cada palabra cuando desempeña ese papel con respecto a las otras palabras en la oración y verifica si la semántica es correcta.

Por ejemplo, la oración 'La piedra se come al hombre' es sintácticamente correcta pero no necesariamente semánticamente correcta (a menos que en su mundo las piedras, tal vez las piedras mágicas, puedan comer hombres).

Si también la semántica es correcta, puede, por ejemplo, cambiar el mundo de acuerdo con ella. Esto podría cambiar el contexto y, por lo tanto, la misma oración ya no podría ser semánticamente correcta (por ejemplo, no podría haber un hombre para comer)

www.Sillitoy.com
fuente
1

Utilicé el motor Tads3 (www.tads3.org) para algunas de las aventuras de texto que escribí. Sin embargo, es más para programadores informáticos, pero es un lenguaje muy poderoso. Si eres un programador, Tads3 será mucho más fácil codificar cosas más rápido que Inform7, que también he usado antes. El problema con Inform7 para programadores es tan famoso como "adivina el verbo" es para los jugadores de aventuras de texto en el sentido de que si no escribes tus oraciones MUY cuidadosamente, vas a romper el juego. Si tiene paciencia para hacerlo, puede escribir fácilmente un analizador en Java utilizando la clase Tokenizer. Ejemplo que escribí usando un JTextArea global y una matriz global String []. Elimina los caracteres no deseados, excepto las hojas AZ y 0-9, así como el signo de interrogación (para un atajo de comando "ayuda"):

// put these as global variables just after your main class definition
public static String[] parsed = new String[100];
// outputArea should be a non-editable JTextArea to display our results
JTextArea outputArea = new JTextArea();
/*
 * parserArea is the JTextBox used to grab input
 * and be sure to MAKE sure somewhere to add a 
 * java.awt.event.KeyListener on it somewhere where
 * you initialize all your variables and setup the
 * constraints settings for your JTextBox's.
 * The KeyListener method should listen for the ENTER key 
 * being pressed and then call our parseText() method below.
 */
JTextArea parserArea = new JTextArea();

public void parseText(){
    String s0 = parserArea.getText();// parserArea is our global JTextBox
    s0 = s0.replace(',',' ');
    s0 = s0.replaceAll("[^a-zA-Z0-9? ]","");
    // reset parserArea back to a clean starting state
    parserArea.setCaretPosition(0);
    parserArea.setText("");
    // erase what had been parsed before and also make sure no nulls found
    for(int i=0;i < parsed.length; i++){
      parsed[i] = "";
    }
    // split the string s0 to array words by breaking them up between spaces
    StringTokenizer tok = new StringTokenizer(s0, " ");
    // use tokenizer tok and dump the tokens into array: parsed[]
    int iCount = 0;
    if(tok.countTokens() > 0){
      while(tok.hasMoreElements()){
        try{
          parsed[iCount] = tok.nextElement().toString();
          if(parsed[iCount] != null && parsed[iCount].length()>1){
            // if a word ENDS in ? then strip it off
            parsed[iCount] = parsed[iCount].replaceAll("[^a-zA-Z0-9 ]","");
           }
        }catch(Exception e){
          e.printStackTrace();
        }
          iCount++;
        }


      /*
       * handle simple help or ? command.
       * parsed[0] is our first word... parsed[1] the second, etc.
       * we can use iCount from above as needed to see how many...
       * ...words got found.
       */
      if(parsed[0].equalsIgnoreCase("?") || 
        parsed[0].equalsIgnoreCase("help")){
          outputArea.setText("");// erase the output "screen"
          outputArea.append("\nPut help code in here...\n");
        }
      }

      // handle other noun and verb checks of parsed[] array in here...

    }// end of if(tok.countTokens() > 0)... 

}// end of public void parseText() method

... Dejé de lado la definición de clase principal y el método initialize () de variable, etc. porque se supone que si conoces Java ya sabes cómo configurarlo. La clase principal para esto probablemente debería extender JFrame y en su método public main void main () simplemente cree una instancia de él. Esperemos que algo de este código ayude.

EDITADO - Bien, ahora lo que harías a continuación es crear una clase de Acciones y buscar una acción (es decir, "obtener lámpara" o "soltar espada"). Para hacerlo más simple, tendría que tener un objeto o método RoomScan para escanear todo lo visible en el alcance y escanear solo aquellos objetos en esa acción. El objeto en sí mismo maneja el manejo de la acción y, de manera predeterminada, debe tener una clase Item que maneje todas las acciones conocidas de manera predeterminada, lo que se puede anular. Ahora, si, por ejemplo, un elemento que quieres "obtener" está en manos de un personaje que no es jugador, la respuesta predeterminada para que su propietario tenga ese elemento debería ser algo así como "No te permitirá tenerlo". Ahora tendría que crear un montón de respuestas de acción predeterminadas para esto en la clase Item o Thing. Básicamente, esto proviene de una perspectiva de Tads3 sobre todo el diseño. Debido a que en Tads3 cada elemento tiene su propia rutina de manejo de acción predeterminada que llama el analizador si se inicializa una acción en él. Entonces ... solo te digo que Tads3 ya tiene todo esto en su lugar, por lo que es MUY fácil de codificar en una aventura de texto en ese idioma. Pero si quieres hacerlo desde cero, como en Java (arriba), personalmente lo manejaría de la misma manera que Tads3 fue diseñado. De esa forma, puede anular las acciones predeterminadas que manejan rutinas en diferentes objetos, por lo que, por ejemplo, si desea "obtener la lámpara" y el mayordomo la sostiene, podría desencadenar una respuesta en el método de acción "obtener" predeterminado para el Elemento u Objeto y decirte que "El mayordomo se niega a entregar la lámpara de bronce". Quiero decir ... una vez que has sido programador el tiempo suficiente como yo, entonces todo esto es MUY fácil. Tengo más de 50 años y he estado haciendo esto desde que tenía 7 años. Mi padre era instructor de Hewlett Packard en los años 70, así que aprendí un TON de él inicialmente en programación de computadoras. También estoy en las Reservas del Ejército de los EE. UU. Como básicamente un administrador del servidor ahora. Um ... sí, así que no te rindas. No es tan difícil una vez que realmente lo desglosas en lo que quieres que haga tu programa. A veces, la prueba y error es la mejor manera de hacer este tipo de cosas. Solo pruébalo y mira y nunca te rindas. ¿Bueno? La codificación es un arte. Se puede hacer de muchas maneras diferentes. No dejes que una forma u otra parezcan bloquearte en una esquina en el diseño. También estoy en las Reservas del Ejército de los Estados Unidos como básicamente un administrador de servidores ahora. Um ... sí, así que no te rindas. No es tan difícil una vez que realmente lo desglosas en lo que quieres que haga tu programa. A veces, la prueba y error es la mejor manera de hacer este tipo de cosas. Solo pruébalo y mira y nunca te rindas. ¿Bueno? La codificación es un arte. Se puede hacer de muchas maneras diferentes. No dejes que una forma u otra parezcan bloquearte en una esquina en el diseño. También estoy en las Reservas del Ejército de los Estados Unidos como básicamente un administrador de servidores ahora. Um ... sí, así que no te rindas. No es tan difícil una vez que realmente lo desglosas en lo que quieres que haga tu programa. A veces, la prueba y error es la mejor manera de hacer este tipo de cosas. Solo pruébalo y mira y nunca te rindas ¿Bueno? La codificación es un arte. Se puede hacer de muchas maneras diferentes. No dejes que una forma u otra parezcan bloquearte en una esquina en el diseño.

William Chelonis
fuente
Desafortunadamente, esto omite la parte más difícil de un analizador de texto, es decir, identificar el verbo, el sujeto y el objeto de la entrada del usuario y asignarlo a una acción.
Philipp
Es cierto, pero cómo lo haría es crear una clase de acciones y almacenar un montón de acciones en, por ejemplo, una clase de diccionario, luego buscar palabras de acciones. Si la acción involucra una segunda palabra (como para una acción de "tomar", tal vez "tomar una lámpara"), entonces haga escanear un grupo de objetos (o sustantivos) para ver dónde esos objetos mismos tendrían una secuencia de comandos para manejar las acciones realizadas en ellos. Todo esto supone que codificaría todo en Java y no intentaría leer un archivo externo real para compilar aventuras de texto.
William Chelonis