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() 

Add some print statements to self.search_capture() to see where the append to the list is happening incorrectly, as obviously the length never equals zero. Note that in "right" and "left" either the row or the column should be the same, and you add/subtract from both. I would suggest that you make each move a separate function, that you pass a color to, and test each one individually.

Edited 1 Year Ago by woooee

Use a for loop like this:

for x in range(0, 8):
    if validatemove(move) == True:
        capture()

There are 8 posible times of capture in a single move. This doesn't use variables so there is no risk of it running forever.

This article has been dead for over six months. Start a new discussion instead.