Ibrahim Bholat
Ibrahim Bholat

Reputation: 13

How do I loop a players turn until they make a valid choice?

I am currently trying to program a connect 4 game and I have came across a bug where for some reason it will continue on to the Players 2 turn if Player 1 make an invalid move. I was wondering if there is a way to loop the code until Player 1 makes a valid turn and then proceed to Player 2 as normal.

I have tried a while loop on the checking whos turn it is but it gets stuck in a constant loop and crashes. I attached the code I have with my attempt in how to make it work.

I am using Pygame for the graphical portion of the program.

EDIT: I reverted my code back to the original but with simple while loops. I also attached the is_valid() and the main().

# Graphical representation of dropping the piece
def draw_drop_piece(event, turn):
    game_over = False
    while turn == 0:  # Checks to See if its Player 1 Turn
        posx = event.pos[0]
        col = int(math.floor(posx / SQUARESIZE))

        if is_valid(board, col):  # Checks Every Turn if Where the Player is Putting Their Piece is Valid
            row = next_open_row(board, col)
            drop_piece(board, row, col, 1)

            if winning_move(board, 1):  # Checks Every Turn if the Player Won
                label = FONT.render("PLAYER 1 WINS!", 1, RED)
                screen.blit(label, (40, 10))
                game_over = True
                break
            break

        else:
            label = FONT.render("Enter Valid Spot", 1, BLUE)
            screen.blit(label, (40, 10))

    while turn != 0:
        posx = event.pos[0]
        col = int(math.floor(posx / SQUARESIZE))

        if is_valid(board, col):  # Checks Every Turn if Where the Player is Putting Their Piece is Valid
            row = next_open_row(board, col)
            drop_piece(board, row, col, 2)

            if winning_move(board, 2):  # Checks Every Turn if the Player Won
                label = FONT.render("PLAYER 2 WINS!", 1, YELLOW)
                screen.blit(label, (40, 10))
                game_over = True
                break
            break

        else:
            label = FONT.render("Enter Valid Spot", 1, BLUE)
            screen.blit(label, (40, 10))

    return game_over

def is_valid(board, col):
    return board[ROW_COUNT - 1][col] == 0
if __name__ == '__main__':
    pygame.init()
    board = create_board()  # Creates Board
    print_board(board)  # Prints Board
    game_over = False  # The Game Isn't Over as it Just Started
    turn = 0  # Player One Starts First

    FONT = pygame.font.SysFont("monospace", 75)

    width = COLUMN_COUNT * SQUARESIZE
    height = (ROW_COUNT + 1) * SQUARESIZE
    size = (width, height)

    screen = pygame.display.set_mode(size)
    draw_board(board)
    pygame.display.update()

    while not game_over:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:  # Exiting the game
                sys.exit()

            track_mouse()

            if event.type == pygame.MOUSEBUTTONDOWN:
                pygame.draw.rect(screen, BLACK, (0, 0, width, SQUARESIZE))

                game_over = draw_drop_piece(turn)

                print_board(board)
                draw_board(board)

                # This makes sure the turn indicator alternates between 1 and 0
                turn = (turn + 1) % 2

                if game_over:
                    pygame.time.wait(5000)

Upvotes: 0

Views: 169

Answers (2)

Blckknght
Blckknght

Reputation: 104722

Your function needs to be able to return three values, not just the two it returns currently. It needs to signal if the game was won, if it is still ongoing after the move, or if the move was invalid and the turn is not completed yet.

I'm not sure if this is the best approach, but returning None from the function instead of True or False might work if you add special case logic to the calling code:

game_over = draw_drop_piece(turn)

print_board(board)
draw_board(board)

if game_over is not None:             # don't change turns if the attempted move was invalid
    turn = (turn + 1) % 2

The while loop doesn't actually need changing because None is falsey, just like the actual False value.

Here's the change needed in draw_drop_piece:

if is_valid(board, col):
    ... # this part all stays the same

else:
    label = FONT.render("Enter Valid Spot", 1, BLUE)
    screen.blit(label, (40, 10))
    game_over = None                 # signal an invalid move

Upvotes: 1

J.R. BEATS
J.R. BEATS

Reputation: 93

Try structuring something like I did below. That way in the while loop you disable anything having to do with the other player by stating that player2 is false.

player1 = True

player2 = True

while player1:

player2 = False

Upvotes: 0

Related Questions