# -*- coding: utf-8 -*-
import numpy as np
import random
import math
from Policy import *
from my_moduler import get_module_logger, get_state_logger
from mulligan_setting import *
from adjustment_action_code import *
mylogger = get_module_logger(__name__)
# mylogger = get_module_logger('mylogger')
import itertools

#statelogger = get_state_logger('state')
from my_enum import *


class Player:
    def __init__(self, max_hand_num, first=True, policy=RandomPolicy(), mulligan=Random_mulligan_policy()):
        self.hand = []
        self.max_hand_num = max_hand_num
        self.is_first = first
        self.player_num = 1 - int(self.is_first)
        self.life = 20
        self.max_life = 20
        self.policy = policy
        self.mulligan_policy = mulligan
        self.deck = None
        self.lib_out_flg = False
        self.field = None
        self.name = None
        self.class_num = None
        self.effect = []
        self.error_count = 0


    def get_copy(self, field):
        player = Player(self.max_hand_num, first=self.is_first, policy=self.policy, mulligan=self.mulligan_policy)
        #for card in self.hand:
        #    player.hand.append(card.get_copy())
        player.hand = list(map(field.copy_func,self.hand)) if field is not None else []
        player.life = self.life
        player.deck = Deck()
        if self.deck is not None:
            player.deck.set_leader_class(self.deck.leader_class.name)
            #for i,card in enumerate(self.deck.deck):
            #    player.deck.append(card)
            player.deck.deck = deque(map(field.copy_func, self.deck.deck)) if field is not None else deque()
            player.deck.remain_num = int(self.deck.remain_num)
            player.deck.deck_type = int(self.deck.deck_type)

        player.field = field
        player.name = self.name
        player.class_num = self.class_num
        player.effect = copy.copy(self.effect)
        #if len(self.effect) > 0:
        #player.effect = copy.deepcopy(self.effect)

        return player

    def eq(self,other):
        if self.life != other.life:
            return False
        if len(self.deck.deck) != len(other.deck.deck):
            return False
        if len(self.hand) != len(other.hand):
            return False

        checked_cards = []
        for i,card in enumerate(self.hand):
            if card in checked_cards:
                continue
            origin_count = 0
            other_count = 0
            for player_card in self.hand:
                if player_card.eq(card):
                    origin_count += 1
            for other_card in other.hand:
                if other_card.eq(card):
                    other_count += 1
            if origin_count != other_count:
                return False
            checked_cards.append(card)

        return True

    def compare_hand(self,other_hand):
        checked_cards = []
        for i,card in enumerate(self.hand):
            if card in checked_cards:
                continue
            origin_count = 0
            other_count = 0
            for player_card in self.hand:
                if player_card.eq(card):
                    origin_count += 1
            for other_card in other_hand:
                if other_card.eq(card):
                    other_count += 1
            if origin_count != other_count:
                return False
            checked_cards.append(card)

        return True

    def sort_hand(self):
        self.hand.sort(key = lambda card:card.name)

    def get_damage(self, damage):
        if len(self.effect) > 0:
            tmp = int(damage)
            priority_list = list(set([effect.proirity for effect in self.effect]))
            priority_list = sorted(priority_list, reverse=True)

            for i in priority_list:
                for effect in self.effect:
                    if effect.priority == i:
                        tmp = effect(argument=tmp, state_code=State_Code.GET_DAMAGE.value)
            return tmp
        else:
            self.life -= damage
            return damage

    def restore_player_life(self, num=0, virtual=False):
        self.field.restore_player_life(player=self, num=num, virtual=virtual)

    def check_vengeance(self):
        return self.life <= 10

    def check_overflow(self):
        return self.field.cost[self.player_num] >= 7

    def check_resonance(self):
        return len(self.deck.deck) % 2 == 0

    def draw(self, deck, num):
        for i in range(num):
            if len(deck.deck) == 0:
                self.lib_out_flg = True
                return
            card = deck.draw()
            self.field.drawn_cards.append(card,self.player_num)
            self.hand.append(card)
            if len(self.hand) > self.max_hand_num:
                self.field.graveyard.shadows[self.player_num] += 1
                self.hand.pop(-1)

    def append_cards_to_hand(self, cards):
        for card in cards:
            self.hand.append(card)
            if len(self.hand) > self.max_hand_num:
                self.field.graveyard.shadows[self.player_num] += 1
                self.hand.pop(-1)

    def show_hand(self):
        length = 0
        print("Player", self.player_num + 1, "'s hand")
        print("====================================================================")
        hand_len = len(self.hand)
        for i in range(hand_len):
            print(i, ": ", self.hand[i])
            length = i
        print("====================================================================")
        for i in range(9 - length):
            print("")

    def mulligan(self, deck, virtual=False):
        change_cards_id = self.mulligan_policy.decide(self.hand, deck)
        if not virtual:
            mylogger.info("Player{}'s hand".format(self.player_num + 1))
            self.show_hand()
            mylogger.info("change card_id:{}".format(change_cards_id))
        return_cards = [self.hand.pop(i) for i in change_cards_id[::-1]]
        self.draw(deck, len(return_cards))
        if not virtual:
            self.show_hand()
        return_cards_len = len(return_cards)
        for i in range(return_cards_len):
            deck.append(return_cards.pop())

        deck.shuffle()


    def play_card(self, field, card_id, player, opponent, virtual=False, target=None):
        if not virtual:
            mylogger.info("Player {} plays {}".format(self.player_num + 1, self.hand[card_id].name))
        if self.hand[card_id].have_enhance == True and self.hand[card_id].active_enhance_code[0] == True:
            field.remain_cost[self.player_num] -= self.hand[card_id].active_enhance_code[1]
            if not virtual:
                mylogger.info("Enhance active!")
        elif self.hand[card_id].have_accelerate and self.hand[card_id].active_accelerate_code[0]:
            field.remain_cost[self.player_num] -= self.hand[card_id].active_accelerate_code[1]
            if not virtual:
                mylogger.info("Accelerate active!")
            field.play_as_other_card(self.hand, card_id, self.player_num, virtual=virtual, target=target)
            return
        else:
            if field.remain_cost[self.player_num] - self.hand[card_id].cost < 0:
                mylogger.info("{}".format(self.hand[card_id]))
                mylogger.info("minus-pp error:{} < {}"\
                    .format(field.remain_cost[self.player_num],self.hand[card_id].cost))
                raise AssertionError
            #assert field.remain_cost[self.player_num] - self.hand[card_id].cost >= 0, "minus-pp error:{} < {}"\
            #    .format(field.remain_cost[self.player_num],self.hand[card_id].cost)
            field.remain_cost[self.player_num] -= self.hand[card_id].cost


        if self.hand[card_id].card_category == "Creature":
            field.play_creature(self.hand, card_id, self.player_num, player, opponent, virtual=virtual, target=target)
        elif self.hand[card_id].card_category == "Spell":
            field.play_spell(self.hand, card_id, self.player_num, player, opponent, virtual=virtual, target=target)
        elif self.hand[card_id].card_category == "Amulet":
            field.play_amulet(self.hand, card_id, self.player_num, player, opponent, virtual=virtual, target=target)
        field.players_play_num += 1
        field.ability_resolution(virtual=virtual, player_num=self.player_num)

    def attack_to_follower(self, field, attacker_id, target_id, virtual=False):
        field.attack_to_follower([self.player_num, attacker_id], [1 - self.player_num, target_id], field,
                                 virtual=virtual)

    def attack_to_player(self, field, attacker_id, opponent, virtual=False):
        field.attack_to_player([self.player_num, attacker_id], opponent, virtual=virtual)

    def creature_evolve(self, creature, field, target=None, virtual=False):
        assert field.evo_point[self.player_num] > 0
        field.evo_point[self.player_num] -= 1
        field.evolve(creature, virtual=virtual, target=target)

    def discard(self, hand_id, field):
        field.discard_card(self,hand_id)

    def decide(self, player, opponent, field, virtual=False,dual=False):
        field.stack.clear()
        #self.sort_hand()
        (_, _, can_be_attacked, regal_targets) = field.get_situation(self, opponent)
        (can_play, can_attack, can_evo), (able_to_play, able_to_attack, able_to_creature_attack, able_to_evo) \
            = field.get_flag_and_choices(self, opponent, regal_targets)
        if not virtual:
            observable_data = field.get_observable_data(player_num=self.player_num)
            if self.player_num == 0:
                print("first:player")
            else:
                print("first:opponent")
            player_keys = list(observable_data.keys())
            for sub_key in list(observable_data[player_keys[0]].keys()):
                print("{}:{},{}".format(sub_key,observable_data[player_keys[0]][sub_key],
                                        observable_data[player_keys[1]][sub_key]))
            #for key in list(observable_data.keys()):
            #    print("{}".format(key))
            #    for sub_key in list(observable_data[key].keys()):
            #        print("{}:{}".format(sub_key, observable_data[key][sub_key]))
            self.show_hand()
            field.show_field()
            if able_to_play != []:
                mylogger.info("able_to_play:{}".format(able_to_play))
            if able_to_creature_attack != []:
                mylogger.info(
                    "able_to_creature_attack:{} can_be_attacked:{}".format(able_to_creature_attack, can_be_attacked))
            mylogger.info("regal_targets:{}".format(regal_targets))
        #mylogger.info("check1:")
        #field.show_field()
        (action_num, card_id, target_id) = self.policy.decide(self, opponent, field)
        #mylogger.info("check2:")
        #field.show_field()
        #mylogger.info("{},{}".format(action_num,self.policy.policy_type))
        if action_num == Action_Code.ERROR.value:
            #self.policy.starting_node.print_node()
            #assert False
            self.error_count += 1
            #mylogger.info("error_count:{}".format(self.error_count))
            if self.error_count >= 3:
                self.policy.starting_node.print_tree()
                print((action_num, card_id, target_id))
                field.show_field()
                mylogger.info("{}".format(self.policy.type))
                self.policy.current_node.print_tree(single=True)
                assert False
            self.policy.current_node = None
            return self.decide(player, opponent, field, virtual=virtual,dual=dual)

        elif action_num != Action_Code.TURN_END.value and self.policy.policy_type == 4:
            #mylogger.info("adjust")
            sim_field = self.policy.prev_node.field
            action_num, card_id, target_id = adjust_action_code(field,sim_field,self.player_num,
                    action_code=(action_num, card_id, target_id), msg = action_num)


        self.error_count = 0

        if not virtual:
            mylogger.info("action_num:{} card_id:{} target_id:{}".format(action_num, card_id, target_id))
        action = (action_num, card_id, target_id)
        before_action = self.field.get_single_detailed_action_code(self,action)
        end_flg = self.execute_action(field, opponent, action_code=action, virtual=virtual)
        if dual:
            return end_flg, (action_num, card_id, target_id),before_action#(action_num, card_id)
        return end_flg

    def execute_action(self, field, opponent, action_code=None, virtual=False):
        field.reset_time_stamp()
        (action_num, card_id, target_id) = action_code
        if action_num == Action_Code.EVOLVE.value:
            self.creature_evolve(field.card_location[self.player_num][card_id],
                                 field, virtual=virtual, target=target_id)
        elif action_num == Action_Code.TURN_END.value:
            field.turn_end = True
            return True
        elif action_num == Action_Code.PLAY_CARD.value:
            if not virtual:
                if self.hand[card_id].have_enhance \
                        and self.hand[card_id].active_enhance_code[0]:
                    mylogger.info("play_cost:{}".format(self.hand[card_id].active_enhance_code[1]))
                elif self.hand[card_id].have_accelerate \
                        and self.hand[card_id].active_accelerate_code[0]:
                    mylogger.info("play_cost:{}".format(self.hand[card_id].active_accelerate_code[1]))
                else:
                    mylogger.info("play_cost:{}".format(self.hand[card_id].cost))

            self.play_card(field, card_id, self, opponent, target=target_id, virtual=virtual)


        elif action_num == Action_Code.ATTACK_TO_FOLLOWER.value:
            self.attack_to_follower(field, card_id, target_id, virtual=virtual)


        elif action_num == Action_Code.ATTACK_TO_PLAYER.value:
            #assert len(field.get_ward_list(self.player_num)) == 0,"ward_ignore_error"
            self.attack_to_player(field, card_id, opponent, virtual=virtual)


        field.ability_resolution(virtual=virtual, player_num=self.player_num)
        field.check_death(player_num=self.player_num, virtual=virtual)
        return field.check_game_end()


class HumanPlayer(Player):
    def __init__(self, max_hand_num, first=True, policy=HumanPolicy(), mulligan=None):
        self.hand = []
        self.max_hand_num = max_hand_num
        self.is_first = first
        self.player_num = 1 - int(self.is_first)
        self.life = 20
        self.max_life = 20
        self.policy = policy
        self.mulligan_policy = mulligan
        self.deck = None
        self.lib_out_flg = False
        self.field = None
        self.name = None
        self.class_num = None
        self.effect = []
        self.error_count = 0

    def get_copy(self, field):
        player = HumanPlayer(self.max_hand_num, first=self.is_first, policy=HumanPolicy(), mulligan=None)
        player.hand = list(map(field.copy_func,self.hand)) if field is not None else []
        player.life = self.life
        player.deck = Deck()
        if self.deck is not None:
            player.deck.set_leader_class(self.deck.leader_class.name)
            player.deck.deck = deque(map(field.copy_func, self.deck.deck)) if field is not None else deque()
            player.deck.remain_num = int(self.deck.remain_num)
            player.deck.deck_type = int(self.deck.deck_type)

        player.field = field
        player.name = self.name
        player.class_num = self.class_num
        player.effect = copy.copy(self.effect)
        return player

    def mulligan(self, deck, virtual=False):
        self.show_hand()
        tmp = input("input change card id(if you want to change all card,input ↑):")
        hand_len = len(self.hand)
        if tmp == "":
            return
        elif tmp == "\x1b[A":
            tmp = [i for i in range(hand_len )]
        else:
            tmp = tmp.split(",")
        # mylogger.info("tmp:{} type:{}".format(tmp, type(tmp)))
        if len(tmp) > 0:
            change_cards_id = list(map(int, tmp))
            return_cards = [self.hand.pop(i) for i in change_cards_id[::-1]]
            self.draw(deck, len(return_cards))
            self.show_hand()
            return_cards_len = len(return_cards)
            for i in range(return_cards_len):
                deck.append(return_cards.pop())

            deck.shuffle()

    def decide(self, player, opponent, field, virtual=False,dual=False):
        #os.system('clear')
        field.reset_time_stamp()

        (ward_list, can_be_targeted, can_be_attacked, regal_targets) = field.get_situation(player, opponent)

        (can_play, can_attack, can_evo), (able_to_play, able_to_attack, able_to_creature_attack, able_to_evo) \
            = field.get_flag_and_choices(player, opponent, regal_targets)
        observable_data = field.get_observable_data(player_num=self.player_num)
        if self.player_num == 0:
            print("first:player")
        else:
            print("first:opponent")
        player_keys = list(observable_data.keys())
        for sub_key in list(observable_data[player_keys[0]].keys()):
            print("{}:{},{}".format(sub_key,observable_data[player_keys[0]][sub_key],
                                    observable_data[player_keys[1]][sub_key]))

        self.show_hand()
        field.show_field()

        choices = [Action_Code.TURN_END.value]
        if can_evo:
            choices.append(Action_Code.EVOLVE.value)
        if can_play:
            choices.append(Action_Code.PLAY_CARD.value)

        if can_attack:
            if len(can_be_attacked) > 0:
                choices.append(Action_Code.ATTACK_TO_FOLLOWER.value)

            if ward_list == [] and len(able_to_attack) > 0:
                choices.append(Action_Code.ATTACK_TO_PLAYER.value)

        [print("{:<25}:{}".format(Action_Code(i).name,i))for i in choices]

        tmp = input("you can input {} :".format(choices))
        action_num = Action_Code.TURN_END.value
        if tmp == "":
            action_num = Action_Code.TURN_END.value
        elif tmp == "\x1b[C":
            self.deck.show_remain_card_set()
            input("input any key to quit remain_card_set:")
            return can_play, can_attack, field.check_game_end()
        else:
            action_num = int(tmp)
        assert action_num in choices,"{} not in {}".format(action_num,choices)
        if action_num not in choices:
            print("invalid input!")
            return can_play, can_attack, field.check_game_end()
        if action_num == Action_Code.EVOLVE.value:
            print("you can evolve:{}".format(able_to_evo))
            evo_names = ["id:{} name:{}".format(ele, field.card_location[self.player_num][ele].name) for ele in
                         able_to_evo]
            for cell in evo_names:
                mylogger.info("{}".format(cell))
            card_id = int(input("input creature id :"))
            if card_id not in able_to_evo:
                print("already evolved!")
                return can_play, can_attack, field.check_game_end()
            if field.card_location[self.player_num][card_id].evo_target is not None:
                mylogger.info("target-evolve")
                regal = field.get_regal_targets(field.card_location[self.player_num][card_id], target_type=0,
                                                player_num=self.player_num, human=True)
                mylogger.info("targets:{}".format(regal))
                if regal != []:
                    print("you can target:{}".format(regal))
                    target_id = int(input("input target_id :"))
                    if target_id not in regal:
                        print("illigal target!")
                        return can_play, can_attack, field.check_game_end()
                    self.creature_evolve(field.card_location[self.player_num][card_id], field, target=target_id)
                else:
                    mylogger.info("evolve")
                    self.creature_evolve(field.card_location[self.player_num][card_id], field)


            else:
                mylogger.info("evolve")
                self.creature_evolve(field.card_location[self.player_num][card_id], field)

        if action_num == Action_Code.TURN_END.value:
            print("Turn end")
            return True

        if action_num == Action_Code.PLAY_CARD.value:
            self.show_hand()
            print("remain cost:", field.remain_cost[self.player_num])
            print("able to play:{}".format(able_to_play))
            hand_names = ["id:{} name:{}".format(ele, self.hand[ele].name) for ele in able_to_play]
            for cell in hand_names:
                mylogger.info("{}".format(cell))
            card_id = int(input("input card id :"))
            if card_id not in able_to_play:
                print("can't play!")
                return can_play, can_attack, field.check_game_end()
            target_id = None
            if self.hand[card_id].have_target != 0:
                print("valid_targets:{}".format(regal_targets[card_id]))
                target_id = input("input target code(splited by space):")
                target_code = None
                if target_id == "":
                    if self.hand[card_id] != "Spell":
                        target_code = [None]
                    else:
                        print("you can't play spell that have target!")
                        return can_play, can_attack, field.check_game_end()


                else:
                    target_code = tuple(map(int, target_id.split(" ")))
                if len(target_code) == 1:
                    target_code = target_code[0]
                if regal_targets[card_id] == []:
                    target_code = None
                elif target_code not in regal_targets[card_id]:
                    print("Invalid target!")
                    return can_play, can_attack, field.check_game_end()
                target_id = target_code
            print("remain cost:", field.remain_cost[self.player_num])
            self.play_card(field, card_id, player, opponent, target=target_id)
            field.show_field()

        if action_num == Action_Code.ATTACK_TO_FOLLOWER.value:
            field.show_field()
            print("able_to_attack:{}".format(able_to_creature_attack))
            if len(ward_list) > 0:
                print("can_be_attacked:{}".format(ward_list))
            else:
                print("can_be_attacked:{}".format(can_be_attacked))

            card_id = int(input("input creature id you want to let attack:"))
            if card_id > field.card_num[self.player_num] - 1:
                print("invalid card id!")
                return can_play, can_attack, field.check_game_end()
            if card_id not in able_to_creature_attack:
                print("can't attack!")
                return can_play, can_attack, field.check_game_end()
            tmp = int(input("input target creature id you want to attack:"))
            if tmp not in can_be_attacked:
                mylogger.info("invalid target id!")
                return can_play, can_attack, field.check_game_end()

            if len(ward_list) == 0:
                if tmp > field.card_num[1 - self.player_num] - 1:
                    print("invalid target id!")
                    return can_play, can_attack, field.check_game_end()
            else:
                if tmp not in ward_list:
                    print("invalid target id!")
                    return can_play, can_attack, field.check_game_end()

            self.attack_to_follower(field, card_id, tmp)
            if field.card_num[self.player_num] < field.max_field_num and len(able_to_play) > 0:
                can_attack = True

        if action_num == Action_Code.ATTACK_TO_PLAYER.value:
            print("able to attack:{}".format(able_to_attack))
            card_id = input("input creature id you want to let attack:")
            if card_id == "":
                print("invalid id!")
                return can_play, can_attack, field.check_game_end()
            if int(card_id) not in able_to_attack:
                print("can't attack!")
                return can_play, can_attack, False
            card_id = int(card_id)
            self.attack_to_player(field, card_id, opponent)

        field.check_death(player_num=self.player_num, virtual=virtual)
        field.solve_field_trigger_ability(virtual=virtual, player_num=self.player_num)
        field.ability_resolution(virtual=virtual, player_num=self.player_num)
        return field.check_game_end()

# -*- coding: utf-8 -*-
import numpy as np
import random
import math
from Policy import *
from my_moduler import get_module_logger, get_state_logger
from mulligan_setting import *
from adjustment_action_code import *
mylogger = get_module_logger(__name__)
# mylogger = get_module_logger('mylogger')
import itertools

#statelogger = get_state_logger('state')
from my_enum import *


class Player:
    def __init__(self, max_hand_num, first=True, policy=RandomPolicy(), mulligan=Random_mulligan_policy()):
        self.hand = []
        self.max_hand_num = max_hand_num
        self.is_first = first
        self.player_num = 1 - int(self.is_first)
        self.life = 20
        self.max_life = 20
        self.policy = policy
        self.mulligan_policy = mulligan
        self.deck = None
        self.lib_out_flg = False
        self.field = None
        self.name = None
        self.class_num = None
        self.effect = []
        self.error_count = 0


    def get_copy(self, field):
        player = Player(self.max_hand_num, first=self.is_first, policy=self.policy, mulligan=self.mulligan_policy)
        #for card in self.hand:
        #    player.hand.append(card.get_copy())
        player.hand = list(map(field.copy_func,self.hand)) if field is not None else []
        player.life = self.life
        player.deck = Deck()
        if self.deck is not None:
            player.deck.set_leader_class(self.deck.leader_class.name)
            #for i,card in enumerate(self.deck.deck):
            #    player.deck.append(card)
            player.deck.deck = deque(map(field.copy_func, self.deck.deck)) if field is not None else deque()
            player.deck.remain_num = int(self.deck.remain_num)
            player.deck.deck_type = int(self.deck.deck_type)

        player.field = field
        player.name = self.name
        player.class_num = self.class_num
        player.effect = copy.copy(self.effect)
        #if len(self.effect) > 0:
        #player.effect = copy.deepcopy(self.effect)

        return player

    def eq(self,other):
        if self.life != other.life:
            return False
        if len(self.deck.deck) != len(other.deck.deck):
            return False
        if len(self.hand) != len(other.hand):
            return False

        checked_cards = []
        for i,card in enumerate(self.hand):
            if card in checked_cards:
                continue
            origin_count = 0
            other_count = 0
            for player_card in self.hand:
                if player_card.eq(card):
                    origin_count += 1
            for other_card in other.hand:
                if other_card.eq(card):
                    other_count += 1
            if origin_count != other_count:
                return False
            checked_cards.append(card)

        return True

    def compare_hand(self,other_hand):
        checked_cards = []
        for i,card in enumerate(self.hand):
            if card in checked_cards:
                continue
            origin_count = 0
            other_count = 0
            for player_card in self.hand:
                if player_card.eq(card):
                    origin_count += 1
            for other_card in other_hand:
                if other_card.eq(card):
                    other_count += 1
            if origin_count != other_count:
                return False
            checked_cards.append(card)

        return True

    def sort_hand(self):
        self.hand.sort(key = lambda card:card.name)

    def get_damage(self, damage):
        if len(self.effect) > 0:
            tmp = int(damage)
            priority_list = list(set([effect.proirity for effect in self.effect]))
            priority_list = sorted(priority_list, reverse=True)

            for i in priority_list:
                for effect in self.effect:
                    if effect.priority == i:
                        tmp = effect(argument=tmp, state_code=State_Code.GET_DAMAGE.value)
            return tmp
        else:
            self.life -= damage
            return damage

    def restore_player_life(self, num=0, virtual=False):
        self.field.restore_player_life(player=self, num=num, virtual=virtual)

    def check_vengeance(self):
        return self.life <= 10

    def check_overflow(self):
        return self.field.cost[self.player_num] >= 7

    def check_resonance(self):
        return len(self.deck.deck) % 2 == 0

    def draw(self, deck, num):
        for i in range(num):
            if len(deck.deck) == 0:
                self.lib_out_flg = True
                return
            card = deck.draw()
            self.field.drawn_cards.append(card,self.player_num)
            self.hand.append(card)
            if len(self.hand) > self.max_hand_num:
                self.field.graveyard.shadows[self.player_num] += 1
                self.hand.pop(-1)

    def append_cards_to_hand(self, cards):
        for card in cards:
            self.hand.append(card)
            if len(self.hand) > self.max_hand_num:
                self.field.graveyard.shadows[self.player_num] += 1
                self.hand.pop(-1)

    def show_hand(self):
        length = 0
        print("Player", self.player_num + 1, "'s hand")
        print("====================================================================")
        hand_len = len(self.hand)
        for i in range(hand_len):
            print(i, ": ", self.hand[i])
            length = i
        print("====================================================================")
        for i in range(9 - length):
            print("")

    def mulligan(self, deck, virtual=False):
        change_cards_id = self.mulligan_policy.decide(self.hand, deck)
        if not virtual:
            mylogger.info("Player{}'s hand".format(self.player_num + 1))
            self.show_hand()
            mylogger.info("change card_id:{}".format(change_cards_id))
        return_cards = [self.hand.pop(i) for i in change_cards_id[::-1]]
        self.draw(deck, len(return_cards))
        if not virtual:
            self.show_hand()
        return_cards_len = len(return_cards)
        for i in range(return_cards_len):
            deck.append(return_cards.pop())

        deck.shuffle()


    def play_card(self, field, card_id, player, opponent, virtual=False, target=None):
        if not virtual:
            mylogger.info("Player {} plays {}".format(self.player_num + 1, self.hand[card_id].name))
        if self.hand[card_id].have_enhance == True and self.hand[card_id].active_enhance_code[0] == True:
            field.remain_cost[self.player_num] -= self.hand[card_id].active_enhance_code[1]
            if not virtual:
                mylogger.info("Enhance active!")
        elif self.hand[card_id].have_accelerate and self.hand[card_id].active_accelerate_code[0]:
            field.remain_cost[self.player_num] -= self.hand[card_id].active_accelerate_code[1]
            if not virtual:
                mylogger.info("Accelerate active!")
            field.play_as_other_card(self.hand, card_id, self.player_num, virtual=virtual, target=target)
            return
        else:
            if field.remain_cost[self.player_num] - self.hand[card_id].cost < 0:
                mylogger.info("{}".format(self.hand[card_id]))
                mylogger.info("minus-pp error:{} < {}"\
                    .format(field.remain_cost[self.player_num],self.hand[card_id].cost))
                raise AssertionError
            #assert field.remain_cost[self.player_num] - self.hand[card_id].cost >= 0, "minus-pp error:{} < {}"\
            #    .format(field.remain_cost[self.player_num],self.hand[card_id].cost)
            field.remain_cost[self.player_num] -= self.hand[card_id].cost


        if self.hand[card_id].card_category == "Creature":
            field.play_creature(self.hand, card_id, self.player_num, player, opponent, virtual=virtual, target=target)
        elif self.hand[card_id].card_category == "Spell":
            field.play_spell(self.hand, card_id, self.player_num, player, opponent, virtual=virtual, target=target)
        elif self.hand[card_id].card_category == "Amulet":
            field.play_amulet(self.hand, card_id, self.player_num, player, opponent, virtual=virtual, target=target)
        field.players_play_num += 1
        field.ability_resolution(virtual=virtual, player_num=self.player_num)

    def attack_to_follower(self, field, attacker_id, target_id, virtual=False):
        field.attack_to_follower([self.player_num, attacker_id], [1 - self.player_num, target_id], field,
                                 virtual=virtual)

    def attack_to_player(self, field, attacker_id, opponent, virtual=False):
        field.attack_to_player([self.player_num, attacker_id], opponent, virtual=virtual)

    def creature_evolve(self, creature, field, target=None, virtual=False):
        assert field.evo_point[self.player_num] > 0
        field.evo_point[self.player_num] -= 1
        field.evolve(creature, virtual=virtual, target=target)

    def discard(self, hand_id, field):
        field.discard_card(self,hand_id)

    def decide(self, player, opponent, field, virtual=False,dual=False):
        field.stack.clear()
        #self.sort_hand()
        (_, _, can_be_attacked, regal_targets) = field.get_situation(self, opponent)
        (can_play, can_attack, can_evo), (able_to_play, able_to_attack, able_to_creature_attack, able_to_evo) \
            = field.get_flag_and_choices(self, opponent, regal_targets)
        if not virtual:
            observable_data = field.get_observable_data(player_num=self.player_num)
            if self.player_num == 0:
                print("first:player")
            else:
                print("first:opponent")
            player_keys = list(observable_data.keys())
            for sub_key in list(observable_data[player_keys[0]].keys()):
                print("{}:{},{}".format(sub_key,observable_data[player_keys[0]][sub_key],
                                        observable_data[player_keys[1]][sub_key]))
            #for key in list(observable_data.keys()):
            #    print("{}".format(key))
            #    for sub_key in list(observable_data[key].keys()):
            #        print("{}:{}".format(sub_key, observable_data[key][sub_key]))
            self.show_hand()
            field.show_field()
            if able_to_play != []:
                mylogger.info("able_to_play:{}".format(able_to_play))
            if able_to_creature_attack != []:
                mylogger.info(
                    "able_to_creature_attack:{} can_be_attacked:{}".format(able_to_creature_attack, can_be_attacked))
            mylogger.info("regal_targets:{}".format(regal_targets))
        #mylogger.info("check1:")
        #field.show_field()
        (action_num, card_id, target_id) = self.policy.decide(self, opponent, field)
        #mylogger.info("check2:")
        #field.show_field()
        #mylogger.info("{},{}".format(action_num,self.policy.policy_type))
        if action_num == Action_Code.ERROR.value:
            #self.policy.starting_node.print_node()
            #assert False
            self.error_count += 1
            #mylogger.info("error_count:{}".format(self.error_count))
            if self.error_count >= 3:
                self.policy.starting_node.print_tree()
                print((action_num, card_id, target_id))
                field.show_field()
                mylogger.info("{}".format(self.policy.type))
                self.policy.current_node.print_tree(single=True)
                assert False
            self.policy.current_node = None
            return self.decide(player, opponent, field, virtual=virtual,dual=dual)

        elif action_num != Action_Code.TURN_END.value and self.policy.policy_type == 4:
            #mylogger.info("adjust")
            sim_field = self.policy.prev_node.field
            action_num, card_id, target_id = adjust_action_code(field,sim_field,self.player_num,
                    action_code=(action_num, card_id, target_id), msg = action_num)


        self.error_count = 0

        if not virtual:
            mylogger.info("action_num:{} card_id:{} target_id:{}".format(action_num, card_id, target_id))
        action = (action_num, card_id, target_id)
        before_action = self.field.get_single_detailed_action_code(self,action)
        end_flg = self.execute_action(field, opponent, action_code=action, virtual=virtual)
        if dual:
            return end_flg, (action_num, card_id, target_id),before_action#(action_num, card_id)
        return end_flg

    def execute_action(self, field, opponent, action_code=None, virtual=False):
        field.reset_time_stamp()
        (action_num, card_id, target_id) = action_code
        if action_num == Action_Code.EVOLVE.value:
            self.creature_evolve(field.card_location[self.player_num][card_id],
                                 field, virtual=virtual, target=target_id)
        elif action_num == Action_Code.TURN_END.value:
            field.turn_end = True
            return True
        elif action_num == Action_Code.PLAY_CARD.value:
            if not virtual:
                if self.hand[card_id].have_enhance \
                        and self.hand[card_id].active_enhance_code[0]:
                    mylogger.info("play_cost:{}".format(self.hand[card_id].active_enhance_code[1]))
                elif self.hand[card_id].have_accelerate \
                        and self.hand[card_id].active_accelerate_code[0]:
                    mylogger.info("play_cost:{}".format(self.hand[card_id].active_accelerate_code[1]))
                else:
                    mylogger.info("play_cost:{}".format(self.hand[card_id].cost))

            self.play_card(field, card_id, self, opponent, target=target_id, virtual=virtual)


        elif action_num == Action_Code.ATTACK_TO_FOLLOWER.value:
            self.attack_to_follower(field, card_id, target_id, virtual=virtual)


        elif action_num == Action_Code.ATTACK_TO_PLAYER.value:
            #assert len(field.get_ward_list(self.player_num)) == 0,"ward_ignore_error"
            self.attack_to_player(field, card_id, opponent, virtual=virtual)


        field.ability_resolution(virtual=virtual, player_num=self.player_num)
        field.check_death(player_num=self.player_num, virtual=virtual)
        return field.check_game_end()


class HumanPlayer(Player):
    def __init__(self, max_hand_num, first=True, policy=HumanPolicy(), mulligan=None):
        self.hand = []
        self.max_hand_num = max_hand_num
        self.is_first = first
        self.player_num = 1 - int(self.is_first)
        self.life = 20
        self.max_life = 20
        self.policy = policy
        self.mulligan_policy = mulligan
        self.deck = None
        self.lib_out_flg = False
        self.field = None
        self.name = None
        self.class_num = None
        self.effect = []
        self.error_count = 0

    def get_copy(self, field):
        player = HumanPlayer(self.max_hand_num, first=self.is_first, policy=HumanPolicy(), mulligan=None)
        player.hand = list(map(field.copy_func,self.hand)) if field is not None else []
        player.life = self.life
        player.deck = Deck()
        if self.deck is not None:
            player.deck.set_leader_class(self.deck.leader_class.name)
            player.deck.deck = deque(map(field.copy_func, self.deck.deck)) if field is not None else deque()
            player.deck.remain_num = int(self.deck.remain_num)
            player.deck.deck_type = int(self.deck.deck_type)

        player.field = field
        player.name = self.name
        player.class_num = self.class_num
        player.effect = copy.copy(self.effect)
        return player

    def mulligan(self, deck, virtual=False):
        self.show_hand()
        tmp = input("input change card id(if you want to change all card,input ↑):")
        hand_len = len(self.hand)
        if tmp == "":
            return
        elif tmp == "\x1b[A":
            tmp = [i for i in range(hand_len )]
        else:
            tmp = tmp.split(",")
        # mylogger.info("tmp:{} type:{}".format(tmp, type(tmp)))
        if len(tmp) > 0:
            change_cards_id = list(map(int, tmp))
            return_cards = [self.hand.pop(i) for i in change_cards_id[::-1]]
            self.draw(deck, len(return_cards))
            self.show_hand()
            return_cards_len = len(return_cards)
            for i in range(return_cards_len):
                deck.append(return_cards.pop())

            deck.shuffle()

    def decide(self, player, opponent, field, virtual=False,dual=False):
        #os.system('clear')
        field.reset_time_stamp()

        (ward_list, can_be_targeted, can_be_attacked, regal_targets) = field.get_situation(player, opponent)

        (can_play, can_attack, can_evo), (able_to_play, able_to_attack, able_to_creature_attack, able_to_evo) \
            = field.get_flag_and_choices(player, opponent, regal_targets)
        observable_data = field.get_observable_data(player_num=self.player_num)
        if self.player_num == 0:
            print("first:player")
        else:
            print("first:opponent")
        player_keys = list(observable_data.keys())
        for sub_key in list(observable_data[player_keys[0]].keys()):
            print("{}:{},{}".format(sub_key,observable_data[player_keys[0]][sub_key],
                                    observable_data[player_keys[1]][sub_key]))

        self.show_hand()
        field.show_field()

        choices = [Action_Code.TURN_END.value]
        if can_evo:
            choices.append(Action_Code.EVOLVE.value)
        if can_play:
            choices.append(Action_Code.PLAY_CARD.value)

        if can_attack:
            if len(can_be_attacked) > 0:
                choices.append(Action_Code.ATTACK_TO_FOLLOWER.value)

            if ward_list == [] and len(able_to_attack) > 0:
                choices.append(Action_Code.ATTACK_TO_PLAYER.value)

        [print("{:<25}:{}".format(Action_Code(i).name,i))for i in choices]

        tmp = input("you can input {} :".format(choices))
        action_num = Action_Code.TURN_END.value
        if tmp == "":
            action_num = Action_Code.TURN_END.value
        elif tmp == "\x1b[C":
            self.deck.show_remain_card_set()
            input("input any key to quit remain_card_set:")
            return can_play, can_attack, field.check_game_end()
        else:
            action_num = int(tmp)
        assert action_num in choices,"{} not in {}".format(action_num,choices)
        if action_num not in choices:
            print("invalid input!")
            return can_play, can_attack, field.check_game_end()
        if action_num == Action_Code.EVOLVE.value:
            print("you can evolve:{}".format(able_to_evo))
            evo_names = ["id:{} name:{}".format(ele, field.card_location[self.player_num][ele].name) for ele in
                         able_to_evo]
            for cell in evo_names:
                mylogger.info("{}".format(cell))
            card_id = int(input("input creature id :"))
            if card_id not in able_to_evo:
                print("already evolved!")
                return can_play, can_attack, field.check_game_end()
            if field.card_location[self.player_num][card_id].evo_target is not None:
                mylogger.info("target-evolve")
                regal = field.get_regal_targets(field.card_location[self.player_num][card_id], target_type=0,
                                                player_num=self.player_num, human=True)
                mylogger.info("targets:{}".format(regal))
                if regal != []:
                    print("you can target:{}".format(regal))
                    target_id = int(input("input target_id :"))
                    if target_id not in regal:
                        print("illigal target!")
                        return can_play, can_attack, field.check_game_end()
                    self.creature_evolve(field.card_location[self.player_num][card_id], field, target=target_id)
                else:
                    mylogger.info("evolve")
                    self.creature_evolve(field.card_location[self.player_num][card_id], field)


            else:
                mylogger.info("evolve")
                self.creature_evolve(field.card_location[self.player_num][card_id], field)

        if action_num == Action_Code.TURN_END.value:
            print("Turn end")
            return True

        if action_num == Action_Code.PLAY_CARD.value:
            self.show_hand()
            print("remain cost:", field.remain_cost[self.player_num])
            print("able to play:{}".format(able_to_play))
            hand_names = ["id:{} name:{}".format(ele, self.hand[ele].name) for ele in able_to_play]
            for cell in hand_names:
                mylogger.info("{}".format(cell))
            card_id = int(input("input card id :"))
            if card_id not in able_to_play:
                print("can't play!")
                return can_play, can_attack, field.check_game_end()
            target_id = None
            if self.hand[card_id].have_target != 0:
                print("valid_targets:{}".format(regal_targets[card_id]))
                target_id = input("input target code(splited by space):")
                target_code = None
                if target_id == "":
                    if self.hand[card_id] != "Spell":
                        target_code = [None]
                    else:
                        print("you can't play spell that have target!")
                        return can_play, can_attack, field.check_game_end()


                else:
                    target_code = tuple(map(int, target_id.split(" ")))
                if len(target_code) == 1:
                    target_code = target_code[0]
                if regal_targets[card_id] == []:
                    target_code = None
                elif target_code not in regal_targets[card_id]:
                    print("Invalid target!")
                    return can_play, can_attack, field.check_game_end()
                target_id = target_code
            print("remain cost:", field.remain_cost[self.player_num])
            self.play_card(field, card_id, player, opponent, target=target_id)
            field.show_field()

        if action_num == Action_Code.ATTACK_TO_FOLLOWER.value:
            field.show_field()
            print("able_to_attack:{}".format(able_to_creature_attack))
            if len(ward_list) > 0:
                print("can_be_attacked:{}".format(ward_list))
            else:
                print("can_be_attacked:{}".format(can_be_attacked))

            card_id = int(input("input creature id you want to let attack:"))
            if card_id > field.card_num[self.player_num] - 1:
                print("invalid card id!")
                return can_play, can_attack, field.check_game_end()
            if card_id not in able_to_creature_attack:
                print("can't attack!")
                return can_play, can_attack, field.check_game_end()
            tmp = int(input("input target creature id you want to attack:"))
            if tmp not in can_be_attacked:
                mylogger.info("invalid target id!")
                return can_play, can_attack, field.check_game_end()

            if len(ward_list) == 0:
                if tmp > field.card_num[1 - self.player_num] - 1:
                    print("invalid target id!")
                    return can_play, can_attack, field.check_game_end()
            else:
                if tmp not in ward_list:
                    print("invalid target id!")
                    return can_play, can_attack, field.check_game_end()

            self.attack_to_follower(field, card_id, tmp)
            if field.card_num[self.player_num] < field.max_field_num and len(able_to_play) > 0:
                can_attack = True

        if action_num == Action_Code.ATTACK_TO_PLAYER.value:
            print("able to attack:{}".format(able_to_attack))
            card_id = input("input creature id you want to let attack:")
            if card_id == "":
                print("invalid id!")
                return can_play, can_attack, field.check_game_end()
            if int(card_id) not in able_to_attack:
                print("can't attack!")
                return can_play, can_attack, False
            card_id = int(card_id)
            self.attack_to_player(field, card_id, opponent)

        field.check_death(player_num=self.player_num, virtual=virtual)
        field.solve_field_trigger_ability(virtual=virtual, player_num=self.player_num)
        field.ability_resolution(virtual=virtual, player_num=self.player_num)
        return field.check_game_end()

# -*- coding: utf-8 -*- # mylogger = get_module_logger('mylogger') #statelogger = get_state_logger('state') #for card in self.hand: #    player.hand.append(card.get_copy()) #for i,card in enumerate(self.deck.deck): #    player.deck.append(card) #if len(self.effect) > 0: #player.effect = copy.deepcopy(self.effect) #assert field.remain_cost[self.player_num] - self.hand[card_id].cost >= 0, "minus-pp error:{} < {}"\ #    .format(field.remain_cost[self.player_num],self.hand[card_id].cost) #self.sort_hand() #for key in list(observable_data.keys()): #    print("{}".format(key)) #    for sub_key in list(observable_data[key].keys()): #        print("{}:{}".format(sub_key, observable_data[key][sub_key])) #mylogger.info("check1:") #field.show_field() #mylogger.info("check2:") #field.show_field() #mylogger.info("{},{}".format(action_num,self.policy.policy_type)) #self.policy.starting_node.print_node() #assert False #mylogger.info("error_count:{}".format(self.error_count)) #mylogger.info("adjust") #(action_num, card_id) #assert len(field.get_ward_list(self.player_num)) == 0,"ward_ignore_error" # mylogger.info("tmp:{} type:{}".format(tmp, type(tmp))) #os.system('clear')