答えは「猫」なのに、「ねこ」と入力すると不正解になる。謎は解けたのに、アプリの都合で止まってしまうのは、もったいない体験です。
Unityで入力式の謎解きアプリを作るなら、答えの判定は、文字を比較する前に「何を同じ答えとして認めるか」を決めると整理できます。この記事では、C#だけで書ける小さな判定例を紹介します。
目次
ひらがな・漢字の別解は、問題データに持たせる
「ねこ」と「猫」は、意味は同じでも文字列としては別です。読みを自動変換しようとするより、許容する表記を問題ごとに登録すると、意図がわかりやすくなります。
string[] acceptedAnswers = { "ねこ", "猫" };
「ネコ」も認めるなら、配列に加えます。文字そのものを使う謎では、ひらがなとカタカナの違いが仕掛けになることもあるので、全問題に同じ変換をかけるより、問題の意図に合わせて決めます。
比較前に整えること、残すこと
| 入力の違い | この例の扱い |
|---|---|
| 前後の空白 | 取り除く |
| 途中の空白 | 残す |
| 全角・半角など互換文字の違い | 問題ごとに正規化を選ぶ |
| 英字の大文字・小文字 | 問題ごとに無視するか選ぶ |
| 読みや意味が同じ別表記 | 許容する答えとして登録する |
Trim()は、文字列の前後の空白を取り除きます。途中の空白は消えません。「NEW YORK」のように空白を含む答えを扱うなら、この違いが役立ちます。MicrosoftのTrimドキュメント
Normalize(NormalizationForm.FormKC)は、Unicodeの互換性に基づく正規化です。「ABC」と「ABC」をそろえられますが、丸数字の「①」が「1」になるなど、全角・半角以外にも変化します。文字の形や記号の違いが答えになる問題では、この正規化を無効にします。 MicrosoftのNormalizationFormドキュメント
C#で書く、答え判定の例
次の例は、前後の空白を取り除き、空の入力を不正解として扱います。正規化と、大文字・小文字を無視する比較は、初期状態では無効です。
using System;
using System.Collections.Generic;
using System.Text;
public static class RiddleAnswer
{
private static string Prepare(string value, bool unifyWidth)
{
string text = (value ?? "").Trim();
return unifyWidth ? text.Normalize(NormalizationForm.FormKC) : text;
}
public static bool IsCorrect(string input, IEnumerable<string> accepted,
bool unifyWidth = false, bool ignoreCase = false)
{
string value = Prepare(input, unifyWidth);
if (value.Length == 0 || accepted == null) return false;
var comparison = ignoreCase
? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
foreach (string answer in accepted)
{
if (string.IsNullOrWhiteSpace(answer)) continue;
if (string.Equals(value, Prepare(answer, unifyWidth), comparison))
return true;
}
return false;
}
}
たとえば、猫が答えの問題は次のように呼び出せます。
bool correct = RiddleAnswer.IsCorrect(
inputText, new[] { "ねこ", "猫" });
英字の答えで全角入力と大文字・小文字を許容する場合は、明示的に有効にします。
bool correct = RiddleAnswer.IsCorrect(
inputText, new[] { "ABC" },
unifyWidth: true, ignoreCase: true);
比較方法には、文字列を明確なルールで比較するStringComparison.OrdinalとOrdinalIgnoreCaseを指定しています。意味の近さを判断する処理ではなく、登録した答えと一致するかを見る処理です。Microsoftの文字列比較ガイド
「これを正解にする?」を表で確認する
コードを読むだけより、入力例を並べると判定の意図が見えます。たとえば、次のケースを用意してみます。
| 入力 | 許容する答え・設定 | 結果 |
|---|---|---|
| 猫 | ねこ、猫 | 正解 |
| 前後に空白のある「猫」 | ねこ、猫 | 正解 |
| ネコ | ねこ、猫 | 不正解 |
| ね こ | ねこ、猫 | 不正解 |
| ABC | ABC、正規化あり | 正解 |
| abc | ABC、大文字・小文字を無視 | 正解 |
| 空欄 | どの答えでも | 不正解 |
「ネコ」が不正解なのは、今回の配列に登録していないからです。認めたい表記があるなら、コードを複雑にする前に、答えのデータへ加えます。
画面から呼ぶときは、判定と表示を分ける
入力欄が空なら、判定する前に「答えを入力してください」と伝える。正解なら次へ進むボタンを表示する。不正解なら、入力欄を消さずに考え直せるようにする。文字の判定とは別に、画面の反応を設計します。
正解処理が終わるまで回答ボタンを押せないようにすると、連打で結果画面を何度も開くことも防げます。判定関数は文字列の比較に集中させ、画面遷移やクリア記録は、問題画面側で扱うと追いやすくなります。
答えのデータから、遊びやすさを作る
入力式の謎解きでは、解けたときの喜びを、表記の違いで取りこぼさないことが大切です。その一方で、謎の仕掛けに必要な違いまで消してしまわないよう、問題ごとに許容範囲を持たせます。
画面と問題データの全体像はUnityで謎解きアプリを作るための5画面設計へ。解く途中の助け方は謎解きのヒントを3段階で作る方法でも紹介しています。
作った作品を遊んでみたい方は、謎解き千本ノックの紹介とアプリコレクションをご覧ください。
