Làm thế nào tôi nên phân tích đầu vào của người dùng trong một trò chơi phiêu lưu văn bản?


16

Phân tích các lệnh của người dùng trong một cuộc phiêu lưu văn bản là một phổ từ "đi về phía bắc" đơn giản của Adventure đến một số thông minh khó hiểu trong hhgttg .

Tôi dường như nhớ đọc những cách hay trên tạp chí máy tính từ những năm 80, nhưng bây giờ tôi thấy hầu như không có gì trên mạng ngoại trừ một bản giới thiệu Wikipedia ngắn gọn .

Làm thế nào bạn sẽ làm điều đó?


Cập nhật : Tôi đã thực hiện với cách tiếp cận đơn giản nhất có thể trong mục Ludum Dare của tôi .


3
Có vấn đề cụ thể nào bạn đang cố gắng giải quyết không?
Trevor Powell

@TrevorPowell xem xét bắt tay vào thực hiện một cuộc phiêu lưu văn bản nhỏ cho vui, và chỉ muốn làm quen với 'trạng thái của nghệ thuật' thay vì chỉ lặn và giải quyết theo cách của tôi là tất cả
Will

1
Sử dụng Thông tin ; đó là chiến lược tốt nhất bạn có thể sử dụng. Hầu như không có lý do để mã hóa một cuộc phiêu lưu văn bản ngày nay.
Nicol Bolas

@NicolBolas trừ khi Ludum Dare đang đến gần? ;)
Sẽ

1
Nó không phải là kẻ chiến bại nhiều như thực dụng. Đi sâu vào tất cả các kỹ thuật phân tích cú pháp văn bản nâng cao (ngoài những thứ rõ ràng mà bất kỳ ai cũng có thể nghĩ ra) có lẽ nằm ngoài phạm vi của một câu trả lời duy nhất ở đây.
Tetrad

Câu trả lời:


10

Bạn đã tìm kiếm trong cộng đồng tiểu thuyết tương tác? Họ vẫn viết các trình phân tích cú pháp và một số cố gắng đẩy phong bì bằng cách thực hiện các kỹ thuật mới như xử lý ngôn ngữ tự nhiên.

Xem ví dụ liên kết này cho các bài viết mô tả các phương pháp được sử dụng:

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


4
Aha, "phiêu lưu văn bản" trở thành "tiểu thuyết tương tác" và đột nhiên nó trở nên dễ hiểu hơn nhiều! Ai có thể nghĩ nó thậm chí còn đổi tên kể từ khi tôi chơi nó? :) Tuy nhiên, nhìn vào những khách hàng tiềm năng đó, và thực sự không có nhiều điều đáng buồn được giải thích
Will

9

Thuật ngữ bạn muốn là "xử lý ngôn ngữ tự nhiên", hoặc NLP. Tuy nhiên, hãy nhớ rằng các phương pháp chính thức được thiết kế để thử và hiểu các văn bản trong thế giới thực, trong khi bạn thường chỉ cần một cái gì đó hoạt động cho một tập hợp con giới hạn của ngôn ngữ tự nhiên của bạn.

Thông thường bạn có thể bắt đầu với một ngữ pháp và từ vựng đơn giản, sau đó viết một trình phân tích cú pháp cho nó. Một ngữ pháp có thể là một cái gì đó đơn giản như thế này:

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"

Trên đây là một biến thể trên hình thức Backus-Naur, cách tiêu chuẩn để biểu diễn ngữ pháp. Dù sao, bạn có thể sử dụng trình tạo trình phân tích cú pháp để tạo mã để phân tích ngữ pháp này hoặc tự viết một cách khá dễ dàng nếu ngôn ngữ của bạn xử lý chuỗi tốt. (Tra cứu 'trình phân tích cú pháp gốc đệ quy', sử dụng một hàm cho mỗi dòng của ngữ pháp.)

Sau khi phân tích cú pháp, bạn có thể tìm ra nếu câu có ý nghĩa - "đi về phía bắc" có thể có ý nghĩa, nhưng "có được phía bắc xanh" thì không. Bạn có thể giải quyết điều này theo 2 cách; làm cho ngữ pháp trở nên trang trọng hơn (ví dụ: có các loại động từ khác nhau chỉ hợp lệ với một số loại danh từ nhất định) hoặc kiểm tra các danh từ so với động từ sau đó. Cách đầu tiên có thể giúp bạn đưa ra thông báo lỗi tốt hơn cho người chơi, nhưng bạn luôn cần phải thực hiện lần thứ hai ở một mức độ nào đó, vì bạn luôn cần kiểm tra ngữ cảnh - ví dụ. "Lấy chìa khóa xanh" là đúng ngữ pháp và chính xác về mặt cú pháp, nhưng bạn vẫn cần kiểm tra xem chìa khóa xanh có mặt không.

Cuối cùng, chương trình của bạn kết thúc với một lệnh được xác nhận với tất cả các phần khác nhau được kiểm tra; thì đó chỉ là một trường hợp gọi đúng hàm với các đối số để thực hiện hành động.


6

Tình trạng của nghệ thuật thực hiện các cuộc phiêu lưu văn bản ngày nay là sử dụng Thông tin 7 . Thông tin 7 nguồn đọc "như tiếng Anh", giống như cách các trò chơi dựa trên Thông tin cho phép bạn "viết tiếng Anh". Ví dụ: từ Đồng của Emily Short :

Một điều có một số văn bản gọi là mùi hương. Mùi hương của một thứ thường là "không có gì".
Quy tắc ngửi khối không được liệt kê trong bất kỳ quy tắc.
Thực hiện ngửi một cái gì đó:
    nói "Từ [danh từ] bạn ngửi thấy [mùi hương của danh từ]."
Thay vì ngửi một căn phòng:
    nếu người chơi có thể chạm vào một mùi hương, hãy nói "Bạn ngửi [danh sách những thứ có mùi thơm mà người chơi có thể chạm vào].";
    nếu không thì nói "Nơi này không có mùi."

Trình phân tích cú pháp Inform 7 được tích hợp chặt chẽ với IDE 7 thông tin và toàn bộ mã nguồn chưa có sẵn để nghiên cứu:


5

Hai nguồn tốt nhất hiện nay để học cách tạo một trình phân tích cú pháp phiêu lưu văn bản là (như đã đề cập) cộng đồng IF và cộng đồng bùn. Nếu bạn tìm kiếm các diễn đàn lớn cho những người đó (Intfiction.org/forum, nhóm tin rec.arts.int-fiction, Mud Connector, Mudbytes, Mudlab, Top Mud Site) bạn sẽ tìm thấy một số câu trả lời, nhưng nếu bạn chỉ tìm kiếm đối với các bài viết, tôi muốn giới thiệu lời giải thích của Richard Bartle về trình phân tích cú pháp trong MUD II:

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

Và lời giải thích này trên rec.arts.int-hư cấu:

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

Không có sự thiếu tôn trọng đối với các câu trả lời khác, nhưng tạo ra một ngữ pháp CF hoặc sử dụng BNF không phải là giải pháp cho vấn đề này. Điều đó không có nghĩa là nó không thể là một giải pháp cho một vấn đề khác, đó là tạo ra một trình phân tích cú pháp ngôn ngữ tự nhiên tiên tiến hơn, nhưng đó là chủ đề của nghiên cứu đáng kể và không phải IMO trong phạm vi của một cuộc phiêu lưu văn bản.


4

Trong năm đầu tiên ở trường đại học, chúng tôi đã thực hiện một trò chơi phiêu lưu trong Prolog và đối với đầu vào của người dùng, chúng tôi phải sử dụng ngữ pháp mệnh đề xác định hoặc DCG. Xem http://www.amzi.com/manuals/amzi/pro/ref_dcg.htm#DCGCommandL Language để biết ví dụ về việc sử dụng nó làm ngôn ngữ lệnh. Nó có vẻ như là một nguyên tắc (rốt cuộc đó là uni) và cách tiếp cận linh hoạt vào thời điểm đó.


1

Bạn cần xác định một ngôn ngữ cụ thể cho miền là tất cả các câu đúng trong trò chơi của bạn. Để kết thúc này, bạn phải xác định một ngữ pháp cho ngôn ngữ của bạn (từ vựng và cú pháp). Loại ngữ pháp bạn cần là Ngữ pháp không ngữ cảnh và có các công cụ tự động tạo trình phân tích cú pháp bắt đầu từ một mô tả tổng hợp về ngữ pháp như ANTLR (www.antlr.org). Trình phân tích cú pháp chỉ kiểm tra xem một câu có đúng hay không và tạo ra một Cây cú pháp trừu tượng (AST) của câu đó là một đại diện điều hướng của câu trong đó mỗi từ có vai trò bạn chỉ định trong ngữ pháp. Bằng cách điều hướng AST, bạn phải thêm mã để đánh giá ngữ nghĩa của mỗi từ khi thực hiện vai trò đó đối với các từ khác trong câu và xác minh xem ngữ nghĩa có đúng không.

Ví dụ, câu 'Viên đá ăn thịt người' về mặt cú pháp đúng nhưng không nhất thiết phải đúng về mặt ngữ nghĩa (trừ khi trong thế giới của bạn, có thể là đá ma thuật, có thể ăn thịt người).

Nếu cũng đúng ngữ nghĩa thì bạn có thể, ví dụ, thay đổi thế giới theo nó. Điều này có thể thay đổi bối cảnh và do đó, cùng một câu có thể không còn đúng về mặt ngữ nghĩa (ví dụ, không thể có người đàn ông để ăn)


1

Tôi đã sử dụng công cụ Tads3 (www.tads3.org) cho một số cuộc phiêu lưu văn bản tôi đã viết. Đó là nhiều hơn cho các lập trình viên máy tính mặc dù nhưng một ngôn ngữ rất mạnh mẽ. Nếu bạn là lập trình viên, Tads3 sẽ dễ dàng viết mã mọi thứ nhanh hơn so với Inform7, điều mà tôi đã sử dụng trước đây. Vấn đề với Inform7 dành cho lập trình viên cũng nổi tiếng như "đoán động từ" dành cho người chơi phiêu lưu văn bản ở chỗ nếu bạn không viết câu RẤT cẩn thận, bạn sẽ phá game. Nếu bạn đủ kiên nhẫn để làm điều đó, bạn có thể dễ dàng viết một trình phân tích cú pháp trong Java bằng cách sử dụng lớp Tokenizer. Ví dụ tôi đã viết bằng mảng JTextArea toàn cầu và mảng String [] toàn cầu. Nó loại bỏ các ký tự không mong muốn ngoại trừ lá AZ và 0-9 cũng như dấu chấm hỏi (cho phím tắt lệnh "trợ giúp"):

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

... Tôi đã bỏ qua định nghĩa lớp chính và phương thức khởi tạo biến (), v.v. bởi vì nó được giả sử nếu bạn biết Java, bạn đã biết cách thiết lập nó. Lớp chính cho điều này có lẽ nên mở rộng JFrame và trong phương thức void static () tĩnh công khai của bạn chỉ cần tạo một thể hiện của nó. Hy vọng rằng một số mã này sẽ giúp.

EDITED - Được rồi, vì vậy bây giờ những gì bạn sẽ làm tiếp theo là tạo một lớp Hành động và quét một hành động (tức là "lấy đèn" hoặc "thả kiếm"). Để đơn giản hơn, bạn phải có một đối tượng hoặc phương thức RoomScan để quét mọi thứ hiển thị trong phạm vi và chỉ quét những đối tượng trên hành động đó. Đối tượng tự xử lý việc xử lý hành động và theo mặc định, bạn nên có một lớp Item xử lý tất cả các hành động đã biết theo cách mặc định, có thể bị quá tải. Bây giờ, nếu ví dụ, một vật phẩm bạn muốn "lấy" được giữ bởi một nhân vật không phải người chơi, thì phản hồi mặc định để nhận vật phẩm đó do chủ sở hữu của nó nắm giữ sẽ là một cái gì đó như "The will let you have it". Bây giờ bạn phải tạo một tấn phản hồi hành động mặc định cho điều này trong lớp Item hoặc Thing. Điều này về cơ bản đến từ một quan điểm Tads3 trên tất cả các thiết kế. Bởi vì trong Tads3, mỗi mục có thói quen xử lý hành động mặc định riêng trên nó mà trình phân tích cú pháp gọi nếu một hành động trên nó được khởi tạo. Vì vậy, ... tôi chỉ nói với bạn rằng, Tads3 đã có sẵn tất cả những thứ này, vì vậy thật dễ dàng để viết mã trong một cuộc phiêu lưu văn bản bằng ngôn ngữ đó. Nhưng nếu bạn muốn làm điều đó từ đầu, như trong Java (ở trên), thì cá nhân tôi sẽ xử lý nó giống như cách Tads3 được thiết kế. Theo cách đó, bạn có thể ghi đè các hành động mặc định xử lý các thói quen trên các đối tượng khác nhau, vì vậy, ví dụ nếu bạn muốn "lấy đèn" và quản gia đang giữ nó, nó có thể kích hoạt phản hồi trong phương thức hành động "lấy" mặc định cho Mục hoặc Object và nói với bạn rằng "Người quản gia từ chối trao chiếc đèn bằng đồng." Ý tôi là ... một khi bạn đã là một lập trình viên đủ lâu như tôi có, thì đây là tất cả những thứ RẤT dễ dàng. Tôi đã hơn 50 tuổi và đã làm việc này từ khi tôi 7 tuổi. Cha tôi là một hướng dẫn viên của Hewlett Packard vào những năm 70 nên tôi đã học được một TON từ ông ban đầu về lập trình máy tính. Hiện tại tôi cũng đang ở trong Quân đội Hoa Kỳ, về cơ bản là quản trị viên máy chủ. Ừm ... ừ, vậy đừng bỏ cuộc. Không khó lắm một khi bạn thực sự chia nhỏ nó thành những gì bạn muốn chương trình của bạn làm. Đôi khi thử và sai là cách tốt nhất để tiếp tục loại công cụ này. Chỉ cần kiểm tra nó và xem và đừng bao giờ bỏ cuộc. Được chứ? Viết mã là một nghệ thuật. Nó có thể được thực hiện theo nhiều cách khác nhau. Đừng để cách này hay cách khác dường như chặn bạn vào một góc trên thiết kế. m cũng trong Quân đội Hoa Kỳ về cơ bản là một quản trị viên máy chủ. Ừm ... ừ, vậy đừng bỏ cuộc. Không khó lắm một khi bạn thực sự chia nhỏ nó thành những gì bạn muốn chương trình của bạn làm. Đôi khi thử và sai là cách tốt nhất để tiếp tục loại công cụ này. Chỉ cần kiểm tra nó và xem và đừng bao giờ bỏ cuộc. Được chứ? Viết mã là một nghệ thuật. Nó có thể được thực hiện theo nhiều cách khác nhau. Đừng để cách này hay cách khác dường như chặn bạn vào một góc trên thiết kế. m cũng trong Quân đội Hoa Kỳ về cơ bản là một quản trị viên máy chủ. Ừm ... ừ, vậy đừng bỏ cuộc. Không khó lắm một khi bạn thực sự chia nhỏ nó thành những gì bạn muốn chương trình của bạn làm. Đôi khi thử và sai là cách tốt nhất để tiếp tục loại công cụ này. Chỉ cần kiểm tra nó và xem và đừng bao giờ bỏ cuộc. Được chứ? Viết mã là một nghệ thuật. Nó có thể được thực hiện theo nhiều cách khác nhau. Đừng để cách này hay cách khác dường như chặn bạn vào một góc trên thiết kế.


Điều này không may bỏ đi phần khó nhất của trình phân tích cú pháp văn bản, cụ thể là xác định động từ, chủ đề và đối tượng của người dùng nhập và ánh xạ nó thành một hành động.
Philipp

Đúng nhưng cách tôi làm là tạo một lớp hành động và lưu trữ một loạt các hành động, giả sử, một lớp từ điển, sau đó quét các từ hành động. Nếu hành động liên quan đến một từ thứ 2 (như đối với hành động "lấy", có thể là "lấy đèn") thì có một loạt các đối tượng (hoặc danh từ) được quét trong đó chính các đối tượng đó sẽ có kịch bản để xử lý các hành động được thực hiện trên chúng. Đây là tất cả giả sử bạn mã hóa toàn bộ điều ngay vào Java và không thử và tạo một tệp bên ngoài thực tế được đọc để biên dịch các cuộc phiêu lưu văn bản.
William Chelonis
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.