Reputation: 23
So as my first project in python outside of Code Academy, I decided to make a basic molecular dynamics simulator on pygame. It works fine for a while, but as soon as electrons start to move too fast, and strip all the other electrons off their atoms, I get the TypeError in the title. I have no idea where this comes from, and only appears after the program has been running long enough for me to mess up all the physics.
Now I know that the error is telling me that I'm trying to pass a list somewhere I shouldn't, but I've looked over the program and can't figure out where. The error pops up in the bit that tells electrons how to orbit their atom angle = findA(particles[el], particles[nuc]) + 0.001
, which is controlled by the block of code near the end that tells the program in which order to do physics, and the list of what each electron is meant to orbit is controlled by another point, and so on.
So I decided just to give you all the code.
import sys, pygame, math
from pygame.locals import *
pygame.init()
sizeScreen = width, height = 1000, 700
sizeMenu = width, height = 652, 700
e = 1.6 * 10 ** -19
particles = {}
mx, my = 0, 0
selected = []
def findOrbital(el):
for a in particles:
if a != el and particles[a][4] != 'el':
if findD(particles[el], particles[a]) < 5 * 10 ** -11 and PTI[particles[a][4]][7] > len(particles[a][5]):
particles[a][5].append(el)
particles[el][5].append(a)
def searcher(List, item):
for a in List:
if a == item:
return True
return False
def moveAtEls(el, nuc):
angle = findA(particles[el], particles[nuc]) + 0.001
particles[el][0] = particles[nuc][0] + 50 * math.cos(angle)
particles[el][1] = particles[nuc][1] + 50 * math.sin(angle)
def check(each):
if particles[each][0] < 175:
particles[each][2] = -particles[each][2]
particles[each][0] = 175
elif particles[each][0] > 1000:
particles[each][2] = -particles[each][2]
particles[each][0] = 1000
if particles[each][1] < 0:
particles[each][3] = -particles[each][3]
particles[each][1] = 0
elif particles[each][1] > 700:
particles[each][3] = -particles[each][3]
particles[each][1] = 700
if particles[each][4] == 'el':
a = 'n'
findOrbital(each)
if a != 'n':
particles[each][5].append(a)
particles[a][5].append(each)
def findD(self, other):
return math.hypot((self[0] - other[0]), (self[1] - other[1])) * 0.62 * 10 ** -12
def findA(self, other):
return math.atan2((self[1] - other[1]), (self[0] - other[0]))
def move(self):
for other in particles:
if particles[other] != self and self[5] != particles[other] [5] and not searcher(self[5], other):
D = findD(self, particles[other])
if D == 0:
self[5].append(other)
particles[other][5].append(self)
break
angle = findA(self, particles[other])
F = 8987550000 * (PTI[self[4]][4] * PTI[particles[other][4]][4] * e ** 2)/D ** 2
a = int(F/PTI[self[4]][5])
ax = a * math.cos(angle)
ay = a * math.sin(angle)
self[2] += ax/(10 ** 16)
self[3] += ay/(10 ** 16)
self[0] += self[2]/(10 ** 8)
self[1] += self[3]/(10 ** 8)
pressed = ''
press = {'Katom':[2,148,2,32,0],'Knuc':[2,148,36,66,0],'Kel':[2,148,70,100,0]}
PTI = {'el':[0, 0, 0, 0, -1, 9.11 * 10 ** -31, pygame.image.load("electron.png"), 2],
'HNuc' : [185, 214, 8, 37, 1, 1.7 * 10 ** -27, pygame.image.load("nuc/HNuc.png"), 2, 1],
'HeNuc': [586, 613, 8, 37, 2, 6.6 * 10 ** -27, pygame.image.load("nuc/HeNuc.png"), 2, 2],
'LiNuc': [185, 214, 40, 69, 1, 1.16 * 10 ** -26, pygame.image.load("nuc/LiNuc.png"), 8, 1],
'BeNuc': [216, 246, 40, 69, 2, 1.53 * 10 ** -26, pygame.image.load("nuc/BeNuc.png"), 8, 2],
'BNuc' : [428, 457, 40, 69, 3, 1.84 * 10 ** -26, pygame.image.load("nuc/BNuc.png"), 8, 3],
'CNuc' : [460, 489, 40, 69, 4, 2.04 * 10 ** -26, pygame.image.load("nuc/CNuc.png"), 8, 4],
'NNuc' : [492, 520, 40, 69, 5, 2.38 * 10 ** -26, pygame.image.load("nuc/NNuc.png"), 8, 5],
'ONuc' : [523, 551, 40, 69, 6, 2.72 * 10 ** -26, pygame.image.load("nuc/ONuc.png"), 8, 6],
'FNuc' : [554, 583, 40, 69, 7, 3.23 * 10 ** -26, pygame.image.load("nuc/FNuc.png"), 8, 7],
'NeNuc': [586, 613, 40, 69, 8, 3.43 * 10 ** -26, pygame.image.load("nuc/NeNuc.png"), 8, 8]}
menu = pygame.display.set_mode(sizeMenu)
screenColor = pygame.Color(255, 255, 220)
screen = pygame.display.set_mode(sizeScreen)
edgeObj = pygame.image.load("edge.png")
addEl = [pygame.image.load('addElectron1.png'), pygame.image.load('addElectron2.png')]
addAtom = [pygame.image.load("addAtom1.png"), pygame.image.load("addAtom2.png"), pygame.image.load("atomTable.png")]
addNucleus = [pygame.image.load("addNuc1.png"), pygame.image.load("addNuc2.png"), pygame.image.load("NucTable.png")]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(0)
elif event.type == MOUSEMOTION:
mx, my = event.pos
mouseState = pygame.mouse.get_pressed()
if mouseState[0]:
for key in press:
if press[key][0] < mx <press[key][1] and press[key][2] < my < press[key][3]:
pressed = key
press[key][4] = 1
if not mouseState[0] and pressed == 'Kel':
particles[len(particles)] = [mx, my, 0, 0, 'el', []]
pressed = ''
press['Kel'][4] = 0
if pressed != '':
if not mouseState[0]:
if press[pressed][0] < mx <press[pressed][1] and press[pressed][2] < my < press[pressed][3]:
press[pressed][4] = 2
pressed = ''
if press['Knuc'][4] == 2 or press['Katom'][4] == 2:
if mouseState[0]:
if 621 < mx < 651 and 2 < my < 14:
press['Knuc'][4] = 0
press['Katom'][4] = 0
if press['Knuc'][4] == 2:
for nuc in PTI:
if PTI[nuc][0] < mx < PTI[nuc][1] and PTI[nuc][2] < my < PTI[nuc][3]:
press['Knuc'][4] = 0
selected.append(nuc)
if press['Katom'][4] == 2:
for nuc in PTI:
if PTI[nuc][0] < mx < PTI[nuc][1] and PTI[nuc][2] < my < PTI[nuc][3]:
a = 0
selected.append(nuc)
while a < PTI[nuc][8]:
selected.append('el')
a += 1
press['Katom'][4] = 0
if selected != []:
if not mouseState[0]:
a = len(particles)
particles[a] = [mx, my, 0, 0, selected[0], [b for b in range(a+1, len(selected)-1)]]
for item in selected:
if item != selected[0]:
particles[len(particles)] = [mx, my, 0, 0, item, [a]]
selected = []
for each in particles:
check(each)
move(particles[each])
check(each)
if len(particles[each][5]) > 0 and particles[each][4] == 'el':
moveAtEls(each, particles[each][5][0])
particles[each][5] = []
screen.fill(screenColor)
for a in particles:
screen.blit(PTI[particles[a][4]][6], (particles[a][0] - 29, particles[a][1] - 31))
menu.blit(edgeObj, (0, 0))
menu.blit(addNucleus[press['Knuc'][4]], (2, 2))
menu.blit(addAtom[press['Katom'][4]], (2, 2))
menu.blit(addEl[press['Kel'][4]], (2, 2))
pygame.display.flip()
Sorry if I'm being a nuisance by posting all the code, but I'm a complete n00b and I'm surprised I got this far without help. I know the whole thing is untidy, but if you could help with the error I'd greatly appreciate it.
Next time I'll just stick to print("Hello, World!")
Upvotes: 1
Views: 600
Reputation: 64038
So, what I believe is happening is that when execute the line angle = findA(particles[el], particles[nuc]) + 0.001
, either the el
variable or the nuc
variable is a list of some sort, rather then a single object.
This throws an error because particles
is a dict, and you cannot have a list or any mutable type as a key in a dict.
So, given that this error does not execute immediately, I suspect that somewhere along the line, in a piece of code that is not immediately executed, you are accidentally passing in a list
of some sort.
If you did mean to look things up in the particles
dict by using a list as a key, then you should convert the list to a tuple
first: tuples are like lists, but are immutable, and so can be hashed and used as a key of a dict.
Upvotes: 1