Note: The submitted movie file only contains a fraction of the TAS, as the full version was too large to upload in the submission form. Please replace the submitted movie with this userfile which contains the full version.
Astrosmash is a game where you're a laser gun that has to shoot everything out of the sky. Shoot more things, the more points you'll get. Be careful though, if you let asteroids hit the ground, you'll lose points. Let a spinner hit the ground and you'll lose a life! You'll also meet hazards like pulsating missiles which home in on the player, and UFOs which give the most points when killed. There is also a teleport button that moves your gun to a random location and can be helpful when in a sticky situation!
This submission improves upon the previous by a colossal 5 hours, 49 minutes, and 17 seconds... is this the single biggest submission improvement in the history of TASVideos.org? Someone check on that lol. The improvement got this massive thanks to an improvement to my lua script which benchmarks the bot's performance continuously rather than at six key points. I had my poor computer run this script round-the-clock for about a month in order to hammer out this TAS.
Highlights
- 100% completion
- 100% script-generated
- 2 Players (as in both controllers used)
- Aims for maximum score (32,767,995 points)
- Deathless (ends with 32,772 lives)
- Heavy luck manipulation
- Uses hardest difficulty
- Genre: Action/Shooter
Resources
- The lua script (for BizHawk 2.10)
- Useful RAM Addresses
- Instructions Manual
Key Moments
| Score | Significance | Surpassed at | Beats WR by |
|---|---|---|---|
| 20,000 | UFOs begin spawning | 1 min, 19 sec | 3 min, 19 sec |
| 100,000 | Last scoring multiple increase | 3 min, 13 sec | 12 min, 38 sec |
| 1,000,000 | Last difficulty increase | 14 min, 59 sec | 1 hr, 34 min, 37 sec |
| 6,171,485 | World record high score | 1 hr, 11 min, 9 sec | ~12 hr, 31 min |
| 9,999,995 | Maximum nominal score | 1 hr, 52 min, 44 sec | Never achieved by a human |
| 32,767,995 | Maximum score | 5 hr, 59 min, 58 sec | Never achieved by a human |
Basic Game Info
- Large rocks will sometimes split into two small rocks when shot
- If a spinner hits the ground, you instantly die
- The teleport button will move you to a new random position - useful for sticky situations
- An extra life is awarded every 1,000 points
- Score table:
| Score | Multiplier | Big Rock | Small Rock | Big Spinner | Small Spinner | Missile | UFO | Big Rock Miss | Small Rock Miss | Death |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1x | 10 | 20 | 40 | 80 | 50 | — | -5 | -10 | -100 |
| 1000 | 2x | 20 | 40 | 80 | 160 | 100 | — | -10 | -20 | -200 |
| 5000 | 3x | 30 | 60 | 120 | 240 | 150 | — | -15 | -30 | -300 |
| 20,000 | 4x | 40 | 80 | 160 | 320 | 200 | 400 | -20 | -40 | -400 |
| 50,000 | 5x | 50 | 100 | 200 | 400 | 250 | 500 | -25 | -50 | -500 |
| 100,000 | 6x | 60 | 120 | 240 | 480 | 300 | 600 | -30 | -60 | -600 |
- If any of the above targets collide with a missile, both the missile and the colliding target will be destroyed without any points being awarded.
Difficulty Selection
Hardest difficulty, or "top speed" rather, is selected by pressing the disc, side buttons, or keys 4 through Enter on the title screen. There are three easier difficulties which simply introduce more lag frames to make the game slower, with no other differences to my knowledge.
2 Controllers
Both controllers are utilized in the script extensively to minimize button-press conflicts. For instance:
- Controller 1 handles the following:
- Disc inputs
- Small asteroid targeting (lower-left side button
- Large asteroid targeting (lower-right side button)
- Missile, UFO, and Spinner targeting (Upper side button)
- Starting the game (Upper side button)
- Controller 2 handles the following:
- Teleportation (Key 3)
- Large asteroid targeting (lower-right side button)
- Both Controllers
- Random firing for RNG manipulation (lower-right side button)
- Random teleporting for RNG manipulation (Key 3)
- Teleporting to get within range of targets (Key 3)
- Random disc inputs for RNG manipulation
How does the bot work at a basic level?
- If there are no targets spawned, move to the screen center
- If there are targets spawned, move the gun left/right until it can target something
- Shoot a laser if it is anticipated to intercept a target's current trajectory
- Shoot two lasers simultaneously at a big rock to also get the small rocks it may split into
- Move on to the next target if a laser is already on its way to intercepting the current one
- Target UFOs with highest priority, then small spinners, then missiles, then big spinners, then big rocks, then small rocks (i.e., highest to lowest score potential)
- If the bot needs to decide between two targets of the same type, move towards the one with the least distance to travel before interception
- If a target is uninterceptable before hitting the ground, teleport until it can be shot at
- If a target is uninterceptable before despawning at the left or right screen margin, ignore it only if going for it would hinder progress.
- If a hazard comes within a certain rectangle of the player position, press the teleport key
How the hell did I get this to be so good??
OK, so now knowing what the bot's basic protocols are, it's probably easy to see all of that simply isn't enough to make the bot good, and obvious inaccuracies would be made all over the place if it wasn't for one little magic trick I used. Basically, every time the bot does something considered suboptimal, the bot tries that part again and again and again until that situation is either bypassed or forced into an optimal outcome. In the final movie, all of these "suboptimal situations" are cut out, giving the appearance of a much more robustly coded bot, and many insane superhuman moments. But now you know my secret ;) Here are the specifics of that:
- The script only works in TAStudio mode now, which allows for greater ability to seek back and retry sections
- Only one state (or branch when working in TAStudio) is ever saved and loaded now, tracking the best progress made thus far (i.e., highest score in lowest amount of time)
- Each time a suboptimal situation is encountered (i.e., one that does not keep up with the predetermined benchmarks), retry that section according to the following scheme:
- Start out by seeking back 10 frames and retrying the section 32 times from there.
- For each retry, do 1 of 12 predetermined actions at random every frame for ten frames to make the bot try something different and see if it can escape the suboptimal situation
- If unsuccessful after 32 attempts, seek back an additional frame and retry the section another 32 times from there.
- Keep repeating this process until you've seeked back a total of 130 frames.
- If the bot still has not broken free from the suboptimal situation at this point, load the best progress branch, seek back a random number between 30 and 120 frames, and try the entire process again from there.
- This process will repeat until the suboptimal situation is avoided. Eventually, it will work almost every time.
- Sometimes though, I had to manually intervene and put the seekback point greater than 120 frames in the past, which was only required if the benchmark for that current segment was a little too stringent and/or the bot found its way into a remarkably suboptimal situation.
Improved Benchmarking
While the above was certainly an improved scheme over the previous submission, the real key improvement was how we define a "suboptimal situation". Instead of checking progress at 5 key scores and loading a savestate if the desired time is not met, this time we continuously monitor the bot's progress, seeking back in TAStudio at ANY point it is not on track to retry that segment. We do this by assigning a desired time to meet for all 20 level transitions, then linearly interpolating between each to derive a continuous benchmarking scheme.
The table below outlines the benchmarking scheme used in this submission. The "Benchmark" column is the time in minutes we want the bot to reach the corresponding score by, and the "Level Time" is the maximum number of minutes the bot is to spend in the previous level.
| Level | Score | Benchmark | Level Time |
|---|---|---|---|
| 1 | 0 | 0.053 | 0.053 |
| 2 | 1000 | 0.250 | 0.197 |
| 3 | 2000 | 0.350 | 0.100 |
| 4 | 5000 | 0.620 | 0.270 |
| 5 | 7000 | 0.720 | 0.100 |
| 6 | 10,000 | 0.870 | 0.150 |
| 7 | 12,000 | 0.970 | 0.100 |
| 8 | 15,000 | 1.120 | 0.150 |
| 9 | 20,000 | 1.320 | 0.200 |
| 10 | 30,000 | 1.620 | 0.300 |
| 11 | 40,000 | 1.920 | 0.300 |
| 12 | 50,000 | 2.220 | 0.300 |
| 13 | 75,000 | 2.725 | 0.505 |
| 14 | 100,000 | 3.230 | 0.505 |
| 15 | 150,000 | 4.070 | 0.840 |
| 16 | 200,000 | 4.910 | 0.840 |
| 17 | 300,000 | 6.590 | 1.680 |
| 18 | 500,000 | 9.600 | 3.010 |
| 19 | 750,000 | 12.50 | 2.900 |
| 20 | 1,000,000 | 15.00 | 2.500 |
| 20 | 32,767,995 | 360.0 | 345.0 |
A consequence of this continuous benchmarking scheme is that we are retrying segments constantly to stay on the strict paces assigned. As explained earlier, the script randomly selects from 1 of 12 predetermined input combinations each frame for 5 frames total when retrying a segment. With these 12 predetermined input combinations, there is now a 50% chance of registering a teleportation input on either controller every frame, which is why the bot appears to abuse the teleportation feature to such an insane degree in the final run—it is simply an emergent property of having to retry so many segments, and no doubt a lot of optimal solutions were found through teleportation abuse. Here is a breakdown of the 12 input combinations:
| Type | Controller 1 | Controller 2 |
|---|---|---|
| 1 | Teleport | Left |
| 2 | Teleport | Left + Shoot |
| 3 | Teleport | Right |
| 4 | Teleport | Right + Shoot |
| 5 | Teleport | Shoot |
| 6 | Teleport | Teleport |
| 7 | Left | Teleport |
| 8 | Right | Teleport |
| 9 | Left + Shoot | Teleport |
| 10 | Right + Shoot | Teleport |
| 11 | Shoot | Teleport |
| 12 | Shoot | Shoot |
(Update 3/21/2026) This bot discovered and frequently abuses a glitch I was previously unaware of... The effect of the glitch is sometimes targets will immediately explode upon spawning, and the player will receive points for the explosion (so it is not due to a missile spawning on top of the target, which would award no points to the player). My theory is this: after a target is destroyed, its final x and y position is saved in RAM until another target spawns in. When a new target spawns in that object slot, the x and y position are not updated immediately. This would mean that if a player's shot or an explosion sprite overlaps with the position of the old target on the same frame the new target spawns in, the new target would be destroyed immediately. I have no plans to investigate this theory further or to what extent this glitch could truly be abused. All I know is that this would certainly open up new opportunities into destroying targets very early.
Other Improved Criteria for Retrying Segments
UFO projectiles: Whenever UFO projectiles are spawned in, it means there are less object slots available for a target worth actual points to spawn in, and also probably means we could shoot down the UFO quicker. Therefore, this script starts retrying that segment whenever there are two or more UFO projectiles on screen at once.
Stuff touching the ground: As the score table shows, a rock touching the ground can reduce your score by up to 60 points. Allowing this to happen is clearly a hindrance to progress even though it is not as bad as, say, a death. So if a rock touches the ground, we should definitely retry that segment. But why stop there? What if a missile touches the ground? Having a missile touch the ground after a full second of preventing another object from spawning in, and not getting any points for it, is clearly yet another setback to progress, though even slighter than the rock example. Therefore, segments are retried whenever ANY object touches the ground; although I do sometimes allow the bot to forgo this restriction to force progress, but only under special extenuating circumstances.
The Maximum Score
When the maximum score of 32,767,995 points is surpassed, the score underflows to the smallest possible score of -32,768,000 points, resetting the difficulty, speed, and scoring multiple back to level 1. When the score rollover occurs in this TAS, the bot hits a small then large spinner at 32,767,830 points, instantly underflowing the score to -32,768,350 points, thus missing the maximum score target! But don't worry, after input has ended, we incur 2 deaths, miss 12 small rocks, and miss 7 big rocks for a loss of 355 points. Only now is the peak score of 32,767,995 registered for a moment, officially satisfying the maximum score criteria.
nymx: Claiming for judging.
nymx: This is a blowout over the previous TAS. What an impressive improvement! You can clearly see the difference over the previous as you don't even miss and the shots are multiple times faster. Excellent work on this and sure do love seeing more BOTed work.
despoa: Processing...
nymx: Replacing with a full length version.