////////////////////////////////////////////////////////////
// 盲牌（MoPai.cs）
// Copyright (c) by Ysama September, 2024
// (1) 136枚を伏せて（裏）表示。
// (2) 初期設定でランダムに13牌を拾ってきて、最下段に表示。
//    （牌山からは消去－この際、牌の重複を避ける。）
// (3) 最下段の13牌と上段の123牌間で神経衰弱を開始。
////////////////////////////////////////////////////////////
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;		//Assemblyを使う為
using mahjongtable;				//Mahjongtableクラスを利用する

namespace MoPai
{
	///////////////////////////
	//エントリーポイントクラス
	///////////////////////////
	class MoPai : Form
	{
		//メンバーフィールド（変数）
		MahjongTable myTable;				//麻雀台
		int[] MyTiles = new int[13];		//手札13枚のmhTable添字番号
		int trials = 0	;					//試行回数
		bool ontheway = false;				//一枚開いた状態
		int firstNo = 0;					//一枚目の麻雀牌番号
		int secondNo = 0;					//二枚目の麻雀牌番号
		int pairs = 0;						//対を開いた数
		int prevNo = -1;					//直前の麻雀牌番号
		int prevX = 0;						//直前の麻雀牌X座標
		int prevY = 0;						//直前の麻雀牌Y座標

		[STAThread]
		public static void Main()
		{
			Application.Run(new MoPai());
		}

		//コンストラクター
		public MoPai()
		{
			Assembly myOwn = Assembly.GetEntryAssembly();
			this.Icon = Icon.ExtractAssociatedIcon(myOwn.Location);	//プログラムアイコンをフォームにつける
			this.Size = new Size(888, 749);			//調査値
			this.MinimumSize = new Size(658, 561);	//調査値
			this.MaximumSize = new Size(888, 749);	//調査値
			this.BackColor = Color.Black;
			this.Text = "MoPai";
			this.SizeChanged += OnSizeChanged;		//調査用
			myTable = new MahjongTable(864, 702);
			myTable.Location = new Point(0, 0);
			myTable.Size = new Size(ClientSize.Width, ClientSize.Height);
			myTable.Anchor = (AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right);
			myTable.MouseMove += OnMyTableMouseMove;
			myTable.Click += OnMyTableClick;
			this.Controls.Add(myTable);
			Init();
			MessageBox.Show("MoPaiの遊び方\r\n\r\n" +
							"１．MoPaiは自分の手牌のペア牌を取ってゆく神経衰弱型のゲームです。\r\n" +
							"２．MoPaiを起動すると、136枚の伏せ牌が「河（ホウ）」に並べられ、そこからランダムに貴方の手牌が13牌取られ、最下段に表示されます。\r\n" +
							"３．貴方は先ず伏せられた自分の手牌をクリックして一つ選び、それが何か確かめます。（盲牌－表が表示されます。）\r\n" +
							"４．次に河の牌をクリックして一つ選び、その牌の表が表示るので、それが牌種、番号共に同じ牌か否か確認します。\r\n" +
							"５．同じ牌であれば「ペア」が完成し、自分の手牌を減らすことが出来ます。\r\n" +
							"６．13牌の手牌が全てなくなればゲームが終了し、あなたが何手で終了したかが表示されます。\r\n" +
							"７．その後、終了するか、更にゲームを続けるか、確認してください。\r\n\r\n" +
							"Good luck!", "MoPaiの遊び方", MessageBoxButtons.OK, MessageBoxIcon.Information);
		}

		private void OnSizeChanged(object sender, EventArgs e)//調査用
		{
			this.Text = "Width: " + Size.Width.ToString() + ", Height: " + Size.Height.ToString();
		}

		private void OnMyTableMouseMove(object sender, EventArgs e)
		{
			Point p = this.PointToClient(Cursor.Position);
			int No = myTable.GeGridtNo(p.X, p.Y);
	//this.Text = "MoPai - No: " + No.ToString() + ", prevNo = " + prevNo.ToString();
	//this.Text = "MoPai - No = " + No.ToString() + ", prevNo = " + prevNo.ToString() + ", firstNo = " + firstNo.ToString() + ", secondNo = " + secondNo.ToString();
			if(ontheway)
			{
				if(No >= 0 && No <= 135)		//牌山エリア内
				{
					if(prevNo != No)
					{
						if(prevNo >= 0)
						{
							myTable.RemoveTile(prevNo, prevNo % 18, prevNo / 18, true, false);	//選択された牌を消す（Discardedはfalse）
							myTable.ShowTile(prevNo, prevNo % 18, prevNo / 18, true);			//直前の選択牌を元に戻す
							if(myTable.Tiles[No].Discarded)
								return;			//捨てられた牌の場合は赤枠選択しない
						}
						myTable.SelectTile(No, No % 18, No / 18, true);							//新しい選択牌を選択する
						prevNo = No;
					}
				}
			}
			else
			{
				if(No >= 146 && No <= 158)		//手牌エリア内
				{
					int x = (No % 18) * 48 + 3;
					int y = (No / 18) * 78 + 3;
					No = MyTiles[No - 146];
	//this.Text = "MoPai - No: " + No.ToString() + ", prevNo = " + prevNo.ToString();
					if(myTable.Tiles[No].Owner == 0)	//あなた（Player No 1）の手牌でないなら
						return;
					if(prevNo != No)
					{
						if(prevNo >= 0)
						{
							myTable.RemoveTile(prevNo, prevX, prevY);	//選択された牌を消す（Discardedはtrue）
							myTable.ShowTile(prevNo, prevX, prevY);		//直前の選択牌を元に戻す（Discardedはtrue）
						}
						myTable.SelectTile(No, x, y);					//新しい選択牌を選択する
					}
					prevNo = No;
					prevX = x;
					prevY = y;
				}
			}
		}

		private void OnMyTableClick(object sender, EventArgs e)
		{
			if(myTable.msButton == MouseButtons.Left)
			{
				int No = myTable.GeGridtNo(myTable.msX, myTable.msY);
				if(ontheway)
				{
					if(No >= 0 && No <= 135)		//牌山エリア内
					{
						if(myTable.Tiles[No].Discarded)	//Removeされた牌の場所をクリックした場合
						{
							MessageBox.Show("そこに牌はありません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
							return;
						}
						myTable.RemoveTile(prevNo, prevNo % 18, prevNo / 18, true, false);	//選択された牌を消す（Discardedはfalse）
						myTable.ShowTile(prevNo, prevNo % 18, prevNo / 18, true);			//直前の選択牌を元に戻す
						//secondNo指定牌の表表示
						secondNo = No;
						myTable.TurnFace(secondNo, true);
						myTable.ShowTile(secondNo, secondNo % 18, secondNo / 18, true);
						//判定条件（スートが同じで且つ番号が同じ）
						if(myTable.Tiles[firstNo].Suit == myTable.Tiles[secondNo].Suit &&
							myTable.Tiles[firstNo].Number == myTable.Tiles[secondNo].Number)
						{
							MessageBox.Show("同じ牌を開けました。", "正解！", MessageBoxButtons.OK, MessageBoxIcon.Information);
							pairs++;
							this.Text = "MoPai (取得したペアの数：" + pairs.ToString() + "）";
							myTable.RemoveTile(firstNo, prevX, prevY);							//手牌を消す（Discardedはtrue）
							myTable.Tiles[firstNo].Owner = 0;									//貴方の手牌から外す
							myTable.RemoveTile(secondNo, secondNo % 18, secondNo / 18, true);	//手牌を消す（Discardedはtrue）
							if(pairs == 13)
							{
								MessageBox.Show("ゲームが完了しました。あなたの試行回数は" + trials.ToString() + "でした。", "ゲーム完了", MessageBoxButtons.OK, MessageBoxIcon.Information);
								DialogResult res = MessageBox.Show("終了しますか？", "終了確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
								if(res == DialogResult.Yes)
									Close();
								else
								{
									Init();		//再初期化
									return;
								}
							}
						}
						else
						{
							MessageBox.Show("残念！番号が違います。", "不正解！", MessageBoxButtons.OK, MessageBoxIcon.Information);
							myTable.TurnFace(firstNo, false);
							myTable.ShowTile(firstNo, prevX, prevY);
							myTable.RemoveTile(secondNo, secondNo % 18, secondNo / 18, true, false);	//Discardedはfalse
							myTable.TurnFace(secondNo, false);
							myTable.ShowTile(secondNo, secondNo % 18, secondNo / 18, true);
						}
						ontheway = false;
						prevNo = -1;			//prevNoを初期化
					}
				}
				else
				{
					if(No >= 146 && No <= 158)		//手牌エリア内
					{
						myTable.RemoveTile(prevNo, prevX, prevY);	//選択された牌を消す
						myTable.TurnFace(prevNo, true);				//表にして
						myTable.ShowTile(prevNo, prevX, prevY);		//直前の選択牌を表示する
						firstNo = prevNo;							//選択された牌はfirstNo, prevX, prevYで特定
						prevNo = -1;								//prevNoを初期化
						trials++;									//試行数を増やす
						ontheway = true;
					}
				}
			}
			else if(myTable.msButton == MouseButtons.Right)
			{
				int no = myTable.GeGridtNo(myTable.msX, myTable.msY);
				if(no >=0 && no <= 135)
					MessageBox.Show("右ボタン：No = " + no.ToString() + "(Discarded flag: " + myTable.Tiles[no].Discarded + ")", "麻雀牌番号", MessageBoxButtons.OK, MessageBoxIcon.Information);
				else
					MessageBox.Show("範囲外です", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			}
			else
			{
				int no = myTable.GeGridtNo(myTable.msX, myTable.msY);
				if(no >=0 && no <= 135)
					MessageBox.Show("中央ボタン：No = " + no.ToString() + "(Discarded flag: " + myTable.Tiles[no].Discarded + ")", "麻雀牌番号", MessageBoxButtons.OK, MessageBoxIcon.Information);
				else
					MessageBox.Show("範囲外です", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			}
		}

		private void Init()
		{
			//初期設定
			this.Text = "MoPai";
			trials = 0;				//試行回数
			ontheway = false;		//一枚開いた状態
			firstNo = 0;			//一枚目の麻雀牌番号
			secondNo = 0;			//二枚目の麻雀牌番号
			pairs = 0;				//対を開いた数
			myTable.XiPai();		//洗牌
			//初期画面設定
			for(int i = 0; i < 8; i++)
			{
				//牌山の表示（裏面）
				for(int j = 0; j < 18; j++)
				{
					if(i * 18 + j > 135)
						break;
					myTable.TurnFace(i * 18 + j, false);		//選択された牌を裏にする
					myTable.ShowTile(i * 18 + j, j, i, true);	//横(0 - 17) X 縦(0 - 7)のグリッド表示
				}
			}
			//MyTiles13枚の選択
			SelectTiles();

			//DialogResult res = MessageBox.Show("小さい麻雀牌を使いますか？", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
		}

		//MyTiles13枚の選択
		public void SelectTiles()
		{
			//乱数の初期化（発生パターンが時間により変化する）
			Random rand = new Random((int)DateTime.Now.Ticks & 0x0000FFFF);
			int n = 0;
			while(n < 13)						//手札の麻雀牌が13枚になるまで
			{
				int r = rand.Next(136);			//34(数牌3 x 9 + 風牌4 + 三元牌3) x 4
				MyTiles[n] = r;					//牌山（MyTable.Tiles）からランダムに選ぶ
				bool Dup = false;
				for(int i = 0; i < n; i++)
				{
					if(MyTiles[n] == MyTiles[i] ||
						(myTable.Tiles[r].Suit == myTable.Tiles[MyTiles[i]].Suit &&
						myTable.Tiles[r].Number == myTable.Tiles[MyTiles[i]].Number))
					{
						Dup = true;
						break;
					}
				}
				if(!Dup)
				{
					myTable.RemoveTile(r, r % 18, r / 18, true);	//選択された牌を消す（Discardedはtrueになる）
					myTable.Tiles[r].Owner = 1;						//貴方（Player No 1）の牌となる
					myTable.TurnFace(r, false);						//選択された牌を裏にする
					myTable.ShowTile(r, 2 + n, 8, true);			//選択された牌を最下段中央に表示する
					n++;
				}
			}
		}
	}
}
