洪水算法在Pygame中无法正常工作

发布于 2025-02-04 15:50:51 字数 3238 浏览 3 评论 0原文

我尝试在Pygame中实现洪水算法,它起作用,但不能递归地填充整个形状。我尝试了很多,但我无法调试这个问题。请帮助我找到它。这是我的源代码。

import pygame

pygame.init()
SCREEN = WIDTH, HEIGHT = 288, 512
win = pygame.display.set_mode(SCREEN, pygame.NOFRAME)

clock = pygame.time.Clock()
FPS = 60

# COLORS **********************************************************************

WHITE = (255, 255, 255)
BLUE = (30, 144,255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLACK = (0, 0, 0)

colors = [BLUE, RED, GREEN]

# TEXT ************************************************************************

font = pygame.font.SysFont('freesansbold', 26)
text = font.render('Flood Fill Algo test', True, WHITE)

clicked = False
polygon = []

def floodfill(x, y, old, new):
    pixel = win.get_at((x, y))
    if pixel != old:
        return
    elif pixel == new:
        return
    else:
        print(x, y)
        pygame.draw.circle(win, new, (x, y), 1)
        pygame.display.update()

        floodfill(x-1, y, old, new)
        floodfill(x+1, y, old, new)
        floodfill(x, y-1, old, new)
        floodfill(x, y+1, old, new)
        floodfill(x-1, y-1, old, new)
        floodfill(x-1, y+1, old, new)
        floodfill(x+1, y-1, old, new)
        floodfill(x+1, y+1, old, new)

class Rect:
    def __init__(self, x, y, c):
        self.x = x
        self.y = y
        self.c = c
        self.rect = pygame.Rect(x, y, 30, 30)

    def draw(self):
        pygame.draw.rect(win, self.c, self.rect)

r1 = Rect(WIDTH-40, 10, RED)
r2 = Rect(WIDTH-40, 45, GREEN)
r3 = Rect(WIDTH-40, 85, BLUE)

rects = [r1, r2, r3]
color = RED

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
                running = False

        if event.type == pygame.MOUSEBUTTONDOWN:
            pos = event.pos
            btn = pygame.mouse.get_pressed()
            if btn[0]:
                clicked = True

            elif btn[2]:
                if pos[0] < WIDTH - 50:
                    floodfill(pos[0], pos[1], (0,0,0), color)

            if pos[0] > WIDTH - 50:
                for r in rects:
                    if r.rect.collidepoint(pos):
                        color = r.c

        if event.type == pygame.MOUSEBUTTONUP:
            clicked = False

        if event.type == pygame.MOUSEMOTION:
            if clicked:
                pos = event.pos
                btn = pygame.mouse.get_pressed()
                if btn[0]:
                    if pos[0] < WIDTH - 50:
                        pygame.draw.circle(win, WHITE, pos, 5)
                
    pygame.draw.rect(win, WHITE, (0, 0, WIDTH-50, HEIGHT), 3)
    pygame.draw.rect(win, WHITE, (WIDTH-50, 0, 50, HEIGHT), 2)

    win.blit(text, (60, 40))

    for rect in rects:
        rect.draw()

    clock.tick(FPS)
    pygame.display.update()

pygame.quit()

这是我的代码的示例输出,因为您可以看到形状已填充,但不是完全。它在达到算法启动的起始位置后停止。

我尝试通过打印不同的位置来调试它,但没有运气。在这些类型的问题中,是否有更好的方法来调试递归。

I tried implementing the floodfill algorithm in pygame, it works but doesn't fills the entire shape recursively. I tried a lot but i am not able to debug the issue. Kindly help me find it out. Here's my source code.

import pygame

pygame.init()
SCREEN = WIDTH, HEIGHT = 288, 512
win = pygame.display.set_mode(SCREEN, pygame.NOFRAME)

clock = pygame.time.Clock()
FPS = 60

# COLORS **********************************************************************

WHITE = (255, 255, 255)
BLUE = (30, 144,255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLACK = (0, 0, 0)

colors = [BLUE, RED, GREEN]

# TEXT ************************************************************************

font = pygame.font.SysFont('freesansbold', 26)
text = font.render('Flood Fill Algo test', True, WHITE)

clicked = False
polygon = []

def floodfill(x, y, old, new):
    pixel = win.get_at((x, y))
    if pixel != old:
        return
    elif pixel == new:
        return
    else:
        print(x, y)
        pygame.draw.circle(win, new, (x, y), 1)
        pygame.display.update()

        floodfill(x-1, y, old, new)
        floodfill(x+1, y, old, new)
        floodfill(x, y-1, old, new)
        floodfill(x, y+1, old, new)
        floodfill(x-1, y-1, old, new)
        floodfill(x-1, y+1, old, new)
        floodfill(x+1, y-1, old, new)
        floodfill(x+1, y+1, old, new)

class Rect:
    def __init__(self, x, y, c):
        self.x = x
        self.y = y
        self.c = c
        self.rect = pygame.Rect(x, y, 30, 30)

    def draw(self):
        pygame.draw.rect(win, self.c, self.rect)

r1 = Rect(WIDTH-40, 10, RED)
r2 = Rect(WIDTH-40, 45, GREEN)
r3 = Rect(WIDTH-40, 85, BLUE)

rects = [r1, r2, r3]
color = RED

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
                running = False

        if event.type == pygame.MOUSEBUTTONDOWN:
            pos = event.pos
            btn = pygame.mouse.get_pressed()
            if btn[0]:
                clicked = True

            elif btn[2]:
                if pos[0] < WIDTH - 50:
                    floodfill(pos[0], pos[1], (0,0,0), color)

            if pos[0] > WIDTH - 50:
                for r in rects:
                    if r.rect.collidepoint(pos):
                        color = r.c

        if event.type == pygame.MOUSEBUTTONUP:
            clicked = False

        if event.type == pygame.MOUSEMOTION:
            if clicked:
                pos = event.pos
                btn = pygame.mouse.get_pressed()
                if btn[0]:
                    if pos[0] < WIDTH - 50:
                        pygame.draw.circle(win, WHITE, pos, 5)
                
    pygame.draw.rect(win, WHITE, (0, 0, WIDTH-50, HEIGHT), 3)
    pygame.draw.rect(win, WHITE, (WIDTH-50, 0, 50, HEIGHT), 2)

    win.blit(text, (60, 40))

    for rect in rects:
        rect.draw()

    clock.tick(FPS)
    pygame.display.update()

pygame.quit()

Here's the sample output of my code, As you can see the shape is filled but not completely. It stops after reaching the starting position from which the algorithm starts.

floodfill algo

I tried debugging it by printing the different positions but with no luck. Also is there any better way to debug recursions in these type of problems.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

〆凄凉。 2025-02-11 15:50:51

半径1的圆绘制超过1像素。要么设置单个像素,而不是绘制一个圆圈:

pygame.draw.circle(win,new,new,(x,y),1)

win.set_at((x, y), new)

,或者左右步骤2像素:

floodfill(x-2, y, old, new)
floodfill(x+1, y, old, new)
floodfill(x, y-2, old, new)
floodfill(x, y+1, old, new)

我建议使用循环代替递归来避免超过递归极限:

def floodfill(x, y, old, new):
    draw_list = [(x, y)]
    while draw_list:
        p = draw_list[-1]
        draw_list.pop()
        pixel = win.get_at(p)
        if pixel == old:
            win.set_at(p, new)
            new_p = [(p[0]+1, p[1]), (p[0]-1, p[1]), (p[0], p[1]+1), (p[0], p[1]-1)]
            draw_list += new_p`

”“”

A circle with radius 1 draws more than 1 pixel. Either set a single pixel instead of drawing a circle:

pygame.draw.circle(win, new, (x, y), 1)

win.set_at((x, y), new)

or step left and up by 2 pixels:

floodfill(x-2, y, old, new)
floodfill(x+1, y, old, new)
floodfill(x, y-2, old, new)
floodfill(x, y+1, old, new)

I recommend using a loop instead of recursion to avoid exceeding the recursion limit:

def floodfill(x, y, old, new):
    draw_list = [(x, y)]
    while draw_list:
        p = draw_list[-1]
        draw_list.pop()
        pixel = win.get_at(p)
        if pixel == old:
            win.set_at(p, new)
            new_p = [(p[0]+1, p[1]), (p[0]-1, p[1]), (p[0], p[1]+1), (p[0], p[1]-1)]
            draw_list += new_p`

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文