internal static PowerHistory CopyPowerHistory(this HearthNode h) { var copy = new PowerHistory(); //copy.AddRange(h.PowerHistory); return(copy); }
/// <summary> /// /// </summary> /// <param name="state"></param> /// <returns></returns> internal static HearthNode GetObvious(this HearthNode state) { HearthNode obvious = state.Frontier.Count == 1 ? state.GetSingleChoice() : state.PlayQuest(); if (obvious == null) { List <HearthNode> lethalMoves = state.GetLethalMoves(); if (lethalMoves != null) { obvious = lethalMoves[0]; } else if (state.AttackOnly()) { obvious = state.Frontier[0]; } } else { state.BirthPossibility(obvious); } return(obvious); }
internal static double ScoreSpecial(this HearthNode h, double score) { if (h.Action.Source?.Card.Type == CardType.HERO) { score *= 1.15; } else if (h.Parent.Game.CurrentPlayer.BoardZone.Sum(m => m.AttackDamage) >= h.Parent.Game.CurrentOpponent.Hero.Health - 5 && h.Action.PlayerTaskType == PlayerTaskType.MINION_ATTACK && h.Action.Target?.Card.Type == CardType.HERO) { score *= 1.1; } else { IEntity quest = h.Parent.Game.CurrentPlayer.GraveyardZone.Find(q => q.IsQuest); if (quest != null) { if (h.Action.HasSource && h.Action.PlayerTaskType == PlayerTaskType.PLAY_CARD) { if (h.Action.Source.NativeTags.Contains(kv => kv.Key == GameTag.DISPLAYED_CREATOR && kv.Value == quest.NativeTags[GameTag.ENTITY_ID])) { score *= 1.05; } } } } return(score); }
public static HearthNode CreateRoot(Game game) { var root = new HearthNode(null, game, null); //root._root = root; return(root); }
/// <summary> /// If there's only one possible move, no need to simulate /// </summary> /// <param name="state"></param> /// <returns></returns> internal static HearthNode GetSingleChoice(this HearthNode state) { HearthNode choice = state.Frontier[0]; state.Frontier.Remove(choice); state.AddChild(choice); return(choice); }
/// <summary> /// Generates this HearthNode's possible actions from the move options /// available to the current player. /// </summary> internal static void GenPossibleActions(this HearthNode state) { List <PlayerTask> options = state.Game.CurrentPlayer.Options(); for (int i = 0; i < options.Count; ++i) { state.AddFrontier(new HearthNode(state, state.Game, options[i])); } }
internal static List <HearthNode> Purge(this HearthNode state) { var purged = new List <HearthNode>(); for (int i = 0; i < state.Frontier.Count; ++i) { HearthNode p = state.Frontier[i]; if (p.Action.Source?.Card.Name == "Warpath" && state.Game.CurrentOpponent.BoardZone.IsEmpty) { purged.Add(p); } else if (p.Game.CurrentPlayer.Hero.HeroPower.Card.Name == "Bladestorm" && p.Action.PlayerTaskType == PlayerTaskType.HERO_POWER && state.Game.CurrentOpponent.BoardZone.IsEmpty) { purged.Add(p); } else if (p.Action.Source?.Card.Name == "Drywhisker Armorer" && state.Game.CurrentOpponent.BoardZone.IsEmpty && p.Action.PlayerTaskType == PlayerTaskType.PLAY_CARD) { purged.Add(p); } else if (p.Action.Source?.Card.Name == "Serrated Shield" && (p.Action.Target == p.Game.CurrentPlayer || p.Action.Target.Controller == p.Game.CurrentPlayer)) { purged.Add(p); } else if (p.Action.Source?.Card.Name == "Execute" && p.Action.Target.Controller == p.Game.CurrentPlayer) { purged.Add(p); } else if (p.Action.Source?.Card.Name == "Brawl" && (state.Game.BoardCount() > 2) && (state.Game.CurrentPlayer.BoardZone.Sum(m => m.Health) > state.Game.CurrentOpponent.BoardZone.Sum(m => m.AttackDamage) || state.Game.CurrentPlayer.BoardZone.Count(m => m.HasTaunt) > state.Game.CurrentOpponent.BoardZone.Count)) { purged.Add(p); } else if (p.Action.Source?.Card.Name == "Molten Blade") { purged.Add(p); } } return(purged); }
/// <summary> /// Calculates this ActionNode's score; /// </summary> /// <returns></returns> static double SelectionScore(this HearthNode child) { double exploitation = ((double)child.Wins / child.Visits); double exploration = Math.Sqrt(Math.Log((double)child.Parent.Visits / child.Visits)); exploration = Double.IsNaN(exploration) ? 0 : 2.0 * exploration; double score = exploitation + exploration; if (!child.IsEndTurn) { score = child.ScoreSpecial(score); } return(score); }
/// <summary> /// Scores each of state's children, then returns the one with the highest score. /// </summary> /// <param name="state"></param> /// <returns></returns> internal static HearthNode ScoreAndSelect(this HearthNode state) { HearthNode selection = null; double selScore = Int32.MinValue; for (int i = 0; i < state.Children.Count; ++i) { double childScore = state.Children[i].SelectionScore(); if (childScore > selScore) { selScore = childScore; selection = state.Children[i]; } } return(selection); }
/// <summary> /// Finds the HearthNode with the most children, and returns the count /// </summary> /// <param name="h"></param> /// <param name="hWidth"></param> /// <returns></returns> public void CalcDimensions(HearthNode h, int height, int width) { if (h.Children.Count == 0) { return; } int maxHeight = Math.Max(1, height); int maxWidth = Math.Max(width, h.Children.Count); for (int i = 0; i < Root.Children.Count; ++i) { CalcDimensions(Root.Children[i], maxHeight, maxWidth); } _height = maxHeight; _width = maxWidth; }
/// <summary> /// Copy constructor /// </summary> /// <param name="other"></param> protected HearthNode(HearthNode other) { //_root = other.Root; _parent = null; // other.Parent?.Clone() ?? null; _logging = other.Logging; _game = other.Game.Clone(); //_powerHistory = other.CopyPowerHistory(); _action = other.Action; _damage = other.Damage; for (int i = 0; i < other.Frontier.Count; ++i) { AddFrontier(other.Frontier[i]); } for (int i = 0; i < other.Children.Count; ++i) { AddChild(other.Children[i]); } }
/// <summary> /// Base class constructor /// </summary> /// <param name="root"></param> /// <param name="game"></param> public HearthNode(HearthNode parent, Game game, PlayerTask action) //, bool isRoot = false) { //_root = root; _parent = parent; _action = action; _isEndTurn = (Action?.PlayerTaskType ?? PlayerTaskType.ROOT) == PlayerTaskType.END_TURN; _game = game.Clone(); _logging = Game.Logging; //_powerHistory = new PowerHistory(); //IsRoot = isRoot; if (IsRoot) { GenPossibleActions(); } else { Process(); } //PowerHistory.AddRange(game.PowerHistory); }
/// <summary> /// /// </summary> /// <param name="state"></param> /// <returns></returns> internal static HearthNode PlayQuest(this HearthNode state) { return(state.Frontier.Count > 1 ? state.Frontier.Find(p => p.Action?.Source?.Card.IsQuest ?? false) : null); }
/// <summary> /// Default constructor /// </summary> /// <param name="root"></param> public HearthTree(HearthNode root) { _root = root; //CalcDimensions(Root, 1, Root.Children.Count); }