ฉันจะแยกวิเคราะห์การป้อนข้อมูลของผู้ใช้ในเกมผจญภัยข้อความได้อย่างไร


16

แยกคำสั่งที่ใช้ในการผจญภัยข้อความเป็นสเปกตรัมจากการผจญภัยง่าย 's 'ไปทิศตะวันตกเฉียงเหนือ' เพื่อบางคนที่ใจ bogglingly ฉลาดในhhgttg

ฉันดูเหมือนจะจำการอ่านที่ดีวิธีการชำระเงินในนิตยสารคอมพิวเตอร์ย้อนกลับไปในยุค 80 แต่ตอนนี้ผมพบว่าเกือบไม่มีอะไรที่ 'สุทธิยกเว้นสั้นวิกิพีเดียโทษ

วิธีจะคุณจะทำหรือไม่


ปรับปรุง : ฉันไปด้วยวิธีการที่ง่ายที่สุดที่เป็นไปได้ในรายการ Ludum กล้าของฉัน


3
มีปัญหาใดที่คุณพยายามแก้ไขหรือไม่?
เทรเวอร์พาวเวลล์

@TrevorPowell กำลังพิจารณาที่จะเริ่มต้นการผจญภัยข้อความเล็ก ๆ น้อย ๆ เพื่อความสนุกและเพียงต้องการที่จะทำความรู้จักกับ 'state of the art' มากกว่าที่จะดำน้ำและแก้ไขมันในแบบของฉัน
Will

1
ใช้แจ้ง ; นั่นเป็นกลยุทธ์ที่ดีที่สุดที่คุณเคยใช้ แทบจะไม่มีเหตุผลที่จะเขียนโค้ดการผจญภัยด้วยมือในวันนี้
Nicol Bolas

@NicolBolas เว้นแต่ Ludum Dare กำลังใกล้เข้ามา? ;)
จะ

1
มันไม่ได้พ่ายแพ้มากเท่ากับการปฏิบัติ การเข้าสู่ทุกเทคนิคการแยกวิเคราะห์ข้อความขั้นสูง (เกินกว่าสิ่งที่ทุกคนสามารถทำได้) อาจอยู่นอกขอบเขตของคำตอบเดียวที่นี่
Tetrad

คำตอบ:


10

คุณค้นหาในชุมชนนิยายเชิงโต้ตอบหรือไม่? พวกเขายังเขียน parsers และบางคนพยายามที่จะผลักซองจดหมายโดยใช้เทคนิคใหม่เช่นการประมวลผลภาษาธรรมชาติ

ดูตัวอย่างลิงก์นี้สำหรับบทความที่อธิบายวิธีการที่ใช้:

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


4
อ๊ะ "การผจญภัยข้อความ" กลายเป็น "นิยายเชิงโต้ตอบ" และทันใดนั้นก็เป็น googlable อื่น ๆ อีกมากมาย! ใครบ้างที่คิดว่ามันจะเปลี่ยนชื่อตั้งแต่ฉันเล่น :) ยังคงมองไปที่ผู้นำเหล่านั้นและจริง ๆ แล้วไม่ได้รับการอธิบายอย่างน่าเศร้ามาก
จะ

9

คำที่คุณต้องการคือ 'การประมวลผลภาษาธรรมชาติ' หรือ NLP อย่างไรก็ตามโปรดจำไว้ว่าวิธีการอย่างเป็นทางการได้รับการออกแบบมาเพื่อพยายามและเข้าใจตำราโลกแห่งความเป็นจริงในขณะที่คุณมักจะต้องการบางสิ่งบางอย่างที่ใช้งานได้สำหรับภาษาย่อยของคุณ

โดยทั่วไปคุณสามารถเริ่มต้นด้วยไวยากรณ์และคำศัพท์ง่ายๆแล้วเขียนโปรแกรมแยกวิเคราะห์ ไวยากรณ์อาจเป็นสิ่งที่ง่ายเช่นนี้:

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"

ด้านบนเป็นตัวแปรในรูปแบบ Backus-Naur ซึ่งเป็นวิธีมาตรฐานในการแสดงไวยากรณ์ อย่างไรก็ตามคุณสามารถใช้ตัวแยกวิเคราะห์เพื่อสร้างรหัสเพื่อแยกไวยากรณ์นี้หรือเขียนของคุณเองค่อนข้างง่ายถ้าภาษาของคุณมีการจัดการสตริงที่เหมาะสม (ค้นหา 'ตัวแยกวิเคราะห์แบบสืบเชื้อสายซ้ำ' ซึ่งใช้หนึ่งฟังก์ชันสำหรับแต่ละบรรทัดของไวยากรณ์)

เมื่อแยกวิเคราะห์แล้วคุณสามารถออกกำลังกายได้หากประโยคนั้นสมเหตุสมผล - "go north" อาจสมเหตุสมผล แต่ "get the green north" ไม่ได้ คุณสามารถแก้ปัญหานี้ได้ 2 วิธี; ทำให้ไวยากรณ์เป็นทางการมากขึ้น (เช่นมีคำกริยาต่างชนิดที่ใช้ได้กับคำนามบางประเภทเท่านั้น) หรือตรวจสอบคำนามกับคำกริยาในภายหลัง วิธีแรกสามารถช่วยให้คุณส่งข้อความแสดงข้อผิดพลาดที่ดีกว่าให้กับผู้เล่นได้ แต่คุณจะต้องทำในระดับที่สองถึงระดับหนึ่งเสมอเพราะคุณจำเป็นต้องตรวจสอบบริบทเสมอ - เช่น "ใช้ปุ่มสีเขียว" ถูกต้องตามหลักไวยากรณ์และถูกต้องตามหลักไวยากรณ์ แต่คุณยังต้องตรวจสอบว่ามีปุ่มสีเขียวปรากฏอยู่

ในที่สุดโปรแกรมของคุณก็จะจบลงด้วยคำสั่งที่ผ่านการตรวจสอบและมีการตรวจสอบชิ้นส่วนต่าง ๆ ทั้งหมด จากนั้นเป็นเพียงการเรียกใช้ฟังก์ชันที่ถูกต้องพร้อมอาร์กิวเมนต์เพื่อดำเนินการ


6

รัฐของศิลปะในการทำให้ข้อความผจญภัยในวันนี้คือการใช้แจ้ง 7 การแจ้งแหล่งที่มา 7 รายการจะอ่านว่า "เหมือนอังกฤษ" ในลักษณะเดียวกับเกมที่ให้ข้อมูลคุณสามารถ "เขียนภาษาอังกฤษได้" ตัวอย่างเช่นจากบรอนซ์ของ Emily Short :

บางสิ่งมีข้อความที่เรียกว่ากลิ่น กลิ่นของสิ่งต่าง ๆ มักจะเป็น "ไม่มีอะไร"
กฎการดมกลิ่นบล็อกไม่อยู่ในรายการในกฎใด ๆ
ทำสิ่งที่มีกลิ่น:
    พูดว่า "จาก [คำนาม] คุณได้กลิ่น [กลิ่นของคำนาม]"
แทนที่จะทำให้ห้องมีกลิ่น:
    หากผู้เล่นสามารถสัมผัสสิ่งที่มีกลิ่นหอมได้ให้พูดว่า "คุณได้กลิ่น [รายการของสิ่งที่มีกลิ่นหอมซึ่งผู้เล่นสามารถสัมผัสได้]";
    ถ้าอย่างนั้นก็พูดว่า "สถานที่นี้ไม่มีกลิ่นเหม็น"

ตัวแยกวิเคราะห์ Inform 7 ถูกรวมเข้ากับ Inform 7 IDE อย่างใกล้ชิดและซอร์สโค้ดทั้งหมดยังไม่พร้อมสำหรับการศึกษา:


5

แหล่งข้อมูลที่ดีที่สุดสองแหล่งในปัจจุบันสำหรับการเรียนรู้เพื่อสร้างตัวแยกวิเคราะห์ข้อความผจญภัยคือชุมชน IF และชุมชนโคลน หากคุณค้นหาฟอรัมหลักสำหรับบรรดา (Intfiction.org/forum กลุ่มข่าวสาร rec.arts.int-fiction, Mud Connector, Mudbytes, Mudlab, Mud ไซต์ยอดนิยม) คุณจะพบคำตอบ แต่ถ้าคุณแค่มอง สำหรับบทความฉันขอแนะนำคำอธิบายของ Richard Bartle เกี่ยวกับเครื่องมือวิเคราะห์คำใน MUD II:

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

และคำอธิบายนี้เกี่ยวกับ rec.arts.int-fiction:

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

การไม่ดูหมิ่นหมายถึงคำตอบอื่น ๆ แต่การสร้างไวยากรณ์ CF หรือการใช้ BNF ไม่ใช่วิธีแก้ปัญหาสำหรับปัญหานี้ ไม่ได้หมายความว่าจะไม่สามารถแก้ปัญหาที่แตกต่างนั่นก็คือการสร้างตัวแยกวิเคราะห์ภาษาธรรมชาติขั้นสูงขึ้น แต่นั่นเป็นหัวข้อของการวิจัยที่สำคัญและไม่ใช่ IMO ในขอบเขตของการผจญภัยข้อความ


4

ในปีแรกของฉันที่มหาวิทยาลัยเราทำเกมผจญภัยใน Prolog และสำหรับผู้ใช้ที่ป้อนเราต้องใช้ไวยากรณ์ประโยคหรือ DCG ที่ชัดเจน ดูhttp://www.amzi.com/manuals/amzi/pro/ref_dcg.htm#DCGCommandLanguageสำหรับตัวอย่างของการใช้มันเป็นภาษาคำสั่ง ดูเหมือนว่าเป็นหลักการ (มันเป็น uni after all) และแนวทางที่ยืดหยุ่นในเวลานั้น


1

คุณต้องกำหนดภาษาเฉพาะของโดเมนนั่นคือประโยคทั้งหมดที่ถูกต้องในเกมของคุณ ด้วยเหตุนี้คุณต้องกำหนดไวยากรณ์สำหรับภาษาของคุณ (คำศัพท์และไวยากรณ์) ประเภทของไวยากรณ์ที่คุณต้องการคือบริบทไวยากรณ์ฟรีและมีเครื่องมือที่สร้างโปรแกรมแยกวิเคราะห์โดยอัตโนมัติโดยเริ่มจากคำอธิบายสังเคราะห์ของไวยากรณ์เช่น ANTLR (www.antlr.org) โปรแกรมแยกวิเคราะห์จะตรวจสอบว่าประโยคนั้นถูกต้องหรือไม่เท่านั้นและสร้าง Abstract Syntax Tree (AST) ของประโยคที่เป็นการนำทางของประโยคที่แต่ละคำมีบทบาทที่คุณระบุไว้ในไวยากรณ์ โดยการนำ AST คุณต้องเพิ่มรหัสที่ประเมินความหมายของคำแต่ละคำเมื่อเล่นบทบาทนั้นด้วยความเคารพคำอื่น ๆ ในประโยคและตรวจสอบว่า semantics นั้นถูกต้องหรือไม่

ตัวอย่างเช่นประโยค 'หินที่กินมนุษย์' นั้นถูกต้องตามหลักไวยากรณ์ แต่ไม่จำเป็นต้องมีความหมายทางอรรถศาสตร์ (ยกเว้นในหินโลกของคุณอาจเป็นหินวิเศษสามารถกินผู้ชายได้)

ถ้าหากซีแมนทิกส์นั้นถูกต้องคุณสามารถเปลี่ยนแปลงโลกได้ตามนั้น สิ่งนี้สามารถเปลี่ยนบริบทและทำให้ประโยคเดียวกันไม่สามารถแก้ไขความหมายได้อีกต่อไป (ตัวอย่างเช่นไม่มีผู้ชายคนไหนที่จะกิน)


1

ฉันใช้เครื่องมือ Tads3 (www.tads3.org) สำหรับการผจญภัยข้อความที่ฉันเขียน มันมากขึ้นสำหรับโปรแกรมเมอร์คอมพิวเตอร์ แต่ภาษาที่ทรงพลังมาก หากคุณเป็นโปรแกรมเมอร์ Tads3 จะสามารถเขียนโค้ดได้เร็วกว่า Inform7 ซึ่งฉันเคยใช้มาก่อนเช่นกัน ปัญหากับโปรแกรม Inform7 สำหรับโปรแกรมเมอร์นั้นมีชื่อเสียงโด่งดังในฐานะ "เดาคำกริยา" สำหรับผู้เล่นที่ชอบผจญภัยข้อความในกรณีที่คุณไม่ได้เขียนประโยคของคุณอย่างระมัดระวังคุณจะต้องทำลายเกม หากคุณมีความอดทนที่จะทำคุณสามารถเขียน parser ใน Java โดยใช้คลาส Tokenizer ตัวอย่างที่ฉันเขียนโดยใช้ JTextArea ทั่วโลกและสตริงทั่วโลก [] มันจะแยกอักขระที่ไม่ต้องการออกจาก AZ และ 0-9 รวมถึงเครื่องหมายคำถาม (สำหรับทางลัดคำสั่ง "help"):

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

... ฉันออกจากคำจำกัดความของคลาสหลักและเมธอด initialize () เป็นต้นเนื่องจากจะถือว่าถ้าคุณรู้จัก Java คุณก็รู้วิธีตั้งค่านั้นแล้ว คลาสหลักสำหรับสิ่งนี้น่าจะขยาย JFrame และในโมฆะหลักคงที่โมฆะสาธารณะ () ของคุณเพียงแค่สร้างตัวอย่างของมัน หวังว่ารหัสนี้จะช่วยได้บ้าง

แก้ไข - เอาล่ะดังนั้นตอนนี้สิ่งที่คุณต้องทำต่อไปคือสร้างคลาสการกระทำและสแกนหาการกระทำ (เช่น "รับหลอดไฟ" หรือ "วางดาบ") เพื่อให้ง่ายขึ้นคุณจะต้องมีวัตถุหรือวิธีการ RoomScan เพื่อสแกนทุกสิ่งที่มองเห็นได้ในขอบเขตและสแกนหาวัตถุเหล่านั้นในการกระทำนั้นเท่านั้น วัตถุเองจัดการการจัดการการกระทำและโดยค่าเริ่มต้นคุณควรมีคลาสรายการจัดการการกระทำที่รู้จักทั้งหมดในวิธีการเริ่มต้นซึ่งสามารถ over - ridden ตอนนี้ถ้าเช่นรายการที่คุณต้องการที่จะ "รับ" ถูกเก็บไว้โดยตัวละครที่ไม่ใช่ผู้เล่นการตอบสนองเริ่มต้นสำหรับการรับไอเท็มที่เจ้าของรายการนั้นควรจะเป็นเช่น "การไม่ยอมให้คุณมี" ตอนนี้คุณต้องสร้างการตอบกลับการกระทำเริ่มต้นเป็นตันในรายการหรือชั้นสิ่ง นี่คือพื้นฐานมาจากมุมมองของ Tads3 ในทุกการออกแบบ เนื่องจากใน Tads3 แต่ละไอเท็มมีรูทีนการจัดการแอ็คชันเริ่มต้นของตัวเองซึ่ง parser เรียกว่าหากมีการเริ่มต้นแอ็คชัน ดังนั้น ... ฉันแค่บอกคุณ Tads3 มีสิ่งนี้อยู่แล้วดังนั้นมันง่ายมากที่จะเขียนโค้ดในการผจญภัยข้อความในภาษานั้น แต่ถ้าคุณต้องการที่จะทำตั้งแต่เริ่มต้นเช่นใน Java (ด้านบน) จากนั้นฉันจะจัดการกับมันแบบเดียวกับที่ Tads3 ได้รับการออกแบบ ด้วยวิธีนี้คุณสามารถแทนที่การกระทำเริ่มต้นที่จัดการกิจวัตรบนวัตถุที่แตกต่างกันได้เองตัวอย่างเช่นหากคุณต้องการ "รับหลอดไฟ" และผู้ดูแลถือไว้ หรือวัตถุแล้วบอกคุณว่า "พ่อบ้านปฏิเสธที่จะมอบตะเกียงทองเหลือง" ฉันหมายถึง ... เมื่อคุณเป็นโปรแกรมเมอร์มานานพอที่ฉันมีแล้วนี่คือสิ่งที่ง่ายมาก ฉันอายุมากกว่า 50 ปีและทำสิ่งนี้มาตั้งแต่อายุ 7 ขวบพ่อของฉันเป็นอาจารย์สอนของฮิวเลตต์แพคการ์ดในยุค 70 ดังนั้นฉันจึงเรียนรู้ TON จากเขาในตอนแรกเกี่ยวกับการเขียนโปรแกรมคอมพิวเตอร์ ฉันยังอยู่ใน US Army Reserve เพราะโดยทั่วไปเป็นผู้ดูแลเซิร์ฟเวอร์แล้ว อืมใช่แล้วอย่ายอมแพ้ ไม่ใช่เรื่องยากเมื่อคุณแยกแยะสิ่งที่คุณต้องการให้โปรแกรมทำ บางครั้งการลองผิดลองถูกเป็นวิธีที่ดีที่สุดในการทำสิ่งนี้ เพียงแค่ทดสอบและดูและไม่เคยยอมแพ้ ตกลง? การเข้ารหัสเป็นศิลปะ สามารถทำได้หลายวิธี อย่าให้ทางใดทางหนึ่งดูเหมือนจะบล็อกคุณในมุมของการออกแบบ m ยังอยู่ใน US Army Reserve ซึ่งโดยทั่วไปเป็นผู้ดูแลเซิร์ฟเวอร์ในขณะนี้ อืมใช่แล้วอย่ายอมแพ้ ไม่ใช่เรื่องยากเมื่อคุณแยกแยะสิ่งที่คุณต้องการให้โปรแกรมทำ บางครั้งการลองผิดลองถูกเป็นวิธีที่ดีที่สุดในการทำสิ่งนี้ เพียงแค่ทดสอบและดูและไม่เคยยอมแพ้ ตกลง? การเข้ารหัสเป็นศิลปะ สามารถทำได้หลายวิธี อย่าให้ทางใดทางหนึ่งดูเหมือนจะบล็อกคุณในมุมของการออกแบบ m ยังอยู่ใน US Army Reserve ซึ่งโดยทั่วไปเป็นผู้ดูแลเซิร์ฟเวอร์ในขณะนี้ อืมใช่แล้วอย่ายอมแพ้ ไม่ใช่เรื่องยากเมื่อคุณแยกแยะสิ่งที่คุณต้องการให้โปรแกรมทำ บางครั้งการลองผิดลองถูกเป็นวิธีที่ดีที่สุดในการทำสิ่งนี้ เพียงแค่ทดสอบและดูและไม่เคยยอมแพ้ ตกลง? การเข้ารหัสเป็นศิลปะ สามารถทำได้หลายวิธี อย่าให้ทางใดทางหนึ่งดูเหมือนจะบล็อกคุณในมุมของการออกแบบ


โชคไม่ดีที่นี่เป็นส่วนที่ยากที่สุดในการแยกวิเคราะห์ข้อความคือการระบุคำกริยาหัวเรื่องและวัตถุของการป้อนข้อมูลของผู้ใช้
ฟิลิปป์

จริง แต่ฉันจะทำอย่างไรก็คือสร้างคลาสแอคชั่นและเก็บแอคชั่นมากมายไว้พูดคลาสพจนานุกรมจากนั้นสแกนหาคำการกระทำ หากการดำเนินการเกี่ยวข้องกับคำที่ 2 (เช่นการกระทำที่ "ใช้" อาจจะ "รับหลอดไฟ") จากนั้นมีวัตถุสิ่งของ (หรือคำนาม) ที่ถูกสแกนซึ่งวัตถุเหล่านั้นจะมีสคริปต์เพื่อจัดการกับการกระทำของพวกเขา นี่คือทั้งหมดที่สมมติว่าคุณเขียนโค้ดทั้งหมดลงใน Java และไม่ลองและสร้างไฟล์ภายนอกที่แท้จริงเพื่ออ่านการผจญภัยของข้อความ
William Chelonis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.