public double simulate() //It simulates all the way to the end of the game, from currentNode { //Based on the result of the simulation(Win/lose), it return different sim value, used to judge whether its a good node or not MCTSState simState = new MCTSState(state.currentTurn, state.drawDeck, state.discardDeck, state.humanCards, state.AICards, state.hasDrawn, state.lastDiscard, state.lastDrawDeck); simState.stateResult = state.stateResult; int simValue = int.MinValue; while (simState.stateResult == MCTSState.Result.None && simState.drawDeck.Count > 0) { if (!simState.hasDrawn)//In Draw phase { simState.hasDrawn = true; if (simState.currentTurn == Main.Turn.AI) //AI's turn { if (simState.discardDeck.Count > 0) { if (simState.AICards.NumOfCardsOfType(simState.discardDeck.GetTop().MeldType) == 2) //if drawing from discard deck can form a meld { simState.AICards.Add(simState.discardDeck.Pop()); //Draw from discard deck } else { simState.AICards.Add(simState.drawDeck.Pop()); //Other wise just take from draw deck } } else //If no card in discard deck, draw from draw deck { simState.AICards.Add(simState.drawDeck.Pop()); } if (simState.drawDeck.Count <= 0) //After draw finish, if the draw deck is empty, mark the game result as draw { simState.stateResult = MCTSState.Result.Draw; break; } if (CardsInHand.CheckVictory(simState.AICards)) //If victory goal met, mark the game result as AIWIN { simState.stateResult = MCTSState.Result.AIWin; break; } } else if (simState.currentTurn == Main.Turn.Human) //Human's turn,everything same as above, basically duplicated code { if (simState.discardDeck.Count > 0) { if (simState.humanCards.NumOfCardsOfType(simState.discardDeck.GetTop().MeldType) == 2) //if drawing from discard deck can form a meld { simState.humanCards.Add(simState.discardDeck.Pop()); } else { simState.humanCards.Add(simState.drawDeck.Pop()); } } else { simState.humanCards.Add(simState.drawDeck.Pop()); } if (simState.drawDeck.Count <= 0) { simState.stateResult = MCTSState.Result.Draw; break; } if (CardsInHand.CheckVictory(simState.humanCards)) { simState.stateResult = MCTSState.Result.HumanWin; break; } } } else if (simState.hasDrawn)//In discard phase { simState.hasDrawn = false; if (simState.currentTurn == Main.Turn.AI) //AI's turn { MeldType typeToDiscard = MostUselessType(simState.AICards); //Get the least valuable meld type among the cards in hand Card cardToDiscard = simState.AICards.GetCardByMeldType(typeToDiscard); //get a card of that meld type, then discard it simState.AICards.Remove(cardToDiscard); simState.AICards.LeftShiftElement(); simState.discardDeck.Add(cardToDiscard); simState.discardDeck.LeftShiftElement(); simState.currentTurn = Main.Turn.Human; } else //duplicated code { MeldType typeToDiscard = MostUselessType(simState.humanCards); Card cardToDiscard = simState.humanCards.GetCardByMeldType(typeToDiscard); simState.humanCards.Remove(cardToDiscard); simState.humanCards.LeftShiftElement(); simState.discardDeck.Add(cardToDiscard); simState.discardDeck.LeftShiftElement(); simState.currentTurn = Main.Turn.AI; } } } switch (simState.stateResult) { case MCTSState.Result.Draw: { // Debug.Log("Draw result simed"); simValue = 0; break; } case MCTSState.Result.HumanWin: { // Debug.Log("HumanWin result simed"); simValue = -1; //1 means victory, -1 means defeat break; } case MCTSState.Result.AIWin: { //Debug.Log("AIWin result simed"); simValue = 1; break; } default: { // Debug.LogError("illegal simStateResult value"); break; } } return(simValue); }
public TreeNode(MCTSState state) { this.state = state; }