また今日も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)へ続く)