-4

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.

Sam Tubb
  • 945
  • 3
  • 19
  • 40
  • Try to be as specific as possible. What is the exact error message you are getting? – Reinstate Monica Feb 16 '14 at 22:25
  • 3
    "Doing everything besides what I thought it would do" is excruciatingly uninformative. We have nothing to go on. – mhlester Feb 16 '14 at 22:25
  • I've asked multiple questions on this, I figure people would start getting confused. Let me go edit it, please don't close this. – Sam Tubb Feb 16 '14 at 22:27
  • 2
    The fact that you're angry/upset is not relevant. Your questions will keep getting closed until you'd bother to post it according to [the guidelines](http://stackoverflow.com/help/how-to-ask). – Nir Alfasi Feb 16 '14 at 22:28
  • 1
    post a very minimal example that clearly demonstrates the issue ... as well as exactly what the issue is – Joran Beasley Feb 16 '14 at 22:28
  • 1
    `for b in [b for b in blocks if b is not self]` can be shortened to just `for b in blocks if b is not self`. – user2357112 Feb 16 '14 at 22:33
  • you dont even need the powersource on the line ... your just setting all blocks to red when you place a powersource and all to black if you place anything else (wire is only option I think) – Joran Beasley Feb 16 '14 at 22:37
  • Oh, I see. How can I fix it then? – Sam Tubb Feb 16 '14 at 22:39
  • store your data as a 2d array ... blocks = `[[None for _ in screen_width/32] for _ in screen_height/32]` ... this will also make it much easier to get neighbors ... you also probably need to make is_powered some kind of function – Joran Beasley Feb 16 '14 at 22:47
  • What do you mean by 2d array, and your code returns and error for me: `blocks = [[None for x in 640/32] for x in 480/32] TypeError: 'int' object is not iterable` – Sam Tubb Feb 16 '14 at 22:56

1 Answers1

2

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.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • This is making a a whole lot more since now! Thank you! Too bad tons of people already down-voted this question. – Sam Tubb Feb 16 '14 at 23:07
  • @SamTubb: Honestly, it was a pretty bad question before you edited it. If you'd included the information from the edit in the original version, you would have gotten a better response. – user2357112 Feb 16 '14 at 23:12
  • Ok, one last question before I move on, I don't get why you test `if not b.rect.collidepoint(self.rect.left,self.rect.top-5):` what does testing for the block not being above it actually do? – Sam Tubb Feb 16 '14 at 23:14
  • @SamTubb: I think that's a mistake I made. Fixing... – user2357112 Feb 16 '14 at 23:15
  • @SamTubb: Okay, fixed. I misapplied De Morgan's equivalences. – user2357112 Feb 16 '14 at 23:18
  • The power block doesn't have to be connected to the wires to power them, unless I implemented your code wrong.. still better than what it used to be. – Sam Tubb Feb 16 '14 at 23:22
  • 1
    @SamTubb: I edited again after I said "fixed", because I screwed up twice. The second time, I forgot to delete some `not`s. – user2357112 Feb 16 '14 at 23:25
  • Yay it works! No I just have to figure out the flood-fill thing, thank you for all your help, it really means a lot, this has been driving me crazy all day. – Sam Tubb Feb 16 '14 at 23:27