Advertisement
Guest User

Untitled

a guest
Apr 13th, 2020
386
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.08 KB | None | 0 0
  1. class Pos:
  2.     def __init__(self, pos, *y):
  3.         if not y:
  4.             if type(pos) not in (tuple, list) or len(pos) != 2:
  5.                 raise TypeError('Pos coordinates must be a tuple (x, y) '
  6.                                 'or 2 integers. Given : ' + str(pos))
  7.             self.x, self.y = pos
  8.  
  9.         else:
  10.             if type(pos) is not int or type(y[0]) is not int:
  11.                 raise TypeError('Pos coordinates x, y have to be integers')
  12.             self.x, self.y = pos, y[0]
  13.  
  14.     def __getitem__(self, i: int):
  15.         if type(i) is not int:
  16.             raise TypeError('Pos index must be an integer')
  17.         if i not in (0, 1):
  18.             raise IndexError('Pos index is out of range')
  19.  
  20.         return (self.x, self.y)[i]
  21.  
  22.     def __len__(self):
  23.         return 2
  24.  
  25.     def __add__(self, other):
  26.         if type(other) is type(self):
  27.             return Pos(self.x + other.x, self.y + other.y)
  28.  
  29.         elif type(other) is tuple:
  30.             if len(other) != 2:
  31.                 raise ValueError('tuple length has to be 2 to be added'
  32.                                  'to a Pos object')
  33.             tup_x, tup_y = other
  34.             if type(tup_x) is not int or type(tup_y) is not int:
  35.                 raise TypeError('(x, y) have to be integers to be added'
  36.                                 'to a Pos object')
  37.             return Pos(self.x + tup_x, self.y + tup_y)
  38.  
  39.         else:
  40.             raise TypeError('only Pos or tuple can be added to a Pos object')
  41.  
  42.     def __mul__(self, other: int):
  43.         if type(other) is not int:
  44.             raise TypeError('Pos object can only multiplied with an integer')
  45.         return Pos(self.x * other, self.y * other)
  46.  
  47.     def __eq__(self, other):
  48.         if type(other) is type(self):
  49.             return self.x == other.x and self.y == other.y
  50.         elif type(other) is tuple:
  51.             if len(other) != 2:
  52.                 raise ValueError('tuple length has to be 2 to be compared'
  53.                                  'to a Pos object')
  54.             return self.x == other[0] and self.y == other[1]
  55.         else:
  56.             raise TypeError('only Pos or tuple can be added to a Pos object')
  57.  
  58.     def out_of_board(self, board_size=(8, 8)):
  59.         if type(board_size) not in (tuple, list):
  60.             raise TypeError('board_size need to be a tupple or a list.'
  61.                             'Given ' + str(type(board_size)))
  62.         if len(board_size) != 2:
  63.             raise ValueError('board_size needs to have a length of 2')
  64.         if type(board_size[0]) is not int or type(board_size[0]) is not int:
  65.             raise ValueError('board_size x, y must be integers')
  66.  
  67.         max_x, max_y = board_size
  68.  
  69.         if (self.x not in range(1, max_x + 1)
  70.                 or self.y not in range(1, max_y + 1)):
  71.             return True
  72.         else:
  73.             return False
  74.  
  75.     def __repr__(self):
  76.         return str((self.x, self.y))
  77.  
  78.  
  79. class Game:
  80.     def __init__(self):
  81.         self.nb_of_move = 0
  82.  
  83.         # White pieces are numbered from 0 to 15 and black pieces from 16 to 31
  84.         self.pieces = ([Rook(self, 0), Knight(self, 1), Bishop(self, 2),
  85.                         Queen(self, 3), King(self, 4), Bishop(self, 5),
  86.                         Knight(self, 6), Rook(self, 7)]
  87.                        + [Pawn(self, i) for i in range(8, 24)]
  88.                        + [Rook(self, 24), Knight(self, 25), Bishop(self, 26),
  89.                           Queen(self, 27), King(self, 28), Bishop(self, 29),
  90.                           Knight(self, 30), Rook(self, 31)])
  91.  
  92.         self.board = Board(self.pieces)
  93.  
  94.         self.history = []
  95.  
  96.  
  97. class Board:
  98.     def __init__(self, pieces: list):
  99.         self.container = [[pieces[i] for i in range(8)],  # Whites
  100.                           [pieces[i] for i in range(8, 16)],  # White pawns
  101.                           [None] * 8,
  102.                           [None] * 8,
  103.                           [None] * 8,
  104.                           [None] * 8,
  105.                           [pieces[i] for i in range(16, 24)],  # Black pawns
  106.                           [pieces[i] for i in range(24, 32)]]  # Blacks
  107.  
  108.     def __getitem__(self, pos):
  109.         if type(pos) is not tuple and type(pos) is not Pos:
  110.             raise TypeError('Board index must be a tuple or a Pos object.'
  111.                             'Got a ' + str(type(pos)))
  112.         if len(pos) != 2:
  113.             raise ValueError('Board index must have a length of 2')
  114.  
  115.         x, y = pos
  116.         if type(x) is str:
  117.             keys = 'ABCDEFGH'
  118.             mapping = {keys[i]: i+1 for i in range(8)}
  119.             x = mapping[x]
  120.  
  121.         return self.container[y-1][x-1]
  122.  
  123.     def __setitem__(self, pos, value):
  124.         if type(pos) is not tuple and type(pos) is not Pos:
  125.             raise TypeError('Board index must be a tuple or a Pos object. '
  126.                             'Given ' + str(type(pos)))
  127.         if len(pos) != 2:
  128.             raise ValueError('Board index must have a length of 2')
  129.  
  130.         x, y = pos
  131.         if type(x) is str:
  132.             keys = 'ABCDEFGH'
  133.             mapping = {keys[i]: i+1 for i in range(8)}
  134.             x = mapping[x]
  135.  
  136.         self.container[y-1][x-1] = value
  137.  
  138.     def __str__(self):
  139.         str_copy = self.container.copy()
  140.  
  141.         for i in range(8):
  142.             for j in range(8):
  143.                 if isinstance(str_copy[i][j], King):
  144.                     str_copy[i][j] = 'K'
  145.                 elif isinstance(str_copy[i][j], Queen):
  146.                     str_copy[i][j] = 'Q'
  147.                 elif isinstance(str_copy[i][j], Rook):
  148.                     str_copy[i][j] = 'R'
  149.                 elif isinstance(str_copy[i][j], Knight):
  150.                     str_copy[i][j] = 'N'
  151.                 elif isinstance(str_copy[i][j], Bishop):
  152.                     str_copy[i][j] = 'B'
  153.                 elif isinstance(str_copy[i][j], Pawn):
  154.                     str_copy[i][j] = 'P'
  155.                 elif str_copy[i][j] is None:
  156.                     str_copy[i][j] = '_'
  157.  
  158.         return ''.join([str(line) + '\n' for line in str_copy])
  159.  
  160.  
  161. class Piece:
  162.     def __init__(self, game: Game, id: int):
  163.         if type(id) is not int:
  164.             raise TypeError("argument 'id' must be an integer")
  165.         if id not in range(32):
  166.             raise ValueError("id must be beetween in [0:32]")
  167.  
  168.         self.color = 'W' if id < 16 else 'B'
  169.  
  170.         if id < 8:
  171.             self.pos = Pos(id + 1, 1)
  172.         elif id < 16:
  173.             self.pos = Pos(id - 7, 2)
  174.         elif id < 24:
  175.             self.pos = Pos(id - 15, 7)
  176.         elif id < 32:
  177.             self.pos = Pos(id - 23, 8)
  178.  
  179.         self.game = game
  180.         self.id = id
  181.         self.alive = True
  182.  
  183.     def __repr__(self):
  184.         return str(type(self)).split('.')[1][:-2] + ' ' + str(self.id)
  185.  
  186.     def move(self, new_pos: Pos):
  187.         if type(new_pos) is not Pos:
  188.             raise TypeError('new_pos must be a Pos object. Given ',
  189.                             str(type(new_pos)))
  190.  
  191.         if len(self.game.history) == 0:
  192.             if self.color == 'B':
  193.                 raise Exception('White should start')
  194.         else:
  195.             if self.game.history[-1][0].color == self.color:
  196.                 raise Exception('Not your turn')
  197.  
  198.         if new_pos not in self.possible_moves():
  199.             raise ValueError
  200.         if self.game.board[new_pos]:
  201.             self.game.cell[new_pos].alive = False
  202.  
  203.         self.game.board[self.pos] = None
  204.         self.game.board[new_pos] = self
  205.         self.game.history.append((self, self.pos, new_pos))
  206.         self.pos = new_pos
  207.  
  208.     def possible_moves(self, with_pinning=True):
  209.         possible_moves = []
  210.  
  211.         open_directions = [Pos(move) for move in self.basic_moves]
  212.  
  213.         for r in range(1, self.max_range+1):
  214.             map_dir_pos = [(direction, self.pos + direction * r)
  215.                            for direction in open_directions]
  216.  
  217.             for direction, pos in map_dir_pos:
  218.  
  219.                 if pos.out_of_board():
  220.                     open_directions.remove(direction)
  221.                     continue
  222.  
  223.                 if self.game.board[pos]:
  224.                     test = self.game.board
  225.                     open_directions.remove(direction)
  226.  
  227.                     if self.color != self.game.board[pos].color:
  228.                         possible_moves.append(pos)
  229.                     else:
  230.                         continue
  231.                 else:
  232.                     possible_moves.append(pos)
  233.  
  234.         if with_pinning:
  235.             for move in possible_moves:
  236.                 self.game.board[self.pos] = None
  237.                 self.game.board[move] = self
  238.  
  239.                 if self.color == 'W':
  240.                     king_pos = self.game.pieces[4].pos
  241.                     pinning_pieces = ([i for i in range(16, 24)]  # Pawns promo
  242.                                       + [24, 31]  # Rooks
  243.                                       + [26, 29]  # Bishop
  244.                                       + [27])  # Queen
  245.                 else:
  246.                     king_pos = self.game.pieces[28].pos
  247.                     pinning_pieces = ([i for i in range(8, 16)]  # Pawns promo
  248.                                       + [0, 7]  # Rooks
  249.                                       + [2, 5]  # Bishop
  250.                                       + [3])  # Queen
  251.  
  252.                 for attacker in (self.game.pieces[i] for i in pinning_pieces):
  253.                     if king_pos in attacker.possible_moves(with_pinning=False):
  254.                         possible_moves.remove(move)
  255.  
  256.                 self.game.board[self.pos] = self
  257.                 self.game.board[move] = None
  258.  
  259.         return possible_moves
  260.  
  261.  
  262. class King(Piece):
  263.     basic_moves = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1),
  264.                    (1, -1), (1, 0), (1, 1))
  265.     max_range = 1
  266.  
  267.  
  268. class Queen(Piece):
  269.     basic_moves = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1),
  270.                    (1, -1), (1, 0), (1, 1))
  271.     max_range = 7
  272.  
  273.  
  274. class Rook(Piece):
  275.     basic_moves = ((-1, 0), (1, 0), (0, 1), (0, -1))
  276.     max_range = 7
  277.  
  278.  
  279. class Bishop(Piece):
  280.     basic_moves = ((-1, -1), (1, -1), (-1, 1), (1, 1))
  281.     max_range = 7
  282.  
  283.  
  284. class Knight(Piece):
  285.     basic_moves = ((-2, -1), (-2, 1), (-1, -2), (-1, 2),
  286.                    (1, -2), (1, 2), (2, -1), (2, 1))
  287.     max_range = 1
  288.  
  289.  
  290. class Pawn(Piece):
  291.     def possible_moves(self, with_pinning=True):
  292.         possible_moves = []
  293.  
  294.         # basic move
  295.         basic_move = Pos(0, 1) if self.color == 'W' else Pos(0, -1)
  296.         if not (self.pos + basic_move).out_of_board():
  297.             if self.game.board[self.pos + basic_move] is None:
  298.                 possible_moves.append(self.pos + basic_move)
  299.  
  300.                 if not (self.pos + basic_move * 2).out_of_board():
  301.                     if (self not in (item[0] for item in self.game.history)
  302.                             and self.game.board[self.pos + basic_move * 2] is None):
  303.                         possible_moves.append(self.pos + basic_move * 2)
  304.  
  305.         # capture
  306.         capture_move = (basic_move + (-1, 0), basic_move + (1, 0))
  307.         for move in capture_move:
  308.             if (self.pos + move).out_of_board():
  309.                 continue
  310.  
  311.             if self.game.board[self.pos + move] is not None:
  312.                 if self.game.board[self.pos + move].color != self.color:
  313.                     possible_moves.append(self.pos + move)
  314.  
  315.             if len(self.game.history) > 0:
  316.                 last_move = self.game.history[-1]
  317.                 if (type(last_move[0]) is Pawn
  318.                         and abs(last_move[1][1] - last_move[2][1]) == 2
  319.                         and last_move[2] == self.pos + move + (0, -1)):
  320.  
  321.                     possible_moves.append(self.pos + move)
  322.  
  323.         test_pawn = self.game.board  # debug
  324.  
  325.         if with_pinning:
  326.             for move in possible_moves:
  327.                 self.game.board[self.pos] = None
  328.                 self.game.board[move] = self
  329.  
  330.                 if self.color == 'W':
  331.                     king_pos = self.game.pieces[4].pos
  332.                     pinning_pieces = ([i for i in range(16, 24)]  # Pawns promo
  333.                                       + [24, 31]  # Rooks
  334.                                       + [26, 29]  # Bishop
  335.                                       + [27])  # Queen
  336.                 else:
  337.                     king_pos = self.game.pieces[28].pos
  338.                     pinning_pieces = ([i for i in range(8, 16)]  # Pawns promo
  339.                                       + [0, 7]  # Rooks
  340.                                       + [2, 5]  # Bishop
  341.                                       + [3])  # Queen
  342.  
  343.                 for attacker in (self.game.pieces[i] for i in pinning_pieces):
  344.                     if king_pos in attacker.possible_moves(with_pinning=False):
  345.                         possible_moves.remove(move)
  346.  
  347.                 self.game.board[self.pos] = self
  348.                 self.game.board[move] = None
  349.  
  350.         return possible_moves
  351.  
  352.  
  353. if __name__ == "__main__":
  354.     game = Game()
  355.     while True:
  356.         print(game.board)
  357.         i = input('next move : ')
  358.         o = i.split(':')
  359.         id = int(o[0])
  360.         pos = o[1].split(',')
  361.         pos = Pos(int(pos[0]), int(pos[1]))
  362.         game.pieces[id].move(pos)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement