Python 如何递归检查对象中的属性?
我一直在做一个电路模拟器,有点像Minecraft的红石,但是是2d的 到目前为止,我有电源和电线。电源为导线供电,稍后将用于为其他部件供电 我面临的问题是,当电线与电源断开时,它保持通电,因为它的所有邻居都通电 以下是图像中显示的问题: 电线未连接到电源 电线已连接并通电 电源已断开,但导线仍处于活动状态 以下是导线的更新循环,显示了以下内容:Python 如何递归检查对象中的属性?,python,recursion,pygame,circuit,Python,Recursion,Pygame,Circuit,我一直在做一个电路模拟器,有点像Minecraft的红石,但是是2d的 到目前为止,我有电源和电线。电源为导线供电,稍后将用于为其他部件供电 我面临的问题是,当电线与电源断开时,它保持通电,因为它的所有邻居都通电 以下是图像中显示的问题: 电线未连接到电源 电线已连接并通电 电源已断开,但导线仍处于活动状态 以下是导线的更新循环,显示了以下内容: def update(self): self.powered=False for b in blocks: #F
def update(self):
self.powered=False
for b in blocks:
#Find power sources/powered wires
if not b.powered:
continue
adjacent = False
if b.rect.collidepoint(self.rect.left,self.rect.top-5):
adjacent = True
if b.rect.collidepoint(self.rect.left,self.rect.bottom+5):
adjacent = True
if b.rect.collidepoint(self.rect.left-5,self.rect.top):
adjacent = True
if b.rect.collidepoint(self.rect.right+5,self.rect.top):
adjacent = True
if adjacent:
self.powered = True
break
if not self.powered:
pygame.draw.rect(screen, (0,0,0), self.rect, 0)
else:
pygame.draw.rect(screen, (200,0,0), self.rect, 0)
我需要这些电线由其他电线供电,但前提是它们都连接到一个电源。。所以我想,如果我能让每个导线段递归地检查它连接到的所有导线段,以确保它连接到电源,那么我就能实现这一点。但我不知道如何做到这一点
我尝试在wire对象内部使用其他变量,如self.sourceed
,表示电线是否连接到电源,但这导致只能为一根电线供电。(即使当电源断开时,电线也失效了,所以它可以正常工作.)
无论如何,如果有人知道怎么做,请把你的知识借给我
以下是完整的源代码供参考:
import pygame
from pygame.locals import *
pygame.init()
screen=pygame.display.set_mode((640,480))
blocks=[]
class PowerSource(object):
def __init__(self,pos):
self.posx=pos[0]
self.posy=pos[1]
self.rect=pygame.Rect(self.posx,self.posy,32,32)
self.powered=True
def update(self):
pygame.draw.rect(screen, (255,0,0), self.rect, 0)
def repos(self):
pass
class Circuit(object):
def __init__(self,pos):
self.powered=False
self.posx=pos[0]
self.posy=pos[1]
self.rect=pygame.Rect(self.posx,self.posy,32,32)
def update(self):
self.powered=False
for b in blocks:
if not b.powered:
continue
adjacent = False
if b.rect.collidepoint(self.rect.left,self.rect.top-5):
adjacent = True
if b.rect.collidepoint(self.rect.left,self.rect.bottom+5):
adjacent = True
if b.rect.collidepoint(self.rect.left-5,self.rect.top):
adjacent = True
if b.rect.collidepoint(self.rect.right+5,self.rect.top):
adjacent = True
if adjacent:
self.powered = True
break
if not self.powered:
pygame.draw.rect(screen, (0,0,0), self.rect, 0)
else:
pygame.draw.rect(screen, (200,0,0), self.rect, 0)
while True:
place=1
screen.fill((255,255,255))
mse=pygame.mouse.get_pos()
mse=((mse[0]/32)*32,(mse[1]/32)*32)
pressed=pygame.mouse.get_pressed()
if pressed==(1,0,0):
pressed='L'
elif pressed==(0,0,1):
pressed='R'
for b in blocks:
b.update()
pygame.draw.rect(screen, (255,0,0), (mse[0],mse[1],32,32), 2)
for e in pygame.event.get():
if e.type==QUIT:
exit()
key=pygame.key.get_pressed()
if key[K_SPACE]:
for b in blocks:
if b.rect.collidepoint(mse):
place=0
if place==1:
blocks.append(PowerSource(mse))
if pressed=='L':
for b in blocks:
if b.rect.collidepoint(mse):
place=0
if place==1:
blocks.append(Circuit(mse))
elif pressed=='R':
for b in blocks:
if b.rect.collidepoint(mse):
blocks.remove(b)
pygame.display.flip()
根据我的经验,简单的答案是向对象添加一个标志,指示它们是否已经在递归算法中进行了测试。这是因为可以有循环。因此,当你移除电源时,让它调用一个函数来“检查电源”,检查它所接触到的所有模块。在查看是否有源作为邻居之前,每个块将设置自己的标志,说明“我已检查”。如果它有一个源作为邻居,它会返回“是的,我有一个源”。如果没有,那么它将检查是否有任何邻居具有源,但前提是它们尚未被标记为已检查。然后,它将查看是否有任何返回值为“是,我有一个源”,如果是,则返回“是”,如果不是,则返回“否”并关闭。我认为您遇到了一些问题 您可能希望为块提供某种包含数据结构(另一个类,而不仅仅是一个列表),或者让块维护一个邻接列表。我认为后者可能更容易理解这个问题,尽管前者可能更适合您,因为您需要能够删除块(邻接列表有很多簿记)。这取决于你,但我选择邻接列表,因为它对我来说更容易。:) 一旦记下了它,就应该编写另一个方法作为递归入口点。它可以很简单。你可能需要做一些与你去过的地方保持同步的事情;在这里,我把它作为一个集合来完成,它是该方法的一个参数,假设一个名为
邻居的邻接列表
def is_connected_to_powered(self, visited=()):
if self in visited:
return False
visited = set(visited)
visited.add(self)
for neighbor in self.neighbors:
if neighbor.powered or neighbor.is_connected_to_powered(visited):
return True
return False
这回答了这个问题,但我也可以考虑从一个公共基类(块)派生电路和PowerSource,因为我怀疑有适当的OO会帮助你下线。
这不是你的权力问题的一部分,但是我想如果你开始使用更好的数据结构来保存你的块,你会有更容易的时间。网格是一种简单的方法(如果空间为空,则让它保持None
)。或者,如果有太多的内存开销,你可以使用更聪明的东西,比如四叉树。我如何创建邻接列表?看起来是这样的,对吧?[,,,,0,0,0,0,,]其中,\为无,0为对象?@SamTubb这是一种方法,但可能更简单的方法是只在列表中存储邻居,而不是None
。例如,在构造函数中,将名为neights
的成员变量初始化为空列表(甚至一个集合)。当该块获得一个新的邻居时,只需执行block.append(neighbor)
(或add
for set)。我将研究图形数据结构,以帮助您理解,或者考虑建立一个类,它帮助您管理一个2D网格块,因为您正在构建一个块游戏(其他人也建议包含这样的结构)。