I am implementing the last feature of my Python Checkers Game, which is to require the user to make multiple jumps. For captures, I do the following:
1 Check if the move is valid:
2 self.validatedMove = True (The move that has been made is valid.)
3 self.capture() (Captures the piece given a correct user move)
4 How would I implement multiple jumps? I have tried researching for captures
and then calling the capture function until there are no more captures left.
But it ends up being stuck in an infinite loop!
#when Red piece is not a king and piece can jump right
if (self.turn == 'Red' and self.jump == True and len(self.captureDirections) == 1 and self.captureDirection == 'right'):
if (self.newPosition[0] == self.position[0] + 2 and self.newPosition[1] == self.position[1] + 2):
self.validatedMove = True
self.capture()
#Stuck in an infinite loop
while (len(captureDirections) > 0):
self.captureDirections = []
self.search_capture()
self.capture()
Here is the full code:
from tkinter import *
class CheckerSquare(Canvas):
def __init__(self, master, row, column, color):
Canvas.__init__(self, master, width=50, height=50, bg=color)
self.grid(row=row, column=column)
self.position = (row, column)
self.color = None
self.isKing = False
self.bind('<Button>', master.place_piece)
def get_position(self):
return self.position
def get_color(self):
return self.color
def create_piece(self, color):
self.create_oval(10,10,44,44,fill=color, outline=color)
self.color = color
def create_king(self):
self.isKing = True
self.create_text(10, 15, text="*", font=("Garamond", 14), fill="#80FF80")
def is_king(self):
return self.isKing
class CheckerGame(Frame):
def __init__(self, master):
Frame.__init__(self, master, bg='White')
self.grid()
self.squares = {}
self.turn = 'Red'
self.clicks = 0
self.position = ()
self.newPosition = ()
self.jump = False
self.validatedMove = False
self.captureDirection = None
self.captureDirections = []
self.over = False
self.turnIcon = CheckerSquare(self, 9, 2, "#B8B8B8")
self.turnIcon.grid()
self.turnIcon.create_piece(self.turn)
self.turnLabel = Label(self, text = "Turn: ", font = ('Courier New', 8), bg='White')
self.turnLabel.grid(row=9, column=1)
self.directionLabel = Label(self, text="", font = ('Courier New', 8), bg='White')
self.directionLabel.grid(row=9, column=4, columnspan=4, sticky=W)
# Create the checker squares on the board
for row in range(8):
for col in range(8):
if (row % 2 == 0 and col % 2 == 0 or row % 2 == 1 and col % 2 == 1):
self.squares[(row,col)] = CheckerSquare(self, row, col, 'blanched almond')
else:
self.squares[(row,col)] = CheckerSquare(self, row, col, 'dark green')
# Draw the red pieces
for i in range(3):
for n in range(4):
if (i % 2 == 0):
self.squares[(i, 2*n+1)].create_piece('Red')
else:
self.squares[(i,2*n)].create_piece('Red')
# Draw the white pieces
for i in range(5, 8):
for n in range(4):
if (i % 2 == 0):
self.squares[(i,2*n+1)].create_piece('White')
else:
self.squares[(i,2*n)].create_piece('White')
def winnerCheck(self):
#Detects winner if all pieces on red or white are gone
redPieces = 0
whitePieces = 0
for row in range(8):
for column in range(8):
squareColor = self.squares[row, column].get_color()
if (squareColor == 'Red'):
redPieces += 1
if (squareColor == 'White'):
whitePieces += 1
if (redPieces == 0 and self.turn == 'Red'): #No red pieces left - white wins
self.over = True
self.directionLabel["text"] = 'Game Over - White Wins!'
if (whitePieces == 0 and self.turn == 'White'): #No white pieces left - red wins
self.over = True
self.directionLabel["text"] = 'Game Over - Red Wins!'
def update(self, turn):
self.squares[self.position].create_piece('dark green') #clears previous square
self.squares[self.position].color = None #updates color
self.squares[self.newPosition].create_piece(turn) #updates piece position
self.validatedMove = True #move is valid
def capture(self):
if (len(self.captureDirections) == 1):
if (self.squares[self.position].get_color() == 'Red' and self.captureDirection == 'right'):
self.update('Red')
self.squares[self.position[0]+1, self.position[1]+1] = CheckerSquare(self, self.position[0]+1, self.position[1]+1, 'dark green')
self.squares[self.position[0]+1, self.position[1]+1].color = None
if (self.squares[self.position].get_color() == 'Red' and self.captureDirection == 'left'):
self.update('Red')
self.squares[self.position[0]+1, self.position[1]-1] = CheckerSquare(self, self.position[0]+1, self.position[1]-1, 'dark green')
self.squares[self.position[0]+1, self.position[1]-1].color = None
if (self.squares[self.position].get_color() == 'White' and self.captureDirection == 'right'):
self.update('White')
self.squares[self.position[0]-1, self.position[1]+1] = CheckerSquare(self, self.position[0]-1, self.position[1]+1, 'dark green')
self.squares[self.position[0]-1, self.position[1]+1].color = None
if (self.squares[self.position].get_color() == 'White' and self.captureDirection == 'left'):
self.update('White')
self.squares[self.position[0]-1, self.position[1]-1] = CheckerSquare(self, self.position[0]-1, self.position[1]-1, 'dark green')
self.squares[self.position[0]-1, self.position[1]-1].color = None
if (len(self.captureDirections) == 2 and self.squares[self.position].is_king() == False):
if (self.squares[self.position].get_color() == 'White'):
self.update('White')
if (self.position[0]>0 and self.position[1]<7 and self.squares[self.position[0]-1, self.position[1]+1].get_color() == 'Red'):
self.squares[self.position[0]-1, self.position[1]+1] = CheckerSquare(self, self.position[0]-1, self.position[1]+1, 'dark green')
self.squares[self.position[0]-1, self.position[1]+1].color = None
if (self.position[0]>0 and self.position[1]>0 and self.squares[self.position[0]-1, self.position[1]-1].get_color() == 'Red'):
self.squares[self.position[0]-1, self.position[1]-1] = CheckerSquare(self, self.position[0]-1, self.position[1]-1, 'dark green')
self.squares[self.position[0]-1, self.position[1]-1].color = None
if (self.squares[self.position].get_color() == 'Red'):
self.update('Red')
if (self.position[0]<7 and self.position[1]<7 and self.squares[self.position[0]+1, self.position[1]+1].get_color() == 'White'):
self.squares[self.position[0]+1, self.position[1]+1] = CheckerSquare(self, self.position[0]+1, self.position[1]+1, 'dark green')
self.squares[self.position[0]+1, self.position[1]+1].color = None
if (self.position[0]<7 and self.position[1]>0 and self.squares[self.position[0]+1, self.position[1]-1].get_color() == 'White'):
self.squares[self.position[0]+1, self.position[1]-1] = CheckerSquare(self, self.position[0]+1, self.position[1]-1, 'dark green')
self.squares[self.position[0]+1, self.position[1]-1].color = None
if (self.squares[self.position].is_king() == True):
if (len(self.captureDirections) == 1):
if (self.squares[self.position].get_color() == 'White' and self.captureDirections[0] == 'backward right'):
self.update('White')
self.squares[self.position] = CheckerSquare(self, self.position[0], self.position[1], 'dark green')
self.squares[self.position[0]+1, self.position[1]+1] = CheckerSquare(self, self.position[0]+1, self.position[1]+1, 'dark green')
self.squares[self.position[0]+1, self.position[1]+1].color = None
self.squares[self.newPosition].create_king()
if (self.squares[self.position].get_color() == 'White' and self.captureDirections[0] == 'backward left'):
self.update('White')
self.squares[self.position] = CheckerSquare(self, self.position[0], self.position[1], 'dark green')
self.squares[self.position[0]+1, self.position[1]-1] = CheckerSquare(self, self.position[0]+1, self.position[1]-1, 'dark green')
self.squares[self.position[0]+1, self.position[1]-1].color = None
self.squares[self.newPosition].create_king()
if (self.squares[self.position].get_color() == 'Red' and self.captureDirections[0] == 'backward right'):
self.update('Red')
self.squares[self.position] = CheckerSquare(self, self.position[0], self.position[1], 'dark green')
self.squares[self.position[0]-1, self.position[1]+1] = CheckerSquare(self, self.position[0]-1, self.position[1]+1, 'dark green')
self.squares[self.position[0]-1, self.position[1]+1].color = None
self.squares[self.newPosition].create_king()
if (self.squares[self.position].get_color() == 'Red' and self.captureDirections[0] == 'backward left'):
self.update('Red')
self.squares[self.position] = CheckerSquare(self, self.position[0], self.position[1], 'dark green')
self.squares[self.position[0]-1, self.position[1]-1] = CheckerSquare(self, self.position[0]-1, self.position[1]-1, 'dark green')
self.squares[self.position[0]-1, self.position[1]-1].color = None
self.squares[self.newPosition].create_king()
self.jump = False
def search_capture(self):
#Capture
for row in range(8):
for col in range(8):
squareColor = self.squares[(row, col)].get_color()
#Left Capture - Red
if (self.turn == 'Red' and col >= 2 and row <= 5 and squareColor == 'Red' and self.squares[(row + 1, col - 1)].get_color() == 'White' and \
self.squares[(row + 2, col - 2)].get_color() == None):
self.captureDirection = 'left'
self.captureDirections.append('left')
self.jump = True
#Right Capture - Red
if (self.turn == 'Red' and col <= 5 and row <= 5 and squareColor == 'Red' and self.squares[(row + 1, col + 1)].get_color() == 'White' and \
self.squares[(row + 2, col + 2)].get_color() == None):
self.captureDirection = 'right'
self.captureDirections.append('right')
self.jump = True
#Capture for Left - White
if self.turn == 'White' and col >= 2 and row >= 2 and squareColor == 'White' and self.squares[(row - 1, col - 1)].get_color() == 'Red' and \
self.squares[(row - 2, col - 2)].get_color() == None:
self.captureDirection = 'left'
self.captureDirections.append('left')
self.jump = True
#Right Capture - White
if (self.turn == 'White' and col <= 5 and row >= 2 and squareColor == 'White' and self.squares[(row - 1, col + 1)].get_color() == 'Red' and \
self.squares[(row - 2, col + 2)].get_color() == None):
self.captureDirection = 'right'
self.captureDirections.append('right')
self.jump = True
if (self.squares[(row, col)].is_king() == True):
#Backwards Left Capture - Red King
if self.turn == 'Red' and col >= 2 and row >= 2 and squareColor == 'Red' and self.squares[(row - 1, col - 1)].get_color() == 'White' and \
self.squares[(row - 2, col - 2)].get_color() == None:
self.captureDirection = 'backward left'
self.captureDirections.append('backward left')
self.jump = True
#Backwards Right Capture - Red King
if (self.turn == 'Red' and col <= 5 and row >= 2 and squareColor == 'Red' and self.squares[(row - 1, col + 1)].get_color() == 'White' and \
self.squares[(row - 2, col + 2)].get_color() == None):
self.captureDirection = 'backward right'
self.captureDirections.append('backward right')
self.jump = True
#Backwards Left Capture - White King
if (self.turn == 'White' and col >= 2 and row <= 5 and squareColor == 'White' and self.squares[(row + 1, col - 1)].get_color() == 'Red' and \
self.squares[(row + 2, col - 2)].get_color() == None):
self.captureDirection = 'backward left'
self.captureDirections.append('backward left')
self.jump = True
#Backwards Right Capture - White King
if (self.turn == 'White' and col <= 5 and row <= 5 and squareColor == 'White' and self.squares[(row + 1, col + 1)].get_color() == 'Red' and \
self.squares[(row + 2, col + 2)].get_color() == None):
self.captureDirection = 'backward right'
self.captureDirections.append('backward right')
self.jump = True
def place_piece(self, event):
if (self.over == False):
self.validatedMove = False
#Program needs to check the current move
#Adds to number of clicks
self.clicks += 1
#First stage of click (selecting a piece)
if (self.clicks % 2 == 1):
self.captureDirections = []
if event.widget.get_color() == 'Red' or event.widget.get_color() == 'White':
self.position = event.widget.get_position() #retrieve position of selected piece
if (self.turn == self.squares[self.position].get_color()):
self.squares[self.position]['highlightbackground'] = 'black' #outline
else:
self.directionLabel['text'] = "It is " + self.turn + "'s turn!"
self.search_capture()
else: #second stage of click (moves piece to selected position)
self.newPosition = event.widget.get_position()
self.squares[self.position]['highlightbackground'] = 'White' #clears outline
#when Red piece is not a king and the piece cannot jump
if (self.turn == 'Red' and self.jump == False):
if (self.newPosition[0] == self.position[0] + 1 and self.newPosition[1] == self.position[1] + 1 and self.squares[self.newPosition].get_color() == None \
or self.newPosition[0] == self.position[0] + 1 and self.newPosition[1] == self.position[1] - 1 and self.squares[self.newPosition].get_color() == None):
self.update('Red')
self.directionLabel['text'] = "" #clears error message
self.validatedMove = True
else:
self.directionLabel['text'] = "Invalid Move!" #error message
#when White piece is not a king and piece cannot jump
if (self.turn == 'White' and self.jump == False):
if (self.newPosition[0] == self.position[0] - 1 and self.newPosition[1] == self.position[1] + 1 and self.squares[self.newPosition].get_color() == None \
or self.newPosition[0] == self.position[0] - 1 and self.newPosition[1] == self.position[1] - 1 and self.squares[self.newPosition].get_color() == None):
self.update('White')
self.directionLabel['text'] = "" #clears error message
self.validatedMove = True
else:
self.directionLabel['text'] = "Invalid Move!" #error message
#when Red piece is not a king and piece can jump right
if (self.turn == 'Red' and self.jump == True and len(self.captureDirections) == 1 and self.captureDirection == 'right'):
if (self.newPosition[0] == self.position[0] + 2 and self.newPosition[1] == self.position[1] + 2):
self.validatedMove = True
self.capture()
while (len(captureDirections) > 0):
self.captureDirections = []
self.search_capture()
self.capture()
#when Red piece is not a king and piece can jump left
if (self.turn == 'Red' and self.jump == True and len(self.captureDirections) == 1 and self.captureDirection == 'left'):
if (self.newPosition[0] == self.position[0] + 2 and self.newPosition[1] == self.position[1] - 2):
self.validatedMove = True
self.capture()
#when White piece is not a king and piece can jump right
if (self.turn == 'White' and self.jump == True and len(self.captureDirections) == 1 and self.captureDirection == 'right'):
if (self.newPosition[0] == self.position[0] - 2 and self.newPosition[1] == self.position[1] + 2):
self.validatedMove = True
self.capture()
#when White piece is not a king and piece can jump left
if (self.turn == 'White' and self.jump == True and len(self.captureDirections) == 1 and self.captureDirection == 'left'):
if (self.newPosition[0] == self.position[0] - 2 and self.newPosition[1] == self.position[1] - 2):
self.validatedMove = True
self.capture()
#when White piece is not a king and can capture both directions
if (self.turn == 'White' and self.jump == True and len(self.captureDirections) == 2):
if (self.newPosition[0] == self.position[0] - 2 and self.newPosition[1] == self.position[1] + 2 or self.newPosition[1] == self.position[1] - 2):
self.validatedMove = True
self.capture()
#when Red piece is not a king and can capture both directions
if (self.turn == 'Red' and self.jump == True and len(self.captureDirections) == 2):
if (self.newPosition[0] == self.position[0] + 2 and self.newPosition[1] == self.position[1] + 2 or self.newPosition[1] == self.position[1] - 2):
self.validatedMove = True
self.capture()
if (self.squares[self.position].is_king() == True):
#when Red piece is a king and the piece cannot jump
if (self.turn == 'Red' and self.jump == False):
if (self.newPosition[0] == self.position[0] - 1 and self.newPosition[1] == self.position[1] + 1 and self.squares[self.newPosition].get_color() == None \
or self.newPosition[0] == self.position[0] - 1 and self.newPosition[1] == self.position[1] - 1 and self.squares[self.newPosition].get_color() == None):
self.update('Red')
self.squares[self.position] = CheckerSquare(self, self.position[0], self.position[1], 'dark green')
self.squares[self.newPosition].create_king()
self.directionLabel['text'] = "" #clears error message
self.validatedMove = True
else:
self.directionLabel['text'] = "Invalid Move!" #error message
#when White piece is a king and the piece cannot jump
if (self.turn == 'White' and self.jump == False):
if (self.newPosition[0] == self.position[0] + 1 and self.newPosition[1] == self.position[1] + 1 and self.squares[self.newPosition].get_color() == None \
or self.newPosition[0] == self.position[0] + 1 and self.newPosition[1] == self.position[1] - 1 and self.squares[self.newPosition].get_color() == None):
self.update('White')
self.squares[self.position] = CheckerSquare(self, self.position[0], self.position[1], 'dark green')
self.squares[self.newPosition].create_king()
self.directionLabel['text'] = "" #clears error message
self.validatedMove = True
else:
self.directionLabel['text'] = "Invalid Move!" #error message
#when Red piece is a king and the piece can jump backward left
if (self.turn == 'Red' and self.jump == True and len(self.captureDirections) == 1 and self.captureDirection == 'backward left'):
self.capture()
self.validatedMove = True
#when Red piece is a king and the piece can jump backward right
if (self.turn == 'Red' and self.jump == True and len(self.captureDirections) == 1 and self.captureDirection == 'backward right'):
self.capture()
self.validatedMove = True
#when White piece is a king and the piece can jump backward left
if (self.turn == 'White' and self.jump == True and len(self.captureDirections) == 1 and self.captureDirection == 'backward left'):
self.capture()
self.validatedMove = True
#when White piece is a king and the piece can jump backward right
if (self.turn == 'White' and self.jump == True and len(self.captureDirections) == 1 and self.captureDirection == 'backward right'):
self.capture()
self.validatedMove = True
#Checks for king
if (self.turn == 'Red' and self.validatedMove == True and self.newPosition[0] == 7):
self.squares[self.newPosition].create_king()
if (self.turn == 'White' and self.validatedMove == True and self.newPosition[0] == 0):
self.squares[self.newPosition].create_king()
#changes turn
if (self.validatedMove == True):
if (self.turn == 'Red'):
self.turn = 'White'
elif (self.turn == 'White'):
self.turn = 'Red'
#updates player turn icon
self.turnIcon.create_piece(self.turn)
self.winnerCheck() #Checks for winner
def play_checkers():
root = Tk()
root.title('Python Checkers')
CG = CheckerGame(root)
CG.mainloop()
play_checkers()