Bagaimana cara mengurai input pengguna dalam game petualangan teks?

16

Mem-parsing perintah pengguna dalam petualangan teks adalah sebuah spektrum dari "Go North" yang sederhana dari Adventure ke beberapa perintah yang sangat membingungkan di hhgttg .

Sepertinya saya ingat pernah membaca cara-cara bagus di majalah komputer di tahun 80-an, tapi sekarang saya hampir tidak menemukan apa-apa di internet kecuali referensi singkat Wikipedia .

Bagaimana Anda melakukannya?


Pembaruan : Saya menggunakan pendekatan sesederhana mungkin dalam entri Ludum Dare saya .

Akan
sumber
3
Apakah ada masalah tertentu yang Anda coba selesaikan?
Trevor Powell
@TrevorPowell mempertimbangkan memulai membuat petualangan teks kecil untuk bersenang-senang, dan hanya ingin memperkenalkan diri saya pada 'keadaan seni' daripada hanya menyelam dan menyelesaikannya dengan cara saya semua
Will
1
Gunakan Inform ; itulah strategi terbaik yang bisa Anda gunakan. Hampir tidak ada alasan untuk menulis kode petualangan teks hari ini.
Nicol Bolas
@NicolBolas kecuali Ludum Dare mendekat? ;)
Will
1
Itu tidak kalah seperti pragmatis. Memahami semua teknik penguraian teks tingkat lanjut (di luar hal-hal yang bisa dilakukan siapa pun) mungkin di luar cakupan satu jawaban di sini.
Tetrad

Jawaban:

10

Apakah Anda mencari di komunitas fiksi interaktif? Mereka masih menulis parser dan beberapa mencoba mendorong amplop dengan menerapkan teknik baru seperti pemrosesan bahasa alami.

Lihat misalnya tautan ini untuk artikel yang menjelaskan pendekatan yang digunakan:

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

Krolth
sumber
4
Aha, "petualangan teks" menjadi "fiksi interaktif" dan tiba-tiba ini lebih googlable! Siapa yang mengira itu bahkan akan mengubah nama sejak saya memainkannya? :) Tetap saja, melihat petunjuk itu, dan sebenarnya tidak banyak yang bisa dijelaskan dengan sedih
Will
9

Istilah yang Anda inginkan adalah 'pemrosesan bahasa alami', atau NLP. Namun, ingatlah bahwa metode formal dirancang untuk mencoba dan memahami teks-teks dunia nyata, sedangkan Anda biasanya hanya membutuhkan sesuatu yang berfungsi untuk subset terbatas dari bahasa alami Anda.

Biasanya Anda bisa mulai dengan tata bahasa dan kosakata sederhana, kemudian menulis parser untuk itu. Tata bahasa mungkin sesuatu yang sederhana seperti ini:

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"

Di atas adalah varian pada bentuk Backus-Naur, cara standar untuk mewakili tata bahasa. Bagaimanapun, Anda dapat menggunakan generator parser untuk menghasilkan kode untuk menguraikan tata bahasa ini, atau menulis sendiri dengan mudah jika bahasa Anda memiliki penanganan string yang baik. (Cari 'pengurai keturunan rekursif', yang menggunakan satu fungsi untuk setiap baris tata bahasa.)

Setelah diuraikan, Anda dapat menentukan apakah kalimatnya masuk akal - "pergi ke utara" mungkin masuk akal, tetapi "dapatkan hijau utara" tidak. Anda dapat menyelesaikan ini dengan 2 cara; membuat tata bahasa lebih formal (mis. memiliki berbagai jenis kata kerja hanya berlaku untuk beberapa jenis kata benda) atau memeriksa kata benda terhadap kata kerja sesudahnya. Cara pertama dapat membantu Anda untuk memberikan pesan kesalahan yang lebih baik kepada pemain, tetapi Anda tetap harus melakukan yang kedua sampai tingkat tertentu, karena Anda selalu perlu memeriksa konteks - misalnya. "ambil kunci hijau" secara tata bahasa benar dan secara sintaksis benar, tetapi Anda masih perlu memeriksa bahwa kunci hijau itu ada.

Akhirnya program Anda berakhir dengan perintah yang divalidasi dengan semua bagian yang berbeda diperiksa; maka itu hanya kasus memanggil fungsi yang tepat dengan argumen untuk melakukan aksinya.

Kylotan
sumber
6

Keadaan seni untuk membuat petualangan teks hari ini menggunakan Inform 7 . Sumber informan 7 berbunyi "seperti bahasa Inggris," dengan cara yang sama seperti permainan berbasis informasi memungkinkan Anda "menulis bahasa Inggris." Misalnya, dari Emily Short's Bronze :

Suatu benda memiliki beberapa teks yang disebut aroma. Aroma suatu benda biasanya "tidak ada".
Aturan pencekalan tidak dicantumkan dalam buku aturan apa pun.
Lakukan sesuatu yang berbau:
    ucapkan "Dari [kata benda] kamu mencium [aroma kata benda]."
Alih-alih mencium bau ruangan:
    jika sesuatu yang wangi dapat disentuh oleh pemain, katakan "Anda mencium [daftar hal-hal yang wangi yang dapat disentuh oleh pemain].";
    kalau tidak, katakan "Tempat ini benar-benar tidak berbau."

Inform 7 parser terintegrasi dengan IDE 7 Inform, dan seluruh kode sumber belum tersedia untuk dipelajari:


sumber
5

Dua sumber terbaik saat ini untuk belajar membuat parser petualangan teks adalah (seperti yang disebutkan) komunitas IF dan komunitas lumpur. Jika Anda mencari di forum utama (Intfiction.org/forum, newsgroup rec.arts.int-fiction, Connector Mud, Mudbytes, Mudlab, Top Mud Sites) Anda akan menemukan beberapa jawaban, tetapi jika Anda hanya mencari untuk artikel saya akan merekomendasikan penjelasan Richard Bartle tentang pengurai dalam MUD II:

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

Dan penjelasan tentang rec.arts.int-fiction ini:

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

Tidak ada rasa tidak hormat terhadap jawaban lain, tetapi membuat tata bahasa CF atau menggunakan BNF bukanlah solusi untuk masalah ini. Bukan untuk mengatakan itu tidak bisa menjadi solusi untuk masalah yang berbeda, yaitu, membuat parser bahasa alami yang lebih maju, tapi itu adalah subjek penelitian yang cukup dan bukan IMO dalam lingkup petualangan teks.

georgek
sumber
4

Di tahun pertama saya di universitas, kami membuat game petualangan di Prolog, dan untuk input pengguna kami harus menggunakan tata bahasa klausa atau DCG yang pasti. Lihat http://www.amzi.com/manuals/amzi/pro/ref_dcg.htm#DCGCommandLanguage untuk contoh menggunakannya sebagai bahasa perintah. Rasanya seperti pendekatan berprinsip (itu uni setelah semua) dan fleksibel pada saat itu.

Eric
sumber
1

Anda perlu mendefinisikan bahasa khusus domain yang merupakan semua kalimat yang benar dalam permainan Anda. Untuk tujuan ini, Anda harus mendefinisikan tata bahasa untuk bahasa Anda (kosakata dan sintaksis). Jenis tata bahasa yang Anda butuhkan adalah Tata Bahasa Gratis Konteks dan ada alat yang secara otomatis menghasilkan pengurai mulai dari deskripsi sintetik tata bahasa seperti ANTLR (www.antlr.org). Parser hanya memeriksa apakah kalimat itu benar atau tidak dan menghasilkan Pohon Sintaksis Abstrak (AST) dari kalimat yang merupakan representasi kalimat yang dapat dinavigasi di mana setiap kata memiliki peran yang Anda tentukan dalam tata bahasa. Dengan menavigasi AST, Anda harus menambahkan kode yang menilai apa arti semantik yang diambil setiap kata saat memainkan peran tersebut sehubungan dengan kata-kata lain dalam kalimat dan memverifikasi apakah semantiknya benar.

Misalnya kalimat 'Batu itu memakan laki-laki' secara sintaksis benar tetapi tidak secara semantik benar (kecuali di dunia Anda batu, mungkin batu ajaib, bisa memakan laki-laki).

Jika semantiknya benar maka Anda dapat, misalnya, mengubah dunia sesuai dengan itu. Ini bisa mengubah konteks dan dengan demikian kalimat yang sama tidak lagi benar secara semantik (misalnya tidak ada manusia yang bisa makan)

www.Sillitoy.com
sumber
1

Saya menggunakan mesin Tads3 (www.tads3.org) untuk beberapa petualangan teks yang saya tulis. Ini lebih untuk programmer komputer tetapi bahasa yang sangat kuat. Jika Anda seorang programmer, Tads3 akan lebih mudah untuk membuat kode lebih cepat daripada Inform7, yang telah saya gunakan sebelumnya juga. Masalah dengan Inform7 untuk programmer sama terkenalnya dengan "tebak kata kerjanya" adalah untuk para pemain petualangan teks karena jika Anda tidak menulis kalimat Anda SANGAT hati-hati Anda akan merusak permainan. Jika Anda memiliki kesabaran untuk melakukannya, Anda dapat dengan mudah menulis parser di Jawa menggunakan kelas Tokenizer. Contoh saya menulis menggunakan global JTextArea dan global String [] array. Ini menghapus karakter yang tidak diinginkan kecuali daun AZ dan 0-9 serta tanda tanya (untuk pintasan perintah "bantuan"):

// 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

... Saya meninggalkan definisi kelas utama dan variabel initialize () method, dll. Karena diasumsikan jika Anda tahu Java Anda sudah tahu cara mengaturnya. Kelas utama untuk ini mungkin harus memperluas JFrame dan dalam metode public void main () statis Anda, buat saja instance darinya. Semoga beberapa kode ini membantu.

DIedit - Oke, jadi sekarang apa yang akan Anda lakukan selanjutnya adalah membuat kelas Tindakan dan memindai tindakan (yaitu "mendapatkan lampu" atau "jatuhkan pedang"). Untuk membuatnya lebih sederhana, Anda harus memiliki objek atau metode RoomScan untuk memindai semua yang terlihat dalam lingkup dan memindai hanya objek-objek yang ada di tindakan itu. Objek itu sendiri menangani penanganan tindakan dan secara default Anda harus memiliki kelas Item menangani semua tindakan yang diketahui secara default, yang bisa dikuasai secara berlebihan. Sekarang, jika misalnya, item yang Anda ingin "dapatkan" dipegang oleh karakter non-pemain, respons default untuk mendapatkan item yang dipegang oleh pemiliknya haruslah seperti "Tidak akan membiarkan Anda memilikinya." Sekarang Anda harus membuat satu ton respons tindakan default untuk ini di kelas Item atau Thing. Ini pada dasarnya berasal dari perspektif Tads3 di atas semua desain. Karena di Tads3 setiap item memiliki tindakan standar penanganan rutin di atasnya yang dipanggil parser jika tindakan di atasnya diinisialisasi. Jadi ... Saya baru saja memberitahu Anda, Tads3 sudah memiliki semua ini, jadi SANGAT mudah untuk kode dalam petualangan teks dalam bahasa itu. Tetapi jika Anda ingin melakukannya dari awal, seperti di Jawa (di atas), maka saya pribadi akan menanganinya dengan cara yang sama seperti Tads3 dirancang. Dengan cara itu, Anda dapat mengesampingkan tindakan standar yang menangani rutin pada objek yang berbeda itu sendiri, jadi misalnya jika Anda ingin "mendapatkan lampu" dan kepala pelayan memegangnya, itu dapat memicu respons dalam metode tindakan "get" default untuk Item. atau Obyek dan memberi tahu Anda bahwa "Kepala pelayan menolak untuk menyerahkan lampu kuningan." Maksud saya ... setelah Anda menjadi seorang programmer cukup lama seperti yang saya miliki, maka ini semua SANGAT mudah. Saya berusia lebih dari 50 tahun dan telah melakukan ini sejak saya berusia 7. Ayah saya adalah seorang instruktur Hewlett Packard di tahun 70-an jadi saya belajar satu TON darinya awalnya pada pemrograman komputer. Saya juga di Cadangan Angkatan Darat AS karena pada dasarnya administrator server sekarang. Um ... ya, jadi jangan menyerah. Ini tidak sulit setelah Anda benar-benar memecahnya menjadi apa yang Anda ingin program Anda lakukan. Terkadang coba-coba adalah cara terbaik untuk mengerjakan hal-hal semacam ini. Coba saja dan lihat dan jangan pernah menyerah. Baik? Pengkodean adalah seni. Itu dapat dilakukan dengan berbagai cara. Jangan biarkan satu cara atau yang lain tampaknya menghalangi Anda ke sudut pada desain. m juga di Cadangan Angkatan Darat AS karena pada dasarnya administrator server sekarang. Um ... ya, jadi jangan menyerah. Ini tidak sulit setelah Anda benar-benar memecahnya menjadi apa yang Anda ingin program Anda lakukan. Terkadang coba-coba adalah cara terbaik untuk mengerjakan hal-hal semacam ini. Coba saja dan lihat dan jangan pernah menyerah. Baik? Pengkodean adalah seni. Itu dapat dilakukan dengan berbagai cara. Jangan biarkan satu cara atau yang lain tampaknya menghalangi Anda ke sudut pada desain. m juga di Cadangan Angkatan Darat AS karena pada dasarnya administrator server sekarang. Um ... ya, jadi jangan menyerah. Ini tidak sulit setelah Anda benar-benar memecahnya menjadi apa yang Anda ingin program Anda lakukan. Terkadang coba-coba adalah cara terbaik untuk mengerjakan hal-hal semacam ini. Coba saja dan lihat dan jangan pernah menyerah. Baik? Pengkodean adalah seni. Itu dapat dilakukan dengan berbagai cara. Jangan biarkan satu cara atau yang lain tampaknya menghalangi Anda ke sudut pada desain.

William Chelonis
sumber
Sayangnya ini meninggalkan bagian yang paling sulit dari pengurai teks, yaitu mengidentifikasi kata kerja, subjek dan objek dari input pengguna dan memetakannya ke suatu tindakan.
Philipp
Benar tapi bagaimana saya melakukannya adalah membuat kelas tindakan dan menyimpan banyak tindakan di, katakanlah, kelas kamus, lalu pindai kata-kata tindakan. Jika aksinya melibatkan kata ke-2 (seperti untuk aksi "ambil", mungkin "ambil lampu") maka pindai sekelompok item (atau kata benda) objek yang dipindai di mana objek itu sendiri akan memiliki skrip untuk menangani tindakan yang dilakukan pada mereka. Ini semua dengan asumsi Anda akan kode semuanya ke Jawa dan tidak mencoba dan membuat file eksternal yang sebenarnya dibaca untuk mengkompilasi petualangan teks.
William Chelonis