日本語タイピングゲームの「shi」と「si」問題を解決する
タイピングゲームで「し」を「si」と入力しても正解にならない問題。複数のローマ字パターンに対応したマッチングアルゴリズムと、促音・「ん」の特殊処理を含む実装を解説します。
日本語タイピングゲームの「shi」と「si」問題を解決する
「なんで『si』って打ったのに間違いになるの?」
タイピングゲームを作ると必ずぶつかるこの問題。日本語には複数のローマ字入力方法があるのに、多くのタイピングゲームは1パターンしか受け付けません。
この記事では、150以上のローマ字パターンに対応したマッチングアルゴリズムと、促音(っ)や「ん」の特殊処理を含む実装を解説します。
なぜ「shi」だけじゃダメなのか
日本語入力の多様性
日本語のローマ字入力には、複数の流派があります:
| ひらがな | ヘボン式 | 訓令式 | JIS X 4063 |
|---|---|---|---|
| し | shi | si | si |
| ち | chi | ti | ti |
| つ | tsu | tu | tu |
| ふ | fu | hu | hu |
| じ | ji | zi | zi |
さらにIMEごとの方言もあります(Microsoft IME、Google日本語入力、ATOK...)。
ユーザーの期待
ローマ字変換テーブルの設計
基本構造
ひらがな1文字(または2文字)に対して、複数のローマ字パターンを配列で定義します:
拗音(2文字)
拗音は2文字で1つの音なので、優先的にマッチングします:
外来語対応
最近のタイピングでは外来語も頻出:
部分入力マッチング
なぜ「部分一致」が必要か
タイピングゲームでは、ユーザーは1文字ずつ入力します。「sha」を打つ途中の「s」「sh」の段階でも、まだ正解の可能性があると判定する必要があります。
マッチング関数の実装
促音(っ)の処理
子音の重ね
「っ」は次の文字の子音を重ねることで入力します:
実装
マッチング時の処理
「ん」の文脈依存処理
問題:「n」だけで確定できない場合
「ん」は通常nで入力できますが、次の文字によってはnnが必要です:
ルール
| 次の文字 | 必要なパターン |
|---|---|
| 子音(k, s, t...) | n でOK |
| 母音(a, i, u, e, o) | nn または xn が必要 |
| y行(ya, yu, yo) | nn または xn が必要 |
| な行(na, ni...) | nn または xn が必要 |
実装
表示用ターゲット文字列の生成
動的なターゲット表示
ユーザーがsを打った時点で、ターゲット表示を動的に更新します:
実装
getFirstRomajiPattern関数
React Hookとの統合
useTypingGameでの使用
文字表示のカラーリング
対戦モードへの対応
バトルモードでも同じローマ字変換ロジックを使用:
パフォーマンス考慮
変換テーブルのサイズ
150パターン以上のテーブルですが、JavaScriptのオブジェクトアクセスはO(1)なので問題ありません。
文字列操作の最適化
まとめ
| 問題 | 解決策 |
|---|---|
| 複数ローマ字パターン | 配列で複数パターンを定義 |
| 部分入力の判定 | startsWithで前方一致チェック |
| 促音(っ) | 次の文字の子音を取得して重ねる |
| 「ん」の文脈依存 | 次の文字をチェックして条件分岐 |
| 拗音(2文字) | 2文字パターンを優先してマッチング |
この実装により、どんな入力方法のユーザーでも快適にプレイできるタイピングゲームが実現できます。
遊んでみる
実際にタイピングゲームを遊んでみたい方は、こちらからどうぞ:
ソースコード
この記事で紹介したコードの完全版はGitHubで公開しています:
このシリーズの他の記事
このサイトでは、他にもオンライン対戦ゲームの実装記事を公開しています:
- 同一フィールドで戦うスネークバトルを実装してみた - Durable Objectsでサーバー側ゲームロジック
- 2048オンライン対戦で「公平」を実現する方法:シード乱数の魔法 - シード乱数で両プレイヤーに同じタイル配置を保証
- テトリスは運ゲーじゃない!7-bagアルゴリズムとマルチプレイ同期の仕組み - 7-bagとシード乱数の解説