//////////////////////
//    Player.cs
//チンチロ賭博者クラス
//////////////////////
using System;
using System.IO;						//StreamReader/Writerを使う為
using System.Text;						//Encoderを使う為

namespace Players
{
	public class Player
	{
		//定数（代わり）
		const int MinBet = 1000;						//最低掛け金\1,000
		//個性系変数
		public bool IsNew = true;						//新規か否かのフラグ
		public bool IsBankrupt = false;					//破産したか否かのフラグ
		public string Name;								//賭博者の名前（愛称）
		//賭博系変数
		public int Capital;								//掛け金の元手
		public int Luck;								//運、強気（bullish)弱気（bearish）の原因
		public int BullBear;							//強気弱気（掛け金の多寡に影響する）
		//統計系変数
		public int TotalGames;							//累計勝負数
		public int TotalWins;							//累計勝ち数
		public int TotalLoses;							//累計負け数
		public int ThisGames;							//今回勝負数
		public int ThisWins;							//今回勝ち数
		public int ThisLoses;							//今回負け数

		//コンストラクター
		public Player(string name = "")
		{
			if(name == "")				//引数がない場合
				Name = "名無し";		//別途"*.Name ="で名前を設定する（設定しないと「名無し」Playerに統一される）
			else
			{
				Name = name;			//引数の名前を記録
				IsNew = !ReadData();	//ファイルがあれば既存プレーヤー（ない場合は新規）
				if(IsBankrupt)			//破産者は新規プレーヤーとなる（破産者のファイルは残る）
				{
					IsNew = true;
					IsBankrupt = false;
					Name = "名無し";
					Capital = 0;
					Luck = 0;
					BullBear = 0;
					TotalGames = 0;
					TotalWins = 0;
					TotalLoses = 0;
				}
			}
			if(IsNew)
			{
				//「種銭」は新規のみ\10,000～\500,000（最低掛け金\1,000）とする
				Random rnd = new Random();
				Capital = (int)Math.Round((double)rnd.Next(MinBet * 10, MinBet * 500) / (double)1000,  MidpointRounding.AwayFromZero) * 1000;
			}
		}

		//Playerファイルを読む
		private bool ReadData()
		{
			string data = "";				//空文字に初期化する
			//Exeファイルのフォールダーに"Playersフォールダーが無ければ作成する"
			if(!Directory.Exists(".\\Players"))
				Directory.CreateDirectory(".\\Players");
			//ファイル（UTF-8：Encoding.UTF8）を読む
			try
			{
				using(StreamReader sw = new StreamReader(".\\Players\\" + Name + ".dat", Encoding.UTF8, false))
				{
					//ファイルを読む
					data = sw.ReadToEnd();
					if(data == "")			//ファイルが無く読み込めない場合
						return false;
					//文字列の行分割
					string[] lines = data.Split(new[]{"\r\n","\n","\r"},StringSplitOptions.None);
					//第１行（賭博者名, IsBankrupt）
					string[] specs = lines[0].Split(',');
					Name = specs[0];
					if(!Boolean.TryParse(specs[1], out IsBankrupt))
						return false;
					//第２行（Capital、Luck、BullBear）
					string[] gamble = lines[1].Split(',');
					if(!Int32.TryParse(gamble[0], out Capital))
						return false;
					if(!Int32.TryParse(gamble[1], out Luck))
						return false;
					if(!Int32.TryParse(gamble[2], out BullBear))
						return false;
					//第３行（TotalGames、TotalWins、TotalLoses）
					string[] stats = lines[2].Split(',');
					if(!Int32.TryParse(stats[0], out TotalGames))
						return false;
					if(!Int32.TryParse(stats[1], out TotalWins))
						return false;
					if(!Int32.TryParse(stats[2], out TotalLoses))
						return false;
					//ファイルを閉じる
					sw.Close();
				}
			}
			catch(Exception e)
			{
				//エラーコード
				//Console.WriteLine("Generic Exception Handler: {0}", e);
				return false;
			}
			return true;
		}

		//Playerファイルを書く
		private void WriteData()
		{
			//ファイル（UTF-8：Encoding.UTF8）を書く
			using(StreamWriter sw = new StreamWriter(".\\Players\\" + Name + ".dat", false, Encoding.UTF8))
			{
				//第１行（賭博者名）
				string data = Name + "," + IsBankrupt.ToString() + Environment.NewLine;
				//第２行（Capital、Luck、BullBear）
				data += Capital.ToString() + "," + Luck.ToString() + "," + BullBear.ToString() + Environment.NewLine;
				//第３行（TotalGames、TotalWins、TotalLoses）
				data += TotalGames.ToString() + "," + TotalWins.ToString() + "," + TotalLoses.ToString() + Environment.NewLine;
				//ファイルを書く
				sw.Write(data);
				//ファイルを閉じる
				sw.Close();
			}
		}

		//掛け金を決定する
		public int Bet()
		{
			//「種銭」残高チェック
			if(Capital < MinBet)		//掛け金がない場合
			{
				IsBankrupt = true;		//破産宣告され、
				return 0;				//"掛け金 0"（破産を表す）を返す
			}
			//変数宣言
			int sum = 0;				//掛け金
			int Max = 0;				//最大掛け金
			//累計勝率（0.5が標準）
			double totalRate = 0;
			if(TotalGames > 0)
				totalRate = (double)TotalWins / (double)TotalGames;
			//今回勝率（0.5が標準）
			double thisRate = 0;
			if(ThisGames > 0)
				thisRate = (double)ThisWins / (double)ThisGames;
			//運・ツキは今回勝率が累計平均よりも大きくなっているか否かによって判断される
			if(thisRate > totalRate)
				Luck++;
			else if(thisRate < totalRate)
				Luck--;
			//強気弱気は運・ツキと今回のゲーム数（実績）により判断する
			if(Luck > 0)
			{
				if(ThisGames > 5)		//最初の5回までは調整しない
					BullBear++;			//強気＋１
				if(ThisGames > 10)
					BullBear++;			//強気＋２
				if(ThisGames > 20)
					BullBear++;			//強気＋３
				//BullBearのMaxは10
				if(BullBear > 10)
					BullBear = 10;
			}
			else
			{
				if(ThisGames > 5)		//最初の5回までは調整しない
					BullBear--;			//強気－１
				if(ThisGames > 10)
					BullBear--;			//強気－２
				if(ThisGames > 20)
					BullBear--;			//強気－３
				//BullBearのMinは-10
				if(BullBear < -10)
					BullBear = -10;
			}
			//掛け金決定算式
			Random rnd = new Random();
			//最初の5回まで（序盤）
			if(ThisGames <= 5)
			{
				Max = Capital / 10;		//最大掛け金は種銭の1/10
				//ツキが無ければ2倍まで
				if(BullBear <= 0)
					sum = rnd.Next(MinBet, MinBet * 2);
				//ツいてくれば4倍まで
				else
					sum = rnd.Next(MinBet, MinBet * 4);
			}
			//6～10回まで（中盤）
			else if(ThisGames <= 10)
			{
				Max = Capital / 5;		//最大掛け金は種銭の1/5
				//ツキが無ければ2倍まで
				if(BullBear <= 0)
					sum = rnd.Next(MinBet, MinBet * 2);
				//まぁまぁなら2から4倍まで
				else if(BullBear < 2)
					sum = rnd.Next(MinBet * 2, MinBet * 4);
				//ツいてくれば4から10から4倍まで
				else if(BullBear >= 2)
					sum = rnd.Next(MinBet * 4, MinBet * 10);
			}
			//10回以降まで（後盤）
			else if(ThisGames > 10)
			{
				Max = Capital / 2;		//最大掛け金は種銭の1/2
				//ツキが無ければ最低掛け金
				if(BullBear < 0)
					sum = MinBet;
				//まぁまぁなら2から4倍まで
				else if(BullBear < 2)
					sum = rnd.Next(MinBet * 2, MinBet * 4);
				//ツいてくれば4から10から4倍まで
				else if(BullBear >= 2)
					sum = rnd.Next(MinBet * 4, MinBet * 10);
				//更にツけば30倍まで
				else if(BullBear >= 4)
					sum = rnd.Next(MinBet * 10, MinBet * 30);
			}
			//Maxによるチェック
			if(sum > Max)
				sum = Max;
			//sumを千円単位に四捨五入する
			sum = (int)Math.Round((double)sum / (double)1000,  MidpointRounding.AwayFromZero) * 1000;
			return sum;
		}

		//勝負結果によりPlayerの記録を更新する（引き分けの場合は引数不要）戻り値は「賭博継続可（Boolean）」
		public bool Update(int rewards = 0)
		{
			//今回の勝負数を1つ増やす
			ThisGames++;
			//勝負結果を勝ち数、負け数に反映
			if(rewards == 0)		//分け
				return !IsBankrupt;
			else if(rewards > 0)	//勝ち
				ThisWins++;
			else					//負け
				ThisLoses++;
			//「種銭」残高の増減
			Capital += rewards;
			//破産チェック
			return !(IsBankrupt = (Capital < MinBet));
		}

		//勝負終了後、最終成績を更新する
		public void FinalRecord()
		{
			//今回のデータを統計データに落とす
			TotalGames += ThisGames;
			TotalWins += ThisWins;
			TotalLoses += ThisLoses;
			//プレーヤーファイルを書き出す
			WriteData();
		}
	}
}
