/// <summary> /// Performs the tree search. /// </summary> /// <param name="rootState"></param> /// <param name="maxIterations"></param> /// <param name="randomizeState"></param> /// <returns></returns> internal static TreeNode Search(PlayingState rootState, int maxIterations = int.MaxValue, bool randomizeState = true) { var rootNode = new TreeNode(); HandRandomizer randomizer = null; if ((randomizeState) && (rootState.NeedRandomize())) { randomizer = new HandRandomizer(rootState); } for (var i = 0; i < maxIterations; i++) { var node = rootNode; // 1. Determinize. var state = rootState.CloneAndRandomize(randomizer); // 2. Select. var validMoves = state.GetValidMoves(); while ((validMoves != 0) && (node.GetUntriedMoves(validMoves) == 0)) // The node is fully expanded and non-terminal. { node = node.UcbSelectChild(validMoves); state.DoMove(node.Move); validMoves = state.GetValidMoves(); } // 3. Expand. var untriedMoves = node.GetUntriedMoves(validMoves); if (untriedMoves != 0) { var randomMove = GetRandomMove(untriedMoves, state); var activeIndex = state.ActiveIndex; state.DoMove(randomMove); node = node.AddChild(randomMove, activeIndex); } // 4. Simulate. validMoves = state.GetValidMoves(); while (validMoves != 0) { var randomMove = GetRandomMove(validMoves, state); state.DoMove(randomMove); validMoves = state.GetValidMoves(); } // 5. Backpropagate. while (node != null) { node.UpdateStatistics(state); node = node.Parent; } } return(rootNode.GetBestChild()); }
/// <summary> /// Performs the tree search. /// </summary> /// <param name="rootState"></param> /// <param name="maxIterations"></param> /// <param name="randomizeState"></param> /// <returns></returns> internal static TreeNode Search(PlayingState rootState, int maxIterations = int.MaxValue, bool randomizeState = true) { var rootNode = new TreeNode(); HandRandomizer randomizer = null; if ((randomizeState) && (rootState.NeedRandomize())) randomizer = new HandRandomizer(rootState); for (var i = 0; i < maxIterations; i++) { var node = rootNode; // 1. Determinize. var state = rootState.CloneAndRandomize(randomizer); // 2. Select. var validMoves = state.GetValidMoves(); while ((validMoves != 0) && (node.GetUntriedMoves(validMoves) == 0)) // The node is fully expanded and non-terminal. { node = node.UcbSelectChild(validMoves); state.DoMove(node.Move); validMoves = state.GetValidMoves(); } // 3. Expand. var untriedMoves = node.GetUntriedMoves(validMoves); if (untriedMoves != 0) { var randomMove = GetRandomMove(untriedMoves, state); var activeIndex = state.ActiveIndex; state.DoMove(randomMove); node = node.AddChild(randomMove, activeIndex); } // 4. Simulate. validMoves = state.GetValidMoves(); while (validMoves != 0) { var randomMove = GetRandomMove(validMoves, state); state.DoMove(randomMove); validMoves = state.GetValidMoves(); } // 5. Backpropagate. while (node != null) { node.UpdateStatistics(state); node = node.Parent; } } return rootNode.GetBestChild(); }
/// <summary> /// Returns a clone of the state replacing closed (not visible) hands with random card distributions. /// </summary> /// <param name="randomizer">Null to clone without randomizing.</param> /// <returns></returns> internal PlayingState CloneAndRandomize(HandRandomizer randomizer) { PlayingState clone = Clone(); if (randomizer != null) { randomizer.Randomize(); } return(clone); }
private static Move GetRandomMove(int cards, PlayingState state) { if (!state.IsActiveHandOpen) { return(GetRandomCard(cards)); } else { return(GetRandomGroup(cards, state.Discards)); } }
private PlayingState Clone() { var clone = new PlayingState(mContext); for (int i = 0; i < HandCount; i++) { clone.mHands[i] = mHands[i].Clone(); } clone.mActiveIndex = mActiveIndex; clone.mLeadingSuit = mLeadingSuit; clone.mDiscards = mDiscards; return(clone); }
internal HandRandomizer(PlayingState state) { mState = state; CalculateCardSets(); }
internal HandRandomizer(PlayingState state) { mState = state; CalculateCardSets(); }
/// <summary> /// Updates the statistics for this node using the specified state. /// </summary> /// <param name="state"></param> internal void UpdateStatistics(PlayingState state) { VisitCount++; mTotalValue += state.Evaluate(ActiveIndex); }
private PlayingState Clone() { var clone = new PlayingState(mContext); for (int i = 0; i < HandCount; i++) clone.mHands[i] = mHands[i].Clone(); clone.mActiveIndex = mActiveIndex; clone.mLeadingSuit = mLeadingSuit; clone.mDiscards = mDiscards; return clone; }
/// <summary> /// Updates the statistics for this node using the specified state. /// </summary> /// <param name="state"></param> internal void UpdateStatistics(PlayingState state) { VisitCount++; mTotalValue += state.Evaluate(ActiveIndex); }
private static Move GetRandomMove(int cards, PlayingState state) { if (!state.IsActiveHandOpen) return GetRandomCard(cards); else return GetRandomGroup(cards, state.Discards); }