コード例 #1
0
ファイル: test_board.py プロジェクト: jpghacct/pyduel_engine
 def setUp(self):
     self.char1 = Character({'max_hp': 18, 'type': CharType.main,
                             'side': SqState.light, 'pos': Pos(0, 0)})
     self.char2 = Character({'max_hp': 19, 'type': CharType.main,
                             'side': SqState.dark, 'pos': Pos(6, 6)})
     self.pos = Pos(5, 6)
     self.b1 = Board({})
     self.b2 = Board({'name': 'ruins', 'board_type': BoardType.dais})
コード例 #2
0
ファイル: engine.py プロジェクト: jpghacct/pyduel_engine
 def __init__(self, kwargs):
     """Initializer for Engine"""
     self.num_players = kwargs.get('num_players', 0)
     self.turn = kwargs.get('turn', 0)
     self.round_num = kwargs.get('round', 0)
     self.phase = kwargs.get('phase', None)
     self.active_action = kwargs.get('action', None)
     self.active_char = kwargs.get('active_char', None)
     self.target_char = kwargs.get('target_char', None)
     self.target_squad = kwargs.get('target_squad', None)
     self.active_card = kwargs.get('active_card', None)
     self.def_card = kwargs.get('def_card', None)
     self.board = Board({'board_type': kwargs.get('board_type', None)})
     self.squads = kwargs.get('squads')
     self.num_squads = kwargs.get('num_squads', 0)
     self.dice = Dice()
コード例 #3
0
ファイル: test_board.py プロジェクト: jpghacct/pyduel_engine
class TestBoard(unittest.TestCase):

    def setUp(self):
        self.char1 = Character({'max_hp': 18, 'type': CharType.main,
                                'side': SqState.light, 'pos': Pos(0, 0)})
        self.char2 = Character({'max_hp': 19, 'type': CharType.main,
                                'side': SqState.dark, 'pos': Pos(6, 6)})
        self.pos = Pos(5, 6)
        self.b1 = Board({})
        self.b2 = Board({'name': 'ruins', 'board_type': BoardType.dais})

    # ############################# __str__ #################################

    def test_string_method(self):
        self.b2.set_sqr_state(Pos(0, 0), SqState.light)
        self.b2.set_sqr_state(Pos(0, 1), SqState.dark)
        self.assertEqual(self.b2.__str__(), 'BoardType.dais\n'
                                            '    0123456789\n'
                                            '--------------\n'
                                            '0 | LOOOOOEEEE\n'
                                            '1 | DOEEEEEHEH\n'
                                            '2 | EEEEEEHHEH\n'
                                            '3 | EEEEEEEEEE\n'
                                            '4 | EEEEEEHHEH\n'
                                            '5 | OOEEEEEHEH\n'
                                            '6 | OOOOOOEEEE\n')

    # ######################## square_state ##################################

    def test_square_state_board_empty_true(self):
        self.assertEqual(self.b1.get_sqr_state(self.pos), SqState.empty)

    def test_square_state_board_empty_false(self):
        self.assertNotEqual(self.b1.get_sqr_state(self.pos), SqState.light)

    # ######################## is_diagonal ####################################

    def test_if_square_is_diagonal_true(self):
        self.assertTrue((self.char1.pos, self.char2.pos))

    def test_if_square_is_diagonal_false(self):
        self.char2.pos = self.pos
        self.assertFalse(self.char1.pos.is_diagonal(self.char2.pos))

    # ######################## is_parallel ####################################

    def test_if_squares_are_parallel_false(self):
        self.assertFalse(self.char1.pos.is_parallel(self.char2.pos))

    def test_if_squares_are_parallel_true(self):
        self.char2.pos = Pos(0, 6)
        self.assertTrue(self.char1.pos.is_parallel(self.char2.pos))

    # ####################### is_adj ####################################

    def test_if_squares_are_adj_false(self):
        self.assertFalse(self.char1.pos.is_adj(self.char2.pos))

    def test_if_squares_are_adj_true(self):
        self.char2.pos = Pos(0, 1)
        self.assertTrue(self.char1.pos.is_adj(self.char2.pos))

    # ######################## is_parallel_clear ##############################

    def test_if_parallel_squares_clear_false_not_parallel(self):
        self.assertFalse(self.b1.is_parallel_clr(self.char1.pos,
                                                 self.char2.pos))

    def test_parallel_squares_clear_on_x_axis_orig_lt_target_true(self):
        self.assertTrue(self.b1.is_parallel_clr(Pos(2, 2), Pos(2, 5)))

    def test_parallel_squares_clear_on_x_axis_orig_gt_target_true(self):
        self.assertTrue(self.b1.is_parallel_clr(Pos(2, 5), Pos(2, 2)))

    def test_parallel_squares_clear_on_x_axis_target_lt_orig_true(self):
        self.assertTrue(self.b1.is_parallel_clr(Pos(2, 2), Pos(2, 5)))

    def test_parallel_squares_clear_on_x_axis_target_gt_orig_true(self):
        self.assertTrue(self.b1.is_parallel_clr(Pos(2, 2), Pos(5, 2)))

    def test_parallel_squares_clear_on_x_axis_adj_true(self):
        self.assertTrue(self.b1.is_parallel_clr(Pos(2, 2), Pos(2, 3)))

    def test_parallel_squares_clear_on_y_axis_orig_gt_target_true(self):
        self.assertTrue(self.b1.is_parallel_clr(Pos(5, 2), Pos(2, 2)))

    def test_parallel_squares_are_clear_on_x_plane_adj_false(self):
        self.b1.board[0][3]['state'] = SqState.obstacle
        self.assertFalse(self.b1.is_parallel_clr(Pos(0, 0), Pos(0, 6)))

    def test_parallel_squares_are_clear_on_y_plane_adj_false(self):
        self.b1.board[3][0]['state'] = SqState.obstacle
        self.assertFalse(self.b1.is_parallel_clr(Pos(0, 0), Pos(6, 0)))

    # ######################## is_diagonal_clear ##############################

    def test_board_is_diagonal_clear_true(self):
        self.assertTrue(self.b1.is_diagonal_clr(Pos(1, 3), Pos(4, 0)))

    def test_board_is_diagonal_clear_true_inverse(self):
        self.assertTrue(self.b1.is_diagonal_clr(Pos(1, 3), Pos(4, 0)))

    def test_board_is_diagonal_clear_false(self):
        self.b1.board[2][2]['state'] = SqState.dark
        self.assertFalse(self.b1.is_diagonal_clr(Pos(1, 3), Pos(4, 0)))

    # ####################### is_obstructed ##############################

    def test_is_obstructed_surrounded_true(self):
        self.char1.pos = Pos(3, 5)
        self.b1.board[3][6]['state'] = SqState.dark
        self.b1.board[4][5]['state'] = SqState.dark
        self.b1.board[2][5]['state'] = SqState.dark
        self.b1.board[3][4]['state'] = SqState.dark
        self.assertTrue(self.b1.is_obstructed(self.char1))

    def test_is_obstructed_obstacles_true(self):
        self.char1.pos = Pos(3, 5)
        self.b1.board[3][6]['state'] = SqState.obstacle
        self.b1.board[4][5]['state'] = SqState.obstacle
        self.b1.board[2][5]['state'] = SqState.obstacle
        self.b1.board[3][4]['state'] = SqState.obstacle
        self.assertTrue(self.b1.is_obstructed(self.char1))

    def test_is_obstructed_false_one_friendly(self):
        self.char1.pos = Pos(3, 5)
        self.b1.board[3][6]['state'] = SqState.light
        self.b1.board[4][5]['state'] = SqState.dark
        self.b1.board[2][5]['state'] = SqState.dark
        self.b1.board[3][4]['state'] = SqState.dark
        self.assertFalse(self.b1.is_obstructed(self.char1))

    def test_is_obstructed_false_one_empty(self):
        self.char1.pos = Pos(3, 5)
        self.b1.board[3][6]['state'] = SqState.dark
        self.b1.board[4][5]['state'] = SqState.dark
        self.b1.board[2][5]['state'] = SqState.dark
        self.b1.board[3][4]['state'] = SqState.empty
        self.assertFalse(self.b1.is_obstructed(self.char1))

    # ######################## is_out_of_bounds ##############################

    def test_is_out_of_bounds_true_x(self):
        self.assertTrue(self.b1.out_of_bounds(Pos(10, 6)))

    def test_is_out_of_bounds_true_y(self):
        self.assertTrue(self.b1.out_of_bounds(Pos(7, 9)))

    def test_is_out_of_bounds_false(self):
        self.assertFalse(self.b1.out_of_bounds(Pos(9, 6)))

    # ######################## can_move_through ##############################

    def test_can_move_through_true_empty(self):
        self.b1.board[3][5]['state'] = SqState.empty
        self.assertTrue(self.b1.can_move_through(self.char1, Pos(3, 5)))

    def test_can_move_through_true_ally(self):
        self.b1.board[3][5]['state'] = SqState.light
        self.assertTrue(self.b1.can_move_through(SqState.light, Pos(3, 5)))

    def test_can_move_through_false_enemy(self):
        self.b1.board[3][5]['state'] = SqState.dark
        self.assertFalse(self.b1.can_move_through(self.char1, Pos(3, 5)))

    def test_can_move_through_false_hole(self):
        self.b1.board[3][5]['state'] = SqState.hole
        self.assertFalse(self.b1.can_move_through(self.char1, Pos(3, 5)))

    def test_can_move_through_false_obstacle(self):
        self.b1.board[3][5]['state'] = SqState.obstacle
        self.assertFalse(self.b1.can_move_through(self.char1, Pos(3, 5)))

    # ######################## is_valid_move ##############################
    # already covered out_of_bounds and can_move_through methods

    # ######################## can_target ##############################

    def test_can_target_attack_ally_adj(self):
        self.char2.pos = Pos(0, 1)
        self.assertTrue(self.b1.can_target(self.char1, self.char2))

    def test_can_target_attack_false(self):
        self.char1.is_range = False
        self.assertFalse(self.b1.can_target(self.char1, self.char2))

    def test_can_target_attack_true(self):
        self.char1.is_range = True
        self.assertTrue(self.b1.can_target(self.char1, self.char2))

    # ######################## find_moves ##############################

    def test_find_moves_roll_1_true(self):
        self.char1.pos = Pos(3, 4)
        self.assertEqual(len(self.b1.find_moves(self.char1, 1)), 5)

    def test_find_moves_roll_2_true(self):
        self.char1.pos = Pos(3, 4)
        self.assertEqual(len(self.b1.find_moves(self.char1, 2)), 13)

    def test_find_moves_roll_3_true(self):
        self.char1.pos = Pos(3, 4)
        self.assertEqual(len(self.b1.find_moves(self.char1, 3)), 24)

    def test_find_moves_roll_4_true(self):
        self.char1.pos = Pos(3, 4)
        self.assertEqual(len(self.b1.find_moves(self.char1, 4)), 36)

    def test_find_moves_roll_5_true(self):
        self.char1.pos = Pos(3, 4)
        self.assertEqual(len(self.b1.find_moves(self.char1, 5)), 47)

    # ######################## get_adj_empty ##############################

    def test_get_adj_empty_pos_out_of_bounds(self):
        self.assertEqual(self.b1.get_adj_empty_pos(Pos(-1, -1)), [])

    def test_get_adj_empty_pos_none(self):
        self.b1.board[4][3]['state'] = SqState.light
        self.b1.board[4][5]['state'] = SqState.light
        self.b1.board[3][4]['state'] = SqState.light
        self.b1.board[5][4]['state'] = SqState.light
        self.b1.board[3][3]['state'] = SqState.light
        self.b1.board[3][5]['state'] = SqState.light
        self.b1.board[5][3]['state'] = SqState.light
        self.b1.board[5][5]['state'] = SqState.light
        self.assertEqual(self.b1.get_adj_empty_pos(Pos(4, 4)), [])

    def test_get_adj_empty_pos_4(self):
        self.b1.board[3][3]['state'] = SqState.light
        self.b1.board[3][5]['state'] = SqState.light
        self.b1.board[5][3]['state'] = SqState.light
        self.b1.board[5][5]['state'] = SqState.light
        self.assertEqual(self.b1.get_adj_empty_pos(Pos(4, 4)),
                         [Pos(4, 3), Pos(4, 5), Pos(3, 4), Pos(5, 4)])

    # ######################## get_adj_empty ##############################

    def test_print_board_state(self):
        self.b2.set_sqr_state(Pos(0, 0), SqState.light)
        self.b2.set_sqr_state(Pos(0, 1), SqState.dark)
        self.assertEqual(
            self.b2.print_board_coordinates(),
            'BoardType.dais\n'
            '     0    1    2    3    4    5    6    7    8    9   \n'
            '------------------------------------------------------\n'
            '0 | (0,0)(1,0)(2,0)(3,0)(4,0)(5,0)(6,0)(7,0)(8,0)(9,0)\n'
            '1 | (0,1)(1,1)(2,1)(3,1)(4,1)(5,1)(6,1)(7,1)(8,1)(9,1)\n'
            '2 | (0,2)(1,2)(2,2)(3,2)(4,2)(5,2)(6,2)(7,2)(8,2)(9,2)\n'
            '3 | (0,3)(1,3)(2,3)(3,3)(4,3)(5,3)(6,3)(7,3)(8,3)(9,3)\n'
            '4 | (0,4)(1,4)(2,4)(3,4)(4,4)(5,4)(6,4)(7,4)(8,4)(9,4)\n'
            '5 | (0,5)(1,5)(2,5)(3,5)(4,5)(5,5)(6,5)(7,5)(8,5)(9,5)\n'
            '6 | (0,6)(1,6)(2,6)(3,6)(4,6)(5,6)(6,6)(7,6)(8,6)(9,6)\n')
コード例 #4
0
ファイル: engine.py プロジェクト: jpghacct/pyduel_engine
class Engine(object):

    def __init__(self, kwargs):
        """Initializer for Engine"""
        self.num_players = kwargs.get('num_players', 0)
        self.turn = kwargs.get('turn', 0)
        self.round_num = kwargs.get('round', 0)
        self.phase = kwargs.get('phase', None)
        self.active_action = kwargs.get('action', None)
        self.active_char = kwargs.get('active_char', None)
        self.target_char = kwargs.get('target_char', None)
        self.target_squad = kwargs.get('target_squad', None)
        self.active_card = kwargs.get('active_card', None)
        self.def_card = kwargs.get('def_card', None)
        self.board = Board({'board_type': kwargs.get('board_type', None)})
        self.squads = kwargs.get('squads')
        self.num_squads = kwargs.get('num_squads', 0)
        self.dice = Dice()

    def __repr__(self):
        return 'Num Players:{0}\tRound: {1}\tTurn: {2}\tDice: {3}' \
               '\tSquads: {4}\n{5}'.format(self.num_players, self.round_num,
                                           self.turn, self.dice, self.squads,
                                           self.board)

    ##########################################################################
    ######################################################

    def active_squad(self):
        return self.squads[self.turn]

    def target_squad(self):
        return self.squads[self.target_squad]

    ##########################################################################
    # ###################### Board Init functions ############################
    ##########################################################################

    def shuffle_all_decks(self):
        for squad in self.squads:
            squad.deck_shuffle()

    def randomly_place_minor_characters(self):
        # place secondary characters
        for squad in self.squads:
            pos = self.find_minor_placement(squad)
            # print(pos)
            shuffle(pos)
            # hard coding the first two positions for the minor chars
            self.move_char(squad.chars['minor1'], pos[0])
            self.move_char(squad.chars['minor2'], pos[1])

    ##########################################################################
    #                        Game Rules
    ##########################################################################

    def is_game_over(self):
        """returns true if all main dark or light side characters are dead"""
        return (sum(squad.chars['main'].hp for squad in self.squads
                    if squad.side == Sqr.light) == 0) or \
               (sum(squad.chars['main'].hp for squad in self.squads
                    if squad.side == Sqr.dark) == 0)

    # TODO : decrement number of squads as they are defeated

    def can_attack(self, char, target):
        """verify if legal target"""
        if not char.is_range and not char.is_adj(target):
            return False
        return char.side != target.side

    # def can_melee_attack(self, char):
    #     """verify if target can be melee attacked"""
    #     return self.active_char().is_legal_target(char) and self.is_adj(char)

    ###########################################################################
    #                     Movement and Placement
    ###########################################################################

    def move_char(self, char, pos):
        self.board.board[pos.x][pos.y]['state'] = char.side
        if char.pos is not None:
            self.board.make_empty(char.pos)
        char.pos = pos
        logging.info("{0} moved to {1}".format(char.name, pos))

    def remove_char(self, char):
        if char.pos:
            self.board.make_empty(char.pos)
        char.pos = None
        logging.info("{0} removed from the board".format(char.name))

    def find_squad_moves(self, active_chars):
        """returns dictionary of active characters in a squad and all their
        possible moves based on the current dice state
        """
        squad_moves = {}

        for key in active_chars:
            squad_moves[key] = self.get_possible_moves(
                self.active_squad().chars[key])
        return squad_moves

    def move_squad(self, squad_pos, squad_num=None):
        """takes in dictionary of squad moves {'main': Pos, """
        # get list of active characters to know how many loops to iterate
        if squad_num:
            squad = self.squads[squad_num]
        else:
            squad = self.active_squad()

        for k, char in squad.chars.items():
            self.move_char(char, squad_pos[k])

    # def _place_minor_random(self):
    #     """Places minor characters randomly if no pos supplied"""
    #     for squad in self.squads:
    #         list_pos = self.board.get_adj_empty_pos(squad.chars['main'].pos)
    #         self.move_char(squad.chars['minor1'],
    #                        list_pos.pop(randrange(0, len(list_pos))))
    #         if squad.chars['minor2']:
    #             self.move_char(squad.chars['minor2'],
    #                            list_pos.pop(randrange(0, len(list_pos))))

    def initial_placement(self):
        board = self.board.type
        for squad in self.squads:
            pos = squad.chars['main'].init_pos[board]
            self.move_char(squad.chars['main'], pos)

    def find_minor_placement(self, squad):
        return self.board.get_adj_empty_pos(squad.chars['main'].pos)

    ###########################################################################
    #                        Discovery Methods
    ###########################################################################

    def get_possible_moves(self, char=None, moves=None):
        if char is None:
            char = self.active_char
        if moves is None:
            moves = self.dice.num()
        return self.board.find_moves(char, moves)

    def get_possible_actions(self):
        """get dictionary of all available actions"""
        # No actions available

        possible_actions = []
        # Squad related actions
        if not self.active_squad().can_act():
            return possible_actions

        if self.active_squad().can_draw:
            possible_actions.append(Act.draw)

        if self.active_squad().can_heal_main():
            possible_actions.append(Act.heal_main)

        # todo: don't need this, but might be useful for custom decks
        # if self.active_squad().can_heal_minor():
        #     possible_actions.append(Act.heal_minor)

        # Card related Actions
        if self.active_squad().has_hand():
            # get possible attack targets
            squad_targets = self.get_squad_targets()
            for index, card in enumerate(self.active_squad().hand):

                # attack cards with or without special abilities
                if card.is_atk():
                    squad_targets[card.owner]['cards']['attack'] = card
                    # possible_actions.append(index)

                # special abilities
                if card.is_special():
                    squad_targets[card.owner]['cards']['special'] = card

        return possible_actions

    # TODO: Clean this up
    # def get_list_of_char_card_actions(self):
    #     active_chars = self.active_squad().get_active_chars()

    # ######################### Targeting Methods ############################

    def get_squad_targets(self):
        """ Get dictionary of lists for all possible targets
        {char_key: char_object}"""
        active_chars = self.active_squad().get_active_chars()
        squad_targets = {}
        for char_key in active_chars:
            # char = self.active_squad().chars[char_key]
            squad_targets[char_key]['targets'] = self.get_char_targets(
                self.active_squad().chars[char_key])
        return squad_targets

    def get_char_targets(self, char):
        """ Get list of all possible target characters for a single character
        """
        return [target for squad in self.squads if squad.side != char.side
                for k, target in squad.chars.items() if target.is_alive()
                and self.board.can_target(char, target)]

    def get_adj_chars(self, char=None):
        """return list of adj characters. assumes active char unless set"""
        if char:
            origin = char
        else:
            origin = self.active_char

        return [char for squad in self.squads
                for k, char in squad.chars.items()
                if char.is_alive() and origin.pos.is_adj(char.pos)]

    def get_adj_allies_enemies(self, char=None):
        """return list of adj friendly characters"""
        allies = []
        enemies = []
        if char:
            origin = char
        else:
            origin = self.active_char
        for squad in self.squads:
            for k, char in squad.chars.items():
                if char.is_alive() and origin.pos.is_adj(char.pos):
                    if not origin.is_enemy(char):
                        allies.append(char)
                    else:
                        enemies.append(char)
        return allies, enemies

    def get_minor_enemy_chars(self, char=None):
        enemies = []
        if char:
            active_char = char
        else:
            active_char = self.active_char

        for squad in self.squads:
            if squad.side != active_char.side:
                enemies.append(squad.get_minor_chars())
        return enemies

    ##########################################################################
    #                         Action Methods
    ##########################################################################
    # TODO: Clean this up
    # def play_card(self):
    #     card = self.active_squad().active_card
    #     if card.self.ack:
    #         def_card = self.target_squad().active_card
    #         # resolve cards
    #     else:
    #         for effects in card.effects:
    #             # play effects
    #             effects['effect_type']()

    def combat(self):
        pass

    ###########################################################################
    #                              Card Effects
    ###########################################################################

    def damage_adj_chars(self, points, char=None):
        chars = self.get_adj_chars(char)
        for char in chars:
            char.damage(points)

    def damage_char(self, points=1):
        """Throw Debris"""
        self.target_char.damage(points)

    def deal_cards_to_squads(self, num_cards=4):
        """ Deals out hand to each squad Hand defaults to initial 4"""
        for squad in self.squads:
            squad.draw_card(num_cards)

    def draw(self, num):
        """Jedi block, martial defense, serenity, missile launch, taunt,
        masterful fighting, force strike, deadly aim, bowcaster attack,
        Latent Force Ability, gain power"""
        self.active_squad().draw_card(num)

    def reveal_discard_attack_cards(self, squad_num):
        """I will not fight you"""
        self.active_squad().discard_attack_cards()
        self.squads[squad_num].discard_attack_cards()

    def reveal_target_hand(self, squad_num):
        """"""
        # TODO: FIX THIS
        return self.squads[squad_num].hand

    def reveal_target_hand_discard_card(self, squad_num, card_indices):
        """Insight"""
        self.reveal_target_hand(squad_num)
        self.target_discard(squad_num, card_indices)

    def damage_minor_enemy(self, points, char=None):
        """Choke"""
        if char:
            char.damage(points)
        else:
            self.target_char.damage(points)

    def damage_and_discard_random(self, points, squad_num, num_cards):
        """Force Lightning"""
        self.damage_char(points)
        self.target_discard_random(squad_num, num_cards)

    def damage_char_and_adj_chars(self, points=1):
        """Thermal Detonator"""
        self.target_char.damage(points)
        self.damage_adj_chars(points, self.target_char)

    def switch_main_and_minor_pos(self, char):
        """Royal Command"""
        self.active_char.switch_pos(char)

    def heal_main_if_adjacent_alive_or_heal_minor(self, points):
        # """Luke's in trouble"""
        pass

    def heal_more_if_main_alive(self, alive_pts, dead_pts):
        """Protection"""
        if self.active_squad().is_main_dead():
            self.active_char.heal(dead_pts)
        else:
            self.active_char.heal(alive_pts)

    def damage_legal_targets_shuffle_discard_into_deck(self, points):
        """Never Tell Me The Odds"""
        self.damage_legal_targets(points)
        self.active_squad().shuffle_discard_into_deck()

    def heal_target_squad_cannot_draw_next_turn(self, points):
        """Meditation"""
        self.heal(points)
        self.squad_cannot_draw_next_turn()

    def squad_cannot_draw_next_turn(self):
        pass

    # def damage_adj_enemies(self, points):
    #     allies, enemies = self.get_adj_allies_enemies(self.active_char)
    #     self._damage_chars(points, enemies)

    def not_action(self):
        """Sith speed, super sith speed"""
        self.active_squad().actions += 1

    def lose_action(self, squad_num):
        """"""
        self.squads[squad_num] -= 1

    def heal(self, points=None):
        self.active_char().heal(points)

    def heal_and_move(self, points, moves):
        """Wookie Healing"""
        self.heal(points)
        self.move(moves)

    def move_and_damage_target_char(self, pos, points):
        """Its not wise"""
        self.move_char(self.target_char, pos)
        self.target_char.damage(points)

    # def move_and_damage_adj_chars(self, points):
    #     """Flame Thrower"""
    #     # TODO: FIX
    #     chars = self.get_adj_chars(self.active_char)
    #     # for char in chars:
    #     #     self.move_character(char)
    #     #     char.damage(points)

    def move_and_draw(self, moves, num_cards):
        """wisdom, force quickness"""
        self.move(moves)
        self.draw(num_cards)

    def counter(self, points):
        """Counter attack, blinding surge, force rebound"""
        self.active_char().damage(points)

    def move(self, num_moves):
        """Shot on the run, Heroic Retreat, Jedi Attack, Athletic Surge"""
        self.board.find_moves(self.active_char, num_moves)

    def move_squad_draw(self, num_moves, num_cards):
        """Children of the force"""
        self.move_squad(num_moves)
        self.draw(num_cards)

    def move_no_hand_draw_new_hand(self, num_moves, num_cards):
        """Calm"""
        self.move(num_moves)
        self.no_hand_draw(num_cards)

    def no_hand_draw(self, num_cards):
        if not self.active_squad().has_hand():
            self.draw(num_cards)

    def discard_to_draw(self):
        """precise shot"""
        self.active_squad().discard_to_draw()

    def target_dies_draw(self, cards):
        """kyber dart"""
        if self.target_char.hp == 0:
            self.draw(cards)

    def minor_dead_more_damage(self):
        """Justice"""
        if self.active_squad().can_heal_main():
            pass

    def damage_char_squad_loses_action(self, points, action):
        """wrist cable"""
        self.target_char.damage(points)
        # TODO: FIX THIS
        self.lose_action(action)

    def damage_squad(self, points):
        """wrath_vader"""
        self.target_squad.damage(points)

    def damage_legal_targets(self, points):
        """Never tell me the odds, whirlwind"""
        targets = self.get_char_targets(self.active_char)
        for target in targets:
            target.damage(points)

    def target_discard(self, squad_num, card_indices):
        """Let Go of your Hatred"""
        self.squads[squad_num].discard_cards(card_indices=card_indices)

    def target_discard_random(self, squad_num, num_cards):
        """Force Drain"""
        self.squads[squad_num].discard_cards(num_cards=num_cards)

    def damage_legal_target_discard_random(self, squad_num, num_cards):
        """Gambler's luck"""
        self.target_discard_random(squad_num, num_cards)

    def move_all(self, moves):
        # force control
        pass

    def lift_char(self):
        # Force Lift
        pass

    def drop_char(self):
        pass

    def reorder_cards_draw(self, card_indices, num_draw):
        """Future Foreseen"""
        self.reorder_cards(card_indices)
        self.draw(num_draw)

    def preview_deck(self, depth):
        self.active_squad().deck_preview(depth)

    def reorder_cards(self, card_indices):
        self.active_squad().deck_reorder(card_indices)

    def kill_or_die(self):
        """Desperate Shot"""
        if self.target_char.hp != 0:
            self.active_char().kill()

    def hand_size_to_one(self, card_index):
        """anger"""
        self.active_squad().hand_size_to_one(card_index)

    def drain_hp(self, points):
        # """dark side drain"""
        pass

    def hand_size_combat_modifier(self):
        # """battlemind"""
        pass

    def get_card_from_deck(self, card_type):
        """Wookie instincts"""
        self.active_squad().get_card_from_deck(card_type)
        self.active_squad().shuffle()

    def get_card_from_discard(self, card_type):
        """jedi mind trick"""
        self.active_squad().get_card_from_discard(card_type)

    def squad_discard_hand(self, squad_num):
        """You Will Die"""
        self.squads[squad_num].discard_hand()

    def all_squads_discard_hand(self):
        for squad in self.squads:
            squad.discard_hand()

    def squads_discard_redraw(self, num_cards):
        """Force Balance"""
        for squad in self.squads:
            squad.discard_hand()
            squad.draw_card(num_cards)

    def target_squad_reveal_hand(self):
        # TODO: Not sure on exposure
        pass

    def target_squad_discard_special(self):
        """Your Skills Are Not Complete"""
        self.target_squad_reveal_hand()
        pass

    def teleport(self, pos, char=None):
        """rocket retreat, assassination"""
        if char:
            self.move_char(char, pos)
        else:
            self.move_char(self.active_char, pos)

    def teleport_damage_damage(self, pos, points):
        """Force Push"""
        self.teleport(pos, self.target_char)
        self.target_char.damage(points)

    def teleport_adj_to_enemy(self):
        pass

    def teleport_not_action(self, pos, char=None):
        """Fire up the jet pack"""
        self.teleport(pos, char)
        self.not_action()

    def teleport_to_minor_damage(self, points):
        """wrath_anakin"""
        self.teleport_adj_to_enemy()
        self.target_char.damage(points)

    def teleport_to_target_not_action(self):
        """sudden arrival"""
        self.teleport_adj_to_enemy()
        self.not_action()

    def undefended_attack(self):
        """all to easy, sniper shot"""
        self.active_squad()
        pass