Repository: fabiobatalha/chess_master

Issue:
Implement the threatening and threatened validations
improve the Board.place_piece method to:



        Put a given piece on the board.

        (Rule 1) The piece position must not match with the position of any other piece
        already available in the board. If so, it will raise OccupiedSquare
        Exception.

        (Rule 2) The piece position must not be threatened by other pieces already safe
        disposed in the board. If so, it will raise Threatened Exception.
        Exception.

        (Rule 3) The piece must not threatening any other piece already available in
        the board. If so, it will raise Threatening Exception.

Discussion:

Patch:
diff --git a/masterchess/chess.py b/masterchess/chess.py
index 146c8d9..6711231 100644
--- a/masterchess/chess.py
+++ b/masterchess/chess.py
@@ -10,12 +10,23 @@ class OccupiedSquare(BoardExceptions):
     def __init__(self, value):
         self.value = value
 
+class Threatening(BoardExceptions):
+
+    def __init__(self, value):
+        self.value = value
+
+class Threatened(BoardExceptions):
+
+    def __init__(self, value):
+        self.value = value
+
 
 class Board(object):
 
     def __init__(self, size):
         self.board = None
         self.pieces = []
+        self._size = size
         self._setup_board(size)
 
     def _setup_board(self, size):
@@ -27,10 +38,11 @@ class Board(object):
         size -- integer
         """
 
-        if not isinstance(size, int):
+        if not isinstance(self._size, int):
             raise ValueError('board size must be integer')
 
-        self.board = [[None for i in range(size)] for i in range(size)]
+        rg = range(self._size)
+        self.board = [[None for i in rg] for i in rg]
 
     def _update_board(self):
         """
@@ -50,25 +62,58 @@ class Board(object):
         """
         return [[(str(x) if x else x) for x in i] for i in self.board]
 
+    @property
+    def picture_threat(self):
+        """
+        Return a 2 dimension list with a picture of the current state of the
+        board and pieces position.
+
+        It will display T on places where pieces will be threatened and the 
+        piece name where the pieces are allocated.
+        """
+
+        board = self.picture
+
+        for piece in self.pieces:
+            for threat in piece.threatening_zone(self._size):
+                x, y = threat
+                board[x][y] = 'T' if board[x][y] is None else board[x][y]
+
+        return board
+
     def place_piece(self, piece):
         """
         Put a given piece on the board.
 
-        The piece must not threatening any other piece already available in
-        the board. If so, it will raise Threatened Exception.
-
-        The piece position must not match with the position of any other piece
+        (Rule 1) The piece position must not match with the position of any other piece
         already available in the board. If so, it will raise OccupiedSquare
         Exception.
 
+        (Rule 2) The piece position must not be threatened by other pieces already safe
+        disposed in the board. If so, it will raise Threatened Exception.
+        Exception.
+
+        (Rule 3) The piece must not threatening any other piece already available in
+        the board. If so, it will raise Threatening Exception.
+
         Arguments:
         piece -- a instance o Pieces (Pawn, King, Bishop, Queen, Rook, Kinight)
         """
         x, y = piece.position
 
+        # Rule (1)
         if self.picture[x][y] is not None:
             raise OccupiedSquare(str(piece.position))
 
+        # Rule (2)
+        if self.picture_threat[x][y] is not None and self.picture_threat[x][y] == 'T':
+            raise Threatened(str(piece.position))
+
+        # Rule (3)
+        pieces_on_board = [i.position for i in self.pieces]
+        if len(set(piece.threatening_zone(self._size)).intersection(pieces_on_board)) >= 1:
+            raise Threatening(str(piece.position))
+
         self.pieces.append(piece)
         self._update_board()
 
@@ -406,4 +451,3 @@ class Rook(Pieces):
         zone += self._w_positions(max_size)
 
         return zone
-


Test patch:
diff --git a/tests/tests.py b/tests/tests.py
index 2837ed0..4ebc049 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -1225,6 +1225,101 @@ class TestsChessMasterBoard(unittest.TestCase):
 
         self.assertEqual(board.picture, expected)
 
+    def test_picture_threat_1(self):
+
+        board = chess.Board(8)
+        king = chess.King((1, 2))
+        board.place_piece(king)
+
+        expected =[
+            [None, 'T', 'T', 'T', None, None, None, None],
+            [None, 'T', 'king', 'T', None, None, None, None],
+            [None, 'T', 'T', 'T', None, None, None, None],
+            [None, None, None, None, None, None, None, None],
+            [None, None, None, None, None, None, None, None],
+            [None, None, None, None, None, None, None, None],
+            [None, None, None, None, None, None, None, None],
+            [None, None, None, None, None, None, None, None]
+        ]
+        self.assertEqual(board.picture_threat, expected)
+
+    def test_picture_threat_2(self):
+
+        board = chess.Board(4)
+        king = chess.King((0, 3))
+        board.place_piece(king)
+
+        expected = [
+            [None, None, 'T', 'king'],
+            [None, None, 'T', 'T'],
+            [None, None, None, None],
+            [None, None, None, None]
+        ]
+        self.assertEqual(board.picture_threat, expected)
+
+    def test_picture_threat_3(self):
+
+        board = chess.Board(8)
+        queen = chess.Queen((4, 3))
+        board.place_piece(queen)
+
+        expected = [
+            [None, None, None, 'T', None, None, None, 'T'],
+            ['T', None, None, 'T', None, None, 'T', None],
+            [None, 'T', None, 'T', None, 'T', None, None],
+            [None, None, 'T', 'T', 'T', None, None, None],
+            ['T', 'T', 'T', 'queen', 'T', 'T', 'T', 'T'],
+            [None, None, 'T', 'T', 'T', None, None, None],
+            [None, 'T', None, 'T', None, 'T', None, None],
+            ['T', None, None, 'T', None, None, 'T', None]
+        ]
+
+        self.assertEqual(board.picture_threat, expected)
+
+    def test_picture_threat_4_with_2_pieces(self):
+
+        board = chess.Board(8)
+        queen = chess.Queen((4, 3))
+        king = chess.King((1, 1))
+        board.place_piece(queen)
+        board.place_piece(king)
+
+        expected = [
+            ['T', 'T', 'T', 'T', None, None, None, 'T'],
+            ['T', 'king', 'T', 'T', None, None, 'T', None],
+            ['T', 'T', 'T', 'T', None, 'T', None, None],
+            [None, None, 'T', 'T', 'T', None, None, None],
+            ['T', 'T', 'T', 'queen', 'T', 'T', 'T', 'T'],
+            [None, None, 'T', 'T', 'T', None, None, None],
+            [None, 'T', None, 'T', None, 'T', None, None],
+            ['T', None, None, 'T', None, None, 'T', None]
+        ]
+
+        self.assertEqual(board.picture_threat, expected)
+
+    def test_picture_threat_4_with_3_pieces(self):
+
+        board = chess.Board(8)
+        queen = chess.Queen((4, 3))
+        king = chess.King((1, 1))
+        kinight = chess.Kinight((7, 7))
+        board.place_piece(queen)
+        board.place_piece(king)
+        board.place_piece(kinight)
+
+        expected = [
+            ['T', 'T', 'T', 'T', None, None, None, 'T'],
+            ['T', 'king', 'T', 'T', None, None, 'T', None],
+            ['T', 'T', 'T', 'T', None, 'T', None, None],
+            [None, None, 'T', 'T', 'T', None, None, None],
+            ['T', 'T', 'T', 'queen', 'T', 'T', 'T', 'T'],
+            [None, None, 'T', 'T', 'T', None, 'T', None],
+            [None, 'T', None, 'T', None, 'T', None, None],
+            ['T', None, None, 'T', None, None, 'T', 'kinight']
+        ]
+
+        self.assertEqual(board.picture_threat, expected)
+
     def test_put_piece_in_occupied_square(self):
         pawn1 = chess.Pawn((1, 2))
         pawn2 = chess.Pawn((1, 2))
@@ -1236,6 +1331,56 @@ class TestsChessMasterBoard(unittest.TestCase):
         with self.assertRaises(chess.OccupiedSquare):
             board.place_piece(pawn2)
 
+    def test_put_piece_in_threatened_square(self):
+        """
+        Test ThretenedException while trying to put a rook in an place
+        threatened by a queen.
+        [
+            [None, None, None, 'T', None, None, None, 'T'],
+            ['T (trying to put rook here)', None, None, 'T', None, None, 'T', None],
+            [None, 'T', None, 'T', None, 'T', None, None],
+            [None, None, 'T', 'T', 'T', None, None, None],
+            ['T', 'T', 'T', 'queen', 'T', 'T', 'T', 'T'],
+            [None, None, 'T', 'T', 'T', None, None, None],
+            [None, 'T', None, 'T', None, 'T', None, None],
+            ['T', None, None, 'T', None, None, 'T', None]
+        ]
+
+        """
+
+        board = chess.Board(8)
+        queen = chess.Queen((4, 3))
+        board.place_piece(queen)
+
+        with self.assertRaises(chess.Threatened):
+            rook = chess.Rook((1, 0))
+            board.place_piece(rook)
+
+    def test_put_piece_in_threatening_square(self):
+        """
+        Test ThreteningException while trying to put a kinight in an place that
+        will threatening queen.
+        [
+            [None, None, None, 'T', None, None, None, 'T'],
+            ['T', None, None, 'T', None, None, 'T', None],
+            [None, 'T', None (trying to put kinight here), 'T', None, 'T', None, None],
+            [None, None, 'T', 'T', 'T', None, None, None],
+            ['T', 'T', 'T', 'queen', 'T', 'T', 'T', 'T'],
+            [None, None, 'T', 'T', 'T', None, None, None],
+            [None, 'T', None, 'T', None, 'T', None, None],
+            ['T', None, None, 'T', None, None, 'T', None]
+        ]
+
+        """
+
+        board = chess.Board(8)
+        queen = chess.Queen((4, 3))
+        board.place_piece(queen)
+
+        with self.assertRaises(chess.Threatening):
+            kinight = chess.Kinight((2, 2))
+            board.place_piece(kinight)
+
     def test_instanciating_board_wrong_size(self):
 
         with self.assertRaises(ValueError):