Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class Pos:
- def __init__(self, pos, *y):
- if not y:
- if type(pos) not in (tuple, list) or len(pos) != 2:
- raise TypeError('Pos coordinates must be a tuple (x, y) '
- 'or 2 integers. Given : ' + str(pos))
- self.x, self.y = pos
- else:
- if type(pos) is not int or type(y[0]) is not int:
- raise TypeError('Pos coordinates x, y have to be integers')
- self.x, self.y = pos, y[0]
- def __getitem__(self, i: int):
- if type(i) is not int:
- raise TypeError('Pos index must be an integer')
- if i not in (0, 1):
- raise IndexError('Pos index is out of range')
- return (self.x, self.y)[i]
- def __len__(self):
- return 2
- def __add__(self, other):
- if type(other) is type(self):
- return Pos(self.x + other.x, self.y + other.y)
- elif type(other) is tuple:
- if len(other) != 2:
- raise ValueError('tuple length has to be 2 to be added'
- 'to a Pos object')
- tup_x, tup_y = other
- if type(tup_x) is not int or type(tup_y) is not int:
- raise TypeError('(x, y) have to be integers to be added'
- 'to a Pos object')
- return Pos(self.x + tup_x, self.y + tup_y)
- else:
- raise TypeError('only Pos or tuple can be added to a Pos object')
- def __mul__(self, other: int):
- if type(other) is not int:
- raise TypeError('Pos object can only multiplied with an integer')
- return Pos(self.x * other, self.y * other)
- def __eq__(self, other):
- if type(other) is type(self):
- return self.x == other.x and self.y == other.y
- elif type(other) is tuple:
- if len(other) != 2:
- raise ValueError('tuple length has to be 2 to be compared'
- 'to a Pos object')
- return self.x == other[0] and self.y == other[1]
- else:
- raise TypeError('only Pos or tuple can be added to a Pos object')
- def out_of_board(self, board_size=(8, 8)):
- if type(board_size) not in (tuple, list):
- raise TypeError('board_size need to be a tupple or a list.'
- 'Given ' + str(type(board_size)))
- if len(board_size) != 2:
- raise ValueError('board_size needs to have a length of 2')
- if type(board_size[0]) is not int or type(board_size[0]) is not int:
- raise ValueError('board_size x, y must be integers')
- max_x, max_y = board_size
- if (self.x not in range(1, max_x + 1)
- or self.y not in range(1, max_y + 1)):
- return True
- else:
- return False
- def __repr__(self):
- return str((self.x, self.y))
- class Game:
- def __init__(self):
- self.nb_of_move = 0
- # White pieces are numbered from 0 to 15 and black pieces from 16 to 31
- self.pieces = ([Rook(self, 0), Knight(self, 1), Bishop(self, 2),
- Queen(self, 3), King(self, 4), Bishop(self, 5),
- Knight(self, 6), Rook(self, 7)]
- + [Pawn(self, i) for i in range(8, 24)]
- + [Rook(self, 24), Knight(self, 25), Bishop(self, 26),
- Queen(self, 27), King(self, 28), Bishop(self, 29),
- Knight(self, 30), Rook(self, 31)])
- self.board = Board(self.pieces)
- self.history = []
- class Board:
- def __init__(self, pieces: list):
- self.container = [[pieces[i] for i in range(8)], # Whites
- [pieces[i] for i in range(8, 16)], # White pawns
- [None] * 8,
- [None] * 8,
- [None] * 8,
- [None] * 8,
- [pieces[i] for i in range(16, 24)], # Black pawns
- [pieces[i] for i in range(24, 32)]] # Blacks
- def __getitem__(self, pos):
- if type(pos) is not tuple and type(pos) is not Pos:
- raise TypeError('Board index must be a tuple or a Pos object.'
- 'Got a ' + str(type(pos)))
- if len(pos) != 2:
- raise ValueError('Board index must have a length of 2')
- x, y = pos
- if type(x) is str:
- keys = 'ABCDEFGH'
- mapping = {keys[i]: i+1 for i in range(8)}
- x = mapping[x]
- return self.container[y-1][x-1]
- def __setitem__(self, pos, value):
- if type(pos) is not tuple and type(pos) is not Pos:
- raise TypeError('Board index must be a tuple or a Pos object. '
- 'Given ' + str(type(pos)))
- if len(pos) != 2:
- raise ValueError('Board index must have a length of 2')
- x, y = pos
- if type(x) is str:
- keys = 'ABCDEFGH'
- mapping = {keys[i]: i+1 for i in range(8)}
- x = mapping[x]
- self.container[y-1][x-1] = value
- def __str__(self):
- str_copy = self.container.copy()
- for i in range(8):
- for j in range(8):
- if isinstance(str_copy[i][j], King):
- str_copy[i][j] = 'K'
- elif isinstance(str_copy[i][j], Queen):
- str_copy[i][j] = 'Q'
- elif isinstance(str_copy[i][j], Rook):
- str_copy[i][j] = 'R'
- elif isinstance(str_copy[i][j], Knight):
- str_copy[i][j] = 'N'
- elif isinstance(str_copy[i][j], Bishop):
- str_copy[i][j] = 'B'
- elif isinstance(str_copy[i][j], Pawn):
- str_copy[i][j] = 'P'
- elif str_copy[i][j] is None:
- str_copy[i][j] = '_'
- return ''.join([str(line) + '\n' for line in str_copy])
- class Piece:
- def __init__(self, game: Game, id: int):
- if type(id) is not int:
- raise TypeError("argument 'id' must be an integer")
- if id not in range(32):
- raise ValueError("id must be beetween in [0:32]")
- self.color = 'W' if id < 16 else 'B'
- if id < 8:
- self.pos = Pos(id + 1, 1)
- elif id < 16:
- self.pos = Pos(id - 7, 2)
- elif id < 24:
- self.pos = Pos(id - 15, 7)
- elif id < 32:
- self.pos = Pos(id - 23, 8)
- self.game = game
- self.id = id
- self.alive = True
- def __repr__(self):
- return str(type(self)).split('.')[1][:-2] + ' ' + str(self.id)
- def move(self, new_pos: Pos):
- if type(new_pos) is not Pos:
- raise TypeError('new_pos must be a Pos object. Given ',
- str(type(new_pos)))
- if len(self.game.history) == 0:
- if self.color == 'B':
- raise Exception('White should start')
- else:
- if self.game.history[-1][0].color == self.color:
- raise Exception('Not your turn')
- if new_pos not in self.possible_moves():
- raise ValueError
- if self.game.board[new_pos]:
- self.game.cell[new_pos].alive = False
- self.game.board[self.pos] = None
- self.game.board[new_pos] = self
- self.game.history.append((self, self.pos, new_pos))
- self.pos = new_pos
- def possible_moves(self, with_pinning=True):
- possible_moves = []
- open_directions = [Pos(move) for move in self.basic_moves]
- for r in range(1, self.max_range+1):
- map_dir_pos = [(direction, self.pos + direction * r)
- for direction in open_directions]
- for direction, pos in map_dir_pos:
- if pos.out_of_board():
- open_directions.remove(direction)
- continue
- if self.game.board[pos]:
- test = self.game.board
- open_directions.remove(direction)
- if self.color != self.game.board[pos].color:
- possible_moves.append(pos)
- else:
- continue
- else:
- possible_moves.append(pos)
- if with_pinning:
- for move in possible_moves:
- self.game.board[self.pos] = None
- self.game.board[move] = self
- if self.color == 'W':
- king_pos = self.game.pieces[4].pos
- pinning_pieces = ([i for i in range(16, 24)] # Pawns promo
- + [24, 31] # Rooks
- + [26, 29] # Bishop
- + [27]) # Queen
- else:
- king_pos = self.game.pieces[28].pos
- pinning_pieces = ([i for i in range(8, 16)] # Pawns promo
- + [0, 7] # Rooks
- + [2, 5] # Bishop
- + [3]) # Queen
- for attacker in (self.game.pieces[i] for i in pinning_pieces):
- if king_pos in attacker.possible_moves(with_pinning=False):
- possible_moves.remove(move)
- self.game.board[self.pos] = self
- self.game.board[move] = None
- return possible_moves
- class King(Piece):
- basic_moves = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1),
- (1, -1), (1, 0), (1, 1))
- max_range = 1
- class Queen(Piece):
- basic_moves = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1),
- (1, -1), (1, 0), (1, 1))
- max_range = 7
- class Rook(Piece):
- basic_moves = ((-1, 0), (1, 0), (0, 1), (0, -1))
- max_range = 7
- class Bishop(Piece):
- basic_moves = ((-1, -1), (1, -1), (-1, 1), (1, 1))
- max_range = 7
- class Knight(Piece):
- basic_moves = ((-2, -1), (-2, 1), (-1, -2), (-1, 2),
- (1, -2), (1, 2), (2, -1), (2, 1))
- max_range = 1
- class Pawn(Piece):
- def possible_moves(self, with_pinning=True):
- possible_moves = []
- # basic move
- basic_move = Pos(0, 1) if self.color == 'W' else Pos(0, -1)
- if not (self.pos + basic_move).out_of_board():
- if self.game.board[self.pos + basic_move] is None:
- possible_moves.append(self.pos + basic_move)
- if not (self.pos + basic_move * 2).out_of_board():
- if (self not in (item[0] for item in self.game.history)
- and self.game.board[self.pos + basic_move * 2] is None):
- possible_moves.append(self.pos + basic_move * 2)
- # capture
- capture_move = (basic_move + (-1, 0), basic_move + (1, 0))
- for move in capture_move:
- if (self.pos + move).out_of_board():
- continue
- if self.game.board[self.pos + move] is not None:
- if self.game.board[self.pos + move].color != self.color:
- possible_moves.append(self.pos + move)
- if len(self.game.history) > 0:
- last_move = self.game.history[-1]
- if (type(last_move[0]) is Pawn
- and abs(last_move[1][1] - last_move[2][1]) == 2
- and last_move[2] == self.pos + move + (0, -1)):
- possible_moves.append(self.pos + move)
- test_pawn = self.game.board # debug
- if with_pinning:
- for move in possible_moves:
- self.game.board[self.pos] = None
- self.game.board[move] = self
- if self.color == 'W':
- king_pos = self.game.pieces[4].pos
- pinning_pieces = ([i for i in range(16, 24)] # Pawns promo
- + [24, 31] # Rooks
- + [26, 29] # Bishop
- + [27]) # Queen
- else:
- king_pos = self.game.pieces[28].pos
- pinning_pieces = ([i for i in range(8, 16)] # Pawns promo
- + [0, 7] # Rooks
- + [2, 5] # Bishop
- + [3]) # Queen
- for attacker in (self.game.pieces[i] for i in pinning_pieces):
- if king_pos in attacker.possible_moves(with_pinning=False):
- possible_moves.remove(move)
- self.game.board[self.pos] = self
- self.game.board[move] = None
- return possible_moves
- if __name__ == "__main__":
- game = Game()
- while True:
- print(game.board)
- i = input('next move : ')
- o = i.split(':')
- id = int(o[0])
- pos = o[1].split(',')
- pos = Pos(int(pos[0]), int(pos[1]))
- game.pieces[id].move(pos)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement