MichiBros
MichiBros

Reputation: 142

I want to make a visualized bubble sort in pygame, the sort works but the visualization doesn't

like the title says I wanted to create a visualized bubble sort with python and pygame. The sort works perfectly but when it comes to visualize it it never gets the correct output.

Here's the code:

import pygame
import sys
import time

pygame.init()

Vector_len = 0
x = 0
numbers_to_order = []
IsRunning = True

Vector_len = eval(input("How many numbers do you want to sort? "))

for i in range(Vector_len):
    numbers_to_order.append(0)

for i in range(len(numbers_to_order)):
    numbers_to_order[i] = eval(input("Insert number at index "+str(i+1)+": "))

print("Inserted array: "+str(numbers_to_order))

screen = pygame.display.set_mode((1000,500))

while IsRunning:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN:
            IsRunning = False

    for i in range(len(numbers_to_order)):

        for j in range(len(numbers_to_order)):
            try:
                if numbers_to_order[j] > numbers_to_order[j+1]:
                    x = numbers_to_order[j]
                    numbers_to_order[j] = numbers_to_order[j+1]
                    numbers_to_order[j+1] = x
            except(IndexError):
                pass
            pygame.draw.rect(screen,(255,255,255),(j*(1000/len(numbers_to_order)),500-(numbers_to_order[j])*50,(1000/len(numbers_to_order)),(numbers_to_order[j])*50))
            print((j*(1000/len(numbers_to_order)), (numbers_to_order[j])*50))
            pygame.display.flip()
            time.sleep(0.05)

print("Sorted array: "+str(numbers_to_order))
pygame.quit()
sys.exit()

When running, instead of showing the bars sorting correctly, they are displayed in a wrong order but the sort is correct. Any help?

Upvotes: 1

Views: 521

Answers (1)

Rabbid76
Rabbid76

Reputation: 211176

The major issue is that you've to clear the display in every frame and to draw the entire "list" in every frame. Note, if a bar for a large number was drawn at position, then a bar for a smaller number won't "clear" that.

screen.fill(0)
for k, n in enumerate(numbers_to_order):
    pygame.draw.rect(screen,(255,255,255),(k*(1000/len(numbers_to_order)),500-(numbers_to_order[k])*50,(1000/len(numbers_to_order)),(n)*50))

I recommend not to use nested loops in the game loop, which draw the scene. Use the main application loop and increment the control variables i and j in the loop:

i = 0
j = 0

while IsRunning:

    # [...]

    if j < len(numbers_to_order)-1:
        j += 1
    elif i < len(numbers_to_order)-1:
        i += 1
        j = 0

Further i recommend to use pygame.time.Clock()

See the example:

# start control variables
i = 0
j = 0
IsRunning = True

# main loop
clock = pygame.time.Clock()
while IsRunning:

    # handle events
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            IsRunning = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            IsRunning = False

    # clear screen
    screen.fill(0)

    # draw the entire range
    for k, n in enumerate(numbers_to_order):
        pygame.draw.rect(screen,(255,255,255),(k*(1000/len(numbers_to_order)),500-(numbers_to_order[k])*50,(1000/len(numbers_to_order)),(n)*50))

    # update the display
    pygame.display.flip()
    clock.tick(10)

    # sort (1 step)
    print((j*(1000/len(numbers_to_order)), (numbers_to_order[j])*50))
    try:
        if numbers_to_order[j] > numbers_to_order[j+1]:
            x = numbers_to_order[j]
            numbers_to_order[j] = numbers_to_order[j+1]
            numbers_to_order[j+1] = x
    except(IndexError):
        pass

    # increment control variables
    if j < len(numbers_to_order)-1:
        j += 1
    elif i < len(numbers_to_order)-1:
        i += 1
        j = 0

Upvotes: 2

Related Questions