/// <summary> /// Generate a play action for current scene. /// </summary> /// <param name="scene">The scene.</param> /// <returns>The cards to be played.</returns> public RockAction GetPlayAction(RockScene scene) { this.tracer.Verbose(RockJsonSerializer.Serialize(scene)); try { if (string.IsNullOrEmpty(this.configuration.BotEndpoint)) { var robot = new Bot.RockBot(); var action = robot.GetPlayAction(scene); this.tracer.Verbose(RockJsonSerializer.Serialize(action)); return(action); } else { var apiClient = new RockApiClient(); var action = apiClient.Post <RockAction>($"{this.configuration.BotEndpoint}{RockConstants.DefaultBotPlayRelativePath}", scene); this.tracer.Verbose(RockJsonSerializer.Serialize(action)); return(action); } } catch (Exception e) { this.tracer.Error($"Unexpected Exception from Bot: {e}"); return(RockAction.Create()); } }
/// <summary> /// Generate a play action for current scene. /// </summary> /// <param name="scene">The scene.</param> /// <returns>The cards to be played.</returns> public RockAction GetPlayAction(RockScene scene) { // You can just return an null or empty list, which means ends turn. //// return null; //// Put your codes in here. RockSceneContext context = new RockSceneContext(scene); double bestScore = 0d; List <int> bestAction = null; Random r = new Random(); foreach (List <int> action in scene.PlayOptions) { double score = PlayActionScore.ComputeScore(context, action); score += r.NextDouble(); if (score >= bestScore) { bestScore = score; bestAction = action; } } if (bestAction != null) { return(RockAction.Create(bestAction)); } return(this.DefaultGetPlayAction(scene)); }
/// <summary> /// The default implementation of GetPlayAction /// </summary> /// <param name="scene">the scene</param> /// <returns>the cards to be played</returns> private RockAction DefaultGetPlayAction(RockScene scene) { if (scene.PlayOptions.Count == 0) { return(RockAction.Create()); } else { // this smart bot will randomly choose an play action. return(RockAction.Create(scene.PlayOptions[new Random().Next(0, scene.PlayOptions.Count)])); } }
public void TestRockActionFactoryMethods() { var action = RockAction.Create(new List <int>()); Assert.AreEqual(action.Version, 1); Assert.AreEqual(action.Objects.Count, 0); Assert.AreEqual(action.Slot, -1); action = RockAction.Create(new List <int>(), 2); Assert.AreEqual(action.Version, 1); Assert.AreEqual(action.Objects.Count, 0); Assert.AreEqual(action.Slot, 2); }
/// <summary> /// The default implementation of GetMulliganAction /// </summary> /// <param name="scene">the scene</param> /// <returns>the cards to be mulligan-ed</returns> private RockAction DefaultGetMulliganAction(RockScene scene) { List <int> cards = new List <int>(); foreach (RockCard card in scene.Self.Cards) { if (card.Cost >= 4) { cards.Add(card.RockId); } } return(RockAction.Create(cards)); }
/// <summary> /// Sets the action that this rock causes to the player, based on its size /// </summary> private void SetRockAction_() { // if big enough, the rock will knock player over if (_sizeFactor > 0.5f) { _action = RockAction.KnockDown; } // if medium sized, player is knocked back, but not disabled else if (_sizeFactor > 0.35f) { _action = RockAction.KnockBack; } // if small, power up is lost else if (_sizeFactor >= 0.3f) { _action = RockAction.LosePowerUp; } }
public static RockAction RockIt() { RockAction action = new RockAction(); Player player = GameState.Get().GetFriendlySidePlayer(); Player player_enemy = GameState.Get().GetFirstOpponentPlayer(GameState.Get().GetFriendlySidePlayer()); Card hero = player.GetHeroCard(); Card hero_enemy = player_enemy.GetHeroCard(); int resource = player.GetNumAvailableResources(); List<Card> crads = player.GetHandZone().GetCards(); List<Card> minions = player.GetBattlefieldZone().GetCards(); List<Card> minions_enemy = player_enemy.GetBattlefieldZone().GetCards(); Card heropower = player.GetHeroPowerCard(); // find best match taunt attacker List<Card> minion_taunts_enemy = new List<Card>(); List<Card> minion_dangerous_enemy = new List<Card>(); List<Card> minion_notaunts = new List<Card>(); List<Card> minion_taunts = new List<Card>(); List<Card> minion_attacker = new List<Card>(); int attack_count_enemy = 0; foreach (Card minion_enemy in minions_enemy) { attack_count_enemy += minion_enemy.GetEntity().GetATK(); if (minion_enemy.GetEntity().HasWindfury()) { attack_count_enemy += minion_enemy.GetEntity().GetATK(); } } attack_count_enemy += hero_enemy.GetEntity().GetATK(); foreach (Card card_oppo in minions_enemy) { if (card_oppo.GetEntity().CanBeAttacked() && !card_oppo.GetEntity().IsStealthed()) { if (card_oppo.GetEntity().HasTaunt()) { minion_taunts_enemy.Add(card_oppo); } else if (IsEnimyDangerous(card_oppo.GetEntity())) { minion_dangerous_enemy.Add(card_oppo); } } } foreach (Card card in minions) { if (card.GetEntity().CanAttack() && !card.GetEntity().IsExhausted() && !card.GetEntity().IsFrozen() && !card.GetEntity().IsAsleep() && card.GetEntity().GetATK() > 0) { if (card.GetEntity().HasTaunt()) { minion_taunts.Add(card); } else { minion_notaunts.Add(card); } minion_attacker.Add(card); } } minions_enemy.Sort(new CardPowerComparer()); minion_taunts_enemy.Sort(new CardPowerComparer()); minion_notaunts.Sort(new CardPowerComparer()); minion_notaunts.Reverse(); minion_taunts.Sort(new CardPowerComparer()); minion_taunts.Reverse(); minion_attacker.Sort(new CardPowerComparer()); minion_attacker.Reverse(); // PlayEmergencyCard RockAction action_temp = PlayEmergencyCard(resource, crads, hero, hero_enemy, attack_count_enemy); if (action_temp != null) { action = action_temp; return action; } // if coin necessory Card coin_card = null; bool need_coin_card = false; foreach (Card card in crads) { if (card.GetEntity().GetCardId() == "GAME_005") { coin_card = card; continue; } if (resource == card.GetEntity().GetCost() - 1) { need_coin_card = true; } } // use coin if (coin_card != null && need_coin_card) { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = coin_card; return action; } // PlayEmergencyCard again action_temp = PlayEmergencyCard(resource, crads, hero, hero_enemy, attack_count_enemy); if (action_temp != null) { action = action_temp; return action; } // use as much spell as possible foreach (Card card in crads) { // but not the coin if (card.GetEntity().GetCardId() == "GAME_005") { continue; } if (resource < card.GetEntity().GetCost()) { continue; } if (card.GetEntity().IsSpell() || card.GetEntity().IsWeapon()) { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = card; return action; } } // find a minion which can use all resource foreach (Card card in crads) { if (resource < card.GetEntity().GetCost()) { continue; } if (card.GetEntity().IsMinion() && GameState.Get().GetFriendlySidePlayer().GetBattlefieldZone().GetCards().Count < 6 && (card.GetEntity().GetCost() == resource || ((card.GetEntity().GetCost() == resource - 2) && HeroSpellReady))) { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = card; return action; } } // find a minion which can use all resource foreach (Card card in crads) { if (resource < card.GetEntity().GetCost()) { continue; } if (card.GetEntity().IsMinion() && GameState.Get().GetFriendlySidePlayer().GetBattlefieldZone().GetCards().Count < 6) { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = card; return action; } if (card.GetEntity().IsMinion() && GameState.Get().GetFriendlySidePlayer().GetBattlefieldZone().GetCards().Count == 6) { if (card.GetEntity().HasCharge() || card.GetEntity().HasTaunt()) { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = card; return action; } } } // begin attack { // deal with his taunts // PlayKill notaunts > taunts action_temp = PlayKill(minion_taunts_enemy, minion_notaunts); if (action_temp != null) { action = action_temp; return action; } // PlayKill taunts > taunts action_temp = PlayKill(minion_taunts_enemy, minion_taunts); if (action_temp != null) { action = action_temp; return action; } //deal damage with no taunt foreach (Card card_oppo in minion_taunts_enemy) { foreach (Card card in minion_notaunts) { action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = card; action.card2 = card_oppo; return action; } } //deal damage with taunt foreach (Card card_oppo in minion_taunts_enemy) { foreach (Card card in minion_taunts) { action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = card; action.card2 = card_oppo; return action; } } } { // deal with his dangerous // TODO: should check maybe i can kill him // PlayKill notaunts > dangerous action_temp = PlayKill(minion_dangerous_enemy, minion_notaunts); if (action_temp != null) { action = action_temp; return action; } //deal damage with no taunt foreach (Card card_oppo in minion_dangerous_enemy) { foreach (Card card in minion_notaunts) { action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = card; action.card2 = card_oppo; return action; } } } { // deal with enemy depends on my health // TODO: should check maybe i can kill him // no taunt, but in danger if (minion_taunts_enemy.Count == 0 && (hero.GetEntity().GetHealth() - attack_count_enemy) < 10) { foreach (Card card_oppo in minions_enemy) { // find dangerous card if (card_oppo.GetEntity().GetATK() - card_oppo.GetEntity().GetHealth() > 3) { foreach (Card card in minion_attacker) { // if can kill, kill if (card.GetEntity().GetATK() >= card_oppo.GetEntity().GetHealth()) { action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = card; action.card2 = card_oppo; return action; } } } } } // no taunt, but in great danger if (minion_taunts_enemy.Count == 0 && (hero.GetEntity().GetHealth() - attack_count_enemy) < 0) { foreach (Card card_oppo in minions_enemy) { // find dangerous card if (card_oppo.GetEntity().GetATK() - card_oppo.GetEntity().GetHealth() > 1) { foreach (Card card in minion_attacker) { if (card.GetEntity().GetATK() > card_oppo.GetEntity().GetATK()) { continue; } // if can kill, kill if (card.GetEntity().GetATK() >= card_oppo.GetEntity().GetHealth()) { action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = card; action.card2 = card_oppo; return action; } } } } } } // END deal with enemy depends on my health // attack his face! foreach (Card card in minions) { if (card.GetEntity().CanAttack() && !card.GetEntity().IsExhausted() && !card.GetEntity().IsFrozen() && !card.GetEntity().IsAsleep() && card.GetEntity().GetATK() > 0) { foreach (Card card_oppo in minions_enemy) { // for bug, should noy run if (card_oppo.GetEntity().HasTaunt()) { action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = card; action.card2 = card_oppo; return action; } } action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = card; action.card2 = player_enemy.GetHeroCard(); return action; } } // deal with hero weapon and atk HearthrockEngine.Log("HasWeapon " + player.HasWeapon()); if (player.HasWeapon()) { HearthrockEngine.Log("HasWeapon CanAttack " + player.GetWeaponCard().GetEntity().CanAttack()); } if (minion_taunts_enemy.Count == 0 && player.HasWeapon() && player.GetWeaponCard().GetEntity().CanAttack()) { action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = player.GetWeaponCard(); action.card2 = player_enemy.GetHeroCard(); return action; } Entity me = player.GetHeroCard().GetEntity(); if (minion_taunts_enemy.Count == 0 && me.CanAttack() && me.GetATK() > 0) { action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = player.GetHeroCard(); action.card2 = player_enemy.GetHeroCard(); return action; } if (resource >= 2 && HeroSpellReady) { HeroSpellReady = false; TAG_CLASS hero_class = player.GetHeroCard().GetEntity().GetClass(); switch (hero_class) { case TAG_CLASS.WARLOCK: if (crads.Count > 8) { return action; } if (hero.GetEntity().GetRemainingHP() < 5) { return action; } else if (hero.GetEntity().GetRemainingHP() < 12) { if (attack_count_enemy + 2 > hero.GetEntity().GetRemainingHP()) { return action; } else { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = heropower; return action; } } else { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = heropower; return action; } case TAG_CLASS.HUNTER: case TAG_CLASS.DRUID: case TAG_CLASS.PALADIN: case TAG_CLASS.ROGUE: case TAG_CLASS.SHAMAN: case TAG_CLASS.WARRIOR: action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = heropower; return action; case TAG_CLASS.PRIEST: action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = heropower; action.card2 = player.GetHeroCard(); return action; case TAG_CLASS.MAGE: action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = heropower; action.card2 = player_enemy.GetHeroCard(); return action; default: break; } } return action; }
private static RockAction PlayKill(List<Card> minion_target, List<Card> minion_attacker) { RockAction action = new RockAction(); Card target_best = null; Card attacker_best = null; //find taunt kill attacker foreach (Card card_oppo in minion_target) { foreach (Card card in minion_attacker) { if (card_oppo.GetEntity().GetRemainingHP() <= card.GetEntity().GetATK()) { if (target_best == null) { target_best = card_oppo; attacker_best = card; } else { if (attacker_best.GetEntity().GetATK() > card.GetEntity().GetATK()) { attacker_best = card; } } } } if (target_best != null) { action.type = HEARTHROCK_ACTIONTYPE.ATTACK; action.card1 = attacker_best; action.card2 = target_best; return action; } } return null; }
private static RockAction PlayEmergencyCard(int resource, List<Card> crads, Card hero, Card hero_enemy, int attack_count_enemy) { RockAction action = new RockAction(); // best fit taunt foreach (Card card in crads) { if (resource < card.GetEntity().GetCost()) { continue; } if (card.GetEntity().IsMinion() && card.GetEntity().HasTaunt() && GameState.Get().GetFriendlySidePlayer().GetBattlefieldZone().GetCards().Count < 7 && (card.GetEntity().GetCost() == resource || ((card.GetEntity().GetCost() == resource - 2) && HeroSpellReady))) { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = card; return action; } } // if hero has less health, need more emergency taunt if ((hero.GetEntity().GetHealth() - attack_count_enemy) < 10) { // not perfect fit taunt foreach (Card card in crads) { if (resource < card.GetEntity().GetCost()) { continue; } // waste a cost if (card.GetEntity().IsMinion() && card.GetEntity().HasTaunt() && GameState.Get().GetFriendlySidePlayer().GetBattlefieldZone().GetCards().Count < 7 && (card.GetEntity().GetCost() == resource - 1 || ((card.GetEntity().GetCost() == resource - 3) && HeroSpellReady))) { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = card; return action; } } } // if hero has more health, play as much charge as possible if ((hero.GetEntity().GetHealth() - hero_enemy.GetEntity().GetHealth()) > 10) { foreach (Card card in crads) { if (resource < card.GetEntity().GetCost()) { continue; } // waste a cost if (card.GetEntity().IsMinion() && GameState.Get().GetFriendlySidePlayer().GetBattlefieldZone().GetCards().Count < 7) { if (card.GetEntity().HasCharge()) { action.type = HEARTHROCK_ACTIONTYPE.PLAY; action.card1 = card; return action; } } } } return null; }
private void OnRockTurnStart() { HoldBack(5000); ActionRocking = null; TurnReady = true; SingletonEndTurn = false; // OnRocking = false; }
private void OnRockTurnEnd() { if (SingletonEndTurn) return; SingletonEndTurn = true; HoldBack(3000); Notify("Job's Done!"); ActionRocking = null; TurnReady = false; HearthrockRobot.RockEnd(); InputManager.Get().DoEndTurnButton(); // OnRocking = false; }
private void OnRockAI() { if (OnRocking) return; OnRocking = true; try { if (ActionRocking != null && ActionRocking.step == -1) { ActionRocking = null; } if (ActionRocking != null) { try { OnAction(ActionRocking); } catch { ActionRocking = null; } return; } // ActionRocking = should be null; HoldBack(250); if (EndTurnButton.Get().HasNoMorePlays()) { OnRockTurnEnd(); return; } RockAction action = HearthrockRobot.RockIt(); if (action.type == HEARTHROCK_ACTIONTYPE.PLAY) { SingletonEndTurn = false; Notify("Play: " + action.card1.GetEntity().GetName()); ActionRocking = action; } else if (action.type == HEARTHROCK_ACTIONTYPE.ATTACK) { SingletonEndTurn = false; Notify("Attack: " + action.card1.GetEntity().GetName() + " > " + action.card2.GetEntity().GetName()); ActionRocking = action; } else { OnRockTurnEnd(); } } catch (Exception e){ Log("OnRockAI ex " + e.ToString()); } finally { OnRocking = false; } }
private void OnAction(RockAction action) { System.Random r = new System.Random(); if (action.step == 0) { int delay = r.Next(400, 600); HoldBack(delay); /* Spell spell = action.card1.GetBattlecrySpell(); if (spell != null) { } else { Notify("No Spell "); } */ //bool x = GameState.Get().HasResponse(action.card1.GetEntity()); HearthstoneClickCard(action.card1); action.step = 1; } else if (action.step == 1) { int delay = r.Next(300, 600); if (action.type == HEARTHROCK_ACTIONTYPE.ATTACK) { delay += 400; } HoldBack(delay); if (action.type == HEARTHROCK_ACTIONTYPE.PLAY) { InputManager input_mgr = InputManager.Get(); input_mgr.DropHeldCard(); //MethodInfo dynMethod = input_mgr.GetType().GetMethod("DropHeldCard", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null); //dynMethod.Invoke(input_mgr, new object[] { }); action.step = 2; } else if (action.type == HEARTHROCK_ACTIONTYPE.ATTACK) { HearthstoneClickCard(action.card2); action.step = -1; } } else if (action.step == 2) { action.step = -1; return; // maybe can do sth to deal with card with spell if (InputManager.Get().heldObject == null) { action.step = -1; return; } int delay = r.Next(300, 600); HoldBack(delay); if (action.type == HEARTHROCK_ACTIONTYPE.PLAY) { action.step = -1; } } }
private void ClearGameState() { MulliganState = 0; TurnReady = false; ActionRocking = null; OnRocking = false; }