//局面が同一かどうか public bool equals(Kyokumenn k) { //手番の比較 if (this.turn % 2 != k.turn % 2) { return(false); } //盤面の比較 for (int i = 1; i <= 81; i++) { if (this.banKoma[i] != k.banKoma[i]) { return(false); } } //持ち駒の比較 for (int koma = 0; koma < 32; koma++) { if (this.hand [0] [koma] != k.hand [0] [koma] || this.hand [1] [koma] != k.hand [1] [koma]) { return(false); } } return(true); }
public Te getNextTe(Kyokumenn k, int tesu) { Te te; if ((te = joseki.fromjoseki(k, tesu)) != null) { return(te); } leaf = 0; node = 0; List <Te> teList = k.GenerateLegalMoves(); te = teList[Random.Range(0, teList.Count)]; if (k.turn % 2 == 1) { //評価値最大の手をえる this.NegaMax(ref te, k, -1000000, 1000000, 0, DEPTH_MAX); } else { //評価値最小の手をえる this.NegaMax(ref te, k, -100000, 1000000, 0, DEPTH_MAX); } return(te); }
public Te fromjoseki(Kyokumenn k, int tesu) { //tesuには実際の手数が渡されるが、定跡データは0手目から始まるので1ずらしておく tesu = tesu - 1; //定跡にあった候補手を入れる List <Te> teList = new List <Te>(); //定跡で進めた局面を作り、渡された局面と比較する Kyokumenn josekiKyokumenn = new Kyokumenn(); for (int i = 0; i < numJoseki; i++) { //平手で初期化 josekiKyokumenn.BanShokika(); for (int j = 0; j < tesu; j++) { if (josekiData [i][j * 2] == (byte)0 || josekiData [i][j * 2] == (byte)0xff) { break; } Te te = josekiByteToTe(josekiData [i][j * 2], josekiData [i][j * 2 + 1], josekiKyokumenn); josekiKyokumenn.Move(te); josekiKyokumenn.turn += 1; } //局面が一致するか if (josekiKyokumenn.equals(k)) { if (josekiData [i][tesu * 2] == (byte)0 || josekiData [i][tesu * 2] == (byte)0xff) { continue; } //候補手を生成 Te te = josekiByteToTe(josekiData[i][tesu * 2], josekiData[i][tesu * 2 + 1], k); teList.Add(te); } } if (teList.Count == 0) { //候補手がない場合 /* * if(child != null){ * //子定跡がある時は、その結果を返す * return child.fromjoseki(k,tesu); * } */ //候補手がなかったのでnullを返す return(null); } else { //候補手の中からランダム //候補手がない場合 return(teList[UnityEngine.Random.Range(0, teList.Count)]); } }
public Te josekiByteToTe(byte toByte, byte fromByte, Kyokumenn k) { int f = ((int)fromByte) & 0xff; int t = ((int)toByte) & 0xff; int koma = 0; int fs, fd, ts, td; bool promote = false; if (f > 100) { //fが100以上なら、持ち駒を打つ手 if (k.turn % 2 == 1) { koma = (f - 100); } else { koma = (f - 100) + 16; } fs = 0; fd = 1; } else { //fをこのプログラムの中で使う座標の方式へ変換 fs = 10 - ((f - 1) % 9 + 1); //筋 fd = (f + 8) / 9; //段 koma = k.banKoma [(fd - 1) * 9 + fs]; } //tが100以上なら成り手 if (t > 100) { promote = true; t -= 100; } ts = 10 - ((t - 1) % 9 + 1); //筋 td = (t + 8) / 9; //段 Te te = new Te(); te.koma = koma; te.from = (fd - 1) * 9 + fs; te.to = (td - 1) * 9 + ts; te.promote = promote; te.capture = k.banKoma [te.to]; return(te); }
//ゲームを初めから public void Restart() { popupCanvas.GetComponent <Canvas>().enabled = false; resultCanvas.GetComponent <Canvas>().enabled = false; sente.GetComponent <Text> ().text = "P"; gote.GetComponent <Text> ().text = "P"; turn.GetComponent <Text>().text = "先手"; vsCom = false; vsComGote = false; kk = new Kyokumenn(); kk.josekiBool = true; kihu = new List <Te> (); historykyokumenn = new List <Kyokumenn> (); this.isSelectKoma = 0; //スタート時は駒を選択していない sikou.DEPTH_MAX = 4; if (kihu.Count != 0) { kihu.Clear(); } kk.turn = 1; kk.BanShokika(); //初期盤面を入れる for (int masu = 0; masu <= 81; masu++) { kk.banKoma[masu] = Kyokumenn.SHOKI_BAN[masu]; } //ボタンを有効にし、駒を正しく for (int i = 1; i <= 81; i++) { Masu [i - 1].GetComponent <Button> ().interactable = true; Masu [i - 1].GetComponent <Image>().sprite = komaPicture[kk.banKoma[i]]; } for (int koma = 1; koma < 8; koma++) { hand[koma].GetComponent <Text>().text = kk.hand [1] [koma].ToString(); hand[koma + 8].GetComponent <Text>().text = kk.hand [0] [koma + 16].ToString(); } }
public Kyokumenn DeepCopyKyokumenn() //ディープコピー { Kyokumenn obj = new Kyokumenn(); //参照型は全てインスタンスをコピーする obj.turn = (int)this.turn; for (int i = 0; i < 32; i++) { obj.hand [0][i] = this.hand [0] [i]; obj.hand [1] [i] = (int)this.hand [1] [i]; } for (int i = 0; i < 82; i++) { obj.banKoma [i] = (int)this.banKoma[i]; } return(obj); }
// float countTime; /* * public void Update () { * countTime += Time.deltaTime; * Debug.Log ("(●・▽・●)"); * } */ private int NegaMax(ref Te t, Kyokumenn k, int alpha, int beta, int depth, int depthMax) { int value = new int(); //深さが最大に達していたら評価値を返して終了 if (depth >= depthMax) { leaf++; value = k.evaluate(); //先手ならプラス、後手でマイナスの値を返す if (k.turn % 2 == 1) { return(value); } else { return(-value); } } node++; //現在の局面での合法手を生成 var teList = new List <Te>(); teList = k.GenerateLegalMoves(); value = -100000000; for (int i = 0; i < teList.Count; i++) { Te te = teList [i]; //その手で一手進めた局面を作る // KyokumennArray nextKyokumenn = k.DeepCopyKyokumenn (); k.Move(te.DeepCopy()); k.turn += 1; Te tempTe = new Te(); int eval = -NegaMax(ref tempTe, k, -beta, -alpha, depth + 1, depthMax); k.Back(te.DeepCopy()); k.turn -= 1; //大きかったら if (eval > value) { value = eval; //αの値も更新 if (eval > alpha) { alpha = eval; } //最善手を更新 best [depth, depth] = te; t.koma = te.koma; t.from = te.from; t.to = te.to; t.promote = te.promote; t.capture = k.banKoma [te.to]; for (int j = depth + 1; j < depthMax; j++) { best [depth, j] = best [depth + 1, j]; } //βカットの条件を満たしていたらループ終了 if (eval >= beta) { break; } } } return(value); }