//KKKKKKKKKKKKKKKKKKKK public void AutoPut(int p, ref AgentCls AI1) //AIの評価に従って自動で一手配置する { int i1 = p; //配置候補のp番目に配置する//i1は以前の実装の名残 Put(ref putList[i1]); //着手 AI1.Put(ref putList[i1]); //AIの内部盤面も更新 SPutLog += AutoPutString(ref putList[i1]); //配置の履歴を残す(デバッグ) }
//KKKKKKKKKKKKKKKKKKKK //KKKKKKKKKKKKKKKKKKKK public void Save(ref AgentCls aug) //Aiのセーブ { string DebugString = $"Save Agent {aug.MyID}\r\n"; string Key, sJson; // int tmp; int Layer, i1, i2; //A for (Layer = 0; Layer < 5; Layer++) { for (i1 = 0; i1 < 64; i1++) { for (i2 = 0; i2 < 64; i2++) { // tmp = 64 * i1 + i2;//1次元配列までしか対応していないための処置 BufA.A[i2] = aug.A[Layer, i1, i2]; //配列を移し替える } Key = GetKeyString(aug.MyID, "A", Layer, i1); //キーを生成 // sJson = JsonUtility.ToJson(BufA);//AをJson形式に変換 // PlayerPrefs.SetString(Key, sJson);//Josn文字列として保存 DebugString += Key + "\r\n";//何を保存したのか(デバッグ) // Debug.Log("Save Key:"+Key+" : "+sJson); } } //B for (Layer = 0; Layer < 5; Layer++) { for (i1 = 0; i1 < 64; i1++) { BufB.B[i1] = aug.B[Layer, i1]; } Key = GetKeyString(aug.MyID, "B", Layer, 0);//キーを生成 // sJson = JsonUtility.ToJson(BufB);//BをJson形式に変換 // PlayerPrefs.SetString(Key, sJson);//Json文字列として保存 DebugString += Key + "\r\n";//何を保存したのか(デバッグ) // Debug.Log("Save Key:"+Key+" : "+sJson); } //C for (i1 = 0; i1 < 64; i1++) { BufC.C[i1] = aug.C[i1]; } Key = GetKeyString(aug.MyID, "C", 0, 0);//キーを生成 // sJson = JsonUtility.ToJson(BufC);//CをJson形式に変換 // PlayerPrefs.SetString(Key, sJson);//Json文字列として保存 DebugString += Key + "\r\n";//何を保存したのか(デバッグ) // Debug.Log("Save Key:"+Key+" : "+sJson); Debug.Log($"Saved AI {aug.MyID}\r\n{DebugString}"); }
//KKKKKKKKKKKKKKKKKKKK(Init) static void Init() //各インスタンスの初期化 { Debug.Log($"nAgent = {Agent.Length}"); AgentCls AItmp = new AgentCls(); // Pointer.InitPointer();//ポインタクラスは現時点で使われていない // DataSave = new SaveCls(); iGeneration = 0; //世代数初期化 iIteration = 0; //繰り返し計算数初期化 for (int i1 = 0; i1 < Agent.Length; i1++) //エージェント初期化 { Agent[i1] = new AgentCls(); Agent[i1].InitAgent(i1); //SetRandom含む } LoadAll(); //以前の実行時のデータを読み込む //Unity移行から時間がなく、まだデータ読み込み、保存機能が完成していない Boad.InitBoad(); //盤面初期化 }
//KKKKKKKKKKKKKKKKKKKK<<OPTIMIZATION>> //KKKKKKKKKKKKKKKKKKKK static double AutoGame(ref AgentCls AI1, ref AgentCls AI2, bool fD1, bool fD2) { //AIエージェントを引数として渡し、AI同士の対戦を行う //fD1, fD2は、変動ありのパラメータを使うかどうかの設定 double e1; double r; int Select; // Debug.Log("AutoGame Start");//デバッグ // Debug.Log( AutoGameDebug(AI1.MyID, AI2.MyID, fD1, fD2) ); //初期化 AI1.InitAgentBoad(); AI2.InitAgentBoad(); Boad.InitBoad(); //ゲームが終了するまでwhile内が続く while (Boad.nPutList > 0) //石を置くところがあるかぎり→探索、着手 { if (Boad.ActiveFirstPlayer) { (e1, Select) = Boad.CalcEBranch(ref AI1, ref fD1, 3, 0);//最大評価値を計算 } else { (e1, Select) = Boad.CalcEBranch(ref AI2, ref fD2, 3, 0); //最大評価値を計算 } Boad.AutoPut(Select, ref AI1, ref AI2); //最大評価値と一致するところに着手 if (Boad.PutCheck() == 0) { //石を置くところがない→パス(番交代)→置けるところを探す Boad.ChangeActivePlayer(); Boad.PutCheck(); } // Boad.ConsolPrint(); } r = Boad.CalcEAbsolute();//ゲーム終了時の絶対評価値を返す return(r); }
// KKKKKKKKKKKKKKKKKKKK public void Load(ref AgentCls aug) //AIのロード // double Error = 0; { string DebugString = $"Load AI {aug.MyID}\r\n"; // string DebugError = $"Load AI {aug.MyID}\r\n"; string Key, sJson; int Layer = 0, i1 = 0, i2 = 0; //A for (Layer = 0; Layer < 5; Layer++) { for (i1 = 0; i1 < 64; i1++) { Key = GetKeyString(aug.MyID, "A", Layer, i1);//キー取得 // sJson = JsonUtility.ToJson(BufA);//デフォルト値 // sJson= PlayerPrefs.GetString(Key, sJson);//Json形式のロード // Debug.Log("Load Key:"+Key+" : "+sJson); // BufA = JsonUtility.FromJson<SaveBufACls>(sJson);//Json形式の変換 //コピー for (i2 = 0; i2 < 64; i2++) { // Error += Math.Abs( aug.A[Layer,i1,i2] - BufA.A[i2] ); // if( aug.A[Layer,i1,i2] != BufA.A[i2] ){ // DebugError += $"A:{Layer}-{i1}[{i2}] : {aug.A[Layer,i1,i2] - BufA.A[i2]} = {aug.A[Layer,i1,i2]} - {BufA.A[i2]}\r\n"; // } aug.A[Layer, i1, i2] = BufA.A[i2]; //コピー } DebugString += Key + "\r\n"; //何をロードしたのか(デバッグ) } } //B for (Layer = 0; Layer < 5; Layer++) { Key = GetKeyString(aug.MyID, "B", Layer, 0);//キー取得 // sJson = JsonUtility.ToJson(BufB);//デフォルト値 // sJson = PlayerPrefs.GetString(Key, sJson);//Json形式のロード // Debug.Log("Load Key:"+Key+" : "+sJson); // BufB = JsonUtility.FromJson<SaveBufBCls>(sJson);//Json形式の変換 //コピー for (i1 = 0; i1 < 64; i1++) { // Error += Math.Abs( aug.B[Layer,i1] - BufB.B[i1] ); // if( aug.B[Layer,i1] != BufB.B[i1] ){ // DebugError += $"B:{Layer}-[{i1}] : {aug.B[Layer,i1] - BufB.B[i1]} = {aug.B[Layer,i1]} - {BufB.B[i1]}\r\n"; // } aug.B[Layer, i1] = BufB.B[i1]; //コピー } DebugString += Key + "\r\n"; //何をロードしたのか(デバッグ) } //C Key = GetKeyString(aug.MyID, "C", 0, 0);//キー取得 // sJson = JsonUtility.ToJson(BufC);//デフォルト値 // sJson = PlayerPrefs.GetString(Key, sJson);//Json形式のロード // Debug.Log("Load Key:"+Key+" : "+sJson); // BufC = JsonUtility.FromJson<SaveBufCCls>(sJson);//Json形式の変換 //コピー for (i1 = 0; i1 < 64; i1++) { // Error += Math.Abs( aug.C[i1] - BufC.C[i1] ); // if( aug.C[i1] != BufC.C[i1] ){ // DebugError += $"C:-[{i1}] : {aug.C[i1] - BufC.C[i1]} = {aug.C[i1]} - {BufC.C[i1]}\r\n"; // } aug.C[i1] = BufC.C[i1]; //コピー } DebugString += Key + "\r\n"; //何をロードしたのか(デバッグ) Debug.Log($"Loaded AI {aug.MyID}\r\n{DebugString}"); // Debug.Log($"Loaded AI {aug.MyID} Error = {Error}\r\n{DebugError}"); }
//KKKKKKKKKKKKKKKKKKKK public (double e, int p) CalcEBranch(ref AgentCls AI, ref bool fD, int nDeep, int p) //分岐先まで見て最善手と評価を返すはずだった //深度探索は未実装ー>ビットボードの方で実装 //分岐先の盤面を評価し、分岐先の最良値をputListに格納する //nDeep:残り分岐深度、p:putListの開始ポインタ(今の所0で固定) //putListはグローバル変数で共有している(変えようと思う) //だから、どこからが調べるべき分岐なのかpで指示している // string s; // p = 0; { int Color = putList[p].Color; //手番の色 int pEnd = putList[p].nPutList; //配置候補の数 for (int i1 = 0; i1 < pEnd; i1++) //候補すべての評価値を調べる { Put(ref putList[i1]); //着手=>評価=>保存=>もとに戻す、を繰り返す // AI.Put(ref putList[i1]);//AI内部盤面も着手 AI.SetBoad(ref Stone); //(効率化ではなく安定を優先) putList[i1].e = AI.E(fD); //評価値を調べる//=CalcEBranch PutInverse(); //着手を戻す // AI.PutInverse(ref putList[i1]);//着手を戻す } AI.SetBoad(ref Stone);//AI内部盤面をもとに戻す(?いらない) //最良値調査 p = CalcEBranchMinMax(p, pEnd, putList[p].Color); e = putList[p].e;//最良の評価値を返す //再帰の終端の処理:盤面評価値を返す // if( nDeep <= 1){ // e = AI.E( fD );//評価値 // i = p;//ポインタ // }else{ //分岐先の最良値を求める //分岐の候補は計算済み // for(int i1=p; i1<putList[p].nPutList; i1++){//分岐先ポインタから計算開始 // Put(ref putList[i1]); //着手する // AI.Put(ref putList[i1]); //AIの内部盤面も合わせて更新 // //nPutList番目以降に分岐が計算される:追加される // if( PutCheck( putList[p].nPutList ) <= 0){ // //置ける場所がない:パスの場合 // ChangeActivePlayer(); // if( PutCheck( putList[p].nPutList ) <=0 ){ // //置ける場所がない:ゲーム終了時 // s = "Banch-"+nDeep+":"+i1+"\n\r"; // // ConsolPrint(s); // putList[i1].e = CalcEAbsolute();//終局盤面絶対評価値 // }else{//おける時:相手がパスで手番が続く時 // s = "Banch-"+nDeep+":"+i1+"\n\r"; // // ConsolPrint(s); // (putList[i1].e, ) = CalcEBranch(ref AI, ref fD, nDeep-2, putList[p].nPutList); //再帰 // } // }else{ // //置ける場所がある:手番交代 // s = "Banch-"+nDeep+":"+i1+"\n\r"; // // ConsolPrint(s); // (putList[i1].e, ) = CalcEBranch(ref AI, ref fD, nDeep-1, putList[p].nPutList); //再帰 // } // AI.PutInverse(ref putList[i1]);//AIの内部盤面を戻す // PutInverse();//盤面を戻す // s = "Banch-"+(nDeep+1)+":"+p+"\n\r"; // // ConsolPrint(s); // }//for i1 //最良値選択 // eMinMax = putList[p].e; // for(int i1 = p+1; i1<putList[p].nPutList; i1++){ // if(Color == Black){ //黒手番の時:最大値 // eMinMax = Math.Max( eMinMax, putList[i1].e ); // }else{ //白手番の時 :最小値 // eMinMax = Math.Min( eMinMax, putList[i1].e ); // } // } // e = eMinMax; // i = 0; // } return(e, p); }