├── Chess Game ├── kingBlack.gif ├── kingWhite.gif ├── pawnBlack.gif ├── pawnWhite.gif ├── rookBlack.gif ├── rookWhite.gif ├── bishopBlack.gif ├── bishopWhite.gif ├── knightBlack.gif ├── knightWhite.gif ├── queenBlack.gif ├── queenWhite.gif ├── __pycache__ │ ├── board.cpython-35.pyc │ └── board.cpython-36.pyc ├── gui.py └── board.py ├── README.md ├── LICENSE └── Chess.py /Chess Game/kingBlack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/kingBlack.gif -------------------------------------------------------------------------------- /Chess Game/kingWhite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/kingWhite.gif -------------------------------------------------------------------------------- /Chess Game/pawnBlack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/pawnBlack.gif -------------------------------------------------------------------------------- /Chess Game/pawnWhite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/pawnWhite.gif -------------------------------------------------------------------------------- /Chess Game/rookBlack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/rookBlack.gif -------------------------------------------------------------------------------- /Chess Game/rookWhite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/rookWhite.gif -------------------------------------------------------------------------------- /Chess Game/bishopBlack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/bishopBlack.gif -------------------------------------------------------------------------------- /Chess Game/bishopWhite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/bishopWhite.gif -------------------------------------------------------------------------------- /Chess Game/knightBlack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/knightBlack.gif -------------------------------------------------------------------------------- /Chess Game/knightWhite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/knightWhite.gif -------------------------------------------------------------------------------- /Chess Game/queenBlack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/queenBlack.gif -------------------------------------------------------------------------------- /Chess Game/queenWhite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/queenWhite.gif -------------------------------------------------------------------------------- /Chess Game/__pycache__/board.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/__pycache__/board.cpython-35.pyc -------------------------------------------------------------------------------- /Chess Game/__pycache__/board.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ugenteraan/Chess-with-Python/HEAD/Chess Game/__pycache__/board.cpython-36.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chess-with-Python 2 | A complete chess game with GUI using python3 and tkinter (Fully commented). 3 | 4 | To start the program, simply change the path into the directory and invoke the command "python3 gui.py". 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ugenteraan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Chess Game/gui.py: -------------------------------------------------------------------------------- 1 | import board 2 | from tkinter import * 3 | import time 4 | 5 | 6 | 7 | class BoardGUI: 8 | 9 | 10 | #initialize variable 11 | mousePressedX = 0 12 | mousePressedY = 0 13 | mouseReleasedX = 0 14 | mouseReleasedY = 0 15 | 16 | move2compare = [] 17 | 18 | #constructor (will be called automatically when the class is called) 19 | def __init__(self): 20 | #initialize the GUI frame 21 | self.root = Tk() 22 | 23 | #this line prints out the board in the terminal 24 | # for i in range(8): 25 | # print(board.Board().chessBoard[i][:]) 26 | # print ("") 27 | 28 | #set the cavas height and width 29 | self.canvas_width = 800 30 | self.canvas_height = 800 31 | 32 | #set the square size 33 | self.square_size = 80 34 | 35 | #create a container for the whole display 36 | self.myContainer1 = Frame(self.root) 37 | #add the container to the frame 38 | self.myContainer1.pack() 39 | 40 | #create a canvas 41 | self.w = Canvas(self.myContainer1, width=self.canvas_width, height=self.canvas_height) 42 | #add the canvas to the frame 43 | self.w.pack() 44 | 45 | #this creates the chess board 46 | #this goes from left to right, top to bottom 47 | for i in range(8): 48 | for j in range(8): 49 | if (j+i)%2 == 0: 50 | self.w.create_rectangle(i*self.square_size,j*self.square_size,self.square_size*(i+1),self.square_size*(j+1), fill="grey") 51 | else: 52 | self.w.create_rectangle(i*self.square_size,j*self.square_size,self.square_size*(i+1),self.square_size*(j+1), fill="darkgreen") 53 | 54 | 55 | 56 | #this command updates the GUI every 10 miliseconds 57 | #calls the drawPieces() function every 10 miliseconds 58 | self.root.after(10, self.drawPieces) 59 | self.root.mainloop() 60 | 61 | 62 | 63 | #this function fires during a mousepress event 64 | def Mousepress(self,event): 65 | #get the position of the mouse press and divide with the square size to the get the square of which the mouse pointer is pointed 66 | self.mousePressedX = int(event.y/self.square_size) 67 | self.mousePressedY = int(event.x/self.square_size) 68 | #this function returns nothing, it just updates the mousePressedX and mousePressedY variables 69 | return 70 | 71 | #this function fires when the mouse is released 72 | def Mousereleased (self, event): 73 | #get the location of the mouse released event 74 | self.mouseReleasedX = event.y 75 | self.mouseReleasedY = event.x 76 | #initialize a list to verify the move 77 | self.move2compare = [] 78 | #append the position of the mouse clicked and the mouse released location 79 | self.move2compare.append((self.mousePressedX, self.mousePressedY, int(self.mouseReleasedX/self.square_size), int(self.mouseReleasedY/self.square_size))) 80 | #calls the function determinePiece() from the board.py 81 | board.Board().determinePiece(self.move2compare) 82 | #this calls back the function drawPieces() after 100 miliseconds 83 | self.root.after(100, self.drawPieces()) 84 | return 85 | 86 | 87 | 88 | #this function is used to draw the pieces on the board 89 | def drawPieces(self): 90 | 91 | 92 | #all these lines set the variables to the right image path 93 | #subsample function reduces the size of the image 94 | self.w.whiteRook = PhotoImage(file='rookWhite.gif').subsample(4,4) 95 | self.w.whiteKnight = PhotoImage(file='knightWhite.gif').subsample(4,4) 96 | self.w.whiteBishop = PhotoImage(file='bishopWhite.gif').subsample(4,4) 97 | self.w.whiteQueen = PhotoImage(file='queenWhite.gif').subsample(4,4) 98 | self.w.whiteKing = PhotoImage(file='kingWhite.gif').subsample(4,4) 99 | self.w.whitePawn = PhotoImage(file='pawnWhite.gif').subsample(4,4) 100 | 101 | self.w.blackPawn = PhotoImage(file='pawnBlack.gif').subsample(4,4) 102 | self.w.blackRook = PhotoImage(file='rookBlack.gif').subsample(4,4) 103 | self.w.blackKnight = PhotoImage(file='knightBlack.gif').subsample(4,4) 104 | self.w.blackBishop = PhotoImage(file='bishopBlack.gif').subsample(4,4) 105 | self.w.blackQueen = PhotoImage(file='queenBlack.gif').subsample(4,4) 106 | self.w.blackKing = PhotoImage(file='kingBlack.gif').subsample(4,4) 107 | 108 | #iterates through all the tiles 109 | for i in range(64): 110 | #if the particular tile on the board has the letter "R", then a white Rook will be placed 111 | if board.Board().chessBoard[int(i/8)][i%8] == "R": 112 | WRook = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.whiteRook) 113 | self.w.tag_bind(WRook, '', self.Mousepress) #binding the rook image with the function Mousepress() 114 | self.w.tag_bind(WRook, '', self.Mousereleased) #binding the rook image with the function Mousereleased() 115 | 116 | #if the particular tile on the board has the letter "N", then a white Knight will be placed 117 | elif board.Board().chessBoard[int(i/8)][i%8] == "N": 118 | WKnight = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.whiteKnight) 119 | self.w.tag_bind(WKnight, '', self.Mousepress) #binding the knight image with the function Mousepress() 120 | self.w.tag_bind(WKnight, '', self.Mousereleased) #binding the knight image with the function Mousereleased() 121 | 122 | #if the particular tile on the board has the letter "B", then a white Bishop will be placed 123 | elif board.Board().chessBoard[int(i/8)][i%8] == "B": 124 | WBishop = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.whiteBishop) 125 | self.w.tag_bind(WBishop, '', self.Mousepress) #binding the bishop image with the function Mousepress() 126 | self.w.tag_bind(WBishop, '', self.Mousereleased) #binding the bishop image with the function Mousereleased() 127 | 128 | #if the particular tile on the board has the letter "Q", then a white Queen will be placed 129 | elif board.Board().chessBoard[int(i/8)][i%8] == "Q": 130 | WQueen = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.whiteQueen) 131 | self.w.tag_bind(WQueen, '', self.Mousepress) #binding the queen image with the function Mousepress() 132 | self.w.tag_bind(WQueen, '', self.Mousereleased) #binding the queen image with the function Mousereleased() 133 | 134 | elif board.Board().chessBoard[int(i/8)][i%8] == "K": 135 | WKing = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.whiteKing) 136 | self.w.tag_bind(WKing, '', self.Mousepress) 137 | self.w.tag_bind(WKing, '', self.Mousereleased) 138 | 139 | elif board.Board().chessBoard[int(i/8)][i%8] == "P": 140 | WPawn = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.whitePawn) 141 | self.w.tag_bind(WPawn, '', self.Mousepress) 142 | self.w.tag_bind(WPawn, '', self.Mousereleased) 143 | 144 | elif board.Board().chessBoard[int(i/8)][i%8] == "p": 145 | BPawn = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.blackPawn) 146 | self.w.tag_bind(BPawn, '', self.Mousepress) 147 | self.w.tag_bind(BPawn, '', self.Mousereleased) 148 | 149 | elif board.Board().chessBoard[int(i/8)][i%8] == "r": 150 | BRook = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.blackRook) 151 | self.w.tag_bind(BRook, '', self.Mousepress) 152 | self.w.tag_bind(BRook, '', self.Mousereleased) 153 | 154 | elif board.Board().chessBoard[int(i/8)][i%8] == "n": 155 | BKnight = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.blackKnight) 156 | self.w.tag_bind(BKnight, '', self.Mousepress) 157 | self.w.tag_bind(BKnight, '', self.Mousereleased) 158 | 159 | elif board.Board().chessBoard[int(i/8)][i%8] == "b": 160 | BBishop = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.blackBishop) 161 | self.w.tag_bind(BBishop, '', self.Mousepress) 162 | self.w.tag_bind(BBishop, '', self.Mousereleased) 163 | 164 | elif board.Board().chessBoard[int(i/8)][i%8] == "q": 165 | BQueen = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.blackQueen) 166 | self.w.tag_bind(BQueen, '', self.Mousepress) 167 | self.w.tag_bind(BQueen, '', self.Mousereleased) 168 | 169 | elif board.Board().chessBoard[int(i/8)][i%8] == "k": 170 | BKing = self.w.create_image((i%8)*self.square_size+2, int(i/8)*self.square_size+2, anchor='nw', image=self.w.blackKing) 171 | self.w.tag_bind(BKing, '', self.Mousepress) 172 | self.w.tag_bind(BKing, '', self.Mousereleased) 173 | 174 | 175 | #calls the class 176 | BoardGUI() 177 | 178 | -------------------------------------------------------------------------------- /Chess.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | WHITE = "white" 3 | BLACK = "black" 4 | 5 | class Game: 6 | #ive decided since the number of pieces is capped but the type of pieces is not (pawn transformations), I've already coded much of the modularity to support just using a dictionary of pieces 7 | def __init__(self): 8 | self.playersturn = BLACK 9 | self.message = "this is where prompts will go" 10 | self.gameboard = {} 11 | self.placePieces() 12 | print("chess program. enter moves in algebraic notation separated by space") 13 | self.main() 14 | 15 | 16 | def placePieces(self): 17 | 18 | for i in range(0,8): 19 | self.gameboard[(i,1)] = Pawn(WHITE,uniDict[WHITE][Pawn],1) 20 | self.gameboard[(i,6)] = Pawn(BLACK,uniDict[BLACK][Pawn],-1) 21 | 22 | placers = [Rook,Knight,Bishop,Queen,King,Bishop,Knight,Rook] 23 | 24 | for i in range(0,8): 25 | self.gameboard[(i,0)] = placers[i](WHITE,uniDict[WHITE][placers[i]]) 26 | self.gameboard[((7-i),7)] = placers[i](BLACK,uniDict[BLACK][placers[i]]) 27 | placers.reverse() 28 | 29 | 30 | def main(self): 31 | 32 | while True: 33 | self.printBoard() 34 | print(self.message) 35 | self.message = "" 36 | startpos,endpos = self.parseInput() 37 | try: 38 | target = self.gameboard[startpos] 39 | except: 40 | self.message = "could not find piece; index probably out of range" 41 | target = None 42 | 43 | if target: 44 | print("found "+str(target)) 45 | if target.Color != self.playersturn: 46 | self.message = "you aren't allowed to move that piece this turn" 47 | continue 48 | if target.isValid(startpos,endpos,target.Color,self.gameboard): 49 | self.message = "that is a valid move" 50 | self.gameboard[endpos] = self.gameboard[startpos] 51 | del self.gameboard[startpos] 52 | self.isCheck() 53 | if self.playersturn == BLACK: 54 | self.playersturn = WHITE 55 | else : self.playersturn = BLACK 56 | else : 57 | self.message = "invalid move" + str(target.availableMoves(startpos[0],startpos[1],self.gameboard)) 58 | print(target.availableMoves(startpos[0],startpos[1],self.gameboard)) 59 | else : self.message = "there is no piece in that space" 60 | 61 | def isCheck(self): 62 | #ascertain where the kings are, check all pieces of opposing color against those kings, then if either get hit, check if its checkmate 63 | king = King 64 | kingDict = {} 65 | pieceDict = {BLACK : [], WHITE : []} 66 | for position,piece in self.gameboard.items(): 67 | if type(piece) == King: 68 | kingDict[piece.Color] = position 69 | print(piece) 70 | pieceDict[piece.Color].append((piece,position)) 71 | #white 72 | if self.canSeeKing(kingDict[WHITE],pieceDict[BLACK]): 73 | self.message = "White player is in check" 74 | if self.canSeeKing(kingDict[BLACK],pieceDict[WHITE]): 75 | self.message = "Black player is in check" 76 | 77 | 78 | def canSeeKing(self,kingpos,piecelist): 79 | #checks if any pieces in piece list (which is an array of (piece,position) tuples) can see the king in kingpos 80 | for piece,position in piecelist: 81 | if piece.isValid(position,kingpos,piece.Color,self.gameboard): 82 | return True 83 | 84 | def parseInput(self): 85 | try: 86 | a,b = input().split() 87 | a = ((ord(a[0])-97), int(a[1])-1) 88 | b = (ord(b[0])-97, int(b[1])-1) 89 | print(a,b) 90 | return (a,b) 91 | except: 92 | print("error decoding input. please try again") 93 | return((-1,-1),(-1,-1)) 94 | 95 | """def validateInput(self, *kargs): 96 | for arg in kargs: 97 | if type(arg[0]) is not type(1) or type(arg[1]) is not type(1): 98 | return False 99 | return True""" 100 | 101 | def printBoard(self): 102 | print(" 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |") 103 | for i in range(0,8): 104 | print("-"*32) 105 | print(chr(i+97),end="|") 106 | for j in range(0,8): 107 | item = self.gameboard.get((i,j)," ") 108 | print(str(item)+' |', end = " ") 109 | print() 110 | print("-"*32) 111 | 112 | 113 | 114 | """game class. contains the following members and methods: 115 | two arrays of pieces for each player 116 | 8x8 piece array with references to these pieces 117 | a parse function, which turns the input from the user into a list of two tuples denoting start and end points 118 | a checkmateExists function which checks if either players are in checkmate 119 | a checkExists function which checks if either players are in check (woah, I just got that nonsequitur) 120 | a main loop, which takes input, runs it through the parser, asks the piece if the move is valid, and moves the piece if it is. if the move conflicts with another piece, that piece is removed. ischeck(mate) is run, and if there is a checkmate, the game prints a message as to who wins 121 | """ 122 | 123 | class Piece: 124 | 125 | def __init__(self,color,name): 126 | self.name = name 127 | self.position = None 128 | self.Color = color 129 | def isValid(self,startpos,endpos,Color,gameboard): 130 | if endpos in self.availableMoves(startpos[0],startpos[1],gameboard, Color = Color): 131 | return True 132 | return False 133 | def __repr__(self): 134 | return self.name 135 | 136 | def __str__(self): 137 | return self.name 138 | 139 | def availableMoves(self,x,y,gameboard): 140 | print("ERROR: no movement for base class") 141 | 142 | def AdNauseum(self,x,y,gameboard, Color, intervals): 143 | """repeats the given interval until another piece is run into. 144 | if that piece is not of the same color, that square is added and 145 | then the list is returned""" 146 | answers = [] 147 | for xint,yint in intervals: 148 | xtemp,ytemp = x+xint,y+yint 149 | while self.isInBounds(xtemp,ytemp): 150 | #print(str((xtemp,ytemp))+"is in bounds") 151 | 152 | target = gameboard.get((xtemp,ytemp),None) 153 | if target is None: answers.append((xtemp,ytemp)) 154 | elif target.Color != Color: 155 | answers.append((xtemp,ytemp)) 156 | break 157 | else: 158 | break 159 | 160 | xtemp,ytemp = xtemp + xint,ytemp + yint 161 | return answers 162 | 163 | def isInBounds(self,x,y): 164 | "checks if a position is on the board" 165 | if x >= 0 and x < 8 and y >= 0 and y < 8: 166 | return True 167 | return False 168 | 169 | def noConflict(self,gameboard,initialColor,x,y): 170 | "checks if a single position poses no conflict to the rules of chess" 171 | if self.isInBounds(x,y) and (((x,y) not in gameboard) or gameboard[(x,y)].Color != initialColor) : return True 172 | return False 173 | 174 | 175 | chessCardinals = [(1,0),(0,1),(-1,0),(0,-1)] 176 | chessDiagonals = [(1,1),(-1,1),(1,-1),(-1,-1)] 177 | 178 | def knightList(x,y,int1,int2): 179 | """sepcifically for the rook, permutes the values needed around a position for noConflict tests""" 180 | return [(x+int1,y+int2),(x-int1,y+int2),(x+int1,y-int2),(x-int1,y-int2),(x+int2,y+int1),(x-int2,y+int1),(x+int2,y-int1),(x-int2,y-int1)] 181 | def kingList(x,y): 182 | return [(x+1,y),(x+1,y+1),(x+1,y-1),(x,y+1),(x,y-1),(x-1,y),(x-1,y+1),(x-1,y-1)] 183 | 184 | 185 | 186 | class Knight(Piece): 187 | def availableMoves(self,x,y,gameboard, Color = None): 188 | if Color is None : Color = self.Color 189 | return [(xx,yy) for xx,yy in knightList(x,y,2,1) if self.noConflict(gameboard, Color, xx, yy)] 190 | 191 | class Rook(Piece): 192 | def availableMoves(self,x,y,gameboard ,Color = None): 193 | if Color is None : Color = self.Color 194 | return self.AdNauseum(x, y, gameboard, Color, chessCardinals) 195 | 196 | class Bishop(Piece): 197 | def availableMoves(self,x,y,gameboard, Color = None): 198 | if Color is None : Color = self.Color 199 | return self.AdNauseum(x, y, gameboard, Color, chessDiagonals) 200 | 201 | class Queen(Piece): 202 | def availableMoves(self,x,y,gameboard, Color = None): 203 | if Color is None : Color = self.Color 204 | return self.AdNauseum(x, y, gameboard, Color, chessCardinals+chessDiagonals) 205 | 206 | class King(Piece): 207 | def availableMoves(self,x,y,gameboard, Color = None): 208 | if Color is None : Color = self.Color 209 | return [(xx,yy) for xx,yy in kingList(x,y) if self.noConflict(gameboard, Color, xx, yy)] 210 | 211 | class Pawn(Piece): 212 | def __init__(self,color,name,direction): 213 | self.name = name 214 | self.Color = color 215 | #of course, the smallest piece is the hardest to code. direction should be either 1 or -1, should be -1 if the pawn is traveling "backwards" 216 | self.direction = direction 217 | def availableMoves(self,x,y,gameboard, Color = None): 218 | if Color is None : Color = self.Color 219 | answers = [] 220 | if (x+1,y+self.direction) in gameboard and self.noConflict(gameboard, Color, x+1, y+self.direction) : answers.append((x+1,y+self.direction)) 221 | if (x-1,y+self.direction) in gameboard and self.noConflict(gameboard, Color, x-1, y+self.direction) : answers.append((x-1,y+self.direction)) 222 | if (x,y+self.direction) not in gameboard and Color == self.Color : answers.append((x,y+self.direction))# the condition after the and is to make sure the non-capturing movement (the only fucking one in the game) is not used in the calculation of checkmate 223 | return answers 224 | 225 | uniDict = {WHITE : {Pawn : "♙", Rook : "♖", Knight : "♘", Bishop : "♗", King : "♔", Queen : "♕" }, BLACK : {Pawn : "♟", Rook : "♜", Knight : "♞", Bishop : "♝", King : "♚", Queen : "♛" }} 226 | 227 | Game() 228 | -------------------------------------------------------------------------------- /Chess Game/board.py: -------------------------------------------------------------------------------- 1 | #Initiliazes the global variables to keep up with the states in chess 2 | KingcastlingStateWhite = True 3 | KingcastlingStateBlack = True 4 | QueencastlingStateBlack = True 5 | QueencastlingStateWhite = True 6 | whiteUnderCheck = False 7 | blackUnderCheck = False 8 | whiteMoveMade = False 9 | checkMate = False 10 | 11 | class Board: 12 | 13 | #initialize the board and the pieces' position in a 2-D list 14 | #lowercase lettes represent the black pieces while uppercase letters represent the white pieces 15 | #8X8 sized list 16 | chessBoard = [["r", "n" ,"b", "q", "k", "b","n", "r"], 17 | ["p", "p" ,"p", "p", "p", "p","p", "p"], #lowercase n = black knight, uppercase N = white knight 18 | [" ", " " ," ", " ", " ", " "," ", " "], #lowercase r = black rook, uppercase R = white rook 19 | [" ", " " ," ", " ", " ", " "," ", " "], #lowercase b = black bishop, uppercase B = white bishop 20 | [" ", " " ," ", " ", " ", " "," ", " "], #lowercase q = black queen, uppercase Q = white queen 21 | [" ", " " ," ", " ", " ", " "," ", " "], #lowercase k = black king, uppercase K = white king 22 | ["P", "P" ,"P", "P", "P", "P","P", "P"], #lowercase p = black pawn, uppercase P = white pawn 23 | ["R", "N" ,"B", "Q", "K", "B","N", "R"]] 24 | 25 | #this function is evoked by the GUI to determine the position of the piece that was selected to move 26 | def determinePiece(self, move2compare): 27 | #get the global variables 28 | global KingcastlingStateBlack 29 | global KingcastlingStateWhite 30 | global QueencastlingStateWhite 31 | global QueencastlingStateBlack 32 | 33 | #variable initialization 34 | self.move2compare = move2compare 35 | Kingcolour = "" 36 | colour = "" 37 | 38 | #get the coordinates of the move that was made 39 | self.x1 = self.move2compare[0][0] 40 | self.y1 = self.move2compare[0][1] 41 | self.x2 = self.move2compare[0][2] 42 | self.y2 = self.move2compare[0][3] 43 | 44 | 45 | #get the name of the piece on that particular coordinate 46 | self.pieceOnBoard = self.chessBoard[self.x1][self.y1] 47 | 48 | #get all the possible moves that can be made by that particular piece 49 | the_possible_moves = self.possibleMoves(self.pieceOnBoard) 50 | 51 | #this if-else statement is required to check for castling moves 52 | #this following statement checks for king's movement over 1 tiles 53 | if (self.pieceOnBoard == "K" or self.pieceOnBoard == 'k') and (self.y2 - self.y1 == 2 or self.y2 - self.y1 == -2): 54 | 55 | if KingcastlingStateBlack == True or KingcastlingStateWhite == True or QueencastlingStateWhite == True or QueencastlingStateBlack == True : 56 | 57 | #check for white's castling state 58 | if self.pieceOnBoard == "K" and (QueencastlingStateWhite == True or KingcastlingStateWhite == True): 59 | #if the above checks are passed, the Castling function will be called by passing the necessary parameters 60 | if (self.x2 == 7 and self.y2 == 6) and KingcastlingStateWhite == True: 61 | self.Kingcolour = "White" 62 | self.Castling(self.Kingcolour, self.x1, self.y1, self.x2, self.y2) 63 | #if the above checks are passed, the Castling function will be called by passing the necessary parameters 64 | elif (self.x2 == 7 and self.y2 == 2) and QueencastlingStateWhite == True: 65 | self.Kingcolour = "White" 66 | self.Castling(self.Kingcolour, self.x1, self.y1, self.x2, self.y2) 67 | 68 | #checck for black's castling state 69 | elif self.pieceOnBoard == "k" and (QueencastlingStateBlack == True or KingcastlingStateBlack == True): 70 | if (self.x2 == 0 and self.y2 == 6) and KingcastlingStateBlack == True: 71 | #if the above checks are passed, the Castling function will be called by passing the necessary parameters 72 | self.Kingcolour ="Black" 73 | self.Castling(self.Kingcolour, self.x1, self.y1, self.x2, self.y2) 74 | elif (self.x2 == 0 and self.y2 == 2) and QueencastlingStateBlack == True: 75 | #if the above checks are passed, the Castling function will be called by passing the necessary parameters 76 | self.Kingcolour ="Black" 77 | self.Castling(self.Kingcolour, self.x1, self.y1, self.x2, self.y2) 78 | else: 79 | pass 80 | 81 | #possibleOrNot() function is called to check if the proposed move is in the list of the possible moves 82 | elif(self.possibleOrNot(self.move2compare, the_possible_moves)): 83 | #if the above check is passed, then makeMove() function will be fired to execute the move. Parameter 3 is simply given to notify that this is not a castling call. 84 | self.makeMove(move2compare, 3) 85 | else: 86 | pass 87 | 88 | #this function deter4mines whether the move made by the players are possible or not by comparing with all the possible moves on the board for the particular piece 89 | def possibleOrNot(self, proposedMove, thepossibleMoves): 90 | 91 | #variable initialization 92 | self.proposedMove = proposedMove 93 | self.possibleMoveslist = thepossibleMoves 94 | 95 | #list initialization 96 | proposedMove2compare = [] 97 | 98 | #get the coordinates of the user's move 99 | self.x1 = self.proposedMove[0][0] 100 | self.y1 = self.proposedMove[0][1] 101 | self.x2 = self.proposedMove[0][2] 102 | self.y2 = self.proposedMove[0][3] 103 | 104 | #if the user made a move to capture the opponent's piece, then the captured piece will be recorded at the end of the string 105 | if self.chessBoard[self.x2][self.y2] != " ": 106 | proposedMove2compare.append((self.x1, self.y1, self.x2, self.y2, self.chessBoard[self.x2][self.y2])) 107 | else: 108 | proposedMove2compare.append((self.x1,self.y1,self.x2,self.y2)) 109 | 110 | #this function will finally return the boolean value produced from the comparison of the move made by the user and the possible moves of the piece on the board 111 | return set(proposedMove2compare) <= set(self.possibleMoveslist) 112 | 113 | #this function is responsible for executing the move made by the user. 114 | #the function takes the move made by the user and a number representing whether it's a casting move or not 115 | #castling move made for the white piece is denoted by the integer "1", "2" for black and "3" for not castling move 116 | def makeMove(self, proposedMove, castlingState): 117 | #get the coordinates of the user's move 118 | self.x1 = proposedMove[0][0] 119 | self.y1 = proposedMove[0][1] 120 | self.x2 = proposedMove[0][2] 121 | self.y2 = proposedMove[0][3] 122 | 123 | #this statement will initialize the following variable as "White" if the move was made by the black piece player and "Black" if otherwise 124 | colour_to_check_opponent_threat = "White" if ord(self.chessBoard[self.x1][self.y1]) >= 97 else "Black" 125 | 126 | #get the global variables to update accordingly 127 | global whiteMoveMade 128 | global QueencastlingStateWhite 129 | global KingcastlingStateWhite 130 | global KingcastlingStateBlack 131 | global QueencastlingStateBlack 132 | global blackUnderCheck 133 | global whiteUnderCheck 134 | 135 | tempPiece = "" 136 | #get the piece that the user selected to move 137 | self.getChar = self.chessBoard[self.x1][self.y1] 138 | #if the piece moved was a king or rook, set the castling state to false. If a rook is moved, the rook will be checked first and then set the state accordingly. 139 | if self.getChar == "K" or self.getChar == "R": 140 | #if it was a rook that has been moved, the rook will be identified first 141 | if self.getChar == "R": 142 | #if it is the King's side rook, then the King's side castling state will be set to false 143 | if self.x1 == 7 and self.y1 == 7: 144 | KingcastlingStateWhite = False 145 | #if it is the Queen's side rook, then the Queen's side castling state will be set to false. 146 | elif self.x1 == 7 and self.y1 == 0: 147 | QueencastlingStateWhite = False 148 | #if it was the king that has been moved, then both of the castling state will be set to false 149 | if self.getChar == "K": 150 | QueencastlingStateWhite = False 151 | KingcastlingStateWhite = False 152 | 153 | elif self.getChar == "k" or self.getChar == "r": 154 | #if it was a rook that has been moved, the rook will be identified first 155 | if self.getChar == 'r': 156 | #if it is the Queen's side rook, then the Queen's side castling state will be set to false 157 | if self.x1 == 0 and self.y1 == 0: 158 | QueencastlingStateWhite = False 159 | #if it is the King's side rook, then the King's side castling state will be set to false 160 | elif self.x1 == 0 and self.y1 == 7: 161 | KingcastlingStateBlack = False 162 | #if it was the king that has been moved, then both of the castling state will be set to false 163 | if self.getChar == "k": 164 | QueencastlingStateBlack = False 165 | KingcastlingStateBlack = False 166 | else: 167 | pass 168 | 169 | #check if the move is made by the white piece player 170 | #the variable whiteMoveMade = False indicates that white piece player has yet to make a move 171 | if (ord(self.getChar) >= 65 and ord(self.getChar) <= 90) and whiteMoveMade == False: 172 | 173 | 174 | self.chessBoard[self.x1][self.y1] = " " #make the current tile empty 175 | tempPiece = self.chessBoard[self.x2][self.y2] #keep the piece of the tile the move was made to in the variable 176 | self.chessBoard[self.x2][self.y2] = self.getChar #make the tile where the move is made occupied with the piece that was selected to make the move 177 | whiteMoveMade = True #set the variable to indicate that the white piece player has made a move 178 | 179 | 180 | if self.CheckState("White") == True: #if the white piece player's move exposes the King, then the move will be retreated back 181 | self.chessBoard[self.x1][self.y1] = self.getChar 182 | self.chessBoard[self.x2][self.y2] = tempPiece 183 | whiteMoveMade = False #returns the value back to false 184 | else: 185 | #check if the pawn has made it to promotion or not 186 | self.Promotion_Check("White") 187 | 188 | #check if the move is made by the black piece player 189 | #the variable whiteMoveMade = False indicates that black piece player has yet to make a move 190 | elif (ord(self.getChar) >= 97 and ord(self.getChar) <= 122) and whiteMoveMade == True: 191 | 192 | self.chessBoard[self.x1][self.y1] = " " #make the current tile empty 193 | tempPiece = self.chessBoard[self.x2][self.y2] #keep the piece of the tile the move was made to in the variable 194 | self.chessBoard[self.x2][self.y2] = self.getChar #make the tile where the move is made occupied with the piece that was selected to make the move 195 | whiteMoveMade = False #set the variable to indicate that the black piece player has made a move 196 | 197 | if self.CheckState("Black") == True: #if the black piece player's move exposes the King, then the move will be retreated back 198 | 199 | self.chessBoard[self.x1][self.y1] = self.getChar 200 | self.chessBoard[self.x2][self.y2] = tempPiece 201 | whiteMoveMade = True 202 | else: 203 | #check if the pawn has made it to promotion or not 204 | self.Promotion_Check("Black") 205 | else: 206 | pass 207 | 208 | #if the move was a castling move, the whiteMoveMade variable will be set to false to allow the Rook to move for the second time after the King 209 | if castlingState == 1: 210 | whiteMoveMade = False 211 | elif castlingState == 2: 212 | whiteMoveMade = True 213 | else: 214 | pass 215 | 216 | #CheckState() is a function to check if the move made has "Checked" the opponent's King or not 217 | if colour_to_check_opponent_threat == "White": 218 | whiteUnderCheck = self.CheckState(colour_to_check_opponent_threat) 219 | elif colour_to_check_opponent_threat == "Black": 220 | blackUnderCheck = self.CheckState(colour_to_check_opponent_threat) 221 | else: 222 | pass 223 | #if the CheckState() function returns true, Check_Checkmate() is called to check if a checkmate is made or not. 224 | if self.CheckState("Black") == True: 225 | self.Check_CheckMate("Black") 226 | if self.CheckState("White") == True: 227 | self.Check_CheckMate("White") 228 | 229 | 230 | 231 | 232 | #calculate all the legal moves 233 | def possibleMoves(self, piece): 234 | 235 | self.piece = piece 236 | #initialize the list to store the legal moves 237 | movesList = [] 238 | #iterates over all the tiles on the board 239 | for i in range(64): 240 | 241 | #in Python3, int have to be used to floor the value 242 | 243 | #check if there's a white rook at the coordinate 244 | if self.chessBoard[int(i/8)][i%8] == "R" and self.piece == "R": 245 | movesList += self.RookMove(i, "White") 246 | 247 | #check if there's a black rook at the coordinate 248 | elif self.chessBoard[int(i/8)][i%8] == 'r' and self.piece == 'r': 249 | movesList += self.RookMove(i, "Black") 250 | 251 | #check if there's a white knight at the coordinate 252 | elif self.chessBoard[int(i/8)][i%8] == "N" and self.piece == 'N' : 253 | movesList += self.KnightMove(i, "White") 254 | 255 | #check if there's a black knight at the coordinate 256 | elif self.chessBoard[int(i/8)][i%8] == "n" and self.piece == 'n' : 257 | movesList += self.KnightMove(i, "Black") 258 | 259 | #check if there's a white bishop at the coordinate 260 | elif self.chessBoard[int(i/8)][i%8] == "B" and self.piece == 'B' : 261 | movesList += self.BishopMove(i, "White") 262 | 263 | #check if there's a black bishop at the coordinate 264 | elif self.chessBoard[int(i/8)][i%8] == "b" and self.piece == 'b' : 265 | movesList += self.BishopMove(i, "Black") 266 | 267 | #check if there's a white queen at the coordinate 268 | elif self.chessBoard[int(i/8)][i%8] == "Q" and self.piece == 'Q' : 269 | movesList += self.QueenMove(i, "White") 270 | 271 | #check if there's a black queen at the coordinate 272 | elif self.chessBoard[int(i/8)][i%8] == "q" and self.piece == 'q' : 273 | movesList += self.QueenMove(i, "Black") 274 | 275 | #check if there's a white king at the coordinate 276 | elif self.chessBoard[int(i/8)][i%8] == "K" and self.piece == 'K' : 277 | movesList += self.KingMove(i, "White") 278 | 279 | elif self.chessBoard[int(i/8)][i%8] == "k" and self.piece == 'k' : 280 | movesList += self.KingMove(i, "Black") 281 | 282 | # check if there's a white pawn at the coordinate 283 | elif self.chessBoard[int(i/8)][i%8] == "P" and self.piece == 'P' : 284 | movesList += self.WhitePawnMove(i) 285 | 286 | # check if there's a black pawn at the coordinate 287 | elif self.chessBoard[int(i/8)][i%8] == 'p' and self.piece == 'p' : 288 | movesList += self.BlackPawnMove(i) 289 | 290 | #returns the list of appended movement lists 291 | return movesList 292 | 293 | 294 | ################### MOVEMENT OF PIECES ##################################### 295 | 296 | 297 | ############# BEGINNING OF PAWN'S MOVEMENTS ################# 298 | 299 | #function to calculate the legal moves for white pawns 300 | def WhitePawnMove(self,position): 301 | 302 | #initialize the list to return later 303 | moves = [] 304 | 305 | #initialize the variable to check if there's a piece in front of the pawn 306 | firstStepBlock = False 307 | 308 | #get the coordinates 309 | r = int(position / 8) 310 | c = position % 8 311 | 312 | # row 6 is white pawn's initial position 313 | if r == 6: 314 | #looping for 2 boxes ahead 315 | for x in range(5, 3, -1): 316 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 317 | try: 318 | #check whether the box in front is empty or not 319 | if self.chessBoard[x][c] == " " and firstStepBlock == False: 320 | #these 4 lines appends the original position and the target position 321 | moves.append((r,c,x,c)) 322 | 323 | 324 | else: 325 | #if there is a piece in front, the variable will be set to true 326 | firstStepBlock = True 327 | 328 | except Exception as e: 329 | pass 330 | else: 331 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 332 | try: 333 | if self.chessBoard[r-1][c] == " ": 334 | #these 4 lines appends the original position and the target position 335 | moves.append((r,c,r-1,c)) 336 | 337 | except Exception as e: 338 | pass 339 | 340 | 341 | if r-1 >= 0: 342 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 343 | try: 344 | #test whether the pawns can take any materials or not (ord function cross checks with ASCII characters for lower case characters) 345 | if ord(self.chessBoard[r-1][c+1]) >= 97 and ord(self.chessBoard[r-1][c+1]) <= 122: 346 | 347 | #these 4 lines appends the original position and the target position 348 | moves.append((r,c, r-1, c+1, self.chessBoard[r-1][c+1])) 349 | except Exception as e: 350 | pass 351 | 352 | if r-1 >= 0 and c-1 >= 0: 353 | try: 354 | #test whether the pawns can take materials or not (ord function cross checks with ASCII characters for lower case characters) 355 | if ord(self.chessBoard[r-1][c-1]) >= 97 and ord(self.chessBoard[r-1][c-1]) <=122: 356 | 357 | #these 4 lines appends the original position and the target position 358 | moves.append((r,c, r-1, c-1, self.chessBoard[r-1][c-1])) 359 | 360 | except Exception as e: 361 | pass 362 | 363 | #returns all the legal moves 364 | return moves 365 | ###################### END OF WHITE PAWN'S MOVEMENT ################### 366 | 367 | ###################### BEGINNING OF BLACK PAWN'S MOVEMENT ############# 368 | def BlackPawnMove(self,position): 369 | 370 | #initialize the list to return later 371 | moves = [] 372 | 373 | #initialize the variable to check if there's a piece in front of the pawn 374 | firstStepBlock = False 375 | 376 | #get the coordinates 377 | r = int(position / 8) 378 | c = position % 8 379 | 380 | # row 1 is black pawn's initial position 381 | if r == 1: 382 | #looping for 2 boxes ahead 383 | for x in range(2, 4): 384 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 385 | try: 386 | #check whether the box in front is empty or not 387 | if self.chessBoard[x][c] == " " and firstStepBlock == False: 388 | #these 4 lines appends the original position and the target position 389 | moves.append((r,c,x,c)) 390 | 391 | 392 | else: 393 | #if there is a piece in front, the variable will be set to true 394 | firstStepBlock = True 395 | 396 | except Exception as e: 397 | pass 398 | else: 399 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 400 | try: 401 | if self.chessBoard[r+1][c] == " ": 402 | #these 4 lines appends the original position and the target position 403 | moves.append((r,c, r+1, c)) 404 | 405 | except Exception as e: 406 | pass 407 | 408 | 409 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 410 | try: 411 | 412 | #test whether the pawns can take any materials or not (ord function cross checks with ASCII characters for lower case characters) 413 | if r+1 >= 0 and c-1 >= 0: 414 | if ord(self.chessBoard[r+1][c+1]) >= 65 and ord(self.chessBoard[r+1][c+1]) <= 90: 415 | #these 4 lines appends the original position and the target position 416 | moves.append((r,c, r+1, c+1, self.chessBoard[r+1][c+1])) 417 | except Exception as e: 418 | pass 419 | 420 | try: 421 | #test whether the pawns can take materials or not (ord function cross checks with ASCII characters for lower case characters) 422 | if ord(self.chessBoard[r+1][c-1]) >= 65 and ord(self.chessBoard[r+1][c-1]) <=90: 423 | #these 4 lines appends the original position and the target position 424 | moves.append((r,c, r+1, c-1, self.chessBoard[r+1][c-1])) 425 | except Exception as e: 426 | pass 427 | 428 | 429 | 430 | #returns all the legal moves 431 | return moves 432 | 433 | ###################### END OF BLACK PAWN'S MOVEMENT ################### 434 | 435 | 436 | ###################### BEGINNING OF ROOK'S MOVEMENT ############# 437 | def RookMove(self, position, colour): 438 | 439 | #set the variables according to colour of the piece 440 | if colour == "White": 441 | #these values represents the range of lowercase letters 442 | ordA, ordB = 97, 122 443 | 444 | elif colour == "Black": 445 | #these values represents the range of uppercase letters 446 | ordA, ordB = 65, 90 447 | 448 | #list initialization 449 | moves = [] 450 | 451 | #coordinate of the pieces 452 | r = int(position / 8) 453 | c = position % 8 454 | 455 | #variable initialization to iterate until the end of the board 456 | temp = 1 457 | 458 | #this loop iterates from -1 to 1 to change the direction of the iterations ( bottom, top ,right and left) 459 | for j in range (-1, 2, 2): 460 | 461 | #initialize the variable back to 1 462 | temp = 1 463 | 464 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 465 | try: 466 | 467 | #iteration to the end of the board until there's a piece in the way 468 | while(self.chessBoard[r+temp*j][c] == " " and temp < 8): 469 | 470 | #if statement to make sure the value of the row does not go below 0 471 | if r+temp*j >= 0: 472 | #append the legal moves to the list 473 | moves.append((r,c,r+temp*j,c)) 474 | #increase the value to iterate through the remaining boxes 475 | temp = temp + 1 476 | 477 | #check whether there is an enemy's piece to be captured or not 478 | if ord(self.chessBoard[r+temp*j][c]) >= ordA and ord(self.chessBoard[r+temp*j][c]) <= ordB: 479 | 480 | #if statement to make sure the value of the row does not go below 0 481 | if r+temp*j >= 0: 482 | #append the legal moves to the list 483 | moves.append((r,c,r+temp*j,c, self.chessBoard[r+temp*j][c])) 484 | 485 | except IndexError: 486 | pass 487 | 488 | #initialize the variable back 489 | temp=1 490 | 491 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 492 | try: 493 | #iteration to the end of the board until there's a piece in the way 494 | while(self.chessBoard[r][c+temp*j] == " " and temp < 8): 495 | 496 | #if statement to make sure the value of the column does not go below 0 497 | if c+temp*j >= 0: 498 | #append the legal moves to the list 499 | moves.append((r,c,r,c+temp*j)) 500 | #increase the value to iterate through the remaining boxes 501 | temp = temp + 1 502 | 503 | #check whether there is an enemy's piece to be captured or not 504 | if ord(self.chessBoard[r][c+temp*j]) >= ordA and ord(self.chessBoard[r][c+temp*j]) <= ordB: 505 | 506 | #if statement to make sure the value of the column does not go below 0 507 | if c+temp*j >= 0: 508 | #append the legal moves to the list 509 | moves.append((r,c,r,c+temp*j,self.chessBoard[r][c+temp*j])) 510 | 511 | except IndexError: 512 | pass 513 | #returns all the legal moves 514 | return moves 515 | 516 | ###################### END OF ROOK'S MOVEMENT ############# 517 | 518 | ########### BEGINNING OF KNIGHTS' MOVEMENT ######################## 519 | 520 | def KnightMove(self, position, colour): 521 | 522 | #set the variables according to colour of the piece 523 | if colour == "White": 524 | #these values represents the range of lowercase letters 525 | ordA, ordB = 97, 122 526 | 527 | elif colour == "Black": 528 | #these values represents the range of uppercase letters 529 | ordA, ordB = 65, 90 530 | 531 | #list initialization 532 | moves = [] 533 | 534 | #get the coordinate 535 | r = int(position / 8) 536 | c = position % 8 537 | 538 | #these nested loops will complete all the 8 possible route for a knight 539 | for j in range(-1 ,2, 2): 540 | 541 | for k in range(-1, 2, 2): 542 | 543 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 544 | try: 545 | #checks if the target box is empty or occupied with an enemy's piece 546 | if self.chessBoard[r+j][c+k*2] == " " or (ord(self.chessBoard[r+j][c+k*2]) >= ordA and ord(self.chessBoard[r+j][c+k*2]) <= ordB): 547 | 548 | 549 | #makes sure the row or column does not have a value less than 0 550 | if r+j >=0 and c+k*2 >= 0: 551 | #append the legal moves into the list 552 | if self.chessBoard[r+j][c+k*2] == " ": 553 | moves.append((r,c,r+j,c+k*2)) 554 | else: 555 | moves.append((r,c,r+j,c+k*2,self.chessBoard[r+j][c+k*2])) 556 | 557 | except IndexError: 558 | pass 559 | 560 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 561 | try: 562 | #checks if the target box is empty or occupied with an enemy's piece 563 | if self.chessBoard[r+j*2][c+k] == " " or (ord(self.chessBoard[r+j*2][c+k]) >= ordA and ord(self.chessBoard[r+j*2][c+k]) <= ordB): 564 | 565 | #makes sure the row or column does not have a value less than 0 566 | if r+j*2 >= 0 and c+k >= 0: 567 | #append the legal moves into the list 568 | if self.chessBoard[r+j*2][c+k] == " ": 569 | moves.append((r,c,r+j*2,c+k)) 570 | else: 571 | moves.append((r,c,r+j*2,c+k,self.chessBoard[r+j*2][c+k])) 572 | 573 | except IndexError: 574 | pass 575 | 576 | #return all the possible moves 577 | return moves 578 | 579 | ###### END OF KNIGHT'S MOVEMENT ######################################### 580 | 581 | ###### BEGINNING OF BISHOP'S MOVEMENT ###################################### 582 | 583 | 584 | def BishopMove(self, position, colour): 585 | 586 | #set the variables according to colour of the piece 587 | if colour == "White": 588 | #these values represents the range of lowercase letters 589 | ordA, ordB = 97, 122 590 | 591 | elif colour == "Black": 592 | #these values represents the range of uppercase letters 593 | ordA, ordB = 65, 90 594 | 595 | #initialize list 596 | moves = [] 597 | 598 | #get the coordinate 599 | r = int(position / 8) 600 | c = position % 8 601 | 602 | #variable initialization to iterate through the diagonal line to the end 603 | temp = 1 604 | 605 | #these nested loops will be responsible for the movement to top, bottom, right and left by constantly changing from -1 to 1 606 | for j in range(-1,2,2): 607 | 608 | for k in range(-1,2,2): 609 | 610 | #initialize it back 611 | temp = 1 612 | 613 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 614 | try: 615 | #this while loop will iterate until there is no empty box to the end of the board 616 | while (self.chessBoard[r+temp*j][c+temp*k] == " " and temp < 8): 617 | 618 | #test to make sure the value of the row and column does not go below 0 619 | if r+temp*j >= 0 and c+temp*k >= 0: 620 | #append the legal moves into the list 621 | moves.append((r,c,r+temp*j,c+temp*k)) 622 | 623 | #increase the value to iterate through the remaining boxes 624 | temp = temp + 1 625 | 626 | #check whether there is an enemy's piece to be captured or not 627 | if (ord(self.chessBoard[r+temp*j][c+temp*k]) >= ordA and ord(self.chessBoard[r+temp*j][c+temp*k]) <=ordB) and temp < 8 : 628 | 629 | #test to make sure the value of the row and column does not go below 0 630 | if r+temp*j >= 0 and c+temp*k >= 0: 631 | 632 | #append the legal moves into the list 633 | moves.append((r,c, r+temp*j, c+temp*k, self.chessBoard[r+temp*j][c+temp*k])) 634 | 635 | except IndexError: 636 | pass 637 | 638 | return moves 639 | ########## ENDING OF THE WHITE BISHOP'S MOVEMENT ####################### 640 | 641 | ########## BEGINNING OF THE WHITE QUEEN'S MOVEMENT ##################### 642 | def QueenMove(self, position, colour): 643 | 644 | #set the variables according to colour of the piece 645 | if colour == "White": 646 | #these values represents the range of lowercase letters 647 | ordA, ordB = 97, 122 648 | 649 | elif colour == "Black": 650 | #these values represents the range of uppercase letters 651 | ordA, ordB = 65, 90 652 | 653 | #initialize list 654 | moves = [] 655 | 656 | #get the coordinate 657 | r = int(position / 8) 658 | c = position % 8 659 | 660 | #initialize the variable 661 | temp = 1 662 | 663 | #nested loop that implements the movement of a rook and bishop 664 | #first loop for the horizontal and vertical iteration 665 | for j in range(-1,2,2): 666 | 667 | #initialize the variable to iterate all over again 668 | temp = 1 669 | 670 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 671 | try: 672 | 673 | #iterate through the boxes vertically both way 674 | while(self.chessBoard[r+temp*j][c] == " " and temp < 8): 675 | 676 | #makes sure that the index of the row does not go below 0 677 | if r+temp*j >= 0: 678 | #append the legal moves into the list 679 | moves.append((r,c,r+temp*j,c)) 680 | 681 | #increase the value to iterate through the remaining boxes 682 | temp = temp + 1 683 | 684 | #check whether there is an enemy's piece to be captured or not 685 | if (ord(self.chessBoard[r+temp*j][c]) >= ordA and ord(self.chessBoard[r+temp*j][c]) <= ordB) and temp < 8: 686 | #makes sure that the index of the row does not go below 0 687 | if r+temp*j >= 0: 688 | #append the legal moves into the list 689 | moves.append((r,c,r+temp*j,c, self.chessBoard[r+temp*j][c])) 690 | 691 | except IndexError: 692 | pass 693 | 694 | #initialize back the variable 695 | temp = 1 696 | 697 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 698 | try: 699 | #iterate through the boxes horizontally both way 700 | while (self.chessBoard[r][c+temp*j] == " " and temp < 8): 701 | 702 | #makes sure that the index of the column does not go below 0 703 | if c+temp*j >= 0: 704 | #append the legal moves into the list 705 | moves.append((r,c,r,c+temp*j)) 706 | 707 | temp = temp + 1 708 | 709 | if (ord(self.chessBoard[r][c+temp*j]) >= ordA and ord(self.chessBoard[r][c+temp*j]) <= ordB ) and temp < 8: 710 | 711 | #makes sure that the index of the column does not go below 0 712 | if c+temp*j >= 0: 713 | #append the legal moves into the list 714 | moves.append((r,c,r,c+temp*j,self.chessBoard[r][c+temp*j])) 715 | 716 | except IndexError: 717 | pass 718 | 719 | #second loop for the diagonal iteration 720 | for k in range(-1,2,2): 721 | 722 | #initialize back the variable 723 | temp = 1 724 | 725 | #iterate through the boxes diagonally both way 726 | try: 727 | while (self.chessBoard[r+temp*j][c+temp*k] == " " and temp < 8): 728 | 729 | #makes sure that the index of the column and row does not go below 0 730 | if r+temp*j >= 0 and c+temp*k >=0 : 731 | #append the legal moves into the list 732 | moves.append((r,c, r+temp*j, c+temp*k)) 733 | #increase the value to iterate through the remaining boxes 734 | temp = temp + 1 735 | 736 | #check whether there is an enemy's piece to be captured or not 737 | if (ord(self.chessBoard[r+temp*j][c+temp*k]) >= ordA and ord(self.chessBoard[r+temp*j][c+temp*k]) <= ordB) and temp < 8: 738 | 739 | #makes sure that the index of the column and row does not go below 0 740 | if r+temp*j >= 0 and c+temp*k >= 0: 741 | #append the legal moves into the list 742 | moves.append((r,c, r+temp*j, c+temp*k, self.chessBoard[r+temp*j][c+temp*k])) 743 | 744 | except IndexError: 745 | pass 746 | #returns all the legal moves 747 | return moves 748 | 749 | ################## ENDING OF THE QUEEN'S MOVEMENT ############################ 750 | 751 | ################## BEGINNING OF THE KING'S MOVEMENT ########################## 752 | 753 | def KingMove(self, position, colour): 754 | 755 | #set the variables according to colour of the piece 756 | if colour == "White": 757 | #these values represents the range of lowercase letters 758 | ordA, ordB = 97, 122 759 | 760 | elif colour == "Black": 761 | #these values represents the range of uppercase letters 762 | ordA, ordB = 65, 90 763 | 764 | #initialize the list 765 | moves = [] 766 | 767 | #get the coordinate 768 | r = int(position / 8) 769 | c = position % 8 770 | 771 | #initialize the variable 772 | temp = 1 773 | 774 | #nested loop that implements the movement of a rook and bishop 775 | #first loop for the horizontal and vertical iteration 776 | for j in range(-1,2,2): 777 | 778 | #initialize the variable to iterate all over again 779 | temp = 1 780 | 781 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 782 | try: 783 | 784 | #iterate through the boxes vertically both way 785 | while(self.chessBoard[r+temp*j][c] == " " and temp < 2): 786 | 787 | #makes sure that the index of the row does not go below 0 788 | if r+temp*j >= 0: 789 | #append the legal moves into the list 790 | moves.append((r,c, r+temp*j, c)) 791 | #increase the value to iterate through the remaining boxes 792 | temp = temp + 1 793 | 794 | #check whether there is an enemy's piece to be captured or not 795 | if (ord(self.chessBoard[r+temp*j][c]) >= ordA and ord(self.chessBoard[r+temp*j][c]) <= ordB) and temp < 2: 796 | #makes sure that the index of the row does not go below 0 797 | if r+temp*j >= 0: 798 | #append the legal moves into the list 799 | moves.append((r,c, r+temp*j,c, self.chessBoard[r+temp*j][c])) 800 | 801 | 802 | except IndexError: 803 | pass 804 | 805 | #initialize back the variable 806 | temp = 1 807 | 808 | #Try-Exception is used to avoid errors regarding out of bounds index when the coordinates are beyond the chess board 809 | try: 810 | #iterate through the boxes horizontally both way 811 | while (self.chessBoard[r][c+temp*j] == " " and temp < 2): 812 | 813 | #makes sure that the index of the column does not go below 0 814 | if c+temp*j >= 0: 815 | #append the legal moves into the list 816 | moves.append((r,c,r,c+temp*j)) 817 | 818 | temp = temp + 1 819 | 820 | if (ord(self.chessBoard[r][c+temp*j]) >= ordA and ord(self.chessBoard[r][c+temp*j]) <= ordB ) and temp < 2: 821 | 822 | #makes sure that the index of the column does not go below 0 823 | if c+temp*j >= 0: 824 | #append the legal moves into the list 825 | moves.append((r,c,r,c+temp*j, self.chessBoard[r][c+temp*j])) 826 | 827 | except IndexError: 828 | pass 829 | 830 | #second loop for the diagonal iteration 831 | for k in range(-1,2,2): 832 | 833 | #initialize back the variable 834 | temp = 1 835 | 836 | #iterate through the boxes diagonally both way 837 | try: 838 | while (self.chessBoard[r+temp*j][c+temp*k] == " " and temp < 2): 839 | 840 | #makes sure that the index of the column and row does not go below 0 841 | if r+temp*j >= 0 and c+temp*k >=0 : 842 | #append the legal moves into the list 843 | moves.append((r,c, r+temp*j, c+temp*k)) 844 | 845 | #increase the value to iterate through the remaining boxes 846 | temp = temp + 1 847 | 848 | #check whether there is an enemy's piece to be captured or not 849 | if (ord(self.chessBoard[r+temp*j][c+temp*k]) >= ordA and ord(self.chessBoard[r+temp*j][c+temp*k]) <= ordB) and temp < 2: 850 | 851 | #makes sure that the index of the column and row does not go below 0 852 | if r+temp*j >= 0 and c+temp*k >= 0: 853 | #append the legal moves into the list 854 | moves.append((r,c, r+temp*j, c+temp*k, self.chessBoard[r+temp*j][c+temp*k])) 855 | 856 | 857 | except IndexError: 858 | pass 859 | return moves 860 | 861 | ################## END OF THE KING'S MOVEMENT ########################## 862 | 863 | ######################################## END OF PIECES' MOVEMENT ########################################## 864 | 865 | 866 | 867 | ######################## THREAD DETECTION AND CASTLING ################################################## 868 | 869 | #function to perform castling 870 | def Castling(self, colour, x1, y1, x2, y2): 871 | 872 | #variable initialization 873 | KingMove = [] 874 | RookMove = [] 875 | castlingAbility = True 876 | 877 | #check to see if the castling move was made by white piece player 878 | #x1 = 7 and y1 = 4 indicates that the King is in the initial position 879 | if colour == "White" and x1 == 7 and y1 == 4: 880 | #x2 = 7 and y2 = 6 indicates that the King is moved to the right side 2 tiles (King's side castling) 881 | if x2 == 7 and y2 == 6: 882 | #check if there exists a rook at the right end and the tiles between are empty 883 | if self.chessBoard[7][7] == "R" and self.chessBoard[7][5] == " " and self.chessBoard[7][6] == " ": 884 | #initialize these sets to check if they are attacked 885 | setA = [7,5] 886 | setB = [7,6] 887 | #Check_Opponent_Threat() is a function that detects all the threats that are made by a certain player 888 | for every_set in self.Check_Opponent_Threat("White", "Threat"): 889 | #if there exists a threat on the tiles that are about to be passed by the King, the castlingAbility variable will be set to false to deny the castling move 890 | if setA == every_set: 891 | castlingAbility = False 892 | if setB == every_set: 893 | castlingAbility = False 894 | #if there exists no threat on the selected tiles, the castling move can proceed 895 | if castlingAbility == True: 896 | #calling the makeMove function with parameter 1 to denote the white's castling move 897 | #calling the makeMove function for the second time with parameter 3 to denote the end of castling move 898 | KingMove.append((x1,y1,x2,y2)) 899 | RookMove.append((7,7,7,5)) 900 | self.makeMove(KingMove, 1) 901 | self.makeMove(RookMove, 3) 902 | 903 | 904 | else: 905 | pass 906 | #x2 = 7 and y2 = 2 indicates that the King is moved to the left side 2 tiles (Quuen's side castling) 907 | elif x2 == 7 and y2 == 2: 908 | #check if there exists a rook at the left end and the tiles between are empty 909 | if self.chessBoard[7][0] == "R" and self.chessBoard[7][1] == " " and self.chessBoard[7][2] == " " and self.chessBoard[7][3] == " ": 910 | #initialize these sets to check if they are attacked 911 | setA = [7,2] 912 | setB = [7,3] 913 | 914 | #Check_Opponent_Threat() is a function that detects all the threats that are made by a certain player 915 | for every_set in self.Check_Opponent_Threat("White", "Threat"): 916 | #if there exists a threat on the tiles that are about to be passed by the King, the castlingAbility variable will be set to false to deny the castling move 917 | if setA == every_set: 918 | castlingAbility = False 919 | 920 | if setB == every_set: 921 | castlingAbility = False 922 | 923 | 924 | 925 | if castlingAbility == True: 926 | #calling the makeMove function with parameter 1 to denote the white's castling move 927 | #calling the makeMove function for the second time with parameter 3 to denote the end of castling move 928 | KingMove.append((x1,y1,x2,y2)) 929 | RookMove.append((7,0,7,3)) 930 | self.makeMove(KingMove, 1) 931 | self.makeMove(RookMove, 3) 932 | else: 933 | pass 934 | #check to see if the castling move was made by black piece player 935 | elif colour == "Black" and x1 == 0 and y1 == 4: 936 | #x2 = 0 and y2 = 6 indicates that the King is moved to the right side 2 tiles (King's side castling) 937 | if x2 == 0 and y2 == 6: 938 | #check if there exists a rook at the right end and the tiles between are empty 939 | if self.chessBoard[0][7] == "r" and self.chessBoard[0][6] == " " and self.chessBoard[0][5] == " ": 940 | #initialize these sets to check if they are attacked 941 | setA = [0,6] 942 | setB = [0,5] 943 | 944 | #Check_Opponent_Threat() is a function that detects all the threats that are made by a certain player 945 | for every_set in self.Check_Opponent_Threat("Black", "Threat"): 946 | #if there exists a threat on the tiles that are about to be passed by the King, the castlingAbility variable will be set to false to deny the castling move 947 | if setA == every_set: 948 | castlingAbility = False 949 | 950 | if setB == every_set: 951 | castlingAbility = False 952 | 953 | if castlingAbility == True: 954 | #calling the makeMove function with parameter 2 to denote the black's castling move 955 | #calling the makeMove function for the second time with parameter 3 to denote the end of castling move 956 | KingMove.append((x1,y1,x2,y2)) 957 | RookMove.append((0,7,0,5)) 958 | self.makeMove(KingMove, 2) 959 | self.makeMove(RookMove, 3) 960 | 961 | else: 962 | pass 963 | #x2 = 0 and y2 = 2 indicates that the King is moved to the left side 2 tiles (Queen's side castling) 964 | elif x2 == 0 and y2 == 2: 965 | #check if there exists a rook at the right end and the tiles between are empty 966 | if self.chessBoard[0][0] == "r" and self.chessBoard[0][1] == " " and self.chessBoard[0][2] == " " and self.chessBoard[0][3] == " ": 967 | #initialize these sets to check if they are attacked 968 | setA = [0,2] 969 | setB = [0,3] 970 | #Check_Opponent_Threat() is a function that detects all the threats that are made by a certain player 971 | for every_set in self.Check_Opponent_Threat("Black", "Threat"): 972 | #if there exists a threat on the tiles that are about to be passed by the King, the castlingAbility variable will be set to false to deny the castling move 973 | if setA == every_set: 974 | castlingAbility = False 975 | 976 | if setB == every_set: 977 | castlingAbility = False 978 | 979 | if castlingAbility == True: 980 | #calling the makeMove function with parameter 2 to denote the black's castling move 981 | #calling the makeMove function for the second time with parameter 3 to denote the end of castling move 982 | KingMove.append((x1,y1,x2,y2)) 983 | RookMove.append((0,0,0,3)) 984 | self.makeMove(KingMove, 2) 985 | self.makeMove(RookMove, 3) 986 | 987 | else: 988 | pass 989 | 990 | #this function is to check a particular player's threat to the other player 991 | #this function is can also be used to return all the possible moves that can be made by a player, thus the paremeter desire is used accordingly 992 | #note that this function is not the same as the possibleMoves() function as possiblMoves() function can only be passed with one single character at one time (Means can only calculate the possible moves of one particular piece) 993 | def Check_Opponent_Threat(self, colour, desire): 994 | #create a list of pieces for black and white players 995 | mylists_for_black = ["p","r","n","b","q","k"] 996 | mylists_for_white = ["P","R","N","B","Q","K"] 997 | all_the_possible_moves = [] 998 | threats = [] 999 | 1000 | 1001 | #if the parameter was passed in with "White" colour, then the possible moves for black will be generated and vice versa 1002 | if colour == "White": 1003 | #iterate through all the 6 pieces 1004 | for i in range(6): 1005 | all_the_possible_moves += self.possibleMoves(mylists_for_black[i]) 1006 | 1007 | elif colour == "Black": 1008 | #iterate through all the 6 pieces 1009 | for i in range(6): 1010 | all_the_possible_moves += self.possibleMoves(mylists_for_white[i]) 1011 | else: 1012 | pass 1013 | #if the desire was only to calculate the possible moves, then the function shall return the possible moves immediately 1014 | if desire == "PossibleMovesOnly": 1015 | # print(all_the_possible_moves) 1016 | return all_the_possible_moves 1017 | 1018 | else: 1019 | #this loop returns just the last 2 values of the coordinate, 3 if there's a piece that can be captured 1020 | for k in range(len(all_the_possible_moves)): 1021 | #variable initialization is made here so that it will be emptied everytime a loop of k is made 1022 | temp=[] 1023 | temp1 = [] 1024 | for j in range(2, len(all_the_possible_moves[k])): 1025 | 1026 | temp.append(all_the_possible_moves[k][j]) 1027 | 1028 | if j == len(all_the_possible_moves[k]) - 1: 1029 | temp1.append((temp)) 1030 | threats += temp1 1031 | 1032 | #returns the list of the threats 1033 | return threats 1034 | 1035 | #this function is used to check whether a player is in Check or not 1036 | def CheckState(self,colour): 1037 | 1038 | #initialize the variables 1039 | check_state = False 1040 | colour_to_check = "" 1041 | setA = [] 1042 | 1043 | #set the King's character according to the colour 1044 | if colour == "White": 1045 | setA = ["K"] 1046 | colour_to_check = "White" 1047 | elif colour == "Black": 1048 | setA = ["k"] 1049 | colour_to_check = "Black" 1050 | 1051 | #get the threats of the opponent player 1052 | threat = self.Check_Opponent_Threat(colour_to_check, "Threat") 1053 | #check if there exists a "K" or 'k' in the threats 1054 | for each in threat: 1055 | #comparison 1056 | if set(setA) <= set(each): 1057 | check_state = True 1058 | 1059 | #returns the boolean value of the check_state 1060 | return check_state 1061 | 1062 | #this function is to check whether a player has been checkmated or not 1063 | #this is the function that fires when a player is in check 1064 | def Check_CheckMate(self, colour): 1065 | 1066 | if colour == "White": 1067 | #by giving the parameter "PossibleMovesOnly" to the Check_Opponent_Threat() function, the function will return only the possible moves, not the threats. 1068 | allPossibleMoves = self.Check_Opponent_Threat("Black", "PossibleMovesOnly") 1069 | #initialize counter 1070 | counter = 0 1071 | 1072 | #iterate through all the possible moves 1073 | for each_possible_move in allPossibleMoves: 1074 | 1075 | #get the coordinates of the possible moves 1076 | x1 = each_possible_move[0] 1077 | y1 = each_possible_move[1] 1078 | x2 = each_possible_move[2] 1079 | y2 = each_possible_move[3] 1080 | 1081 | 1082 | self.character = self.chessBoard[x1][y1] #get the piece 1083 | self.chessBoard[x1][y1] = " " #empty the current tile 1084 | tempPiece = self.chessBoard[x2][y2] #get the piece in the tile that the move has been made to 1085 | self.chessBoard[x2][y2] = self.character #replace the tile that the move was made to with the piece that the move was made 1086 | 1087 | #for every move of white that ends in check, the counter will be increased by 1 1088 | if self.CheckState("White") == True: 1089 | counter = counter + 1 1090 | #undo back the move 1091 | self.chessBoard[x1][y1] = self.character 1092 | self.chessBoard[x2][y2] = tempPiece 1093 | 1094 | #if every single move of white ends in Check, that denotes Checkmate! 1095 | if counter == len(allPossibleMoves): 1096 | print("Checkmate") 1097 | 1098 | #Checkmate test for black 1099 | elif colour == "Black": 1100 | #by giving the parameter "PossibleMovesOnly" to the Check_Opponent_Threat() function, the function will return only the possible moves, not the threats. 1101 | allPossibleMoves = self.Check_Opponent_Threat("White", "PossibleMovesOnly") 1102 | #initialize counter 1103 | counter = 0 1104 | 1105 | #iterate through all the possible moves 1106 | for each_possible_move in allPossibleMoves: 1107 | #get the coordinates of the possible moves 1108 | x1 = each_possible_move[0] 1109 | y1 = each_possible_move[1] 1110 | x2 = each_possible_move[2] 1111 | y2 = each_possible_move[3] 1112 | 1113 | 1114 | 1115 | self.character = self.chessBoard[x1][y1]#get the piece 1116 | self.chessBoard[x1][y1] = " " #empty the current tile 1117 | tempPiece = self.chessBoard[x2][y2] #get the piece in the tile that the move has been made to 1118 | self.chessBoard[x2][y2] = self.character #replace the tile that the move was made to with the piece that the move was made 1119 | 1120 | #if every single move of black ends in Check, that denotes Checkmate! 1121 | if self.CheckState("Black") == True: 1122 | counter = counter + 1 1123 | #undo back the move 1124 | self.chessBoard[x1][y1] = self.character 1125 | self.chessBoard[x2][y2] = tempPiece 1126 | 1127 | #if every single move of black ends in Check, that denotes Checkmate! 1128 | if counter == len(allPossibleMoves): 1129 | print("Checkmate") 1130 | 1131 | 1132 | #this function is used to check if there's a pawn that has reached the final rank 1133 | def Promotion_Check(self, colour): 1134 | 1135 | #if the check is performed for the white piece player, then the row that should be checked is row 0 1136 | if colour == "White": 1137 | row = 0 1138 | 1139 | #if the check is performed for the white piece player, then the row that should be checked is row 7 1140 | if colour == "Black": 1141 | row = 7 1142 | 1143 | #this iterates through all the column in that particular row 1144 | for i in range(8): 1145 | #check if there is a pawn on that particular row 1146 | if self.chessBoard[row][i] == "P": 1147 | #if there exists a white pawn in the final rank, the Promotion_Pick() function will be called by passing three parameters. The colour of the piece, the row and the column the piece is located. 1148 | self.Promotion_Pick("White", row, i) 1149 | elif self.chessBoard[row][i] == 'p': 1150 | #if there exists a black pawn in the final rank, the Promotion_Pick() function will be called by passing three parameters. The colour of the piece, the row and the column the piece is located. 1151 | self.Promotion_Pick("Black", row, i) 1152 | 1153 | 1154 | #this function is called when there is a promotion move available for any of the two players 1155 | def Promotion_Pick(self, colour, row, column): 1156 | #initiliaze the variable 1157 | promotionpiece="" 1158 | 1159 | #these 2 lines is to prompt the players for their desired promotion piece 1160 | print("What would you like your pawn to be promoted to? Default is Queen") 1161 | promotionpiece = input() 1162 | 1163 | #for players that play the white pieces 1164 | if colour=="White": 1165 | 1166 | if promotionpiece == "Rook": 1167 | #replaces the pawn's position with a Rook 1168 | self.chessBoard[row][column] = "R" 1169 | elif promotionpiece == "Queen": 1170 | #replaces the pawn's position with a Queen 1171 | self.chessBoard[row][column] = "Q" 1172 | elif promotionpiece == "Knight": 1173 | #replaces the pawn's position with a Knight 1174 | self.chessBoard[row][column] = "N" 1175 | elif promotionpiece == "Bishop": 1176 | #replaces the pawn's position with a Bishop 1177 | self.chessBoard[row][column] = "B" 1178 | else: 1179 | #if the user did not enter anything, or entered something else other than the 4 words above, a Queen will be automatically given 1180 | self.chessBoard[row][column] = "Q" 1181 | 1182 | #for players that play the black pieces 1183 | if colour=="Black": 1184 | if promotionpiece == "Rook": 1185 | #replaces the pawn's position with a Rook 1186 | self.chessBoard[row][column] = "r" 1187 | elif promotionpiece == "Queen": 1188 | #replaces the pawn's position with a Queen 1189 | self.chessBoard[row][column] = "q" 1190 | elif promotionpiece == "Knight": 1191 | #replaces the pawn's position with a Knight 1192 | self.chessBoard[row][column] = "n" 1193 | elif promotionpiece == "Bishop": 1194 | #replaces the pawn's position with a Bishop 1195 | self.chessBoard[row][column] = "b" 1196 | else: 1197 | #if the user did not enter anything, or entered something else other than the 4 words above, a Queen will be automatically given 1198 | self.chessBoard[row][column] = "q" 1199 | 1200 | --------------------------------------------------------------------------------