/// <summary> /// 根据当前局面拓展一个未拓展节点 /// </summary> /// <param name="ThisChessBoard">当前局面棋盘</param> /// <param name="FatherNode">父节点</param> public void Expand(ChessBoard ThisChessBoard, MonteCartoTreeNode FatherNode) { if (SonNode.Count == 0)//未拓展节点 { EnumNowPlayer PlayerSave = NowQuoridor.ReversePlayer(FatherNode.NodePlayer); NowQuoridor.Player_Now = PlayerSave; List <QuoridorAction> QABuff = NowQuoridor.ActionList; // QABuff = NowQuoridor.CreateActionList(ThisChessBoard, EnumNowPlayer.Player2); //QABuff = NowQuoridor.CreateActionList_ALL(ThisChessBoard); /*完全拓展*/ foreach (QuoridorAction QA in QABuff) { MonteCartoTreeNode MTSonNode = new MonteCartoTreeNode(); MTSonNode.NodePlayer = PlayerSave; MTSonNode.NodeAction = QA.PlayerAction; MTSonNode.ActionLocation.X = QA.ActionPoint.X; MTSonNode.ActionLocation.Y = QA.ActionPoint.Y; MTSonNode._P = QA.WholeScore; MTSonNode.FatherNode = FatherNode; SonNode.Add(MTSonNode); //if (QA.PlayerAction == NowAction.Action_PlaceHorizontalBoard || QA.PlayerAction == NowAction.Action_PlaceVerticalBoard) //{ // if (QA.OpponentScore - QA.SelfScore >= 5) // { // MTSonNode.IfWin = true; // SonNode = new List<MonteCartoTreeNode>(); // SonNode.Add(MTSonNode); // break; // } //} } } }
/// <summary> /// 计算一个子节点的UCT值,用于Select /// </summary> /// <param name="FatherNode">父节点</param> /// <param name="SonNode">子节点</param> /// <returns>SonNode的UCT值</returns> public static double CalUCTValue_UCT(MonteCartoTreeNode FatherNode, MonteCartoTreeNode SonNode) { double UCTBuff = 0; double ExploitationComponent = 0, ExplorationComponent = 0; /*普通的UCT*/ //ExploitationComponent = SonNode._Q / SonNode._N; //ExplorationComponent = _C * Math.Sqrt((Math.Log10(FatherNode._N) / SonNode._N)); //UCTBuff = ExploitationComponent + ExplorationComponent; /*与P值有关的UCT*/ UCTBuff = _C * SonNode._P * Math.Sqrt(FatherNode._N / (1 + SonNode._N)); return(UCTBuff); }
/// <summary> /// Select操作 /// </summary> /// <param name="FatherNode">父节点</param> /// <returns>选择要去拓展的子节点</returns> public static MonteCartoTreeNode Select(MonteCartoTreeNode FatherNode) { MonteCartoTreeNode MTNode = new MonteCartoTreeNode(); double MaxQUCT = -100; foreach (MonteCartoTreeNode NodeBuff in FatherNode.SonNode) { NodeBuff._UCT = CalUCTValue_UCT(FatherNode, NodeBuff); if (MaxQUCT < NodeBuff._UCT + NodeBuff._Q)//选择最大UCT + Q值的节点 { MaxQUCT = NodeBuff._UCT + NodeBuff._Q; MTNode = NodeBuff; } } return(MTNode); }
/// <summary> /// 进行一次模拟(Simluation) /// </summary> /// <param name="InitChessBoard">当前决策节点局面</param> /// <param name="RootNode">根节点</param> public static void SimluationOnce(ChessBoard InitChessBoard, MonteCartoTreeNode RootNode) { #region 暂存挡板数量 int Board1Save = InitChessBoard.NumPlayer1Board; int Board2Save = InitChessBoard.NumPlayer2Board; #endregion if (RootNode.SonNode.Count == 0) //初始根节点 { RootNode.Expand(InitChessBoard, RootNode); //先拓展一次 } ChessBoard SimluationChessBoard = new ChessBoard(); ChessBoard.SaveChessBoard(ref SimluationChessBoard, InitChessBoard);//相当于拷贝了 MonteCartoTreeNode NextExpandNode = RootNode; while (true) { #region 提前终止局面检测 if (NextExpandNode.SonNode.Count == 1) { if (NextExpandNode.SonNode[0].IfWin) { double leaf_value = -1; if (JudgePlayer != NextExpandNode.SonNode[0].NodePlayer) { leaf_value = 1; } NextExpandNode.BackPropagation(leaf_value); break; } } #endregion /*选择*/ NextExpandNode = Select(NextExpandNode); #region 模拟落子 string Hint = NowQuoridor.QuoridorRule.Action(ref SimluationChessBoard , NextExpandNode.ActionLocation.X, NextExpandNode.ActionLocation.Y, NextExpandNode.NodeAction); try { if (Hint != "OK") { Exception e = new Exception(); } } catch (Exception) { throw; } if (NextExpandNode.NodePlayer == EnumNowPlayer.Player1) { if (NextExpandNode.NodeAction == NowAction.Action_PlaceVerticalBoard || NextExpandNode.NodeAction == NowAction.Action_PlaceHorizontalBoard) { SimluationChessBoard.NumPlayer1Board -= 2; } } else if (NextExpandNode.NodePlayer == EnumNowPlayer.Player2) { if (NextExpandNode.NodeAction == NowAction.Action_PlaceVerticalBoard || NextExpandNode.NodeAction == NowAction.Action_PlaceHorizontalBoard) { SimluationChessBoard.NumPlayer2Board -= 2; } } #endregion //SimluationChessBoard.DrawNowChessBoard(ref Form1.Gr, Form1.form1.ChessWhitePB, Form1.form1.ChessBlackPB); //Form1.form1.ChessBoardPB.Refresh(); //System.Threading.Thread.Sleep(500); string SucessHint = RuleEngine.CheckResult(SimluationChessBoard); if (SucessHint != "No success")//搜索到胜利节点了 { double leaf_value = -1; if (JudgePlayer == EnumNowPlayer.Player1 && SucessHint == "Player1 Success!") { leaf_value = 1; } if (JudgePlayer == EnumNowPlayer.Player2 && SucessHint == "Player2 Success!") { leaf_value = 1; } NextExpandNode.BackPropagation(leaf_value); break; } double dis_player1 = RuleEngine.AstarEngine.AstarRestart(SimluationChessBoard, EnumNowPlayer.Player1 , SimluationChessBoard.Player1Location.X, SimluationChessBoard.Player1Location.Y); double dis_player2 = RuleEngine.AstarEngine.AstarRestart(SimluationChessBoard, EnumNowPlayer.Player2 , SimluationChessBoard.Player2Location.X, SimluationChessBoard.Player2Location.Y); EnumNowPlayer Winner = EnumNowPlayer.Player1; # region 必赢必输局面检测 //if (dis_player1 >= 14 || dis_player2 >= 14)//某人步数过大 //{ // if (dis_player2 - dis_player1 >= 5) // { // Winner = EnumNowPlayer.Player2; // } //} //else if (SimluationChessBoard.NumPlayer2Board == 0 && SimluationChessBoard.NumPlayer1Board == 0)//挡板已用完 //{ // #region 是否存在跳棋检测(未写) // #endregion // if (dis_player2 - dis_player1 > 0) // { // Winner = EnumNowPlayer.Player2; // } //} //double leaf_value2 = -1; //if (JudgePlayer == EnumNowPlayer.Player1 && Winner == EnumNowPlayer.Player1)//下一步是P2走 //{ // leaf_value2 = 1; //} //if (JudgePlayer == EnumNowPlayer.Player2 && Winner == EnumNowPlayer.Player2)//下一步是P1走 //{ // leaf_value2 = 1; //} //NextExpandNode.BackPropagation(leaf_value2); #endregion /*拓展*/ NextExpandNode.Expand(SimluationChessBoard, NextExpandNode); }