Open31

【Unity】タイピングゲームにおける柔軟なタイピングの対応

スタジオしまづスタジオしまづ

iを打った瞬間の見かけ上の処理
・kya -> kiとxyaに分割
・きゃ, あ -> 「き, ゃ, あ」に分割

コードの処理
・iを打ったときに、
・辞書から検索してくる文字の対象で「きゃ」に該当するものを探す。
・今回は「きゃ, kya」を見つけてくるが、入力と一致しないので不適?(予想)
・次に、検索文字「きゃ」を右から削って検索する。つまり「き」で該当するものを探す
・今回は「き, ki」を見つけてこれて、入力と一致しているので正解とする

*問題:どうやって、残りの文字「ゃ, xya」を作っているのか?

for (int i = SL.FuriList[ST.Listnum].Length; i != 0 && !jud; i--)
            {
                // 「く」 cu, qu
                var SearchStr = SL.FuriList[ST.Listnum].Substring(0, i); // 表示されている問題の文字 TODO:1文字だからSubstringいらないのでは?
                Debug.Log($"Start:SearchStr:{SearchStr}:{SL.FuriList[ST.Listnum]}");
                // Debug.Log(SearchStr+":"+ SL.FuriList[ST.Listnum] + ":"+i);
                // 今、1文字目でなくて、 0文字目が「っ」なら
                if (i != 1 && SL.FuriList[ST.Listnum][0].ToString() == "っ")
                {
                    SearchStr = SearchStr.Substring(1, SearchStr.Length - 1);
                    Debug.Log($"SearchStr:{SearchStr}");
                    Debug.Log(string.Join(",", Dic.SearchTotaldicKey(SearchStr)));
                }

                // 問題の文字で入力可能なものを探す 問題が「く」なら[cu,qu] (kuは最初の判定で正解となっている)
                var list = Dic.SearchTotaldicKey(SearchStr);
                // Debug.Log(string.Join(",", list));
                // 候補([cu,qu])について入力と一致するか判別する
                foreach (var d in list)
                {
                    var MatchStr = "";

                    // 今、1文字目でなくて、 0文字目が「っ」なら
                    if (i != 1 && SL.FuriList[ST.Listnum][0].ToString() == "っ")
                    {
                        // cを入力に追加する
                        MatchStr += d.Value.Substring(0, 1);
                        Debug.Log($"MatchStr:{MatchStr}");
                    }

                    // TODO JudgeStr.Length <= MatchStr.Length + d.Value.Length ???なんの比較?
                    if (JudgeStr.Length <= MatchStr.Length + d.Value.Length && !jud)
                    {

                        MatchStr += d.Value;
                        // Debug.Log(MatchStr+":"+ JudgeStr+":"+ MatchStr.Substring(0, JudgeStr.Length));
                        // JudgeStr:入力値
                        // MatchStr.Substring(0, JudgeStr.Length):候補 => 一致するなら正解とする
                        if (JudgeStr == MatchStr.Substring(0, JudgeStr.Length))
                        {
                            //print(MatchStr + "で見つかりました");
                            TypeMatch(i, MatchStr);
                            Debug.Log($"正解!:{MatchStr}");
                        }
                    }
                }
スタジオしまづスタジオしまづ

*どうやって、残りの文字「ゃ, xya」を作っているのか?
・TypeMatch関数が重要っぽい
・TypeMatch(i, MatchStr);で使ってて、ここのiが「きゃ」なら2, 「き」なら1になっている。
・このiはおそらく検索文字を何文字にするのかを決める数字
・今回、kiまで正解したと考えると、検索文字は「き」で1文字だから

i:1, MatchStr:"ki"

となる(ログで確認した)。
・このときの、関数内の処理を読みとく

        void TypeMatch(int num, string MatchStr)
        {
            jud = true;
            var Furistr = SL.FuriList[ST.Listnum];
            SL.FuriList[ST.Listnum] = Furistr.Substring(0, num);
            SL.RomaList[ST.Listnum] = MatchStr;

            if (Furistr.Length != num)
            {
                SL.FuriList.Insert(ST.Listnum + 1, Furistr.Substring(num));
                SL.RomaList.Insert(ST.Listnum + 1, Dic.SearchdicKey(SL.FuriList[ST.Listnum + 1]).Value);
            }

            Typedstr = JudgeStr;
            RightEnter();
        }
スタジオしまづスタジオしまづ

わかった流れ
・本来入力すべき文字SL.FuriList[ST.Listnum]、つまり「きゃ」をvar Furistrに代入
・そこから、入力に成功したi文字(今回は1文字)、つまり「き」を切り取って、SL.FuriList[ST.Listnum]に代入
・SL.FuriList[ST.Listnum]は入力すべき文字なので「きゃ」から「き」になったことがわかる
・SL.RomaList[ST.Listnum]にも入力に成功した「ki」を代入
------ここまでで、「きゃ:kya」と入力すべきものが「き:ki」に変わった----
ここからxyaの生成のはず
・Furistr.Length != num つまり、文字の分割をするならば
・SL.FuriListのST.Listnum+1(次の入力)に「ゃ」を追加
・SL.RomaListのST.Listnum+1(次の入力)に「xya」を追加

スタジオしまづスタジオしまづ

よって、「きゃ」の入力でやること
・デフォルトで「きゃ,kya」とする
・k->iと入力されたら、「きゃ」を後ろの文字から削って検索
 ・「きゃ」でkiの入力に一致しないか検索 => 「kya」なのでしない
 ・「き」でkiの入力に一致しないか検索 => 「ki」で一致
・一致したら
 ・入力すべき文字「きゃ, kya」を「き, ki」に変える
 ・「ゃ,xya」を挿入して、次に入力する文字とする

(他の文字でも問題なく動くか調べる)

スタジオしまづスタジオしまづ

k->iと入力したとき、検索文字が「き」となっており、それに正解した時点で「きゃ」の入力が正解と判断される
(手元ではそうなってないがそうなるはず)

正解時に次の文字が「ゃ」なら差し込んでみるといいのでは?

スタジオしまづスタジオしまづ

ぼちぼちうまくいった

 void Correct()
    {
        // 次の文字が「ゃ」なら
        int furiCount = _furiCountList[_aNum];
        if (_furiCountList[_aNum] != _furiCountList[_aNum+1])
        {
            string nextMoji = _fString[furiCount + 1].ToString();
            // 辞書からとってくる
            string a = cd.dic[nextMoji];
            Debug.Log($"次の文字{nextMoji}:{a}");
            // romslicelistに挿入
            _romSliceList.Insert(furiCount + 1, a);
            ReCreateList(_romSliceList);
            _aString = string.Join("", _romSliceList);
        }
        // 正解した時の処理(やりたいこと)
        _aNum++;
        aText.text = "<color=#6A6A6A>" + _aString.Substring(0,_aNum) + "</color>" + _aString.Substring(_aNum);
        //Debug.Log(_aNum);
    }
スタジオしまづスタジオしまづ

「kya」と入力したときも「kyaxya」と挿入されるからそこの判断。
今打ったのがデフォルトの正解なら、この処理をやらないってすればいいか

スタジオしまづスタジオしまづ

いけた。「しゃ」の場合もいけるだろうか
「しゃ」は「し」の段階で「si, shi」とあるからデフォルト以外もあるんよな。。。

スタジオしまづスタジオしまづ

correctの際に、イレギュラーか判断

    void Correct(bool irregularType)
    {
        if (irregularType)
        {
            // 次の文字が「ゃ」なら
            int furiCount = _furiCountList[_aNum];
            // 「ゃ」のところを探して挿入
            for (int i= _aNum; _aNum + 1< _furiCountList.Count; i++)
            {
                if (_furiCountList[i] != _furiCountList[i + 1])
                {
                    string nextMoji = _fString[furiCount + 1].ToString();
                    // 辞書からとってくる
                    string a = cd.dic[nextMoji];
                    Debug.Log($"次の文字{nextMoji}:{a}");
                    // romslicelistに挿入
                    _romSliceList.Insert(furiCount + 1, a);
                    ReCreateList(_romSliceList);
                    _aString = string.Join("", _romSliceList);
                    break;
                }
            }
        }

ってことはイレギュラーな文字は必ずxyaを入れることになる。
(syaとかshaの対応ができない。だから参考資料の方が「し」だけじゃなくて「しゃ」を調べて候補を探した後「し」を調べてるのか! => 今後の課題)

スタジオしまづスタジオしまづ

「しゃ」の入力でs->iと入力するとciと変換された。
これはiを入力時点で、「し」で検索されているからciが候補となり、iの入力があってるから正解とみなされるバグ。
入力前のローマ字も一致するか調べる必要あるので以下のように修正

                        string rom = stringList[i];
                        int romNum = _romNumList[_aNum];
                        bool preCheck = true;
                        for (int nn = 0; nn<romNum; nn++)
                        {
                            if(rom[nn] != _romSliceList[furiCount][nn])
                            {
                                preCheck = false;
                            }
                        }
                        if (preCheck && Input.GetKeyDown(rom[romNum].ToString()))
スタジオしまづスタジオしまづ

とりあえず、現状の課題を整理しておこう。いいところまではいった
・「しゃ」に関して、xyaの変換が優先されるのでsha,syaのどちらかしか柔軟な対応ができない
=>解決方法は参考資料になるので、真似すればいけそうなレベルまで持ってこれた

変更点はこんな感じ

    void Update()
    {
///------///
                    // stringList[0] ci, stringList[1] shi
                    for (int i = 0; i < stringList.Count; i++)
                    {

                        string rom = stringList[i];
                        int romNum = _romNumList[_aNum];
                        bool preCheck = true;
                        for (int nn = 0; nn<romNum; nn++)
                        {
                            if(rom[nn] != _romSliceList[furiCount][nn])
                            {
                                preCheck = false;
                            }
                        }
                        if (preCheck && Input.GetKeyDown(rom[romNum].ToString()))
                        {
    }


    void CreatRomSliceList(string moji)
    {
        _romSliceList.Clear();
        _furiCountList.Clear();
        _romNumList.Clear();

        // 「し」→「si」,「ん」→「n」
        for (int i = 0; i < moji.Length; i++)
        {
            string a = cd.dic[moji[i].ToString()];


            if (moji[i].ToString() == "ゃ" || moji[i].ToString() == "ゅ" || moji[i].ToString() == "ょ")
            {
                // 次のループへ行ってください
                continue;
            }
            else if (moji[i].ToString() == "っ" && i + 1 < moji.Length)
            {
                a = cd.dic[moji[i + 1].ToString()][0].ToString();
            }
            else if (i + 1 < moji.Length)
            {
                // 次の文字も含めて辞書から探す
                string addNextMoji = moji[i].ToString() + moji[i + 1].ToString();
                if (cd.dic.ContainsKey(addNextMoji))
                {
                    a = cd.dic[addNextMoji];
                }
            }
            // k + i -> xya , lya : iを入れた場合
            // kya : 基本の入力

            _romSliceList.Add(a);

            for (int j = 0; j < a.Length; j++)
            {
                _furiCountList.Add(i);
                _romNumList.Add(j);
            }
        }
    }

    // 正解用の関数
    void Correct(bool irregularType)
    {
        if (irregularType)
        {
            // TODOここの説明を書いてみたがうまくない
            // 次の文字が「ゃ」なら「ゃ」のところに「xya」を挿入
            // 現状の文字の場所
            int furiCount = _furiCountList[_aNum];
            // 「きゃ」ならkの入力時点で次の文字が「ゃ」になる。これだとkの時点でkixyaなりiを打つとkixyaxyaとなるはず
            // この問題を解消するために、_furiCountListを使う
            // _furiCountListは「きゃあ」なら{0,0,0, 2}で、0から2に変わった時が、「xya」を入れるタイミング
            // _furiCountListは「きゃ」なら{0,0,0}で最後まで変わらない
            for (int i= _aNum; _aNum< _furiCountList.Count; i++)
            {
                if (i== _furiCountList.Count-1 || _furiCountList[i] != _furiCountList[i + 1])
                {
                    string nextMoji = _fString[furiCount + 1].ToString();
                    // 辞書からとってくる
                    string a = cd.dic[nextMoji];
                    Debug.Log($"次の文字{nextMoji}:{a}");
                    // romslicelistに挿入と表示の反映
                    _romSliceList.Insert(furiCount + 1, a);
                    ReCreateList(_romSliceList);
                    _aString = string.Join("", _romSliceList);
                    break;
                }
            }
        }
        // 正解した時の処理(やりたいこと)
        _aNum++;
        aText.text = "<color=#6A6A6A>" + _aString.Substring(0,_aNum) + "</color>" + _aString.Substring(_aNum);
        //Debug.Log(_aNum);
    }



スタジオしまづスタジオしまづ

・「しゃ」に関して、xyaの変換が優先されるのでsha,syaのどちらかしか柔軟な対応ができない
=>解決方法は参考資料になるので、真似すればいけそうなレベルまで持ってこれた

っと思っていたが、ReCreateListの対応ができていない。

スタジオしまづスタジオしまづ

課題の整理:
現状の問題:FuricountがReCreateListした時におかしくなる。
本来なら、1個と飛ばしになるはずが、ならない

スタジオしまづスタジオしまづ

なぜか?
ReCreateListは、_romSliceListの数だけループして、_furiCountListを作成する。
一方 CreatRomSliceListは、「ゃ, ゅ, ょ」が来たときにスキップ(continue)する。
この差
スキップせずに、例外処理を入れるのはどうか?

スタジオしまづスタジオしまづ

CreatRomSliceList関数でcontinueしていたところをSKIPにする

            if (moji[i].ToString() == "ゃ" || moji[i].ToString() == "ゅ" || moji[i].ToString() == "ょ")
            {
                a = "SKIP"; // TODO:変更した
            }
            else if (moji[i].ToString() == "っ" && i + 1 < moji.Length)
            {
                a = cd.dic[moji[i + 1].ToString()][0].ToString();
            }

_romSliceListにのみ追加

            _romSliceList.Add(a);

            // TODO:追加した
            if (a == "SKIP")
            {
                continue;
            }

            for (int j = 0; j < a.Length; j++)
            {
                _furiCountList.Add(i);
                _romNumList.Add(j);
            }

ReCreateList関数でSKIPがあれば飛ばすようにする(これでReCreateListでもSKIPが適応できた!!)

    void ReCreateList(List<string> romList)
    {
        _furiCountList.Clear();
        _romNumList.Clear();
        for (int i = 0; i < romList.Count; i++)
        {
            string a = romList[i];
            if (a == "SKIP")
            {
                continue;
            }
            for (int j = 0; j < a.Length; j++)
            {
                _furiCountList.Add(i);
                _romNumList.Add(j);
            }
        }
    }
スタジオしまづスタジオしまづ

ただ、現状の _romSliceListならSKIPが入っているので、SKIPを除外して取得する関数を用意する

        _aString = string.Join("", GetRomSliceListWithoutSkip()); // TODO: 変更した
    // TODO: 追加した:
    List<string> GetRomSliceListWithoutSkip()
    {
        List<string> returnList = new List<string>();
        foreach (string rom in _romSliceList)
        {
            if (rom == "SKIP")
            {
                continue;
            }
            returnList.Add(rom);
        }
        return returnList;
    }
スタジオしまづスタジオしまづ

Correct関数で、kyoをkixyoに変更するとき、xyoを追加する処理をやっているが、xyoとなれば「ょ」の1文字として考えられるのでSKIPする必要がない。そのためRemoveする

            for (int i= _aNum; _aNum< _furiCountList.Count; i++)
            {
                if (i== _furiCountList.Count-1 || _furiCountList[i] != _furiCountList[i + 1])
                {
                    string nextMoji = _fString[furiCount + 1].ToString();
                    // 辞書からとってくる
                    string a = cd.dic[nextMoji];
                    // romslicelistに挿入と表示の反映
                    _romSliceList.Insert(furiCount + 1, a);
                    // SKIPを削除する
                    _romSliceList.RemoveAt(furiCount + 2);
                    ReCreateList(_romSliceList);
                    _aString = string.Join("", GetRomSliceListWithoutSkip());
                    break;
                }
            }
スタジオしまづスタジオしまづ

次は、shaからsya、syaからshaを検索する方法

CheckIrregularType関数を作って、2文字検索と1文字検索で分ければOK

                // 最後の文字じゃないならTODO:追加した 
                if (furiCount < _fString.Length - 1)
                {
                    // 2文字考慮した候補検索「しゃ」(この対応で shaからsyaが検索できる)
                    string addNextMoji = _fString[furiCount].ToString() + _fString[furiCount + 1].ToString();
                    CheckIrregularType(addNextMoji, furiCount, false);
                }
                if (!isCorrect)
                {
                    // 今まで通りの候補検索「し」
                    string currentFuri = _fString[furiCount].ToString();
                    CheckIrregularType(currentFuri, furiCount, true);
                }
スタジオしまづスタジオしまづ

追加する文字が小文字かどうかで判断するってので解決!

                    string a = cd.dic[nextMoji];
                    // TODO:追加 次の文字が小文字じゃないなら飛ばす
                    if (a[0] != 'x' && a[0] != 'l')
                    {
                        continue;
                    }

あとすぐ上のfor文の条件間違ってた。

            for (int i= _aNum; i< _furiCountList.Count; i++)
スタジオしまづスタジオしまづ

文字の追加処理を見直した。
// ・イレギュラーな入力(関数の実行時点で判別している)
// ・次の文字が小文字なら入力

 void AddSmallMoji()
    {
        int nextMojiIndex = _furiCountList[_aNum]+1;
        // 次の文字が小文字なら追加:どんな時に「xya」を追加する?
        // ・イレギュラーな入力(関数の実行時点で判別している)
        // ・次の文字が小文字なら入力
        if (_fString.Length -1 < nextMojiIndex)
        {
            return;
        }
        string nextMoji = _fString[nextMojiIndex].ToString();
        // 辞書からとってくる
        string a = cd.dic[nextMoji];
        // Debug.Log($"次の文字{nextMoji}, 挿入文字:{a}, nextMojiIndex:{nextMojiIndex}");

        // TODO:追加 次の文字が小文字じゃないなら飛ばす
        if (a[0] != 'x' && a[0] != 'l')
        {
            return;
        }
        // romslicelistに挿入と表示の反映
        _romSliceList.Insert(nextMojiIndex, a);
        // SKIPを削除する
        _romSliceList.RemoveAt(nextMojiIndex + 1);
        ReCreateList(_romSliceList);
        _aString = string.Join("", GetRomSliceListWithoutSkip());
    }
スタジオしまづスタジオしまづ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;

// 画面にあるテキストの文字を変更したい
public class TypingManager : MonoBehaviour
{
    // 画面にあるテキストを持ってくる
    [SerializeField] Text fText; // ふりがな用のテキスト
    [SerializeField] Text qText; // 問題用のテキスト
    [SerializeField] Text aText; // 答え用のテキスト

    // テキストデータを読み込む
    [SerializeField] TextAsset _furigana;
    [SerializeField] TextAsset _question;

    // テキストデータを格納するためのリスト
    [SerializeField] private List<string> _fList = new List<string>();
    private List<string> _qList = new List<string>();

    // 何番目か指定するためのstring
    private string _fString;
    private string _qString;
    private string _aString;

    // 何番目の問題か
    private int _qNum;

    // 問題の何文字目か
    private int _aNum;

    // 合ってるかどうかの判断
    bool isCorrect;

    private ChangeDictionary cd;

    // しんぶん→"si","n","bu","n"
    // しんぶん→"shi","n","bu","n"
    // {0,0,1,2,2,3}
    // {0,1,0,0,1,0}
    [SerializeField] private List<string> _romSliceList = new List<string>();
    [SerializeField] private List<int> _furiCountList = new List<int>();
    [SerializeField] private List<int> _romNumList = new List<int>();
    // ゲームを始めた時に1度だけ呼ばれるもの
    void Start()
    {
        cd = GetComponent<ChangeDictionary>();

        // テキストデータをリストに入れる
        SetList();

        // 問題を出す
        OutPut();
    }

    void Update()
    {
        // 入力された時に判断する
        if (Input.anyKeyDown)
        {
            isCorrect = false;
            int furiCount = _furiCountList[_aNum];

            // 完全に合ってたら正解!
            // し s  i
            if (Input.GetKeyDown(_aString[_aNum].ToString()))
            {
                // trueにする
                isCorrect = true;

                // 正解
                Correct(false);

                // 最後の文字に正解したら
                if (_aNum >= _aString.Length)
                {
                    // 問題を変える
                    OutPut();
                }
            }
            else if (Input.GetKeyDown("n") && furiCount > 0 && _romSliceList[furiCount - 1] == "n")
            {
                // nnにしたい
                _romSliceList[furiCount - 1] = "nn";
                _aString = string.Join("", _romSliceList);

                ReCreateList(_romSliceList);

                // trueにする
                isCorrect = true;

                // 正解
                Correct(false);

                // 最後の文字に正解したら
                if (_aNum >= _aString.Length)
                {
                    // 問題を変える
                    OutPut();
                }
            }
            else
            {
                // し →si, ci, shi
                // 柔軟な入力があるかどうか
                // 「し」-> "si" , "shi"
                // 今どの ふりがな を打たないといけないのかを取得する

                // 最後の文字じゃないならTODO:追加した 
                if (furiCount < _fString.Length - 1)
                {
                    // 2文字考慮した候補検索「しゃ」(この対応で shaからsyaが検索できる)
                    string addNextMoji = _fString[furiCount].ToString() + _fString[furiCount + 1].ToString();
                    CheckIrregularType(addNextMoji, furiCount, false);
                }
                if (!isCorrect)
                {
                    // 今まで通りの候補検索「し」
                    string currentFuri = _fString[furiCount].ToString();
                    CheckIrregularType(currentFuri, furiCount, true);
                }

            }

            // 正解じゃなかったら
            if(!isCorrect)
            {
                // 失敗
                Miss();
            }
        }
    }

    void CheckIrregularType(string currentFuri, int furiCount, bool addSmallMoji)
    {
        if (cd.dicEx.ContainsKey(currentFuri))
        {
            List<string> stringList = cd.dicEx[currentFuri]; // ci, shi
            // stringList[0] ci, stringList[1] shi
            for (int i = 0; i < stringList.Count; i++)
            {

                string rom = stringList[i];
                int romNum = _romNumList[_aNum];

                // TODO:追加した. kiのiを入力するとき、ciが正解と判断されるので、iより前の文字も一致しているか判定している
                bool preCheck = true;
                for (int nn = 0; nn < romNum; nn++)
                {
                    if (rom[nn] != _romSliceList[furiCount][nn])
                    {
                        preCheck = false;
                    }
                }
                if (preCheck && Input.GetKeyDown(rom[romNum].ToString()))
                {
                    _romSliceList[furiCount] = rom;
                    _aString = string.Join("", GetRomSliceListWithoutSkip());

                    ReCreateList(_romSliceList);

                    // trueにする
                    isCorrect = true;

                    // 正解
                    Correct(addSmallMoji);

                    // 最後の文字に正解したら
                    if (_aNum >= _aString.Length)
                    {
                        // 問題を変える
                        OutPut();
                    }
                    break;
                }
            }
        }
    }


    void SetList()
    {
        string[] _fArray = _furigana.text.Split('\n');
        _fList.AddRange(_fArray);

        string[] _qArray = _question.text.Split('\n');
        _qList.AddRange(_qArray);
    }

    // しんぶん→"shi","n","bu","n"
    // { 0, 0, 1, 2, 2, 3 }
    // { 0, 1, 0, 0, 1, 0 }
    void CreatRomSliceList(string moji)
    {
        _romSliceList.Clear();
        _furiCountList.Clear();
        _romNumList.Clear();




        // 「し」→「si」,「ん」→「n」
        for (int i = 0; i < moji.Length; i++)
        {
            string a = cd.dic[moji[i].ToString()];


            if (moji[i].ToString() == "ゃ" || moji[i].ToString() == "ゅ" || moji[i].ToString() == "ょ")
            {
                a = "SKIP"; // TODO:変更した
            }
            else if (moji[i].ToString() == "っ" && i + 1 < moji.Length)
            {
                a = cd.dic[moji[i + 1].ToString()][0].ToString();
            }
            else if (i + 1 < moji.Length)
            {
                // 次の文字も含めて辞書から探す
                string addNextMoji = moji[i].ToString() + moji[i + 1].ToString();
                if (cd.dic.ContainsKey(addNextMoji))
                {
                    a = cd.dic[addNextMoji];
                }
            }

            _romSliceList.Add(a);

            // TODO:追加した
            if (a == "SKIP")
            {
                continue;
            }

            for (int j = 0; j < a.Length; j++)
            {
                _furiCountList.Add(i);
                _romNumList.Add(j);
            }
        }
        //Debug.Log(string.Join(",", _furiCountList));
        //Debug.Log(string.Join(",", _romNumList));
        //Debug.Log(string.Join(",", _romSliceList));
    }


    void ReCreateList(List<string> romList)
    {
        _furiCountList.Clear();
        _romNumList.Clear();
        for (int i = 0; i < romList.Count; i++)
        {
            string a = romList[i];
            if (a == "SKIP")
            {
                continue;
            }
            for (int j = 0; j < a.Length; j++)
            {
                _furiCountList.Add(i);
                _romNumList.Add(j);
            }
        }
    }

    // TODO: 追加した:
    List<string> GetRomSliceListWithoutSkip()
    {
        List<string> returnList = new List<string>();
        foreach (string rom in _romSliceList)
        {
            if (rom == "SKIP")
            {
                continue;
            }
            returnList.Add(rom);
        }
        return returnList;
    }

    // 問題を出すための関数
    void OutPut()
    {
        // 0番目の文字に戻す
        _aNum = 0;

        // _qNumに0〜問題数の数までのランダムな数字を1つ入れる
        _qNum = Random.Range(0, _qList.Count);

        _fString = _fList[_qNum];
        _qString = _qList[_qNum];

        CreatRomSliceList(_fString);

        // _aString = string.Join("", _romSliceList); 
        _aString = string.Join("", GetRomSliceListWithoutSkip()); // TODO: 変更した

        // 文字を変更する
        fText.text = _fString;
        qText.text = _qString;
        aText.text = _aString;
    }

    // 正解用の関数
    void Correct(bool addSmallMoji)
    {
        if (addSmallMoji)
        {
            // HACK
            AddSmallMoji();
        }
        // 正解した時の処理(やりたいこと)
        _aNum++;
        aText.text = "<color=#6A6A6A>" + _aString.Substring(0,_aNum) + "</color>" + _aString.Substring(_aNum);
    }

    void AddSmallMoji()
    {
        int nextMojiIndex = _furiCountList[_aNum]+1;
        // 次の文字が小文字なら追加:どんな時に「xya」を追加する?
        // ・イレギュラーな入力(関数の実行時点で判別している)
        // ・次の文字が小文字なら入力
        if (_fString.Length -1 < nextMojiIndex)
        {
            return;
        }
        string nextMoji = _fString[nextMojiIndex].ToString();
        // 辞書からとってくる
        string a = cd.dic[nextMoji];
        // Debug.Log($"次の文字{nextMoji}, 挿入文字:{a}, nextMojiIndex:{nextMojiIndex}");

        // TODO:追加 次の文字が小文字じゃないなら飛ばす
        if (a[0] != 'x' && a[0] != 'l')
        {
            return;
        }
        // romslicelistに挿入と表示の反映
        _romSliceList.Insert(nextMojiIndex, a);
        // SKIPを削除する
        _romSliceList.RemoveAt(nextMojiIndex + 1);
        ReCreateList(_romSliceList);
        _aString = string.Join("", GetRomSliceListWithoutSkip());
    }

    // 間違え用の関数
    void Miss()
    {
        // 間違えた時にやりたいこと
        aText.text = "<color=#6A6A6A>" + _aString.Substring(0, _aNum) + "</color>"
            + "<color=#FF0000>" + _aString.Substring(_aNum, 1) + "</color>"
            + _aString.Substring(_aNum + 1);
    }
}