C#手遊び (ソシャゲのガチャ計算：ほんのちょっとLinq)

#この記事、何?
この前、without Visual StudioでC#コンパイルできるだよね、って記事を書いた。
だったら何かちょっとした計算をさせたくなった。
手になじむまでは、最初の public ~~string~~static void string argsあたりでつまずくので、なんか動くコードを上げておきたかったから。
(※追記※ ほら、つまずいてるし。。。)

じゃあ、しばらく前からやってるソシャゲのガチャを計算してみた。

・・・いや、決してゲームアディクトというわけではなく。。。


#どういう人向け?
~~デレステが好きな人向け~~
まあ、C#のコードでちょっとした計算をさせたい人向け。
まあ、たまたま目の前にあった端末にpython入ってないこともあるけど、今どきのWindowsならcsc.exeはあるでしょ、多分。
これあれば中身いじってどこででもC#でexe作って何か計算できるな、と。


#参考URL
■乱数を生成する
https://dobon.net/vb/dotnet/programing/random.html

■LINQ とは
https://ufcpp.net/study/csharp/sp3_linq.html

■アイドルマスター シンデレラガールズ スターライトステージ
https://cinderella.idolmaster.jp/sl-stage/

#とりあえず何を計算したいかの軽い説明
たまに無償で引けるガシャなどでレアリティ「R」が手に入る。同じ子のRを重ねると☆1が☆2、☆3とかって増える。
で、10枚手に入れるとRの上限の☆10ができる。ちょっとうれしい。
全部で103種類あるけど、いつになったらそろうのか、という話。
なので、ガシャ数を引数にシミュレートしてどれくらい出るか試してみたい。


#コーディング方針

##初期条件
まあまあそろったので、残り44人。
すでに9枚持っているのが9人、8枚が9人、7枚が11人・・・という状態なのでこんな。

```csharp

        //現在の数: 9人 -> 2人 (8種類で合計44人)
        int[] current = { 9, 9, 11, 7, 3, 2, 1, 2 };
```

##ざっくりPS
C#の乱数使って0以上103未満の数を取得して103種類取る。これがガシャの試行に相当する。
上記の44人を配列を作って、44人の初期☆数を入れておいて、その子の整数が来たらincrementする。
で、最後に☆10に届いてない子のリストを出す。


#できあがり

```csharp

using System;
using System.Linq;

public class Calc
{
    public static void Main(string[] args)
    {
        //繰り返し数を引数から取得(なければ0)
        int iteration = 0;
        if (args.Length == 1)
        {
            int.TryParse(args[0], out iteration);
            if (iteration < 0) { iteration = 0; }
        }

        Console.WriteLine("繰り返し数 = " + iteration.ToString());

        //現在の数: 9人 -> 2人 (8種類で合計44人)
        int[] current = { 9, 9, 11, 7, 3, 2, 1, 2 };
        
        //44人分の空配列
        int[] r = new int[current.Sum()];

        // 9人 -> 2人 で8回ループして44人の現在保持数を設定
        int startRemain = 9;
        int idx = 0;
        for (int i = 0; i < current.Length; i++)
        {
            for (int tmp = 0; tmp < current[i]; tmp++)
            {
                r[idx + tmp] = startRemain;
            }
            startRemain--;
            idx += current[i];
        }

        var rand = new Random();

        //ガシャを引く。。。
        for (int i = 0; i < iteration; i++)
        {
            //対象内の誰かだったら☆数を++
            int tmp = rand.Next(103);
            if (tmp < current.Sum())
            {
                r[tmp]++;
            }
        }

        //結果発表♪
        int remain = 0;
        for (int i = 0; i < r.Length; i++)
        {
            int tmp = r[i];
            //☆10に届いてない分だけ表示
            if (tmp < 10)
            {
                Console.WriteLine((i + 1).ToString() + "人目: ☆" +  r[i].ToString());
                remain++;
            }
        }
        Console.WriteLine("残り" + remain.ToString() + "人");
    }
}


```

#コンパイル
これ参照。
■C#手遊び(Compiler w/o Visual Studio)
https://qiita.com/siinai/items/8a325ad4eade1a2f6e9e

ぶっちゃけ、csc.exe code.cs だけでOK。

#実行結果

初期値確認のための0回と、200回、500回、1000回(を何度か)の結果がこれ。


```

C:\projects\qiita\draft\21>
C:\projects\qiita\draft\21>calc
繰り返し数 = 0
1人目: ☆9
2人目: ☆9
3人目: ☆9
4人目: ☆9
5人目: ☆9
6人目: ☆9
7人目: ☆9
8人目: ☆9
9人目: ☆9
10人目: ☆8
11人目: ☆8
12人目: ☆8
13人目: ☆8
14人目: ☆8
15人目: ☆8
16人目: ☆8
17人目: ☆8
18人目: ☆8
19人目: ☆7
20人目: ☆7
21人目: ☆7
22人目: ☆7
23人目: ☆7
24人目: ☆7
25人目: ☆7
26人目: ☆7
27人目: ☆7
28人目: ☆7
29人目: ☆7
30人目: ☆6
31人目: ☆6
32人目: ☆6
33人目: ☆6
34人目: ☆6
35人目: ☆6
36人目: ☆6
37人目: ☆5
38人目: ☆5
39人目: ☆5
40人目: ☆4
41人目: ☆4
42人目: ☆3
43人目: ☆2
44人目: ☆2
残り44人

C:\projects\qiita\draft\21>calc 200
繰り返し数 = 200
3人目: ☆9
8人目: ☆9
10人目: ☆9
14人目: ☆9
17人目: ☆8
19人目: ☆8
20人目: ☆8
21人目: ☆8
22人目: ☆9
23人目: ☆9
24人目: ☆8
25人目: ☆8
26人目: ☆7
28人目: ☆9
29人目: ☆9
30人目: ☆9
31人目: ☆8
32人目: ☆9
33人目: ☆6
34人目: ☆8
35人目: ☆8
36人目: ☆9
37人目: ☆9
38人目: ☆7
39人目: ☆6
40人目: ☆6
41人目: ☆4
42人目: ☆5
43人目: ☆5
44人目: ☆2
残り30人

C:\projects\qiita\draft\21>calc 500
繰り返し数 = 500
11人目: ☆8
23人目: ☆9
29人目: ☆9
31人目: ☆8
34人目: ☆8
37人目: ☆8
41人目: ☆9
42人目: ☆6
43人目: ☆9
44人目: ☆3
残り10人

C:\projects\qiita\draft\21>calc 1000
繰り返し数 = 1000
残り0人

C:\projects\qiita\draft\21>calc 1000
繰り返し数 = 1000
42人目: ☆7
43人目: ☆8
残り2人

C:\projects\qiita\draft\21>calc 1000
繰り返し数 = 1000
44人目: ☆8
残り1人

C:\projects\qiita\draft\21>calc 1000
繰り返し数 = 1000
44人目: ☆9
残り1人

C:\projects\qiita\draft\21>calc 1000
繰り返し数 = 1000
42人目: ☆9
残り1人

C:\projects\qiita\draft\21>calc 1000
繰り返し数 = 1000
残り0人

C:\projects\qiita\draft\21>calc 1000
繰り返し数 = 1000
42人目: ☆5
残り1人

C:\projects\qiita\draft\21>calc 1000
繰り返し数 = 1000
44人目: ☆9
残り1人

C:\projects\qiita\draft\21>calc 1000
繰り返し数 = 1000
43人目: ☆8
残り1人


```

#コーディング中の感想
pythonもそうだったけど、些細な書きミスはcsc.exeが「〇行目の〇文字目がおかしいです」って言ってくる。
だから、ほとんどの場合、一目で修正方法に気づく。
今回、0ByteのテキストファイルをVisual Studio Codeで開いて編集した。
ほんの少しIntelliSenseも利くし、これくらいの計算タスクならVisual Studio Codeでいいな、と思った。


#統計的な見地(のふりをしたゲーム観点)

へぇ・・・200回くらいじゃまだまだ、で、500回くらいでかなり減った感じ。
1000回もすればすでに終わっているか最後の一人とかそんな感じか・・・なるほど。

まあ、大体そんな感じかなぁ・・・と思っていた通り。どちらかというときもち早いかも。
けど、やっぱりガシャは闇だよね。

500回試したログで、ほぼ全員☆8か☆9になっているのに、44人目が☆3だって。
初期値(=現状)が最小☆2だから、よりにもよって一番枚数が必要な子が500回引いて1枚しか来てないということ。
10回くらい繰り返した1000回の試行の一つにも「42人目: ☆5」ってあるし。

いやぁ・・・リアルにこれだったら長くやきもきしそう。

あっ、そういうことじゃなくて、あとで検定かけてみましょう。
上記例が極めてまれなのかどうか。


#今後
今回、Sum()ひとつだけどLinq入れてみた。
とりあえず動くべたコード書いてからリファクタリングしてたら、そういう機能ありそうだなぁ・・・と思って調べてみた。
Linqいいね。SQLに近い書き方で「あれここーして、それからあーやって」ってしゃべる感じでかけそう。
もっと攻略しよう。
あと、Python慣れしたいのでpython手遊びとして、書いてみようかなぁ?
と、だいぶたって、C#少し慣れたら改めてリファクタリング検討してみたい。
もう少しましになりそうな気がする。