Posts for Derakon


Experienced Forum User
Joined: 7/2/2007
Posts: 3960
This is a bit for fun and a bit for serious. Jetblade, the open-source game I've been working on off and on, has a spacefilling automaton that I use to carve tunnels into the game world. Here's an example animation showing how the algorithm works: Basically a selection of "seeds" are laid down along the various lines that describe where the game wants to place tunnels. These seeds have two attributes: an owner and a lifespan. Each tick, they attempt to replace all neighboring cells with a copy of themselves with shorter life, and make an open space. If there's already a seed adjacent to them with a different owner, however, then they create a wall instead. There's a problem, though: this is slow. For a (fairly small) map of 250x250 cells, seed expansion takes 7 seconds, and this scales approximately linearly with the number of cells (35 seconds at 500x500). So here's the function; do you see any notable improvements that could be made?
Language: python

## Run a spacefilling automaton to divide a grid up into different sectors. # \param seeds A mapping of locations to Seed instances # \param blocks A grid of cells to be converted to walls and open space # Each seed ordinarily replaces all neighbor spaces with copies of itself # that have 1 less turn to live. When a seed dies (has 0 life), its location # is marked as open in the blocks grid. Dead seeds are retained so we can # map spaces to the sectors that own those spaces. # When two expanding seeds collide, they merge if they are for the same # sector (as determined by their 'owner' property), or form a wall between # them if they are not. def expandSeeds(self, seeds, blocks): deadSeeds = dict() numCols = len(blocks) numRows = len(blocks[0]) logger.debug("Expanding seeds for a",numCols,"by",numRows,"grid") while len(seeds): newSeeds = dict() for loc, curSeed in seeds.iteritems(): # If the counter expires while the seed is not in open space, # replace it with a wall. if (not self.getIsInBounds(loc, numCols, numRows) or (curSeed.life <= 0 and blocks[loc.ix][loc.iy] != BLOCK_EMPTY)): deadSeeds[loc] = curSeed blocks[loc.ix][loc.iy] = BLOCK_WALL continue if (blocks[loc.ix][loc.iy] == BLOCK_WALL): # A wall sprung up under us. Check if there's a dead # seed there; if so, try to merge with it. if loc in deadSeeds: newSeed = self.tryMergeDeadSeed(curSeed, loc, seeds, deadSeeds, numCols, numRows) if newSeed is not None: newSeeds[loc] = newSeed del deadSeeds[loc] blocks[loc.ix][loc.iy] = BLOCK_UNALLOCATED else: # No seeds on walls. continue if blocks[loc.ix][loc.iy] == BLOCK_EMPTY: # No seeds on empty space deadSeeds[loc] = curSeed continue for adjLoc in loc.perimeter(): # Check adjacent blocks for seeds. If none, expand into the # space. If there is a seed, make a wall, unless it's our # own seed in which case we merge with it. if not self.getIsInBounds(adjLoc, numCols, numRows): continue if adjLoc in seeds or adjLoc in newSeeds: # Two adjacent seeds; either merge or make wall. altSeed = None if adjLoc in seeds: altSeed = seeds[adjLoc] else: altSeed = newSeeds[adjLoc] if altSeed.owner == curSeed.owner: # Merge the seeds newSeeds[adjLoc] = seed.Seed(curSeed.owner, max(curSeed.life, altSeed.life) - 1, max(curSeed.age, altSeed.age) + 1) else: # Conflict; make a wall. altSeed.life = 0 altSeed.age = constants.BIGNUM curSeed.life = 0 curSeed.age = constants.BIGNUM blocks[loc.ix][loc.iy] = BLOCK_WALL blocks[adjLoc.ix][adjLoc.iy] = BLOCK_WALL elif blocks[loc.ix][loc.iy] == BLOCK_UNALLOCATED: # No seed there; plant one. newSeeds[adjLoc] = seed.Seed(curSeed.owner, curSeed.life - 1, curSeed.age + 1) elif (blocks[adjLoc.ix][adjLoc.iy] != BLOCK_EMPTY and deadSeeds.has_key(adjLoc)): # Hit a wall containing a dead seed; try to merge # with it. newSeed = self.tryMergeDeadSeed(curSeed, adjLoc, seeds, deadSeeds, numCols, numRows) if newSeed is not None: newSeeds[adjLoc] = newSeed del deadSeeds[adjLoc] blocks[adjLoc.ix][adjLoc.iy] = BLOCK_UNALLOCATED # Done expanding; zero our location if we didn't wall it # earlier. if blocks[loc.ix][loc.iy] != BLOCK_WALL: blocks[loc.ix][loc.iy] = BLOCK_EMPTY deadSeeds[loc] = curSeed seeds = newSeeds return (blocks, deadSeeds)
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
What's an "IL point of view"? I don't think upgrades or alternate vehicles are really necessary, personally. The base missions give you a good variety of vehicles to use, and the upgrades shouldn't make that much of a difference (unless you plan to pull out Vader's ship and just spam cluster missiles, but who the hell would want to see that?).
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Is it really a desync, or is it just the game being laggy? You might have your frame-advance action defaulting to skipping lag frames, since you can't provide input during those frames anyway.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Rolanmen: the Slug requires a different pickup to get more shells. Picking up grenades when in the Slug just means you have more grenades when you get out of it. Actually, I don't think there are any shell pickups in MS1. So very very not getting involved in the nascent flamewar over when it's reasonable to vote no. It has precisely zero impact on whether or not the run will be published anyway.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Fantastic work, X2poet. Gotta love shooting down aircraft with shotguns. :) Whenever you have to make a decision between entertainment and speed, someone out there is going to disagree with you. Don't let it bother you too much.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Bootcamp and some kind of VM solution like VirtualBox are basically your best bets, the one for getting high-speed emulation (should only be an issue for the more advanced consoles), the other for saving you from having to reboot your computer when you want to TAS. In both cases you will need a valid Windows install to work from.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
"So long"? Seven hours from submission to encode is damned fast. It's a pity I'm at work right now. Have to watch it later.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
I've made a ~4 minute TAS in FCEU that synced just fine. I don't see why they wouldn't sync, to be quite honest; the emulators are running on the same operating system as they always do. It's just not as fast as usual. 3D might be a different matter, but only because of the horrible graphics card that VirtualBox sets you up with. Basically, if your program uses software rendering, then VirtualBox should be fine; if you need hardware acceleration, then it probably won't be. Even then, though, it's a matter of performance, not sync.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
You missed the second part of my post, where I said that Goldeneye does not have a perfectly realtime physics system. You can absolutely cause massive slowdown (where things take more real time to happen) by e.g. looking at a couple of explosions. I wouldn't be surprised if the same thing happens to a lesser extent if you make the game draw lots of things, by not looking at the ground.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
The difference between Bootcamp and VirtualBox is that VirtualBox runs a virtual machine within your main OS, so you don't have to reboot. But as you noted, it's not as capable as running the main OS directly.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Thanks for the encode, Nahoc! The run looked great as always, Kriole. A solid improvement to a solid TAS.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Got a chance to watch this, and, uh, the second boss is Clown Ben Franklin? I suggest a screenshot from around here (taken from 4:20 in the YouTube encode): Voting yes, of course. Great work, Ryuto! The playarounds during the bosses, and the humiliation of the AI bombermen in the arena, were much appreciated.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
There's also VirtualBox, which allows you to run virtual computers which can have other OSes from your primary OS. So you could install Windows on a virtual computer and run emulators in it. VirtualBox doesn't provide a very good "graphics card", though. It should work fine for 8- and 16-bit consoles.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
wicked wrote:
is he invenciible forever?
From the previous run that this obsoletes:
Nitsuja wrote:
Because each level starts with a decently long period of invincibility, the optimal thing to do is the really cheap thing to do: lay down tons of bombs and walk around the level as a giant chain-reaction explosion before the invincibility runs out. While cheap, it works wonders and fills the screen with explosions, so I abused it as much as possible in every single level. When not invincible, a single hit from any explosion or contact with any monster means instant death AND loss of most powerups collected.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
My understanding is that lookdown is used because the game's in-game timer counts lag frames in addition to normal frames -- it's effectively a real-time clock instead of the usual frame counter. Thus, anything you can do to reduce lag will get you a faster time. We're just not used to this applying to real-time runners as well as to TASers. :) I doubt it impacts your running speed in RAM, which is almost certainly expressed in units per frame to avoid having the physics depend on how laggy an area is. That way madness lies. Your description of framerate vs. playing speed certainly doesn't apply entirely to Goldeneye. You can easily overload it and cause slowdown (not just low display framerate) just by causing a couple of explosions. Even if the physics updates are decoupled from the display updates, the game is clearly only willing to wait so long between display updates.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Some of the consoles are supported by the TAS movie editor which should be able to help you with hex-editing. Otherwise, you can do it manually. The movie files are basically sequences of button presses (and, with more advanced consoles, analog stick positions). Hexing is "merely" inserting the newly-desired input into the middle of the previous input. This does require you to be able to read the input file, though, which can be more or less complicated depending on the file format. Also, hexing isn't always possible. Let's say that there's a platform in the game whose position is dependent on a global timer. If you hex an earlier part of the run to be faster, then when you get to that platform it's not where it was the first time you encountered it. Think of hex-editing as time travel: you went back in time and changed things, so now in the present the game world is different. Depending on the game, things may change more or less drastically.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Man, that fight goes much faster when they aren't continually spamming ninjitsu. Nice! Your coin plan looks reasonable to me.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
It sounds to me like there's something different in nfq's setup that means that he doesn't run into the same problems between levels that Wyster does -- i.e. a run syncs for nfq when it doesn't for Wyster. nfq, didn't you earlier say that you were able to do the last few levels of the previous run without any between-level desync problems? Perhaps you two should compare notes and see if there's something going wrong on Wyster's end.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Thanks for all the work you put into this encode, Aktan. It looks great!
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
My impression is that most game-breaking glitches are found through a combination of experimentation and intuition. An experienced programmer or TASer will know about a large variety of potential bugs and the general situations required to trigger them. For example, most TASers know about trying L+R or U+D in various scenarios (on the ground, in the air, climbing a ladder, etc.). Less well-known is corner boosting, but anyone who's ever implemented their own bounding box-based "physics engine" will know that the direction you get pushed out of a bit of scenery is not always the direction you entered from; combine that knowledge with TASing and the application becomes reasonably clear. I shouldn't deprecate the amount of time spent on experimentation, though. Plenty of time is spent with memory watch open, just manually figuring out the fastest way to move. The Aria of Sorrow TASers went through four or five iterations of "Ah! This sequence of button presses is 11% faster on slopes than the old method!" for example. I also can't count the number if times I've seen "I was just playing the game normally, and something bizarre happened, so I went back and figured out how to replicate it" on these forums. On that note, always be recording your gameplay if you intend to TAS a game; I also can't count the number of times I've seen "I was playing the game normally, and something bizarre happened, but I wasn't recording and now I can't replicate it. :(" on these forums. Honestly I suspect that if you really want to improve your TASing through programming knowledge, you'd be better off trying to write your own game in the genre you want to TAS. That seems more likely to give you insight into the potential bug types than learning to read the ASM of a specific game will, at least in terms of results per time invested.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
I'm having trouble gleaning from that brief WIP what the problem is with TASing Canvas Curse.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
nfq: I'd expect the usual reason to prefer 1.0 is that 1.1 sometimes fixes some bugs that could be useful. If that's not the case, though, then why not use the most recent version? I rather doubt there'd be an impact on sync-stability in any case.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
Looked good to me. What's the differences between the machinegun, bazooka, and flamethrower?
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
I didn't make it more than a minute into watching this before I stopped with absolutely zero interest in continuing. From what I saw, this isn't quite the epitome of bad game choice, but it comes close.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.
Experienced Forum User
Joined: 7/2/2007
Posts: 3960
We don't play inane forum games here.
Pyrel - an open-source rewrite of the Angband roguelike game in Python.