Submission #6125: HappyLee's NES Super Mario Bros. "warpless" in 19:26.35

(Link to video)
Nintendo Entertainment System
warpless
FCEUX 2.2.1
70096
60.0988138974405
7416
Unknown
Super Mario Bros. (JU) [!].nes
Submitted by HappyLee on 10/10/2018 1:55:46 PM
Submission Comments
HappyLee: Definitely not intended for publication because it's not as fast as me and Mars608's latest SMB warpless TAS, but pardon me for submitting it here, as it may make an interesting submission (for some).
This is a full-length TAS done entirely by a bot, an Lua script that I call it SMBbot. It's not an artificial intelligence, but what I call an "artificial idiot", as it's really dumb.
It doesn't read map or level information, doesn't evolve, doesn't have much memory. It basically just jumps randomly, and loads savestates after dying or bumping into a wall.
As dumb as it is, but it's the first bot ever to complete SMB, and in speedrun style! Only 7416 retries, 4:49 in real-time computing, it completes SMB warpless in 19:26.35. Not exactly as fast as best human speedrunners, but surely more stable and fast in average.

Idea

One day I was watching LuigI/O (a neural network playing SMB), and I thought, "this isn't intelligent", because after tens of thousands times of improving, LuigI/O still doesn't seem to know what it's doing or basic principles of the game. So I decided to build a smarter AI manually, and see how well it can play the game.
At first, my plan was to let the bot calculate map and analyze possible routes, and calculate jumping time and strength. It's rather complicated, so I wrote random jumping code initially and gave it a go. To my surprise, the bot finished 1-1 easily, and completed the whole World 1 after many attempts at 1-2 pipe jump. And I thought, "this could work", so I continued developing the bot and kept it jumping randomly instead of reading the map.
The basic function is to save state when Mario lands. Each savestate has 10 chances. Mario will do jump randomly in the range between the savestate and the frame Mario will die or fall. This basic function alone is enough to complete World 1, but will be stopped by the high wall in 2-1, so I added some features:
  • Backward jump acceleration: by playing a series of inputs at the beginning, just for fun. Used for every stage start.
  • Wall-allow: if Mario bumps into the same wall over 99 times and still can't jump over it, Mario would be allowed to touch that wall. This allows Mario to jump over the high wall in 2-1 (by walljump or Springboard), and will be used again in places like 8-2.
  • Swimming mode: two swimming probabilities (frequent and not frequent); Mario presses down when X speed > 16; savestate is made every 2 seconds. This allows Mario to complete water stages.
  • Death state: if Mario dies in similar ways too many times from a savestate point, that point might become a death state, which Mario land on the same spot again and then retry. This helps reduce retry count in places like 1-3 where Mario easily falls on the same spot and die meaninglessly too many times.
  • Retry 1/3 of the times when Mario falls. This helps prevent Mario from falling too much, and increase chances like passing 4-4 first maze.
  • Maze detection: if Mario walks through a maze check point and triggered a loop, it would trigger retry. If Mario fails to pass the check point correctly over 20 times, it starts over from the stable state (usually the beginning of the stage, but in maze levels, the last correct check point).
  • Wall-free mode: if Mario bumps into walls over 800 times (would be reduced when screen stops scrolling or Mario fails to solve a maze) and still fails to make progress, Mario would be allowed to touch any wall. There are one or two timers that will judge how Mario is doing after hitting the wall, to prevent meaningless wall bumps. If it's regular maze stage (like 4-4), Mario has 2/3 chance to walk towards left. Mario also has higher chance to do walljumps. Wall-free mode opens till Mario makes real progress. This allows Mario to solve the maze in 4-4 and 8-4, and may become useful in other places, too.
  • Every 1000 unsuccessful deaths brings Mario to the stable state (usually the beginning of the stage). Too many wall bumps from the right side of the screen also, to prevent Mario from being stuck in Warp Zone in 4-2 and 1-2 (sometimes happens).
  • First-frame jump chance increases as Mario's death grows without real progress. This helps to solve hard stages with hard jumps like 4-3.
  • If Mario dies from enemies over 500 times, it starts over from the stable state with a random chance of pressing left for 0 to 2 seconds. This helps if Mario is stuck with a bad Firebar in 5-4 or 6-4.
  • Number of allowed attempts from a savestate (originally 10) increases if Mario dies too much before making to the savestate. This helps to prevent Mario from losing valuable progress.
  • Pipe maze detection: if Mario's in a maze with pipe exits information, a part of pipe exit information is stored to prevent loop. If Mario's in the pipe maze with a non-loop pipe exit information, down is pressed every time Mario lands and sometimes during Mario running. This allows Mario to enter pipes to solve 8-4 maze.
Source code of the script: https://pastebin.com/vNHjw7Ca
I did this experiment of running it 20 times, and here are the results:
AttemptTAS timeRetryReal-timeNote
#0119:28.71111805:48
#0219:29.91119466:42
#0319:26.35 (2nd)7416 (1st)4:49 (1st)
#0419:30.958703 (3rd)5:14 (2nd)Desynced at 5-3 first lift
#0519:33.62111466:52
#0619:28.09110076:52
#0719:35.1112026:45
#0819:28.8689435:30
#0919:32.2112876:26
#1019:30.948572 (2nd)5:20
#1119:29.76115006:21
#1219:34.58118846:57Desynced in 8-4 water stage
#1319:32.09140977:48
#1419:35.18 (last)115307:32
#1519:25.25 (1st)112536:48Desynced in 8-4 water stage
#1619:30.9794345:17 (3rd)
#1719:30.51114797:06
#1819:30.1114670 (last)7:43
#1919:29.42145078:37 (last)
#2019:27.23 (3rd)117017:26
Average19:30.4911172.96:36
Unfortunately, the best TAS time attempt (#15) desynced in 8-4 water stage, probably due to a bug in my script or a bug of FCEUX. It happens so rarely that I can't detect it or fix it. Since the best attempt is not usable, I have to choose the second best attampt (#03).
Such bug won't happen if I run the bot while recording the movie. In order to save computing time (loading savestates in FCEUX while recording a movie can be quite slow), I used some arrays to store input, and sort them into .fm2 input format after meeting the Princess. Would be best if I can fix this bug so it can generate movies without desync and as fast as possible.
To see the bot working in normal speed (without fast-forward): https://youtu.be/9Tlif_XU4Jg

Conclusion

I think the biggest contribution this project has made is to prove that this game can be solved by a dumb random jumping bot that doesn't know where it is or what it's doing.
Also, since real-time SMB speedrunners have become so good, and generating a decent speedrun by a bot has become so easy, SMB TASers should work hard to bring entertainment to a new level, more like a superplay and less like RTA speedruns or bot playing, which exactly was my idea in the discussion of the the latest SMB warpless TAS.

"Definitely not intended for publication"
Masterjun: Okay. Cancelled for not being a serious submission.
Last Edited by adelikat on 10/28/2023 8:15 PM
Page History Latest diff List referrers