「進捗・どう・です・か」をランダムに表示し「進捗どうですか」が完成したら煽ってくるプログラム（C#で挑戦）

[「進捗・どう・です・か」をランダムに表示し「進捗どうですか」が完成したら煽ってくるClojure](http://qiita.com/esehara@github/items/c57cafa57aa92dc1e3c2)
[「進捗・どう・です・か」をランダムに表示し「進捗どうですか」が完成したら煽ってくるプログラム](http://elephnote.com/blog/archives/936)
[「進捗・どう・です・か」をHaskellで書いてみた](http://qiita.com/lotz/items/b47913cb27052cf9e127)
[golang の進捗どうですか](http://qiita.com/mattn/items/4b4ce89396d660a155a9)

おもしろそうだったのでC#で挑戦してみました。

うまい人が書くと、もっとシンプルになるんでしょうけど、まぁ。
（思いつくままに書いたコメントとかテスト用コードとかそのままです）

```csharp:Program.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Word = System.Int32;

namespace ShinchokuDoudesuka
{
    class Program
    {
        static readonly string[] SDDK_WORDS = new string[] { "進捗", "どう", "です", "か" };

        static void Main()
        {
#if DEBUG
            Console.WriteLine("デバッグモードです");
            // テストデータ文字列（最後は必ず0123で終わること）
            string tstDatStr = "0002030100130120012101221230123";

            // テストデータを変換（文字列→数値配列）
            int x = 0;
            int[] tstDat = tstDatStr.Select(s => int.Parse(s.ToString())).ToArray<int>();

            Console.WriteLine("テストデータ確認");
            foreach (int ts in tstDat)
            {
                Console.Write(ts);
            }
            Console.WriteLine("");
#endif
            Random rnd = new Random();

            bool aoriFlg = false;   // 煽るか？ t⇒煽る f⇒煽らない
            int tryCnt = 0;         // 試行回数
            bool asyStcFlg = false; // 文を組み立て中か？　t⇒組み立て進行中 f⇒組み立ててない
            Word befW = 0;          // 1つ前の単語（比較用）
            #region 文が完成する（煽る）までの間、文を生成し続ける
            while (!aoriFlg)
            {
                //「進捗・どう・です・か」をランダムに取得し、表示する
                Word w = rnd.Next(SDDK_WORDS.Length);
#if DEBUG
                //乱数の代わりにテストデータを順に渡す
                w = tstDat[x++];
                Debug.Write(w);
#endif
                Console.Write(SDDK_WORDS[w]);

                #region 文が完成したか判定する
                if (asyStcFlg)
                {
                    #region 文を組み立て中の場合
                    if (w == (befW + 1))  // w == ++befWでも良いかも？
                    {
                        #region 単語が連続している場合
                        if (w == SDDK_WORDS.Length - 1)
                        {
                            // 文が完成した場合、煽る
                            tryCnt++;
                            aoriFlg = true;
                        }
                        else
                        {
                            // 組み立てが進行
                            befW = w;   // w == ++befWだったら、ここ削れる？
                        }
                        #endregion 単語が連続している場合
                    }
                    else
                    {
                        // 組み立てが失敗
                        asyStcFlg = false;
                        tryCnt++;
                    }
                    #endregion 文を組み立て中の場合
                }
                else
                {
                    #region 文を組み立ててない場合
                    if (w == 0)
                    {
                        // 組み立て開始
                        asyStcFlg = true;
                        befW = w;
                    }
                    else
                    {
                        // 失敗
                        tryCnt++;
                    }
                    #endregion 文を組み立ててない場合
                }
                #endregion 文が完成したか判定する
            }
            #endregion 文が完成する（煽る）までの間、文を生成し続ける

            Console.WriteLine("");
            Console.WriteLine("＿人人人人人人人＿");
            Console.WriteLine("＞進捗どうですか＜");
            Console.WriteLine("￣Y^Y^Y^Y^Y^Y^Y￣");
            Console.WriteLine(string.Format("{0}回で煽られました", tryCnt));
        }
    }
}
```

2015/07/22 追記
[「進捗・どう・です・か」をランダムに表示し「進捗どうですか」が完成したら煽ってくるプログラム（C#/LINQ）](http://qiita.com/shoooo/items/ec84418c37f08ecf7576)
に感銘を受け、書き直してみた。

しかし……あんまり進歩してない。

とりあえず、クラスに詰め込んでみた。
クラス設計、未だによく分からない。

ネストは減らせた。
ifまわりまだ整理できそうだけど、前より改善されたから良しとする。

```csharp:Program.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
//using Word = System.Int32;

namespace ShinchokuDoudesuka
{
    class Program
    {
        public class Shinchoku
        {
            #region 定数＆変数
            readonly string[] SDDK_WORDS = { "進捗", "どう", "です", "か" };   // 正解を文字列配列で定義
            readonly string SDDK_RLT_STR;                                      // 正解を文字列で定義

            List<string> words;                                                // LINQ用リスト（HashSetの方が速かった気がするけど、使い慣れたListで）。
            Random rnd;                                                        // 擬似乱数用変数
            int tryCnt;                                                        // 試行回数

            /// <summary>
            /// コンストラクタ
            /// </summary>
            public Shinchoku()
            {
                SDDK_RLT_STR = string.Join("", SDDK_WORDS);
                words = new List<string>();
                rnd = new Random();
                tryCnt = 0;
            }
            #endregion 定数＆変数

            /// <summary>
            /// 完成したら煽る関数
            /// </summary>
            public void Aoru()
            {
                // 完成するまで表示を続ける
                while (!TryMakeWords())
                {
                    //必要なら復活しても良い
                    //Thread.Sleep(1);
                }

                Console.WriteLine("");
                Console.WriteLine("＿人人人人人人人＿");
                Console.WriteLine("＞進捗どうですか＜");
                Console.WriteLine("￣Y^Y^Y^Y^Y^Y^Y￣");
                Console.WriteLine(string.Format("{0}回で煽られました", tryCnt));
            }

            /// <summary>
            /// 「進捗・どう・です・か」を1回だけ組み立ててみる
            /// </summary>
            /// <returns>完成したか？　true⇒完成、false⇒未完成</returns>
            private bool TryMakeWords()
            {
                bool ret = false;

                // 1つの単語を追加する
                words.Add(SDDK_WORDS[rnd.Next(SDDK_WORDS.Length)]);

                // ここまでに作ったものmakingWordsと正解checkStrとを比べる
                string makingWords = string.Join("", words);
                string checkStr = string.Join("", SDDK_WORDS.Where((e, i) => i < words.Count));

                if (makingWords == checkStr)
                {
                    // 正解と完全一致したら完成
                    if (makingWords == SDDK_RLT_STR)
                    {
                        Console.Write(makingWords);
                        tryCnt++;
                        ret = true;
                    }
                }
                else
                {
                    // 不一致
                    Console.Write(makingWords);
                    tryCnt++;
                    words.Clear();
                }

                return ret;
            }
        }

        static void Main()
        {
            Shinchoku s = new Shinchoku();
            s.Aoru();
        }
    }
}
```