また今日もWPFと格闘してしまいましたが、チンチロリンを先に済ませておきましょう。

 

(解説(2)からの続き) 

       /////////////////////
        //チンチロリン一勝負
        /////////////////////

        private bool Match(int roller)    //親Bakuto[Banker]と子Bakuto[roller]の対局
        {
            //戻り値(true-親落ち、false-続投)
            bool change = false;
            //賽子を表示する(解説:ここでDiceの登場です。)
            dice1.Visible = true;
            dice2.Visible = true;
            dice3.Visible = true;
            int result = 0;        //賽子を振った結果(WinOrNotメソッドの戻り値)
            //親(Banker)の投賽
            for(int i = 0; i < 3; i++)     //目無し(0)の場合、3回迄続けられる
            {
                //投賽処理
                dice1.DiceSound(false);        //代表して投賽音を鳴らす
                result = WinOrNot(dice1.Roll(), dice2.Roll(), dice3.Roll());
                if(result != 0)    //解説:「目無し」でなければ処理を続けます。
                    break;
            }
            //結果処理
            string str = "";
            if(result < 4)
            {    //resultは勝ち(正)または負け(負)で掛金の倍数
                if(result == 0)    //解説:親の「目無し(負け)」で「親落ち」です。
                {
                    str = "親の負け:目無しでした。";
                    Bakuto[Banker].Update(-LastBet[roller]);
                    playerList.SetTextInSubItems(Banker, 3, String.Format("{0:C}", -LastBet[roller]));
                    Bakuto[roller].Update(LastBet[roller]);
                    playerList.SetTextInSubItems(roller, 3, String.Format("{0:C}", LastBet[roller]));
                    change = true;
                }
                else if(result > 0)
                {
                    str = "親の勝ち:親の" + result.ToString() + "倍取りです。";
                    Bakuto[Banker].Update(LastBet[roller] * result);
                    playerList.SetTextInSubItems(Banker, 3, String.Format("{0:C}", LastBet[roller] * result));
                    Bakuto[roller].Update(-LastBet[roller] * result);
                    playerList.SetTextInSubItems(roller, 3, String.Format("{0:C}", -LastBet[roller] * result));
                 }
                else
                {
                    str = "親の負け:親の" + (-result).ToString() + "倍付けです。";
                    Bakuto[Banker].Update(LastBet[roller] * result);
                    playerList.SetTextInSubItems(Banker, 3, String.Format("{0:C}", LastBet[roller] * result));
                    Bakuto[roller].Update(LastBet[roller] * -result);
                    playerList.SetTextInSubItems(roller, 3, String.Format("{0:C}", LastBet[roller] * -result));
                    change = true;
                }
            }
            else
            {
                //親の出目 = result -2;
                int banker_roll = result -2;    //2~5の場合の親の出目
                MessageBox.Show("親の出目は" + banker_roll.ToString() + "でした。", "親の出目", MessageBoxButtons.OK, MessageBoxIcon.Information);
                //子(roller)の投賽(解説:親の出目が2~5の時に初めて子の投賽が許されます。)
                for(int i = 0; i < 3; i++)     //目無し(0)の場合、3回迄続けられる
                {
                    //投賽処理(解説:親と同じ処理です。)
                    dice1.DiceSound(false);        //代表して投賽音を鳴らす
                    result = WinOrNot(dice1.Roll(), dice2.Roll(), dice3.Roll());
                    if(result != 0)
                        break;
                }
                //結果処理
                if(result < 4)
                {    //resultは勝ち(正)または負け(負)で掛金の倍数
                    if(result == 0)
                    {
                        str = "子の負け:目無しでした。";
                        Bakuto[Banker].Update(LastBet[roller]);
                        playerList.SetTextInSubItems(Banker, 3, String.Format("{0:C}", LastBet[roller]));
                        Bakuto[roller].Update(-LastBet[roller]);
                        playerList.SetTextInSubItems(roller, 3, String.Format("{0:C}", -LastBet[roller]));
                    }
                    else if(result > 0)
                    {
                        str = "子の勝ち:子の" + result.ToString() + "倍取りです。";
                        Bakuto[Banker].Update(-LastBet[roller] * result);
                        playerList.SetTextInSubItems(Banker, 3, String.Format("{0:C}", -LastBet[roller] * result));
                        Bakuto[roller].Update(LastBet[roller] * result);
                        playerList.SetTextInSubItems(roller, 3, String.Format("{0:C}", LastBet[roller] * result));
                    }
                    else
                    {
                        str = "子の負け:子の" + (-result).ToString() + "倍付けです。";
                        Bakuto[Banker].Update(LastBet[roller] * -result);
                        playerList.SetTextInSubItems(Banker, 3, String.Format("{0:C}", LastBet[roller] * -result));
                        Bakuto[roller].Update(LastBet[roller] * result);
                        playerList.SetTextInSubItems(roller, 3, String.Format("{0:C}", LastBet[roller] * result));
                    }
                }
                else    //解説:ここで初めて親の出目と子の出目が比較されます。
                {
                    //子の出目 = result -2;
                    if(banker_roll > result - 2)
                    {
                        str = "子の負け:親(" + banker_roll.ToString() + ")対子(" + (result - 2).ToString() + ")で負け。";
                        Bakuto[Banker].Update(LastBet[roller]);
                        playerList.SetTextInSubItems(Banker, 3, String.Format("{0:C}", LastBet[roller]));
                        Bakuto[roller].Update(-LastBet[roller]);
                        playerList.SetTextInSubItems(roller, 3, String.Format("{0:C}", -LastBet[roller]));
                    }
                    else if(banker_roll == result - 2)
                    {
                        Bakuto[Banker].Update();
                        Bakuto[roller].Update();
                        str = "引き分け:親(" + banker_roll.ToString() + ")対子(" + (result - 2).ToString() + ")で分け。";
                    }
                    else
                    {
                        str = "子の勝ち:親(" + banker_roll.ToString() + ")対子(" + (result - 2).ToString() + ")で勝ち。";
                        Bakuto[Banker].Update(-LastBet[roller]);
                        playerList.SetTextInSubItems(Banker, 3, String.Format("{0:C}", -LastBet[roller]));
                        Bakuto[roller].Update(LastBet[roller]);
                        playerList.SetTextInSubItems(roller, 3, String.Format("{0:C}", LastBet[roller]));
                    }
                }
            }
            MessageBox.Show(str, "チンチロリン勝負", MessageBoxButtons.OK, MessageBoxIcon.Information);
            //賽子を非表示にする
            dice1.Visible = false;
            dice2.Visible = false;
            dice3.Visible = false;
            //戻り値がtrueなら親落ち
            return change;
        }

        //////////////////////////////////////////
        //チンチロリン勝敗判定(解説:以下は「戻り値」の解説です。)
        //戻り値:0(出目無し-3回まで投賽可能)
        //正-勝  1-1倍取り(出目6)
        //負-負  2-2倍取り(シゴロ-456)
        //        3-3倍取り(アラシ-ゾロ目)
        //       -1-1倍付け(出目1)
        //       -2-2倍付け(ヒフミ-123)
        //     4~7-出目の数(2~5の目)
        //////////////////////////////////////////

        private int WinOrNot(int D1, int D2, int D3)
        {
            int Num_OR = D1 | D2 | D3;
            int Num_AND = D1 & D2 & D3;
            int Num_XOR = D1 ^ D2 ^ D3;
            bool Num_EQ = (D1 == D2) | (D2 == D3) | (D3 == D1);
            if(Num_OR == Num_AND)                    //アラシの場合
            {
                return 3;
            }
            else if(Num_XOR == 7 && Num_AND == 4)    //456の場合
            {
                return 2;
            }
            else if(Num_XOR == 0 && Num_OR == 3)    //123の場合
            {
                return -2;
            }
            else if(Num_EQ)                            //目が出た場合
            {
                if(Num_XOR == 6)                    //6の目の場合
                {
                    return 1;
                }
                else if(Num_XOR == 1)                //1の目の場合
                {
                    return -1;
                }
                else                                //その他の目が出た場合
                {
                    return Num_XOR + 2;
                }
            }
            else                                    //役も目も出ない場合
                return 0;
        }

        ///////////////
        //親落ち・変更
        ///////////////

        private void ChangeBanker()
        {
            //旧親の〇印を消す(解説:親が落ちたので。)
            playerList.SetTextInSubItems(Banker, 1, "");
            //廻り胴なので次の親候補を仮親とする
            Banker++;
            if(Banker == NoOfBakuto)    //既に最後の博徒([NoOfBakuto - 1])まで来ていたら
                Banker -= NoOfBakuto;    //最初の博徒(0)に戻る
            //仮親が破産者の場合、その次にする
            for(int i = 0; i < NoOfBakuto - 1; i++)    //前の親は対象外なので(博徒数- 1)繰り返す
            {
                if(Bakuto[Banker].IsBankrupt)        //破産チェック
                {
                    Banker++;
                    if(Banker == NoOfBakuto)        //既に最後の博徒(NoOfBakuto - 1)まで来ていたら
                        Banker -= NoOfBakuto;        //最初の博徒(0)に戻る
                }
                else                                //破産者ではない
                    break;                            //その博徒に決定する
            }
            //新親に〇印をつける
            playerList.SetTextInSubItems(Banker, 1, "〇");
            //親の表示(解説:ステータスバーに表示します。)
            tssl[1].Text = Bakuto[Banker].Name;
        }
    }


    /////////////////////
    // PlayerListクラス
    /////////////////////

    public class PlayerList : Form
    {
        //フォームの「閉じるボタン」を無効化する(解説:これをC#では用意していませんでした。)
        //出典:https://www.codeproject.com/Articles/20379/Disabling-Close-Button-on-Forms

        private const int CP_NOCLOSE_BUTTON = 0x200;
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams myCp = base.CreateParams;
                myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON ;
                return myCp;
            }
        }

        //クラスメンバー変数
        public string Players_List = "";        //カンマ区切りプレーヤーリスト
        ListView player_List;                    //プレーヤーリスト用リストビュー
        ContextMenu contextMenu;                //コンテキストメニュー
        MenuItem mi1, mi2, mi3;                    //コンテキストメニューアイテム

        public PlayerList()
        {
            this.FormBorderStyle = FormBorderStyle.FixedSingle;    //サイズの変更を不可にする
            this.ClientSize = new Size(640, 137);    //親子合計6名
            this.BackColor = SystemColors.Window;
            this.MaximizeBox = false;                //最大化ボタンを非表示
            this.MinimizeBox = true;                //最小化ボタンを表示
            this.ShowInTaskbar = false;                //タスクバー上表示
            this.Left = 570;
            this.Top = 100;
            this.StartPosition = FormStartPosition.Manual;
            this.Text = "Player List";
            this.Load += new EventHandler(PlayerList_Load);
        }

        //WM_CREATE時処理
        private void PlayerList_Load(object sender, EventArgs e)
        {
            //リストビューの生成とプロパティの設定
            player_List = new ListView();
            player_List.Size = new Size(ClientSize.Width - 20, ClientSize.Height - 20);    //サイズ
            player_List.Location = new Point(10,  10);            //位置
            player_List.Anchor = (AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right);
            player_List.FullRowSelect = true;                    //一行選択
            player_List.GridLines = true;                        //グリッドラインの表示
            player_List.MultiSelect = true;                        //複数選択を許す
            player_List.HoverSelection = false;                    //ポイントで選択できるようにする
            player_List.Activation = ItemActivation.OneClick;    //シングルクリック選択
            player_List.CheckBoxes = false;                        //チェックボックス無効化
            player_List.View = View.Details;                    //リストビューの表示方法
            player_List.Scrollable = true;                        //スクロールバーを表示
            //イベントハンドラの追加
            player_List.ColumnClick += new ColumnClickEventHandler(OnLV_ColumnClick);
            //ヘッダー定義
            player_List.Columns.Add("博徒名", 160, HorizontalAlignment.Left);
            player_List.Columns.Add("親", 32, HorizontalAlignment.Center);
            player_List.Columns.Add("賭金", 80, HorizontalAlignment.Center);
            player_List.Columns.Add("勝負結果", 344, HorizontalAlignment.Center);
            player_List.Columns.Add("破産者", 80, HorizontalAlignment.Center);
            player_List.Columns.Add("累計勝負数", 120, HorizontalAlignment.Center);
            player_List.Columns.Add("累計勝数", 120, HorizontalAlignment.Center);
            player_List.Columns.Add("累計負数", 120, HorizontalAlignment.Center);
            player_List.Columns.Add("累計勝率", 120, HorizontalAlignment.Center);
            //コンテキストメニュー関連
            mi1 = new MenuItem();
            mi1.Index = 0;
            mi1.Text = "博徒の読み込み";
            mi2 = new MenuItem();
            mi2.Index = 0;
            mi2.Text = "博徒の削除";
            mi2.Enabled = false;                //博徒を読み込んだ時に有効にする
             mi3 = new MenuItem();
            mi3.Index = 0;
            mi3.Text = "確定";
            mi3.Enabled = false;                //定員が6名以内になった時に有効にする
            contextMenu = new ContextMenu();
            contextMenu.MenuItems.Add(mi1);
            contextMenu.MenuItems.Add(mi2);
            contextMenu.MenuItems.Add("-");        //セパレーター
            contextMenu.MenuItems.Add(mi3);
             player_List.ContextMenu = contextMenu;
            mi1.Click += new EventHandler(Read_Players);
            mi2.Click += new EventHandler(Del_Player);
            mi3.Click += new EventHandler(Done);
            //FormにListViewを追加
            this.Controls.Add(player_List);
        }

        //player_Listのコラムがクリックされた時
        private void OnLV_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            //ListViewItemSorterを指定する
            player_List.ListViewItemSorter = new ListViewItemComparer(e.Column);
            //正順、逆順交互に並び替える(ListViewItemSorterを設定するとSortが自動的に呼び出される)
        }

        //「博徒の読み込み」処理
        public void Read_Players(object sender, EventArgs e)
        {
            //Playersフォールダーのデータファイルを読む(解説:ここではPlayerインスタンスは作りません。)
            GetDataFiles();
            if(player_List.Items.Count > 2)    //最低でも博徒は2名必要
                mi2.Enabled = true;
        }

        //「博徒の削除」処理(解説:「博徒ファイル」ではなく、リストビュー上の表示です。)
        public void Del_Player(object sender, EventArgs e)
        {
            int count = player_List.Items.Count;
            if(count > 2)
            {
                foreach(ListViewItem item in player_List.SelectedItems)
                {
                    DialogResult dr = MessageBox.Show("博徒" + item.Text + "を削除しますか?", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if(dr == DialogResult.Yes)
                    {
                        //選択された博徒を削除する
                        item.Remove();
                        count--;
                        if(count == 2)
                        {
                            MessageBox.Show("これ以上博徒を削除できません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            mi2.Enabled = false;
                            break;
                        }
                    }
                }
                if(count > 6)
                    MessageBox.Show("まだ定員(6名)を" + (count - 6) + "名オーバーしています。除外する博徒をクリックしてください。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                else
                    mi3.Enabled = true;    //解説:「確定」メニューを有効にします。
            }
            else
            {
                MessageBox.Show("これ以上博徒を削除できません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                mi2.Enabled = false;
            }
            return;
        }

        //「確定」処理
        public void Done(object sender, EventArgs e)
        {
            //博徒名のリストを作成する
            for(int i = 0; i < player_List.Items.Count; i++)
            {
                Players_List += player_List.Items[i].Text.TrimEnd();    //Textには"\r\n"が付いているので
                if(i < player_List.Items.Count - 1)
                    Players_List += ",";
            }
            //ポップアップメニューを無効にする(解説:一旦確定したら後は編集できません。)
            mi1.Enabled = false;
            mi2.Enabled = false;
            mi3.Enabled = false;
            MessageBox.Show("参加博徒が確定しました\r\nChinchirorin Casinoに戻って「開帳」メニューを選択してください。", "参加博徒確定", MessageBoxButtons.OK, MessageBoxIcon.Information);
            //親フォームにフォーカスを当てる(解説:これをしないと二度クリックする必要があります。)
            this.Owner.Activate();
        }

        //Playersフォールダーの*.datファイルを取得
        public void GetDataFiles()
        {
            //ListViewのデータをクリアする
            player_List.Items.Clear();
            //Playersフォールダーの*.datファイルを表示
            IEnumerable<string> files = null;
            files = Directory.EnumerateFiles(".\\Players", "*.dat", SearchOption.TopDirectoryOnly);
            int count = 0;
            foreach (string file in files)
            {
                string temp = file.Replace(".\\Players\\", "");
                Player pl = new Player(temp.Replace(".dat", ""));    //解説:読み込み用の使い捨てローカルインスタンスです。
                ListViewItem item = player_List.Items.Add(pl.Name);
                item.SubItems.Add("");    //解説:親か否かは未定です。
                item.SubItems.Add("");    //解説:賭金は未定です。
                item.SubItems.Add("");    //解説:勝負結果は未定です。
                if(pl.IsBankrupt)    //解説:破産者か否か、です。
                    item.SubItems.Add("Yes");
                else
                    item.SubItems.Add("-");
                //解説:以下勝負数、勝ち数、負け数の累計と勝率です。

                item.SubItems.Add(String.Format("{0:#,0}", pl.TotalGames));
                item.SubItems.Add(String.Format("{0:#,0}", pl.TotalWins));
                item.SubItems.Add(String.Format("{0:#,0}", pl.TotalLoses));
                if(pl.TotalGames > 0)
                {
                    double rate = (double)pl.TotalWins / (double)pl.TotalGames;
                    item.SubItems.Add(String.Format("{0:P3}", rate));
                }
                else
                    item.SubItems.Add("N/A");    //解説:未勝負なので。
                count++;
            }
            if(count > 6)
                MessageBox.Show("定員(6名)を" + (count - 6) + "名オーバーしています。除外する博徒をクリックしてください。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            else
                mi3.Enabled = true;
        }

        //PlayerのSubItemsに文字列を設定する(解説:汎用メソッドとして作りました。)
        public bool SetTextInSubItems(int row, int column, string data)
        {
            if(column <= 0 || column > 3)        //エラーチェック
                return false;
            if(row >= player_List.Items.Count)
                return false;
            player_List.Items[row].SubItems[column].Text = data;
            player_List.Refresh();                //再描画
            return true;
        }
    }

(解説(4)へ続く)