Re: [pygame] Subtle Memory Bug
--- Kris Schnee <[EMAIL PROTECTED]> wrote: > So, like this? > > foo = [, , etc.] > n = 0 > while n < len(foo): > foo[n].DoStuff() ## Might result in deleting > foo[n] > n += 1 > > I think I've done something like that before, but I > don't remember > whether len(foo) gets evaluated anew each time. I don't remember either, but in this particular situation you can structure the loop so that it doesn't matter. Set n to len(foo) and count downwards to 0. Items that are deleted will be "behind" your count now. __ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com
Re: [pygame] Subtle Memory Bug
Kris Schnee wrote: Bob Ippolito wrote: It's probably not the uniqueness of ID numbers that's breaking his code, it's the fact that he has two different generations in the same data structure. That's simply not how you should do what he's trying to do. So, maybe have a tribes_this_turn dictionary and a next_turn_tribes dictionary, with tribes getting copied into the next only if they haven't been flagged as "gone?" It'd be tricky because what if tribes A and B merge one turn, and in the same turn C tries to interact with them? I guess the tribe that A/B become wouldn't exist till next turn, but then there's the possibility that C will attack and destroy A on the same turn that A has been absorbed into B. The way this is typically handled is to separate actions from effects. For example, simple physical modelling systems will update the velocity and position of all objects before considering collisions and other forces that affect acceleration. In your case, say each tribe has some hit points. Your run loop could look like: for each tribe: attack other tribes, decreasing their hit points flag intent to merge with another tribe remove any tribe with hit points < 0 for each pair of tribe intending to merge: merge the tribes As with a physical system, if your constraints / actions are more complex than this, you may want to solve a linear system or integrate a non-linear system to determine the simultaneous effect of all actions. [This comment is orthagonal to the idea of using separate vectors for current and next generations, which I am also in favour of.] Alex.
Re: [pygame] Subtle Memory Bug
James Hofmann wrote: I'd agree. I've been in similar situations before. What's really wanted(once the problem is discovered) are these two properties: 1. references to list locations, rather than specific items 2. can "step backwards" when size/ordering changes I tend to use a while loop and counter for those purposes. So, like this? foo = [, , etc.] n = 0 while n < len(foo): foo[n].DoStuff() ## Might result in deleting foo[n] n += 1 I think I've done something like that before, but I don't remember whether len(foo) gets evaluated anew each time. I may have had to say: n = 0 done = False while not done: DoStuff() if n >= len(foo): done = True This issue is relevant to my AI code, if I ever really sit down and work on it. I'd been using a big dictionary of neuron-like objects and cycling through them each turn, giving each of them "links" containing ID numbers used to access other units. Instead I might eliminate the ID numbers altogether and give the units direct references to each other, eg.: scint.LinkTo( otherscint ) as opposed to: scint.LinkTo( otherscint.ID ) Kris
Re: [pygame] Subtle Memory Bug
Bob Ippolito wrote: It's probably not the uniqueness of ID numbers that's breaking his code, it's the fact that he has two different generations in the same data structure. That's simply not how you should do what he's trying to do. So, maybe have a tribes_this_turn dictionary and a next_turn_tribes dictionary, with tribes getting copied into the next only if they haven't been flagged as "gone?" It'd be tricky because what if tribes A and B merge one turn, and in the same turn C tries to interact with them? I guess the tribe that A/B become wouldn't exist till next turn, but then there's the possibility that C will attack and destroy A on the same turn that A has been absorbed into B. Re: ID numbers, I had set it up so that no new tribe gets an ID number that's currently in use... but if I understand correctly: -The current value of self.alltribes always reflects changes made to the game world, but -The current set of values currently being used in the loop ("for tribe in self.alltribes.values():") isn't affected by those changes because it's evaluated only when the loop starts. Kris
Re: [pygame] Subtle Memory Bug
> I'd create a new alltribes dict on every generation. > It'd be faster > than what you're doing now, be more deterministic, > and a lot easier > to get right. > > I wouldn't classify this as a memory bug either. It > doesn't really > have anything to do with memory. > > -bob > I'd agree. I've been in similar situations before. What's really wanted(once the problem is discovered) are these two properties: 1. references to list locations, rather than specific items 2. can "step backwards" when size/ordering changes I tend to use a while loop and counter for those purposes. __ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com
Re: [pygame] Subtle Memory Bug
Oh, absolutely. However, they should be unique, otherwise there's no point in having them :DOn 7/10/06, Bob Ippolito < [EMAIL PROTECTED]> wrote:It's probably not the uniqueness of ID numbers that's breaking his code, it's the fact that he has two different generations in the same data structure. That's simply not how you should do what he's trying to do. -bobOn Jul 10, 2006, at 4:51 PM, andrew baker wrote:If you're using ID numbers, they really should be unique. On 7/10/06, Bob Ippolito <[EMAIL PROTECTED] > wrote: On Jul 10, 2006, at 2:27 PM, Kris Schnee wrote:> I've just solved a tricky bug (I think) whose solution might help > others> who encounter a similar problem.>> I was playing with cellular automata, a bunch of "tribes" that move> and> grow as squares on a grid. Each tribe was stored in a game object, > in a> dictionary, by an ID number. I had a loop that made each tribe take an> action, like so:>> for tribe in self.alltribes.values(): ## Line 1> ## Make sure tribe is still in play before activating. > if tribe.ID in self.alltribes.keys(): ## Line 2> tribe.Go()> self.age += 1>> Some events would cause a tribe to merge with another, deleting> both and> creating a new tribe with a new ID value. Other events would create a > new tribe. I was getting a strange error in which a tribe would try to> move from coordinates that it wasn't actually at, crashing the> program.> I narrowed down that this only happened when a tribe was deleted, and > then another tribe was randomly created with the same ID in the> same turn.>> The reason seems to be this. Line 1 creates a list of tribes when the> loop begins, _containing the tribe objects themselves_. When a game > event deletes a tribe, it's still present in memory until the end> of the> loop... so the loop checks the deleted tribe's ID, sees that there's> still a tribe with that ID (the newly created one), and runs _the > deleted tribe_, which shouldn't happen. So I changed line 2 to:>> if tribe in self.alltribes.values(): ## Line 2b>> This way, the tribe is checked not as an ID#, but as a Python object, > against the list of objects in self.alltribes.values. If the tribe is> deleted, it won't show up in the list when it's checked, so the test> will fail as it should.Well, I'm not sure I'd say that's a good solution either way. You should think *really* carefully about iterating over a dictionaryyou're also mutating. It also seems like a really strange way to docellular automata, since you're letting the hash order of thedictionary influence the algorithm. The way you're using the dict is really strange too, "foo in dict.keys()" is an order of magnitudeslower than "foo in dict".. and checking existence in values() is apretty good sign you're doing something wrong or using the wrong kind of data structure.I'd create a new alltribes dict on every generation. It'd be fasterthan what you're doing now, be more deterministic, and a lot easierto get right.I wouldn't classify this as a memory bug either. It doesn't really have anything to do with memory.-bob-- Andrew Ulysses Baker"failrate" -- Andrew Ulysses Baker"failrate"
Re: [pygame] Subtle Memory Bug
It's probably not the uniqueness of ID numbers that's breaking his code, it's the fact that he has two different generations in the same data structure. That's simply not how you should do what he's trying to do.-bobOn Jul 10, 2006, at 4:51 PM, andrew baker wrote:If you're using ID numbers, they really should be unique.On 7/10/06, Bob Ippolito <[EMAIL PROTECTED]> wrote: On Jul 10, 2006, at 2:27 PM, Kris Schnee wrote:> I've just solved a tricky bug (I think) whose solution might help > others> who encounter a similar problem.>> I was playing with cellular automata, a bunch of "tribes" that move> and> grow as squares on a grid. Each tribe was stored in a game object, > in a> dictionary, by an ID number. I had a loop that made each tribe take an> action, like so:>> for tribe in self.alltribes.values(): ## Line 1> ## Make sure tribe is still in play before activating. > if tribe.ID in self.alltribes.keys(): ## Line 2> tribe.Go()> self.age += 1>> Some events would cause a tribe to merge with another, deleting> both and> creating a new tribe with a new ID value. Other events would create a > new tribe. I was getting a strange error in which a tribe would try to> move from coordinates that it wasn't actually at, crashing the> program.> I narrowed down that this only happened when a tribe was deleted, and > then another tribe was randomly created with the same ID in the> same turn.>> The reason seems to be this. Line 1 creates a list of tribes when the> loop begins, _containing the tribe objects themselves_. When a game > event deletes a tribe, it's still present in memory until the end> of the> loop... so the loop checks the deleted tribe's ID, sees that there's> still a tribe with that ID (the newly created one), and runs _the > deleted tribe_, which shouldn't happen. So I changed line 2 to:>> if tribe in self.alltribes.values(): ## Line 2b>> This way, the tribe is checked not as an ID#, but as a Python object, > against the list of objects in self.alltribes.values. If the tribe is> deleted, it won't show up in the list when it's checked, so the test> will fail as it should.Well, I'm not sure I'd say that's a good solution either way. You should think *really* carefully about iterating over a dictionaryyou're also mutating. It also seems like a really strange way to docellular automata, since you're letting the hash order of thedictionary influence the algorithm. The way you're using the dict is really strange too, "foo in dict.keys()" is an order of magnitudeslower than "foo in dict".. and checking existence in values() is apretty good sign you're doing something wrong or using the wrong kind of data structure.I'd create a new alltribes dict on every generation. It'd be fasterthan what you're doing now, be more deterministic, and a lot easierto get right.I wouldn't classify this as a memory bug either. It doesn't really have anything to do with memory.-bob-- Andrew Ulysses Baker"failrate"
Re: [pygame] Subtle Memory Bug
If you're using ID numbers, they really should be unique.On 7/10/06, Bob Ippolito <[EMAIL PROTECTED]> wrote: On Jul 10, 2006, at 2:27 PM, Kris Schnee wrote:> I've just solved a tricky bug (I think) whose solution might help > others> who encounter a similar problem.>> I was playing with cellular automata, a bunch of "tribes" that move> and> grow as squares on a grid. Each tribe was stored in a game object, > in a> dictionary, by an ID number. I had a loop that made each tribe take an> action, like so:>> for tribe in self.alltribes.values(): ## Line 1> ## Make sure tribe is still in play before activating. > if tribe.ID in self.alltribes.keys(): ## Line 2> tribe.Go()> self.age += 1>> Some events would cause a tribe to merge with another, deleting> both and> creating a new tribe with a new ID value. Other events would create a > new tribe. I was getting a strange error in which a tribe would try to> move from coordinates that it wasn't actually at, crashing the> program.> I narrowed down that this only happened when a tribe was deleted, and > then another tribe was randomly created with the same ID in the> same turn.>> The reason seems to be this. Line 1 creates a list of tribes when the> loop begins, _containing the tribe objects themselves_. When a game > event deletes a tribe, it's still present in memory until the end> of the> loop... so the loop checks the deleted tribe's ID, sees that there's> still a tribe with that ID (the newly created one), and runs _the > deleted tribe_, which shouldn't happen. So I changed line 2 to:>> if tribe in self.alltribes.values(): ## Line 2b>> This way, the tribe is checked not as an ID#, but as a Python object, > against the list of objects in self.alltribes.values. If the tribe is> deleted, it won't show up in the list when it's checked, so the test> will fail as it should.Well, I'm not sure I'd say that's a good solution either way. You should think *really* carefully about iterating over a dictionaryyou're also mutating. It also seems like a really strange way to docellular automata, since you're letting the hash order of thedictionary influence the algorithm. The way you're using the dict is really strange too, "foo in dict.keys()" is an order of magnitudeslower than "foo in dict".. and checking existence in values() is apretty good sign you're doing something wrong or using the wrong kind of data structure.I'd create a new alltribes dict on every generation. It'd be fasterthan what you're doing now, be more deterministic, and a lot easierto get right.I wouldn't classify this as a memory bug either. It doesn't really have anything to do with memory.-bob-- Andrew Ulysses Baker"failrate"
Re: [pygame] Subtle Memory Bug
On Jul 10, 2006, at 2:27 PM, Kris Schnee wrote: I've just solved a tricky bug (I think) whose solution might help others who encounter a similar problem. I was playing with cellular automata, a bunch of "tribes" that move and grow as squares on a grid. Each tribe was stored in a game object, in a dictionary, by an ID number. I had a loop that made each tribe take an action, like so: for tribe in self.alltribes.values(): ## Line 1 ## Make sure tribe is still in play before activating. if tribe.ID in self.alltribes.keys(): ## Line 2 tribe.Go() self.age += 1 Some events would cause a tribe to merge with another, deleting both and creating a new tribe with a new ID value. Other events would create a new tribe. I was getting a strange error in which a tribe would try to move from coordinates that it wasn't actually at, crashing the program. I narrowed down that this only happened when a tribe was deleted, and then another tribe was randomly created with the same ID in the same turn. The reason seems to be this. Line 1 creates a list of tribes when the loop begins, _containing the tribe objects themselves_. When a game event deletes a tribe, it's still present in memory until the end of the loop... so the loop checks the deleted tribe's ID, sees that there's still a tribe with that ID (the newly created one), and runs _the deleted tribe_, which shouldn't happen. So I changed line 2 to: if tribe in self.alltribes.values(): ## Line 2b This way, the tribe is checked not as an ID#, but as a Python object, against the list of objects in self.alltribes.values. If the tribe is deleted, it won't show up in the list when it's checked, so the test will fail as it should. Well, I'm not sure I'd say that's a good solution either way. You should think *really* carefully about iterating over a dictionary you're also mutating. It also seems like a really strange way to do cellular automata, since you're letting the hash order of the dictionary influence the algorithm. The way you're using the dict is really strange too, "foo in dict.keys()" is an order of magnitude slower than "foo in dict".. and checking existence in values() is a pretty good sign you're doing something wrong or using the wrong kind of data structure. I'd create a new alltribes dict on every generation. It'd be faster than what you're doing now, be more deterministic, and a lot easier to get right. I wouldn't classify this as a memory bug either. It doesn't really have anything to do with memory. -bob
[pygame] Subtle Memory Bug
I've just solved a tricky bug (I think) whose solution might help others who encounter a similar problem. I was playing with cellular automata, a bunch of "tribes" that move and grow as squares on a grid. Each tribe was stored in a game object, in a dictionary, by an ID number. I had a loop that made each tribe take an action, like so: for tribe in self.alltribes.values(): ## Line 1 ## Make sure tribe is still in play before activating. if tribe.ID in self.alltribes.keys(): ## Line 2 tribe.Go() self.age += 1 Some events would cause a tribe to merge with another, deleting both and creating a new tribe with a new ID value. Other events would create a new tribe. I was getting a strange error in which a tribe would try to move from coordinates that it wasn't actually at, crashing the program. I narrowed down that this only happened when a tribe was deleted, and then another tribe was randomly created with the same ID in the same turn. The reason seems to be this. Line 1 creates a list of tribes when the loop begins, _containing the tribe objects themselves_. When a game event deletes a tribe, it's still present in memory until the end of the loop... so the loop checks the deleted tribe's ID, sees that there's still a tribe with that ID (the newly created one), and runs _the deleted tribe_, which shouldn't happen. So I changed line 2 to: if tribe in self.alltribes.values(): ## Line 2b This way, the tribe is checked not as an ID#, but as a Python object, against the list of objects in self.alltribes.values. If the tribe is deleted, it won't show up in the list when it's checked, so the test will fail as it should. Anyway, I learned something from this problem about the persistence of objects in memory. Perhaps this will help someone else. Kris ...Defeated the Bug and got 1 experience points!