def __init__(self): super(TinderWall, self).__init__('Tinder Wall', is_permanent=True) tinder_wall_play_action = Action('Tinder Wall', 'Play', requirements=[ CardInHand(self.name), ManaInPool(ColorDict({'Green': 1})) ], consequences=[ MoveCard(self.name, 'Hand', 'Battlefield'), ReduceMana(ColorDict({'Green': 1})), AddStorm() ]) tinder_wall_mana_action = Action('Tinder Wall', 'Sacrifice', requirements=[CardInPlay(self.name)], consequences=[ MoveCard(self.name, 'Battlefield', 'Graveyard'), AddMana(ColorDict({'Red': 2})) ]) self.add_action(tinder_wall_play_action) self.add_action(tinder_wall_mana_action)
def reset_game(self, draw_opening_hand=True, test=False): for card, maindeck, sideboard in self.cards: self.deck[card.name] = maindeck if sideboard > 0: self.sideboard[card.name] = sideboard self.hand[card.name] = 0 self.exile[card.name] = 0 if card.is_permanent: self.battlefield[card.name] = 0 self.graveyard[card.name] = 0 if card.is_tappable: self.tapped[card.name] = 0 self.mana_pool = ColorDict() self.goblins = 0 self.storm_count = 0 self.opp_life_total = 20 self.taiga_bottom = False self.turn = 1 self.lost = False self.won = False if draw_opening_hand: self.draw_opening_hand() if test: self.add_mana(ColorDict({'Red': 2})) self.increase_card_count('Goblin Charbelcher', 'Battlefield') self.increase_card_count('Taiga', 'Battlefield') #self.increase_card_count('Seething Song', 'Hand') self.reduce_card_count('Goblin Charbelcher', 'Deck') self.reduce_card_count('Taiga', 'Deck')
def __init__(self): super(ChromeMox, self).__init__('Chrome Mox', is_tappable=True, is_permanent=True) for card_for_chrome_mox in CARDS_FOR_CHROME_MOX: chrome_mox_play = Action('Chrome Mox', 'Play', requirements=[ CardInHand(self.name), CardInHand(card_for_chrome_mox) ], consequences=[ MoveCard(self.name, 'Hand', 'Battlefield'), MoveCard(card_for_chrome_mox, 'Hand', 'Exile'), AddStorm() ]) self.add_action(chrome_mox_play) chrome_mox_activate = Action('Chrome Mox', 'Activate', requirements=[CardUntapped(self.name)], consequences=[Tap(self.name)]) self.add_mana_action(chrome_mox_activate, adding=[ColorDict({c: 1}) for c in COLORS])
def __init__(self): super(RiteOfFlame, self).__init__('Rite of Flame') rite_of_flame_action = Action('Rite of Flame', 'Play', requirements=[ CardInHand(self.name), ManaInPool(ColorDict({'Red': 1})) ], consequences=[ MoveCard(self.name, 'Hand', 'Graveyard'), ReduceMana(ColorDict({'Red': 1})), AddStorm(), AddRiteMana() ]) self.add_action(rite_of_flame_action)
def __init__(self): super(SeethingSong, self).__init__('Seething Song') seething_song_action = Action('Seething Song', 'Play', requirements=[CardInHand(self.name)], consequences=[ AddMana(ColorDict({'Red': 5})), MoveCard(self.name, 'Hand', 'Graveyard'), AddStorm() ]) self.add_mana_action(seething_song_action, paying=color_combinations( ColorDict({ 'Red': 1, 'Colorless': 2 })))
def __init__(self): super(Manamorphose, self).__init__('Manamorphose') manamorphose_action = Action('Manamorphose', 'Play', requirements=[CardInHand(self.name)], consequences=[ MoveCard(self.name, 'Hand', 'Graveyard'), DrawCard(), AddStorm() ]) self.add_mana_action( manamorphose_action, paying=color_combinations(ColorDict({ 'Red': 1, 'Colorless': 1 })), adding=fill_up_remaining_colors(2, COLORS, ColorDict(), []))
def color_combinations(mana_cost): """ :param mana_cost: :return: list of ColorDicts, representing the possbile mana combinations """ always = ColorDict(mana_cost) colorless_remaining = mana_cost['Colorless'] del always['Colorless'] options = fill_up_remaining_colors(colorless_remaining, COLORS, always, []) return options
def __init__(self): super(SimianSpiritGuide, self).__init__('Simian Spirit Guide') simian_spirit_guide_action = Action( 'Simian Spirit Guide', 'Exile', requirements=[CardInHand(self.name)], consequences=[ AddMana(ColorDict({'Red': 1})), MoveCard(self.name, 'Hand', 'Exile') ]) self.add_action(simian_spirit_guide_action)
def __init__(self): super(ElvishSpiritGuide, self).__init__('Elvish Spirit Guide') elvish_spirit_guide_action = Action( 'Elvish Spirit Guide', 'Exile', requirements=[CardInHand(self.name)], consequences=[ AddMana(ColorDict({'Green': 1})), MoveCard(self.name, 'Hand', 'Exile') ]) self.add_action(elvish_spirit_guide_action)
def __init__(self): self.deck = {} self.hand = {} self.exile = {} self.sideboard = {} self.battlefield = {} self.graveyard = {} self.tapped = {} self.mana_pool = ColorDict() self.goblins = 0 self.storm_count = 0 self.opp_life_total = 20 self.taiga_bottom = False self.turn = 1 self.lost = False self.won = False self.actions_set = False self.actions = [] self.cards = []
def __init__(self): super(ReforgeTheSoul, self).__init__('Reforge the Soul') reforge_the_soul_action = Action( 'Reforge the Soul', 'Play', requirements=[CardInHand(self.name)], consequences=[DiscardHand(), DrawCard(7), AddStorm()]) self.add_mana_action(reforge_the_soul_action, paying=color_combinations( ColorDict({ 'Red': 2, 'Colorless': 3 })))
def __init__(self): super(GoblinCharbelcher, self).__init__('Goblin Charbelcher', is_tappable=True, is_permanent=True) charbelcher_play = Action('Goblin Charbelcher', 'Play', requirements=[CardInHand(self.name)], consequences=[ MoveCard(self.name, 'Hand', 'Battlefield'), AddStorm() ]) charbelcher_activate = Action( 'Goblin Charbelcher', 'Activate', requirements=[CardInPlay(self.name), CardUntapped(self.name)], consequences=[Tap(self.name), Belch()]) self.add_mana_action(charbelcher_play, paying=color_combinations( ColorDict({'Colorless': 4}))) self.add_mana_action(charbelcher_activate, paying=color_combinations( ColorDict({'Colorless': 3})))
def __init__(self): super(EmptyTheWarrens, self).__init__('Empty the Warrens') empty_the_warrens_action = Action('Empty the Warrens', 'Play', requirements=[CardInHand(self.name)], consequences=[ AddStorm(), AddGoblins(), MoveCard(self.name, 'Hand', 'Graveyard') ]) self.add_mana_action(empty_the_warrens_action, paying=color_combinations( ColorDict({ 'Red': 1, 'Colorless': 3 })))
def __init__(self): super(DesperateRitual, self).__init__('Desperate Ritual') desperate_ritual_action = Action('Desperate Ritual', 'Play', requirements=[CardInHand(self.name)], consequences=[ AddMana({'Red': 3}), AddStorm(), MoveCard(self.name, 'Hand', 'Graveyard') ]) self.add_mana_action(desperate_ritual_action, paying=color_combinations( ColorDict({ 'Red': 1, 'Colorless': 1 })))
def __init__(self): super(Taiga, self).__init__('Taiga', is_tappable=True, is_permanent=True) taiga_action_play = Action( 'Taiga', 'Play', requirements=[CardInHand(self.name)], consequences=[MoveCard(self.name, 'Hand', 'Battlefield')]) taiga_action_tap = Action('Taiga', 'Tap', requirements=[CardUntapped(self.name)], consequences=[Tap(self.name)]) self.add_action(taiga_action_play) self.add_mana_action(taiga_action_tap, adding=fill_up_remaining_colors( 1, ['Red', 'Green'], ColorDict(), []))
def __init__(self): super(LotusPetal, self).__init__('Lotus Petal', is_permanent=True) lotus_petal_play = Action('Lotus Petal', 'Play', requirements=[CardInHand(self.name)], consequences=[ MoveCard(self.name, 'Hand', 'Battlefield'), AddStorm() ]) lotus_petal_activate = Action( 'Lotus Petal', 'Sacrifice', requirements=[CardInPlay(self.name)], consequences=[MoveCard(self.name, 'Battlefield', 'Graveyard')]) self.add_action(lotus_petal_play) self.add_mana_action(lotus_petal_activate, adding=[ColorDict({c: 1}) for c in COLORS])
def __init__(self): super(BurningWish, self).__init__('Burning Wish') for card_for_burning_wish in CARDS_FOR_BURNING_WISH: burning_wish_wish = Action( 'Burning Wish', 'Play ' + card_for_burning_wish, requirements=[ CardInHand(self.name), CardInSideboard(card_for_burning_wish) ], consequences=[ MoveCard(self.name, 'Hand', 'Exile'), MoveCard(card_for_burning_wish, 'Sideboard', 'Hand'), AddStorm() ]) self.add_mana_action(burning_wish_wish, paying=color_combinations( ColorDict({ 'Red': 1, 'Colorless': 1 })))
def __init__(self): super(LionsEyeDiamond, self).__init__('Lions Eye Diamond', is_permanent=True) lions_eye_diamond_play = Action('Lions Eye Diamond', 'Play', requirements=[CardInHand(self.name)], consequences=[ MoveCard(self.name, 'Hand', 'Battlefield'), AddStorm() ]) lions_eye_diamond_activate = Action( 'Lions Eye Diamond', 'Sacrifice', requirements=[CardInPlay(self.name)], consequences=[ DiscardHand(), MoveCard(self.name, 'Battlefield', 'Graveyard') ]) self.add_action(lions_eye_diamond_play) self.add_mana_action(lions_eye_diamond_activate, adding=[ColorDict({c: 3}) for c in COLORS])
class GameState(object): def __init__(self): self.deck = {} self.hand = {} self.exile = {} self.sideboard = {} self.battlefield = {} self.graveyard = {} self.tapped = {} self.mana_pool = ColorDict() self.goblins = 0 self.storm_count = 0 self.opp_life_total = 20 self.taiga_bottom = False self.turn = 1 self.lost = False self.won = False self.actions_set = False self.actions = [] self.cards = [] def add_card(self, card, maindeck, sideboard): self.cards.append((card, maindeck, sideboard)) def reset_game(self, draw_opening_hand=True, test=False): for card, maindeck, sideboard in self.cards: self.deck[card.name] = maindeck if sideboard > 0: self.sideboard[card.name] = sideboard self.hand[card.name] = 0 self.exile[card.name] = 0 if card.is_permanent: self.battlefield[card.name] = 0 self.graveyard[card.name] = 0 if card.is_tappable: self.tapped[card.name] = 0 self.mana_pool = ColorDict() self.goblins = 0 self.storm_count = 0 self.opp_life_total = 20 self.taiga_bottom = False self.turn = 1 self.lost = False self.won = False if draw_opening_hand: self.draw_opening_hand() if test: self.add_mana(ColorDict({'Red': 2})) self.increase_card_count('Goblin Charbelcher', 'Battlefield') self.increase_card_count('Taiga', 'Battlefield') #self.increase_card_count('Seething Song', 'Hand') self.reduce_card_count('Goblin Charbelcher', 'Deck') self.reduce_card_count('Taiga', 'Deck') #self.reduce_card_count('Seething Song', 'Deck') def possible_actions(self): """ List of binary numbers to represent if that action is available :return: """ all_actions = self.all_actions() legal_actions = [x.allowed(self) * 1 for x in all_actions] return legal_actions, all_actions def reward(self): if not self.won and not self.lost: return None if self.won: return 60 - self.turn return 1 def all_actions(self): if self.actions_set: return self.actions self.actions = [ Action('Game', 'Pass turn', requirements=[], consequences=[ AddTurn(), UntapPermanents(), ResetManaPool(), StormCountZero(), DrawCard(), DealGoblinDamage() ]) ] for card, _, _ in self.cards: print(card.name, len(self.actions)) self.actions.extend(card.actions) self.actions_set = True return self.actions def state_space(self): # We should make it so we can just add em all up for the correct representation. # The objects should know representation_list = [] for card, _, _ in self.cards: representation_list.append(self.deck[card.name] / 4) for card, _, _ in self.cards: representation_list.append(self.hand[card.name] / 4) ## List over only permanents for card, _, _ in self.cards: representation_list.append(self.battlefield[card.name] / 4) for card, _, _ in self.cards: representation_list.append(self.graveyard[card.name] / 4) for card, _, _ in self.cards: if card.name in self.tapped: representation_list.append(self.tapped[card.name] / 4) for card, _, _ in self.cards: if card.name in self.sideboard: representation_list.append(self.sideboard[card.name]) for color in COLORS: representation_list.append(self.mana_pool[color] / 2) representation_list.append(self.goblins / 10) representation_list.append(self.storm_count / 4) representation_list.append(self.opp_life_total / 20) representation_list.append(self.taiga_bottom * 1) representation_list.append(self.turn / 10) number_cards_in_deck = sum([self.deck[k] for k in self.deck]) / 53 representation_list.append(number_cards_in_deck) return representation_list def untapped(self, card): return self.battlefield[card] > self.tapped[card] def mana_floating(self, c_dict): for k in c_dict: if self.mana_pool[k] < c_dict[k]: return False return True def card_in_hand(self, card): return self.hand[card] > 0 def card_in_play(self, card): return self.battlefield[card] > 0 def card_in_sideboard(self, card): return self.sideboard[card] > 0 def card_in_deck(self, card): return self.deck[card] > 0 def storm_count_zero(self): self.storm_count = 0 def goblin_damage(self): self.opp_life_total -= self.goblins if self.opp_life_total < 1: self.won = True def damage_opponent(self, damage): self.opp_life_total -= damage if self.opp_life_total < 1: self.won = True def untap_permanents(self): for card, _, _ in self.cards: if card.is_tappable: self.tapped[card.name] = 0 def add_rite_mana(self): self.add_mana(ColorDict({'Red': 2 + self.graveyard['Rite of Flame']})) def belch(self): deck_list = self._list_deck(True, True) total_damage = 0 for card in deck_list: if card == 'Taiga': total_damage *= 2 break total_damage += 1 self.damage_opponent(total_damage) self.taiga_bottom = True def discard_hand(self): for card_name in self.hand: self.graveyard[card_name] += self.hand[card_name] self.hand[card_name] = 0 def shuffle(self): self.taiga_bottom = False def draw_cards(self, amount): list_deck = self._list_deck() if len(list_deck) < amount: self.lost = True else: cards_to_draw = choice(list_deck, amount, False) for card_to_draw in cards_to_draw: self.deck[card_to_draw] -= 1 self.hand[card_to_draw] += 1 def _list_deck(self, include_Taiga=True, shuffle_list=False): deck_list = [] for card_name in self.deck: if card_name != 'Taiga' or not self.taiga_bottom: deck_list.extend( [card_name for _ in range(self.deck[card_name])]) if shuffle_list: shuffle(deck_list) if self.taiga_bottom and include_Taiga and self.deck['Taiga'] > 0: deck_list.append('Taiga') return deck_list def tap_card(self, card): self.tapped[card] += 1 def add_storm(self): self.storm_count += 1 def add_goblins(self): self.goblins += 2 * self.storm_count def add_mana(self, c_dict): self.mana_pool.add_mana(c_dict) def reduce_mana(self, c_dict): self.mana_pool.subtract_mana(c_dict) def reset_mana_pool(self): self.mana_pool.subtract_mana(self.mana_pool) def increase_card_count(self, card, zone): self._zone_dispatcher(zone)[card] += 1 def reduce_card_count(self, card, zone): self._zone_dispatcher(zone)[card] -= 1 def draw_opening_hand(self): self.draw_cards(7) def add_turn(self): self.turn += 1 def _zone_dispatcher(self, zone): if zone == 'Graveyard': return self.graveyard if zone == 'Battlefield': return self.battlefield elif zone == 'Hand': return self.hand elif zone == 'Exile': return self.exile elif zone == 'Deck': return self.deck elif zone == 'Sideboard': return self.sideboard raise ValueError('Incorrect zone type', zone) def __str__(self): # It'd be nice to rely on something higher level to represent the game in string form. # I find big functions like this hard to manage, but they might not ever really change. repr_str = 'GAME STATE: \n' #repr_str += ' Cards in hand: ' + str(sum([self.hand[k] for k in self.hand])) + '\n' #repr_str += ' Cards in deck: ' + str(sum([self.deck[k] for k in self.deck])) + '\n' #repr_str += ' Cards in play: ' + str(sum([self.battlefield[k] for k in self.battlefield])) + '\n' #repr_str += ' Cards in graveyard: ' + str(sum([self.graveyard[k] for k in self.graveyard])) + '\n' #repr_str += ' Cards in sideboard: ' + str(sum([self.sideboard[k] for k in self.sideboard])) + '\n' repr_str += 'Hand: ' + str(sum([self.hand[k] for k in self.hand])) + ', ' repr_str += 'Deck: ' + str(sum([self.deck[k] for k in self.deck])) + ', ' repr_str += 'Play: ' + str( sum([self.battlefield[k] for k in self.battlefield])) + ', ' repr_str += 'GY: ' + str( sum([self.graveyard[k] for k in self.graveyard])) + ', ' #repr_str += ' Cards in sideboard: ' + str(sum([self.sideboard[k] for k in self.sideboard])) + '\n' repr_str += '\nHAND: \n' for k in self.hand: if self.hand[k] > 0: repr_str += k + ': ' + str(self.hand[k]) + ', ' repr_str += '\nPLAY: \n' for k in self.battlefield: if self.battlefield[k] > 0: repr_str += k + ': ' + str(self.battlefield[k]) + ', ' repr_str += '\nTAPPED: \n' for k in self.tapped: if self.tapped[k] > 0: repr_str += k + ': ' + str(self.tapped[k]) + ', ' repr_str += '\nMANA POOL: ' for c in COLORS: repr_str += ' ' + c + ': ' + str(self.mana_pool[c]) + ', ' repr_str += '\nACTIONS: ' + str(sum(self.possible_actions()[0])) + '\n' repr_str += 'GOBLINS: ' + str(self.goblins) + '\n' repr_str += 'TURN: ' + str(self.turn) + '\n' repr_str += 'OPP LIFETOTAL: ' + str(self.opp_life_total) + '\n' return repr_str
def add_rite_mana(self): self.add_mana(ColorDict({'Red': 2 + self.graveyard['Rite of Flame']}))