1from .lutils.attack import getAttacks, piecesAttackingCord
2from .const import NB_OF_CASES
3from .lutils.ldata import PIECE_VALUES
4from .Cord import Cord
5from pychess.Utils.const import KING
6
7
8# This file contains algorithm helping the users to choose the right decisions
9# The first algorithm gives to the user all the pieces attacked and not protected by the foe
10class DecisionSupportAlgorithm:
11
12    def __init__(self):
13        self.local_game = False
14        self.activationEnabled = False
15
16        # to avoid calculating once more the coordinates, we save them
17        self.coordinate_in_danger = []
18
19    def enableDisableAlgo(self, enable_algorithm):
20        self.activationEnabled = enable_algorithm
21
22    def set_foe_as_bot(self):
23        self.local_game = True
24
25    def calculate_coordinate_in_danger(self, board, mycolor, newTurn=True):
26        '''this function should be used for applying the algorithm'''
27        if not newTurn:
28            return self.coordinate_in_danger
29
30        self.coordinate_in_danger = []
31
32        self.coordinate_in_danger = self.__apply_algorithm(board, mycolor, self.__not_protected)
33        self.coordinate_in_danger += self.__apply_algorithm(board, mycolor, self.__attacked_and_not_protected)
34
35        return self.coordinate_in_danger
36
37    def __apply_algorithm(self, board, mycolor, algorithm):
38        """returns the list of coordinate in danger for player playing with mycolor pieces
39         according to the algorithm used
40        args : board of type Board, coordinate of type Cord, algorithm : function taking two arguments
41        board, mycolor and the current coordinate we are looking
42
43        WARNING : The king is currently excluded of the calculus => it is never considered as in danger"""
44        coordinate_in_danger = []
45
46        if self.local_game and self.activationEnabled:
47            # TODO: tests
48            for i in range(NB_OF_CASES):
49                c = Cord(i)
50                number, letter = c.cords
51                piece = board.data[letter][number]
52                if piece is not None and piece.piece is not KING:
53                    if piece.color == mycolor:
54                        coordinate_in_color = algorithm(board, mycolor, c)
55                        if coordinate_in_color is not None:
56                            coordinate_in_danger.append(coordinate_in_color)
57
58        return coordinate_in_danger
59
60    def __not_protected(self, board, mycolor, coordinate):
61        """returns the coord with the color yellow if the coord is not protected, None if it is
62        args : board of type Board, coordinate of type Cord, mycolor of value BLACK or WHITE
63        which is the color of the player who will play the next move"""
64
65        c_colored = None
66        attacks = getAttacks(board.board, coordinate.cord, 1 - mycolor)
67        defense = getAttacks(board.board, coordinate.cord, mycolor)
68
69        # if one of the piece is not protected but not attacked, danger
70        # means that towers are highlighted at the start of the game
71        if attacks == 0 and defense == 0:
72            c_colored = Cord(coordinate.cord, color="Y")
73
74        return c_colored
75
76    def __attacked_and_not_protected(self, board, mycolor, coordinate):
77        """returns the coord with the color red if the coord is not protected and attacked, None if it is not
78        args : board of type Board, cord of type Cord, mycolor of value BLACK or WHITE
79        which is the color of the player who will play the next move"""
80
81        pieces_attacking = piecesAttackingCord(board.board, coordinate.cord, 1 - mycolor)
82        defense = getAttacks(board.board, coordinate.cord, mycolor)
83
84        c_colored = None
85
86        number, letter = coordinate.cords
87        piece = board.data[letter][number]
88
89        if len(pieces_attacking) != 0:
90            # if one of the piece is not protected and attacked, very dangerous
91            if defense == 0:
92                c_colored = Cord(coordinate.cord, color="R")
93            else:
94                # if one of the piece attacking is weaker than piece attacked, very dangerous
95
96                # in this part we find the weakest ennemy pieces attacking our piece
97                piece_attacking = pieces_attacking[0]
98                min_value = PIECE_VALUES[piece_attacking]
99                for piece_found in pieces_attacking:
100                    if PIECE_VALUES[piece_found] <= min_value:
101                        min_value = PIECE_VALUES[piece_found]
102                        piece_attacking = piece_found
103
104                # then we compare it to the value of the piece
105                # currently, we consider trades as not dangerous, this behaviour could be changed
106                if PIECE_VALUES[piece_attacking] < PIECE_VALUES[piece.piece]:
107                    c_colored = Cord(coordinate.cord, color="R")
108
109        return c_colored
110