#1 Mark for including all classes given by the UML class diagram, with correct inheritance structure (ETO) #1 Mark if all class attributes are made private/public/protected as specified by the UML class diagram #1 Mark if all class methods are made private/public/protected as specified by the UML class diagram from abc import ABCMeta, abstractmethod class Board(): #1 Mark for defining a constructor for the class Board with appropriate attributes def __init__(self): self.__columns = 8 self.__rows = 8 self.__board = [[None]*self.__columns for i in range(self.__rows)] self.__gameOver = False self.__setUp() #1 Mark for implementing the display method as described (ETO) def display(self): firstLine = " " for c in range(self.__columns): firstLine += ("| " + str(c+1) + " ") firstLine += "|" print(firstLine) print("-"*((5*self.__columns)+4)) for r in range(self.__rows): print(str(" " + chr(r+65)) + " ", end='') for x in self.__board[r]: if x == None: y = " " z = " " else: y = x.getType()[0] z = "(" + x.getColour()[0].lower() + ")" print("|" + y + z, end="") print("|") print("-"*((5*self.__columns)+4)) print() #1 Mark for creating relevant accessor methods to access Board's private attributes def getWidth(self): return self.__columns def getHeight(self): return self.__rows def gameOver(self): return self.__gameOver #1 Mark for implementing the pieceAt method as described def pieceAt(self, location): try: return self.__board[location[0]][location[1]] except: return None #1 Mark for implementing the movePiece method as described (ETO) def movePiece(self, colour, startPos, endPos): startPiece = self.__board[startPos[0]][startPos[1]] endPiece = self.__board[endPos[0]][endPos[1]] if startPiece != None: if startPiece.getColour() == colour: if startPiece.validMove(self, startPos, endPos): print(colour + "'s " + startPiece.getType() + " was moved to " + str(chr(endPos[0]+65)) + str(endPos[1]+1) + ".") self.__takePiece(startPiece, endPiece) self.__board[startPos[0]][startPos[1]] = None self.__board[endPos[0]][endPos[1]] = startPiece self.__upgradePiece(startPiece, endPos) print() return True print("That is not a valid move! Please try again.") return False #1 Mark for implementing the takePiece method as described def __takePiece(self, startPiece, endPiece): if endPiece != None: print(startPiece.getColour() + "'s " + startPiece.getType() + " took " + endPiece.getColour() + "'s " + endPiece.getType() + ".") if endPiece.getType() == "King": print(startPiece.getColour() + " has won the game!") self.__gameOver = True #1 Mark for implementing the upgradePiece method as described def __upgradePiece(self, startPiece, endPos): if startPiece.getType() == "pawn": if startPiece.getColour() == "White" and endPos[0] == 0: self.__board[endPos[0]][endPos[1]] = Queen("White") elif startPiece.getColour() == "Black" and endPos[0] == self.__rows - 1: self.__board[endPos[0]][endPos[1]] = Queen("Black") else: return print(startPiece.getColour() + "'s pawn became a Queen!") #1 Mark for implementing the setUp method as described def __setUp(self): for c in range(self.__columns): self.__board[1][c] = Pawn("Black") self.__board[self.__rows - 2][c] = Pawn("White") if c == 0 or c == self.__columns - 1: self.__board[0][c] = Rook("Black") self.__board[self.__rows - 1][c] = Rook("White") elif c == 1 or c == self.__columns - 2: self.__board[0][c] = Knight("Black") self.__board[self.__rows - 1][c] = Knight("White") elif c == 2 or c == self.__columns - 3: self.__board[0][c] = Bishop("Black") self.__board[self.__rows - 1][c] = Bishop("White") elif c == 3: self.__board[0][c] = King("Black") self.__board[self.__rows - 1][c] = King("White") elif c == self.__columns - 4: self.__board[0][c] = Queen("Black") self.__board[self.__rows - 1][c] = Queen("White") class BasicMovement(): #1 Mark for implementing the validMove method as described (ETO) def validMove(self, colour, board, startPos, endPos): if endPos[0] >= 0 and endPos[0] < board.getHeight(): if endPos[1] >= 0 and endPos[1] < board.getWidth(): if startPos != endPos: if board.pieceAt(endPos) != None: if board.pieceAt(endPos).getColour() != colour: return True else: return True return False class StraightMovement(): def validMove(self, colour, board, startPos, endPos, pieceRange): #1 Mark for working correctly for horizontal movement (ETO) if startPos[0] == endPos[0]: if pieceRange >= abs(endPos[1] - startPos[1]): for i in range(1, endPos[1] - startPos[1]): tempPos = [startPos[0], startPos[1] + i] if board.pieceAt(tempPos) != None: return False return True #1 Mark for working correctly for vertical movement (ETO) if startPos[1] == endPos[1]: if pieceRange >= abs(endPos[0] - startPos[0]): for i in range(1, endPos[0] - startPos[0]): tempPos = [startPos[0] + i, startPos[1]] if board.pieceAt(tempPos) != None: return False return True return False class DiagonalMovement(): #1 Mark for working for movement in some diagonal directions (ETO) #1 Mark extra for working for movement in all diagonal directions (ETO) def validMove(self, colour, board, startPos, endPos, pieceRange): if abs(endPos[0] - startPos[0]) != abs(endPos[1] - startPos[1]): return False length = abs(endPos[0] - startPos[0]) columnChange = 1 rowChange = 1 if endPos[0] < startPos[0]: rowChange = -1 if endPos[1] < startPos[1]: columnChange = -1 if pieceRange >= length: if length == 1: return True for r in range(1, abs(endPos[0] - startPos[0])): tempPos = [startPos[0] + r * rowChange, startPos[1] + r * columnChange] if board.pieceAt(tempPos) != None: return False return True return False class Piece(): #1 Mark for defining a constructor for the class Piece with appropriate attributes def __init__(self, colour): self._colour = colour self._type = None self._range = 7 self._basic = BasicMovement() #1 Mark for creating relevant accessor methods to access Piece's private attributes def getType(self): return self._type def getColour(self): return self._colour #1 Mark for implementing the validMove method as described (ETO) def validMove(self, board, startPos, endPos): if self._basic.validMove(self._colour, board, startPos, endPos): return True else: return False #1 Mark for defining constructors for all of the child classes of Piece with appropriate attributes #1 Mark for adding relevant movement classes (if any are needed) to all of the child classes of Piece to make composite classes class Pawn(Piece): def __init__(self, colour): super().__init__(colour) self._type = "pawn" self._range = 1 self.__straight = StraightMovement() self.__diagonal = DiagonalMovement() def validMove(self, board, startPos, endPos): if not super().validMove(board, startPos, endPos): return False #1 Mark for valid direction depending on the pawn's colour (ETO) if self._colour == "White" and startPos[0] < endPos[0]: return False elif self._colour == "Black" and startPos[0] > endPos[0]: return False #1 Mark for only allowing diagonal movement if taking a piece and only allowing straight movement if not taking a piece (ETO) if startPos[1] == endPos[1]: if board.pieceAt(endPos) != None: return False else: #1 Mark for allowing the pawn to move forward 2 spaces if it is in its starting location (ETO) if self._colour == "White" and startPos[0] == board.getHeight() - 2 or self._colour == "Black" and startPos[0] == 1: if self.__straight.validMove(self._colour, board, startPos, endPos, self._range + 1): return True elif self.__straight.validMove(self._colour, board, startPos, endPos, self._range): return True if startPos[1] != endPos[1]: if board.pieceAt(endPos) == None: return False else: if self.__diagonal.validMove(self._colour, board, startPos, endPos, self._range): return True return False class King(Piece): def __init__(self, colour): super().__init__(colour) self._type = "King" self._range = 1 self.__straight = StraightMovement() self.__diagonal = DiagonalMovement() #1 Mark for implementing the validMove method as described def validMove(self, board, startPos, endPos): if not super().validMove(board, startPos, endPos): return False if self.__straight.validMove(self._colour, board, startPos, endPos, self._range): return True elif self.__diagonal.validMove(self._colour, board, startPos, endPos, self._range): return True return False class Queen(Piece): def __init__(self, colour): super().__init__(colour) self._type = "Queen" self.__straight = StraightMovement() self.__diagonal = DiagonalMovement() #1 Mark for implementing the validMove method as described def validMove(self, board, startPos, endPos): if not super().validMove(board, startPos, endPos): return False if self.__straight.validMove(self._colour, board, startPos, endPos, self._range): return True elif self.__diagonal.validMove(self._colour, board, startPos, endPos, self._range): return True return False class Rook(Piece): def __init__(self, colour): super().__init__(colour) self._type = "rook" self.__straight = StraightMovement() #1 Mark for implementing the validMove method as described def validMove(self, board, startPos, endPos): if not super().validMove(board, startPos, endPos): return False if self.__straight.validMove(self._colour, board, startPos, endPos, self._range): return True return False class Bishop(Piece): def __init__(self, colour): super().__init__(colour) self._type = "bishop" self.__diagonal = DiagonalMovement() #1 Mark for implementing the validMove method as described def validMove(self, board, startPos, endPos): if not super().validMove(board, startPos, endPos): return False if self.__diagonal.validMove(self._colour, board, startPos, endPos, self._range): return True return False class Knight(Piece): def __init__(self, colour): super().__init__(colour) self._type = "knight" #1 Mark for implementing the validMove method as described def validMove(self, board, startPos, endPos): if not super().validMove(board, startPos, endPos): return False if abs(endPos[0] - startPos[0]) == 2: if abs(endPos[1] - startPos[1]) != 1: return False elif abs(endPos[0] - startPos[0]) == 1: if abs(endPos[1] - startPos[1]) != 2: return False else: return False return True class Player(metaclass=ABCMeta): #1 Mark for defining a constructor for the class Player with appropriate attributes def __init__(self, colour): self._colour = colour #1 Mark for creating relevant accessor methods to access Player's private attributes def getColour(self): return self._colour #1 Mark for defining appropriate abstract method @abstractmethod def movePiece(self): pass class HumanPlayer(Player): def movePiece(self, board): end = False while end != True: #1 Mark for getting move from user (ETO) posSet = False while not posSet: board.display() print() print(self._colour + "'s turn:") startDisplay = input("Enter the location of the piece you would like to move (e.g. A1):") print() startPos = self.__getPos(board, self._colour, startDisplay) if startPos != None and board.pieceAt(startPos) != None and board.pieceAt(startPos).getColour() == self._colour: posSet = True else: print("You don't have a piece at " + startDisplay + " to move! Please try again.") print() board.display() print() print(self._colour + "'s turn:") endPos = input("Where would you like to move the " + board.pieceAt(startPos).getType() + " from " + startDisplay.upper() + " to?:") print() #1 Mark for ending only once a move is successfully made (ETO) end = self.__getPos(board, self._colour, startPos, endPos) print() print() #1 Mark for returning the value of whether or not the game is over (ETO) return board.gameOver() #1 Mark for overriding getPos to allow it to work with either one or two positions given (ETO) def __getPos(self, board, colour, startPos, endPos = None): if endPos == None: checkPos = startPos else: checkPos = endPos #1 Mark for accepting input in the form LetterNumber (A5, E5, E2 etc.) (ETO) if len(checkPos) > 2: return None try: if endPos == None: startRow = int(ord(startPos[0].upper())) - 65 startColumn = int(startPos[1]) - 1 if startRow < 0 or startRow >= board.getHeight() or startColumn < 0 or startColumn >= board.getHeight(): return None else: checkPos = [startRow, startColumn] else: endRow = int(ord(endPos[0].upper())) - 65 endColumn = int(endPos[1]) - 1 if endRow < 0 or endRow >= board.getHeight() or endColumn < 0 or endColumn >= board.getHeight(): return None else: checkPos = [endRow, endColumn] except: return None if endPos == None and board.pieceAt(checkPos) == None: return None #1 Mark for returning an integer array of the location if only the start position is given (ETO) elif endPos == None: return checkPos #1 Mark for making the move if both the start and end positions are given (ETO) elif endPos != None: return board.movePiece(colour, startPos, checkPos) else: return None def main(): board = Board() white = HumanPlayer("White") black = HumanPlayer("Black") gameOver = False while not gameOver: print() print("It's White's turn to move:") gameOver = white.movePiece(board) if gameOver: break print() print("It's Black's turn to move:") gameOver = black.movePiece(board) board.display() input() if __name__ == '__main__': main()