Search code examples
pythonfractalsvpython

VPython fractal: Can't create an array of shapes


I'm trying to create a menger sponge using VPython.

I built the base piece with no problem (image below) and I'm trying to create an array filled with the base piece in the same configuration. However, I can't get it to work. The display doesn't change and still shows just one base piece.



enter image description here



Here is the code:

from vpython import *

l,w,h = 1,1,1

cubes = []
def basePiece():
    L = 1
    for i in range(-L,L+1):
        for j in range(-L,L+1):
            for k in range(-L,L+1):
                sum = abs(i) + abs(j) + abs(k)
                if sum > 1:
                    cube=box(color=vector(1,1,1), opacity=0.9,
                            pos=vector(i,j,k),
                            length=l, height=h, width=w)
                    cubes.append(cube)
    return cubes

fract = []
L = 1
for x in range(L,L+1):
    for y in range(L,L+1):
        for z in range(L,L+1):
            sum = abs(x) + abs(y) + abs(z)
            if sum > 1:
                fract.append(basePiece())

Any help would be appreciated.
Thanks in advance.


Solution

  • The problem is that you wrote range(L, L+1), which means that the iterator only takes one value (L), whereas it should be range(-L, L+1). Another problem is that you should extend the list and not append, since otherwise you build lists of lists (although this is probably less a problem):

    fract = []
    L = 1
    for x in range(-L,L+1):
        for y in range(-L,L+1):
            for z in range(-L,L+1):
                sum = abs(x) + abs(y) + abs(z)
                if sum > 1:
                    fract.extends(basePiece())
    

    So no it will work for:

    x=-1, y=-1, z=-1
    x=-1, y=-1, z= 0
    x=-1, y=-1, z=+1
    
    x=-1, y= 0, z=-1
    x=-1, y= 0, z=+1
    
    x=-1, y=+1, z=-1
    x=-1, y=+1, z= 0
    x=-1, y=+1, z=+1
    
    x= 0, y=-1, z=-1
    x= 0, y=-1, z=+1
    
    x= 0, y=+1, z=-1
    x= 0, y=+1, z=+1
    
    x=+1, y=-1, z=-1
    x=+1, y=-1, z= 0
    x=+1, y=-1, z=+1
    
    x=+1, y= 0, z=-1
    x=+1, y= 0, z=+1
    
    x=+1, y=+1, z=-1
    x=+1, y=+1, z= 0
    x=+1, y=+1, z=+1
    

    In case you use range(1, 1+1), you only would get x = y = z = 1, and hence it would be printed once.

    This is however still not sufficient: you need to be able to move the cubes. So parameterize the basePiece:

    from vpython import *

    l,w,h = 1,1,1
    
    cubes = []
    def basePiece(x0, y0, z0):
        L = 1
        for i in range(-L,L+1):
            for j in range(-L,L+1):
                for k in range(-L,L+1):
                    sum = abs(i) + abs(j) + abs(k)
                    if sum > 1:
                        cube=box(color=vector(1,1,1), opacity=0.9,
                                pos=vector(x0+i,y0+j,z0+k),
                                length=l, height=h, width=w)
                        cubes.append(cube)
        return cubes
    

    and:

    fract = []
    L = 1
    for x in range(-L,L+1):
        for y in range(-L,L+1):
            for z in range(-L,L+1):
                sum = abs(x) + abs(y) + abs(z)
                if sum > 1:
                    fract.extends(basePiece(3*x, 3*y, 3*z))