Domanda

This is driving me crazy, I am working on a circuit simulation program, and every time I ask a question about it it gets closed.

I seriously need help, but my questions get closed before anyone can help me answer them.

Anyways, here is the problem: Actually, I don't know what the problem is, there is something wrong with this code, and I have no idea what it is? It all looks fine, I can't find any bugs, but it just isn't working.

In this program, there are wires and power-sources, when I place a power-source beside a wire, I want it to become powered, and all connected wires to also be powered, but this program is showing very strange behavior and doing everything besides what I'd thought it would do. I wanted the wire to light up when there is a power source connected to it, and disable when there isn't. They light up when I place the power source, but when I place more wire, they all get disabled, and I can't seem to figure out why.

(dark red=powered black=not powered) Here it is when I place one wire beside the power source:

enter image description here

But then I add more and:

enter image description here

Here is the code:

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)
        self.topped=False
        self.lefted=False
        self.righted=False
        self.bottomed=False
    def update(self):
        self.powered=False
        if any(b.rect.collidepoint(self.rect.left,self.rect.top-5) for b in [b for b in blocks if b is not self]):
            if b.powered==True:
                self.powered=True
        if any(b.rect.collidepoint(self.rect.left,self.rect.top+38) for b in [b for b in blocks if b is not self]):
            if b.powered==True:
                self.powered=True
        if any(b.rect.collidepoint(self.rect.left-5,self.rect.top) for b in [b for b in blocks if b is not self]):
            if b.powered==True:
                self.powered=True
        if any(b.rect.collidepoint(self.rect.right+5,self.rect.top) for b in [b for b in blocks if b is not self]):
            if b.powered==True:
                self.powered=True
        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()

Please, please help me! I am very upset.

È stato utile?

Soluzione

There are several problems here. First, the immediate problem.

In update, where do you think b is coming from in this line?

        if b.powered==True:

It's not coming from one of these parts:

    if any(b.rect.collidepoint(self.rect.left,self.rect.top-5) for b in [b for b in blocks if b is not self]):
           ^                                                       ^

It's coming from the last iteration of this list comprehension:

[b for b in blocks if b is not self]

The last not-self block in the block list is used for all if b.powered == True tests. The loop variable of a generator expression isn't available outside the generator expression, and the loop variable of a list comprehension is only available outside the list comprehension due to a design decision made for performance reasons and undone in Python 3.

Instead of trying to use b outside the any call, put the test inside:

if any(b.powered and b is not self and b.rect.collidepoint(self.rect.left,self.rect.top-5) for b in blocks):

or since this is a pretty huge line, split this into an explicit loop instead of an any call. While you're at it, you can merge the 4 any calls into one pass over the list:

for b in blocks:
    if not b.powered:
        continue
    if b is self:
        # You don't actually need this test.
        continue

    adjacent = False
    if b.rect.collidepoint(self.rect.left,self.rect.top-5):
        adjacent = True
    if b.rect.collidepoint(...):
        adjacent = True
    # and the other two adjacency checks
    ...
    if adjacent:
        self.powered = True
        break

Now, the other problems. Your power-up logic only checks adjacent blocks. That means if a block is placed apart from the power source and then connected, it may take many updates for the block to realize it's receiving power. Also, if a block is disconnected from power or the power supply is removed, the block may never turn off, since whenever it looks, all its neighbors are powered. This will require a change to your algorithm. I recommend using a flood fill from the power sources to determine which blocks are powered.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top