2

さて、私は今、基本的なテキストアドベンチャーを作るという目標を持っています. ただし、これを行うには、次のことを実行できる switch ステートメントが必要です。

  • 文字列に SOMEWHERE という単語が含まれているかどうかを確認します。
  • 文字列内のどこかに任意の組み合わせで 2 つの単語があるかどうかを確認します。

どうすればこれを達成できますか? この特定の例のコーディングを教えてください:

ユーザーはデータの入力を求められます。switch ステートメントは、1 つのケースとして「look box」をチェックし、別のケースとして「sleep」をチェックします。プログラムは単語の順序は気にしませんが、文字の順序は気にします。

すべてを詳しく説明してください。コーディングを始めたばかりです。

編集:すべての回答ありがとうございます。これを処理するためのより適切で、より複雑で、より便利な方法があることは理解していますが、まだ私のレベルではありません。

4

6 に答える 6

12

なぜ船を作らないのかと時々聞かれます。私はとても器用で、物を作るのが好きで、セーリングもしています。私はいつも彼らに、セーリングが好きな人はボートを作るべきではないと言っています。なぜなら、セーリングに行く前にガレージでボートを作るのに 3 年も費やすことになるからです。あなたの目標が航海することなら、ボートを購入してください。あなたの目標がボートを作ることなら、ボートを作りなさい。

テキスト アドベンチャーを作成して C# を学習することが目標であれば、多くのことを学ぶことができます。あなたの目標がテキスト アドベンチャーを書くことである場合は、C# を使用せずに Inform7 を使用してください。習得が容易で、テキスト アドベンチャーを書くために特別に設計されており、おそらく世界で最も高度な言語です。これは素晴らしいプログラミング言語であり、強くお勧めします。

あなたの特定の質問に答えるには、それは良い方法ではありません。テキスト アドベンチャー プロセッサが実際に動作する方法は、まず、ユーザーが入力した文をトークンに分割するプログラムを作成することです。スペース、コンマ、ピリオドなどの単語間の境界を探すために、文字列を 1 文字ずつ検索する必要があります。境界を見つけたら、境界間の部分文字列を抽出し、辞書内の単語と比較してすべての単語を認識しようとします。

トークンのシーケンスを取得したら、そのシーケンスを文法と照合します。つまり、一連のトークンが {"look"} のような 1 語のコマンドとして分類できるか、または {"look"、"at"、"the"、"red"、"ボタン"}。あなたはそれを分解したいと思います - "look" は動詞、"at" は前置詞、"the red button" は動詞の目的語、"the" は冠詞、"red" は形容詞、"button" です。名詞です。

あなたは初心者のように聞こえるので、まず語彙分析に集中してください。一度に 1 文字ずつ文字列を調べ、単語の境界を識別し、List<string>トークンを作成します。文法分析の手法は非常に複雑になる場合があります。簡単なことを最初にしっかりと終わらせてください。

于 2011-01-22T15:08:36.920 に答える
2

あなたが始めていることを考えると、最初に単純なケースでこれを見ることができますが、これswitchを達成するためにステートメントを使用することはできません.

簡単にするために、コマンドは 1 つまたは 2 つの単語に制限されており、最初の単語は動詞で、存在する場合は 2 番目の単語は動詞であると仮定しましょう。これにより、かなりの数の可能性が得られます。

North
South
Examine
Take
Drop

等...

次の入力文字列があるとしますstrInput

string strInput = "examine hat";

まずこれを分割したいと思います。を使用してこれを行うことができますString.Split

string[] arguments = strInput.Split(' ');

これにより、文字列配列が得られます。

引数 [0] は調べる

引数 [1] は帽子です

ユーザーが入力した場合、常に2番目のものがあるとは限らないことに注意してください。

`North`

それから:

引数 [0] は北です

これを確認する必要があります。さて、これを確認する恐ろしい(しかし簡単な)方法は次のとおりです。

if(arguments[0] == "North")
{
    // code to go North
}
else if(arguments[0] == "Take")
{
    // code to work with Take.  We'd check on arguments[1] here!
}
// etc...

残念ながら、このコードは長く複雑になり、使用できなくなります。ある段階でできることとできないことをどのようにして知ることができますか? どのように新しいコマンドを追加しますか? それでは、C# のすばらしいデリゲート機能を使用して、Dictionary. ディクショナリを使用すると、ある型 (キー) を別の型 (この場合はデリゲート) にマップできます。このメソッドを使用して、さまざまな種類のコマンドを処理するデリゲートを作成できます。

public delegate void HandleCommand(string[] _input);

ここでは、デリゲートを委任しました。まだ心配する必要はありませんが、コマンドで動作する関数をいくつか紹介しましょう。

public void Handle_North(string[] _input)
{
    // code to go North.  This function could just as easily be something that handles
    // *all* directions and checks _input[0] to see where to go!
}

public void Handle_Take(string[] _input)
{
    if(_input.Length > 1) // Did the user specify an object to take?
    {
        // code to handle Take.
    }
}

等々。次に、コマンドをこれらの関数にマップするための辞書を作成する必要があります。

Dictionary<String, HandleCommand> map = new Dictionary<String, HandleCommand>();

ここで、文字列をデリゲート型にマップする辞書を宣言しますHandleCommand。次に、データを入力する必要があります。

map["north"] = Handle_North;
map["take"]  = Handle_Take;
// and the rest of our commands

さて、前の例を踏まえて、前と同じように文字列を分割し、適切なハンドラーを呼び出しましょう!

string[] arguments = strInput.Split(' ');
if(arguments.Length > 0 && map.ContainsKey(arguments[0]))
    map[arguments[0]](arguments);  // calls our function!

これで、拡張可能なシステムができました。新しいコマンドとハンドラを簡単に追加できます! より複雑になりますが、本質的に、これはあなたが望むことを行うための良い方法です.

編集:あなたの質問は、単語の順序を気にするべきではないと言っていることは承知しています。テキスト アドベンチャー ゲームを作成している場合は、ランダムに入力するのではなく、動詞/名詞などの文法を作成することをお勧めします。

于 2011-01-22T15:07:29.560 に答える
1

を使用してこれを行うことはできませんswitch。if-else-if タイプの構造を使用する必要があります。

string input=...
if(input.Contains("sleep")){ //contains sleep? 
  //do stuff for some word
}else if(input.Contains("look") && input.Contains("box")){ //contains look and box
  //do stuff for the combination thing
}

switchそれぞれにcaseは、静的で一意の値が必要です。そのため、ケースとして使用することはできません.Contains

于 2011-01-22T14:58:50.153 に答える
1

ここに別のアイデアがあります:

    string input = "look at the sleep box";
    bool caseA = input.Contains("sleep");
    bool caseB = input.Contains("look") && input.Contains("box");

    int scenarioId;
    if (caseA && caseB)
        scenarioId = 1;
    else if (caseA)
        scenarioId = 2;
    else if (caseB)
        scenarioId = 3;
    // more logic?
    else
        scenarioId = 0;

    switch (scenarioId)
    {
        case 1:
            Console.WriteLine("Do scenario 1");
            break;
        case 2:
            Console.WriteLine("Do scenario 2");
            break;
        case 3:
            Console.WriteLine("Do scenario 3");
            break;
        // more cases
        default:
            Console.WriteLine("???");
            break;
    }

if/then/else を使用して、入力 like などの潜在的な組み合わせを含む特定のシナリオを評価"look at the sleep box"し、switch ステートメントを使用してそれに応じて実行します。

于 2011-01-22T15:01:27.003 に答える
0

これを直接使用することはできませんが、使用switchすべきではないと思います。おそらく、. を含むロジックとは異なる場所で単語を検索するロジックが必要switchです。

列挙型を使用して、可能なすべてのアクションを含めることを検討してください。

public enum AdventureAction
{
    LookBox,
    Sleep
}

「解析」を行うメソッドを作成することを検討してください。

public static AdventureAction Parse(string text)
{
    if (text.Contains("look") && text.Contains("box"))
        return AdventureAction.LookBox;

    if (text.Contains("sleep"))
        return AdventureAction.Sleep;
}

次に、単純なswitchステートメントを使用してアクションを実行できます。

var action = Parse(input);
switch (action)
{
    case AdventureAction.LookBox:
        // do something interesting with the box
        break;

    case AdventureAction.Sleep:
        // go to sleep
        break;
}
于 2011-01-22T15:03:36.610 に答える
0

私は現在、Inform/Adrift/Quest のすべてが私を悩ませる致命的な欠陥を持っている傾向があるため、独自のテキスト アドベンチャー エンジンを作成しています — Inform の悪夢のような難読化された構文 (これは物事をできるだけ簡単にするのが好きな UX デザイナーから来ています)初心者には可能)、Adrift の醜いリーダー、および Adrift/Quests には実際のクラス/オブジェクトのサポートがありません。

最善の方法ではないかもしれませんが、今のところ問題なく動作しています。私は正規表現を調べましたが、代わりにこの方法で行うことにしました。

最初に行うことは、プレイヤーの入力/コマンド文字列をリストに分割することです。幸いなことに、これらのゲームでは、ほとんどの場合、このリストの最初の要素は動詞です。

  • 見る
  • 青い

「look、examine、ex」など、キーに一致するすべての値を含む、キーでアクセスできる動詞/オブジェクト/その他のデータクラスが必要になります。

class Verb
{
    string uniqueID;
    List<string> values;
}

class Object
{
    public uniqueID; // Because this is shared with Verbs, you could do a better unique ID system, but hey...
    public List<string> articles;
    public List<string> adjectives;
    public List<string> noun;
}

また、プレーヤーの入力から一致する一連の「アクション」サブクラスも必要になります。ここでは、プレーヤーの入力と一致する必要がある文章構造を「構築」します。

  • アクション (基本クラス)
    • 見る
    • {at} [オブジェクト] を見てください
    • 本を見て
    • ジャンプ
    • ジャンプ {on/onto} [オブジェクト]

.

class Action
{
    string uniqueID;
    List<SentenceElement> sentence;

    void Execute();
    bool RestrictionsCheck();
}

class Look : Action
{
    override void Execute();
    override bool RestrictionsCheck();
}

class LookAtObject : Action
{
    override void Execute();
    override bool RestrictionsCheck();
}

class LookAtBook : Action
{
    override void Execute();
    override bool RestrictionsCheck();
}

ベースの Action クラスには、SentenceElements を使用したセンテンス ビルダーがあります。文を 1 つずつ説明するリストにすることができます。

class SentenceElement
{
    List<string> values;
    bool isOptional;
}

class VerbID : SentenceElement {}
class ObjectID : SentenceElement {}
class ObjectAny : SentenceElement {}
class CharacterID : SentenceElement {}
class CharacterAny : SentenceElement {}
class TextOptional : SentenceElement {}
class TextRequired : SentenceElement {}
class Parameter : SentenceElement {}

「Action」クラスを検索し、最初の SentenceElement をプレーヤーの最初の入力動詞と比較し、一致するもののリストを「potentialActions」として保持できるようになりました。「string.Contains」が機能します。

ここで、プレーヤーの入力コマンドをステップ実行し、すべての SentenceElement をステップ実行してそれらを比較することにより、最も一致するアクションを見つける必要があります。それぞれの場所のインデックスを保持します (playerInputIndex、potentialActionsIndex、sentenceElementIndex)。

一致が見つかった場合は、SentenceElement と一致しなくなるまで playerInputIndex をインクリメントし、設定 (isOptional など) を確認してから、次の SentenceElementIndex に移動して、比較を最初からやり直します。最終的に、プレーヤーの入力または SentenceElements のいずれかの終わりに到達します。

「isOptional」である SentenceElements がある場合、複雑さが追加されるため、チェックする必要があります。または、既存のものと一致しないはずのタイプ ObjectAny の SentenceElements を持つアクションが「どのオブジェクトが必要でしたか」を表示する必要があります。たべる?" メッセージ。また、オブジェクトには、動詞とは異なり、考慮すべき接頭辞/形容詞/名詞などの追加の一致パラメーターがあります。

このシステムでは、実行したいアクションごとに新しいクラスも必要になります。各アクションには、「参照されたキャラクターは生きていますか?」など、実行する前に渡す必要があるカスタムの「制限」があります。

于 2015-09-02T06:22:07.467 に答える