//打ち歩詰めの判定関数 public bool IsUtifuDume(Te te) { //歩(1,17)で打たれた時(段が0)に相手に合法手がなければ打ち歩詰め if (te.koma == 1 || te.koma == 17) { if (te.from == 0) { this.Move(te.DeepCopy()); this.turn += 1; if (this.GenerateLegalMoves().Count == 0) { return(true); } this.Back(te.DeepCopy()); this.turn -= 1; } } return(false); }
/* * //手番を進める関数 * void ChangeTurn(Te te){ * * if (kk.turn % 2 == 1) { * turn.GetComponent<Text> ().text = "後手"; * } else { * turn.GetComponent<Text> ().text = "先手"; * } * * * kk.turn = kk.turn + 1; * kihu.Add (te.DeepCopy()); * * if (te.capture != 0 && te.capture != 1 && te.capture != 17) { * phase = true; * } * * if (kk.turn > 10 && phase) { * sikou.DEPTH_MAX = 3; * } * * * * for (int j = 0; j < historykyokumenn.Count; j++) { * if (kk.equals (historykyokumenn [j])) { * kk.sameKyokumenn += 1; * } * * } * * if (kk.sameKyokumenn > 3) { * vsCom = false; * vsComGote = false; * winner.GetComponent<Text>().text = "千日手により引き分けです"; * resultCanvas.GetComponent<Canvas>().enabled = true; * * for (int i = 1;i <= 81 ; i++){ * * Masu [i - 1].GetComponent<Button> ().interactable = false; * Masu [i - 1].GetComponent<Image> ().color = new Color (255f / 255f, 255f / 255f, 255f / 255f, 255f / 255f); * * } * } * kk.sameKyokumenn = 0; * * * historykyokumenn.Add (kk.DeepCopyKyokumenn()); * * * if (kihu.Count > 1) { * Masu [kihu [kk.turn - 3].to - 1].GetComponent<Image> ().color = new Color (255f / 255f, 255f / 255f, 255f / 255f, 255f / 255f); * } * Masu [te.to - 1].GetComponent<Image> ().color = new Color (255f / 255f, 180f / 255f, 0f / 255f, 255f / 255f); * * * //合法手が無くなったら * if (kk.GenerateLegalMoves ().Count == 0) { * * vsCom = false; * vsComGote = false; * print (kk.turn); * * if (kk.turn % 2 == 1) { * winner.GetComponent<Text>().text = "後手の勝利です"; * } else { * winner.GetComponent<Text>().text = "先手の勝利です"; * } * //勝敗がついたらボタンをオフに * for (int i = 1;i <= 81 ; i++){ * * Masu [i - 1].GetComponent<Button> ().interactable = false; * Masu [i - 1].GetComponent<Image> ().color = new Color (255f / 255f, 255f / 255f, 255f / 255f, 255f / 255f); * * } * * resultCanvas.GetComponent<Canvas>().enabled = true; * * } * } * * * */ //手番を進める関数 IEnumerator Changeturn(Te te) { if (kk.turn % 2 == 1) { turn.GetComponent <Text> ().text = "後手"; } else { turn.GetComponent <Text> ().text = "先手"; } yield return(new WaitForEndOfFrame()); kk.turn = kk.turn + 1; kihu.Add(te.DeepCopy()); for (int j = 0; j < historykyokumenn.Count; j++) { if (kk.equals(historykyokumenn [j])) { kk.sameKyokumenn += 1; } } if (kk.sameKyokumenn > 3) { vsCom = false; vsComGote = false; winner.GetComponent <Text>().text = "千日手により引き分けです"; resultCanvas.GetComponent <Canvas>().enabled = true; for (int i = 1; i <= 81; i++) { Masu [i - 1].GetComponent <Button> ().interactable = false; Masu [i - 1].GetComponent <Image> ().color = new Color(255f / 255f, 255f / 255f, 255f / 255f, 255f / 255f); } } kk.sameKyokumenn = 0; historykyokumenn.Add(kk.DeepCopyKyokumenn()); if (kihu.Count > 1) { Masu [kihu [kk.turn - 3].to - 1].GetComponent <Image> ().color = new Color(255f / 255f, 255f / 255f, 255f / 255f, 255f / 255f); } Masu [te.to - 1].GetComponent <Image> ().color = new Color(255f / 255f, 180f / 255f, 0f / 255f, 255f / 255f); //合法手が無くなったら if (kk.GenerateLegalMoves().Count == 0) { vsCom = false; vsComGote = false; print(kk.turn); if (kk.turn % 2 == 1) { winner.GetComponent <Text>().text = "後手の勝利です"; } else { winner.GetComponent <Text>().text = "先手の勝利です"; } //勝敗がついたらボタンをオフに for (int i = 1; i <= 81; i++) { Masu [i - 1].GetComponent <Button> ().interactable = false; Masu [i - 1].GetComponent <Image> ().color = new Color(255f / 255f, 255f / 255f, 255f / 255f, 255f / 255f); } resultCanvas.GetComponent <Canvas>().enabled = true; } }
public List <Te> GenerateLegalMoves() { //合法手を格納する変数 List <Te> teList = new List <Te>(); List <Te> removed = new List <Te>(); Te te = new Te(); for (int masu = 1; masu <= 81; masu++) { int koma = this.banKoma [masu]; //探索する駒が手番の駒かどうか if ((this.turn % 2 == 1 && koma >= 1 && koma <= 16) || (this.turn % 2 == 0 && koma >= 17)) { //各方向に移動する手を生成 for (int direct = 0; direct < 12; direct++) { if (KomaMoves.canMove [direct, koma]) { te.koma = koma; te.to = masu + KomaMoves.diff [direct]; te.from = masu; if ((masu % 9 == 0 && te.to % 9 == 1) || (masu % 9 == 1 && te.to % 9 == 0)) { continue; } //移動先は盤内か if (1 <= te.to && te.to <= 81) { //移動先に自分の駒はないか int toKoma = this.banKoma[te.to]; te.capture = this.banKoma [te.to]; if ((this.turn % 2 == 1 && (toKoma == 0 || toKoma >= 17)) || (this.turn % 2 == 0 && toKoma <= 16)) { //桂馬は敵二段目まで、歩は一段目までで成らずはできない if ((te.koma != 3 || te.to > 18) && (te.koma != 19 || te.to < 64) && (te.koma != 1 || te.to >= 10) && (te.koma != 17 || te.to <= 72)) { te.promote = false; teList.Add(te.DeepCopy()); } //移動先が敵陣 if ((te.to <= 27 && this.turn % 2 == 1) || (te.to >= 55 && this.turn % 2 == 0)) { //成れる駒 if (KomaMoves.canPromote[koma]) { te.promote = true; teList.Add(te.DeepCopy()); } } //移動元が敵陣 if ((te.from <= 27 && this.turn % 2 == 1) || (te.from >= 55 && this.turn % 2 == 0)) { //成れる駒 if (KomaMoves.canPromote[koma]) { te.promote = true; teList.Add(te.DeepCopy()); } } } } } } //各方向に「飛ぶ」手を生成 for (int direct = 0; direct < 8; direct++) { if (KomaMoves.canJump [direct, koma]) { te.from = masu; te.koma = koma; for (int i = 1; i < 9; i++) { //移動先を生成 te.to = masu + KomaMoves.diff[direct] * i; if (((te.to % 9 == 0) && (((te.to - KomaMoves.diff[direct]) % 9) == 1)) || ((te.to % 9 == 1) && ((te.to - KomaMoves.diff[direct]) % 9 == 0))) { break; } //移動先は盤内か if (1 <= te.to && te.to <= 81) { //移動先に自分の駒はないか int toKoma = this.banKoma[te.to]; te.capture = this.banKoma [te.to]; if ((this.turn % 2 == 1 && (toKoma == 0 || toKoma >= 17)) || (this.turn % 2 == 0 && toKoma <= 16)) { //香車は敵の一段目まで行って成らずは不可 if ((te.koma != 2 || te.to > 9) && (te.koma != 18 || te.to < 73)) { te.promote = false; teList.Add(te.DeepCopy()); } //移動先が敵陣 if ((te.to <= 27 && this.turn % 2 == 1) || (te.to >= 55 && this.turn % 2 == 0)) { //成れる駒 if (KomaMoves.canPromote[koma]) { te.promote = true; teList.Add(te.DeepCopy()); } } //移動元が敵陣 if ((te.from <= 27 && this.turn % 2 == 1) || (te.from >= 55 && this.turn % 2 == 0)) { //成れる駒 if (KomaMoves.canPromote[koma]) { te.promote = true; teList.Add(te.DeepCopy()); } } } //空きマスでなければここでループ終わり if (toKoma != 0) { break; } } } } } } } //持ち駒からだす手を追加(銀、金、角、飛車) if (this.turn % 2 == 1) //先手の場合 //銀~飛車までループ { for (int i = 4; i <= 7; i++) { //探索中の駒を持っているか if (this.hand [1] [i] >= 1) { te.koma = i; for (int masu = 1; masu <= 81; masu++) { //駒は(0,0)点からとおく te.to = masu; te.from = 0; te.promote = false; te.capture = this.banKoma [te.to]; if (this.banKoma [masu] == 0) { teList.Add(te.DeepCopy()); } } } } } else //後手の場合 //銀~飛車までループ { for (int i = 20; i <= 23; i++) { //探索中の駒を持っているか if (this.hand [0] [i] >= 1) { te.koma = i; for (int masu = 1; masu <= 81; masu++) { //駒は(0,0)点からとおく te.to = masu; te.from = 0; te.promote = false; te.capture = this.banKoma [te.to]; if (this.banKoma [masu] == 0) { teList.Add(te.DeepCopy()); } } } } } if (this.turn % 2 == 1) //先手の場合 //先手の持ち駒に歩がある { if (this.hand [1] [1] >= 1) { te.koma = 1; //二歩チェック for (int suji = 1; suji <= 9; suji++) { bool isNifu = false; //二歩チェック用変数 for (int dan = 1; dan <= 9; dan++) { if (this.banKoma [(dan - 1) * 9 + suji] == 1) { isNifu = true; } } if (isNifu) { continue; } //これ以上進めない1段目を除き、駒がなければ歩を出す手を追加する for (int dan = 2; dan <= 9; dan++) { //駒は(0,0)点からとおく te.to = (dan - 1) * 9 + suji; te.from = 0; te.promote = false; te.capture = this.banKoma [te.to]; if (this.banKoma [(dan - 1) * 9 + suji] == 0) { teList.Add(te.DeepCopy()); } } } } //先手の持ち駒に香車がある if (this.hand [1] [2] >= 1) { te.koma = 2; for (int masu = 10; masu <= 81; masu++) { //これ以上進めない1段目を除き、駒がなければ香車を出す手を追加する //駒は(0,0)点からとおく te.to = masu; te.from = 0; te.promote = false; te.capture = this.banKoma [te.to]; if (this.banKoma [masu] == 0) { teList.Add(te.DeepCopy()); } } } //先手の持ち駒に桂馬がある if (this.hand [1] [3] >= 1) { te.koma = 3; for (int masu = 19; masu <= 81; masu++) { //これ以上進めない1,2段目を除き、駒がなければ桂馬を出す手を追加する //駒は(0,0)点からとおく te.to = masu; te.from = 0; te.promote = false; te.capture = this.banKoma [te.to]; if (this.banKoma [masu] == 0) { teList.Add(te.DeepCopy()); } } } } else //後手の場合 //持ち駒に歩がある { if (this.hand [0] [17] >= 1) { te.koma = 17; //二歩チェック for (int suji = 1; suji <= 9; suji++) { bool isNifu = false; //二歩チェック用変数 for (int dan = 1; dan <= 9; dan++) { if (this.banKoma [(dan - 1) * 9 + suji] == 17) { isNifu = true; } } if (isNifu) { continue; } //これ以上進めない1段目を除き、駒がなければ歩を出す手を追加する for (int dan = 1; dan <= 8; dan++) { //駒は(0,0)点からとおく te.to = (dan - 1) * 9 + suji; te.from = 0; te.promote = false; te.capture = this.banKoma [te.to]; if (this.banKoma [(dan - 1) * 9 + suji] == 0) { teList.Add(te.DeepCopy()); } } } } //持ち駒に香車がある if (this.hand [0] [18] >= 1) { te.koma = 18; for (int masu = 1; masu <= 72; masu++) { //これ以上進めない1段目を除き、駒がなければ香車を出す手を追加する //駒は(0,0)点からとおく te.to = masu; te.from = 0; te.promote = false; te.capture = this.banKoma [te.to]; if (this.banKoma [masu] == 0) { teList.Add(te.DeepCopy()); } } } //持ち駒に桂馬がある if (this.hand [0] [19] >= 1) { te.koma = 19; for (int masu = 1; masu <= 63; masu++) { //これ以上進めない1段目を除き、駒がなければ桂馬を出す手を追加する //駒は(0,0)点からとおく te.to = masu; te.from = 0; te.promote = false; te.capture = this.banKoma [te.to]; if (this.banKoma [masu] == 0) { teList.Add(te.DeepCopy()); } } } } //王手を放置している手を抜く int gyoku = 0; for (int i = 0; i < teList.Count; i++) { bool isOuteHouchi = false; Te teTest = teList [i]; this.Move(teTest); if (this.turn % 2 == 1) { gyoku = gyokuSente; } else { gyoku = gyokuGote; } // 玉の周辺(12方向)から相手の駒が利いていたら、その手は取り除く for (int direct = 0; direct < 12 && !isOuteHouchi; direct++) { //方向の反対側にある駒の取得 int masuSerch = gyoku - KomaMoves.diff[direct]; if (((masuSerch % 9 == 0) && (((masuSerch + KomaMoves.diff[direct]) % 9) == 1)) || ((masuSerch % 9 == 1) && ((masuSerch + KomaMoves.diff[direct]) % 9 == 0))) { continue; } if (1 <= masuSerch && masuSerch <= 81) { int koma = this.banKoma [masuSerch]; //その駒が敵の駒で手番の玉を取れるか if (this.turn % 2 == 1 && 17 <= koma || this.turn % 2 == 0 && koma <= 16 && 1 <= koma) { //動けるなら、この手は王手を放置しているので追加しない if (KomaMoves.canMove [direct, koma]) { isOuteHouchi = true; break; } } } } // 玉の周り(8方向)から相手の駒の飛び利きがあるなら、その手は取り除く for (int direct = 0; direct < 8 && !isOuteHouchi; direct++) { // 方向の反対方向にある駒を取得 int masuSerch = gyoku - KomaMoves.diff[direct]; // その方向にマスがある限り、駒を探す while (1 <= masuSerch && masuSerch <= 81) { if (((masuSerch % 9 == 0) && (((masuSerch + KomaMoves.diff[direct]) % 9) == 1)) || (((masuSerch % 9 == 1) && ((masuSerch + KomaMoves.diff[direct]) % 9) == 0))) { break; } int koma = this.banKoma [masuSerch]; // 味方駒で利きが遮られているなら、チェック終わり if (this.turn % 2 == 1 && koma <= 16 && 1 <= koma || this.turn % 2 == 0 && 17 <= koma) { break; } // 遮られていない相手の駒の利きがあるなら、王手がかかっている。 if (this.turn % 2 == 1 && 17 <= koma || this.turn % 2 == 0 && koma <= 16 && 1 <= koma) { //動けるなら、この手は王手を放置しているので追加しない if (KomaMoves.canJump [direct, koma]) { isOuteHouchi = true; break; } else { // 敵駒で利きが遮られているから、チェック終わり break; } } //玉から一つ離してループ masuSerch -= KomaMoves.diff[direct]; } } this.Back(teTest); if (!isOuteHouchi) { removed.Add(teList [i]); } } return(removed); }
// 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); }