R.C. Pro-Am II is an extremely fun 4-player racing game. Besides its fast-paced racing action, it contains upgrade mechanics which allows players to improve their remote-controlled cars throughout the game's 36 race circuit.
This movie was produced in two parts: (1) the first 24 races and the entire upgrade optimization were solved by FatRightKnight back in 2018 and (2) the rest of the last 12 races were solved now by eien86 using a routing bot and the help of ktwo
Boot. All the frames from power-up until the start of the first race.
Race. A race starts as soon as the Traffic Light Timer's value becomes 64, indicating a green light. A race ends when the Race Status flag changes from 2 to 1.
Bonus Challenges. After races 8, 16, 24 and 30 there is a bonus challenge where the player needs to tap L/R repeatedly. The same rules of timing as a normal race apply here.
Transition. A transition starts as soon as a race ends. This segment includes the results screen and all the shopping made in between races.
Movie End. This movie's end time is taken at the frame of the last input.
Game End. The actual moment when the last race ends. An alternative movie is provided that optimizes this goal instead.
An in-depth explanation of the game mechanics by ktwo can be found here.
Upgrade strategy
Botting
Botting this game required determining the RAM map of all the relevant values and obtaining a more or less in-depth understanding of the game mechanics. Thankfully, ktwo helped with both aspects.
The reward function for the bot was pretty easy to establish, since the game already provides a faithful progress indicator. The only addition to it was the reward for grabbing boosts -- the bot would ignore a boost if it meant deviating from the immediate fastest route, so it required an extra incentive to go grab them.
Another scripting requirement was the need to restrict places where the boosts could be used. Particularly in race 36, the player obtains 6 boosts. The optimal solution required using these in very precise locations. Using them in other parts of the track is also possible, but leads to a slower solution. Since the bot doesn't know this, it proceeds to burn them as soon as possible, so I had to explicitly limit this freedom.
Running the bot on this game provided a few additional challenges.
First, the movie by FatRatKnight used the FourScore adapter to enable him to play with P4. This allowed him to manipulate RNG, but complicated my life because QuickNES does not support it. In order to make it work, I had to modify the source of QuickNES to encode the FourScore inputs from the standard input produced by directly connected controllers.
Second, since FRK had worked on FCEUX, I had to resync his movie to BizHawk (NesHawk core). This still was not enough, since the bot only accepts QuickNES save states as a starting point. So I had to develop a 'transplant' tool, that copies all the relevant RAM/PPU memory regions for a Mapper07 game from a NesHawk savestate to a QuickNES savestate. Miraculously, this worked (except that I didn't care to copy the palette, so all colors were wacky during botting).
Third, I had to resync the bot's quickNES output back into the NesHawk movie. This was pretty easy because these emulators only seldom differ. The only case where they desync was when NesHawk interpreted some frames as lag, which QuickNES didn't.
Future Work
This movie is by no means perfect. Here are all the ways in which it could be improved in the future:
Refine Bot's exploration
Some aspects of the solutions provided by the bot gave us suspicion that were not really optimal. In particular, the bot sometimes hits itself against the wall, even when not evidently necessary. ktwo noticed this and could find some local refinements of the route by manual optimization. These inefficiencies must be polished in the next version of this movie.
Remove unnecessary inputs
The bot repeatedly presses L and R in parts of the track where only going straight is necessary. This is not necessarily an inefficiency, but could be simplified in the future. I believe this happened because, to reduce exploration space, I didn't take the decimal components of the position/speed into consideration, so without these presses, the bot could have interpreted that straight lines contained repeated states.
Apply the bot to the first 24 movies
The next obvious improvement is to apply the bot to all races, not just the last 12, as The bot showed it could find faster solutions than FRK's manual optimization for comparable races. This is not as simple, however, since in the first part of the game, the entire upgrade logic needs to be taken into account, which is not as simple, and was perhaps the biggest contribution of FRK's research.
Acknowledgements and Attributions
FatRatKnight: Author of the first 24 races and prime mover of this game's TAS effort
eien86: TASer, botter and author of the last 12 races
ktwo: Speedrunner, TASer, researcher and the reason why I ended up involved in this game. His constant review of my work, suggestion, and technical advice were instrumental to getting this TAS done. He has contributed to the technical discussion part of these submission notes.
PinoBatch and Fiskbit: NesDev Discord Server users, who helped me understand how the FourScore adapter worked.
Encoder Information
Suggested Thumbnails
Re-Record Count
The count from FatRatKnight's original 24 races should be used: 14962, plus the ones in this movie (653). The re-records from botting is not counted (otherwise, would contribute hundreds of billions)
Your bot never ceases to amaze me. I feel like it's getting to a point where it can figure out optimality in almost anything. I wish I understood how things worked haha. Yes vote for sure!
More impressive bot work, nice! The bot driven races do look a bit rough though, maybe the fact that you can just bounce off the cpu's to keep pace is effecting the search (ex 25:57 in the encode.) Still cool to see another type of game tackled by your bot. Maybe try puzzle games? I wonder what it could find on ex. Adventures of Lolo games.
As mentioned in the comments, I took part in the making of this TAS. Initially, I thought it would be a directly contributing part by working in tandem with eien86's bot Jaffar in races 25-36. In the end, all the inputs in races 1-24 are from FatRatKnight and all the inputs in 25-36 are from the bot. I'm therefore not listed as a co-author.
I speedran this game on console in 2018 and during that time had an active discussion in the forum thread with FatRatKnight. Most of what we know today of this game's mechanics is a direct result from that discussion (by far the most of the advancements were done by FatRatKnight). So while I focused on the real-time speedrun, FatRatKnight eventually TASed up to race 24. This was done through several iterations to hone the execution, the strats, test different upgrade options and use the latest findings.
I thought it was a pity that the last 12 races were never completed and put it on my own to-do list. The remaining races should normally be the easiest ones to complete, because the car was already fully upgraded at that point and races 25-36 re-use tracks from previous races.
However, before starting on race 25, I planned to TAS one or a few of the earlier races. This would allow me to compare with FatRatKnight's times to ensure I had the right understanding of the methods used to efficiently navigate corners etc. I started this a few times, but I had trouble matching FatRatKnight's solutions and didn't get deep enough into the logic behind how to take corners. If I couldn't match (to be more fair - not even come close to) the execution in the first races, it didn't feel right to continue from race 25.
In conclusion, the above was a somewhat convoluted way of saying that the route and execution in the first 24 races seem solid (and even very impressive) to me. While it has been some time since I was into the details of this game, I can't really think of anything that looked questionable or out of place when watching it played back in real-time.
When I started working with eien86 on improving Solar Jetman, I also mentioned R.C. Pro-Am II as a game that would be interesting to test the bot on. It took some convincing before eien86 decided to try it out though and I was of the understanding that this was new territory for the bot, so it was difficult to predict the results.
While I was busy manually TASing Solar Jetman, eien86 fed race after race to the bot. Before I took a break to look at the bot's solutions, several races were already done. My immediate reaction was that it looked impressively fast, but also a question mark regarding the constant twitched steering, even on straights. I was even able to demonstrate short sections where a few frames could be saved simply by driving in a straighter line. However, due to desynching issues, eien86 was hesitant to redo earlier races.
The question was then how the bot's execution and solutions compared to FatRatKnight's? Well, since a few of the races in the range 25-36 are directly comparable with earlier races, it was just a matter of comparing the completion times. In all four races that were possible to compare, the bot came out on top in terms of execution, was unparallelled to sniff out ways to reduce random lag and on shorter segments managed to pick up some non-obvious strats. However, it struggled when it came to nitro uses. Nitros are collected on the track and can be used at any time in the same race. It's understandable that a human has an advantage in this area over a bot that can't get the same overview of a track. The biggest mistakes were in R33, where the bot was too eager to use the nitros for short-sighted benefits, but was then penalized later on. It should be a lessons learned for the next iteration that the bot's nitro uses need to be more tightly supervised.
I'm very happy to see FatRatKnight's effort be part of a submission for this game. It's also exciting to see eien86's bot adapted to racing games. The bot solutions themselves are in my opinion clearly improvable, but they are at the same time clearly one notch above a very accomplished TASer's concerted efforts. So while a human would be able to provide a smoother a visually more pleasing playthrough of races 25-36, it would take a lot of effort to match the bot's completion times.
My recommendation is to accept this submission, but also that we keep reminding eien86 at regular intervals about his promise to give this game an updated TAS in the future. When work on that update begins, I'd be happy to contribute in whatever way I can to make the end result as good as possible.
Reading the description on the player choice and letter-based upgrades, while the CPU cheating in letters is true, that wasn't my primary reason for selecting P4.
The actual reason is that the letters ask for particular players. The letters on the track can ask for a particular slot, and each slot generates a random letter based on what some player doesn't have.
The slots are as follows:
(1) Based on Player 1
(2) Based on Player 2
(3) Based on Player 3
(4) Based on Player 4
(R) We read the race number, then select a player based on that
(?) We ask the RNG for a player number
Then it's a matter of figuring out what slots each race uses.
Race 1: (1)
Race 2: (?) (2) (R) (3) ... The Race letter picks P2
Race 4: (R) (4) (1) ... The Race letter picks P4
There are eight possible letters out of our PRO-AM II to get in the first four races. When I selected P4, I just wanted to abuse the letter selection at race 4 to guarantee the two generated letters are ones we didn't pick up, as the P4 slot and the Race slot both ask P4 for the letter. Which basically meant the only manipulation necessary at that specific race is to ensure I don't double up on the same letter, apart from I if my route didn't get any of that.
Race 6: (1) (2) (3) (R) (?) (?) ... The Race letter picks P2
Race 7: (4)
In the case of Race 6, while two letters pick the Random slot, they can't be independent of each other, as they're on the same slot. Which means those two letter boxes are tied together no matter what the RNG said. With only 7 letter pick-ups in these two races, the only way for the upgrade to happen at the end of 7 is for the Random slot to pick I, as that's the one letter you can double up on. On the randomness scale, I is bottom priority for letter generation RNG, so that was a bit of "fun" manipulating that, along with every other letter, when I was fresh from the first upgrade and the other CPUs didn't have a lot of cheated letters.
I will point out that, by picking P4, Race 6 could not generate the letter P. The Random boxes are already locked into the need for the I, and the other boxes all depend on the CPU players, who each cheated their own P by now. That left RO-AM II as whatever is left for me to pick up. Once at Race 7, as that letter was asking for P4, it was just a trivial 50% chance of generating the one letter I was missing, another advantage for picking P4. The other letter it could have generated is the I, which is the fallback case for when it couldn't generate any other letter.
So, for the most part, P4 was selected not on the CPU cheating their own letters (with P1 cheating at races 1 and 5), but on the maze of letter pick-ups the developers decided on.
Oh, and fix the link to the forum post under your tires explanation. You included the period in your tag.
As for other thoughts that aren't on the technical reasons why I chose P4 on RNG...
Well, I can't think of a lot to say already. I'm actually not all that good on encouraging descriptions anyway, I claim. It is interesting to note that the bot can beat me on the comparable races, so it's clearly doing something right. I'm curious if it can optimize my early races a little better, with particular constraints of what it must pick up. The bot appears to be pretty robust to have beaten me. ... Sorry, there really isn't a lot I can think of to say. Um, have a thumbs up in writing from me? Again, I claim not to be a particularly wonderful speaker of encouraging things, but just throw me at the technical details or explanations and you'll see what I write.
Thanks for the clarifications and corrections. The comments have been updated.
eien86 is probably better to explain the bot's features, but picking up loot along the way will add complexity for sure. But if I understand it correctly, it's entirely possible to tell the bot what to collect.
When I tried TASing it myself, I first made my own solution and then looked at yours. I couldn't really make out what it was in your method that made it faster though. Same with the bot's solutions compared with yours. It looks to me like it's more aggressive, bumping into the walls, while you're more smoothly drifting around the corners. I didn't deep-dive in a frame-by-frame analysis though, so I don't know if it's the bumping into walls or something else in the bot's solutions that make them fast. Your solutions are visually much more appealing and intuitively look faster (at least in my eyes). But the actual numbers have clearly been in favor of the bot in every comparison we made, except for when the nitro use became too complex. I know that eien86 also botted race 1 as a test before starting the actual TASing and the bot came out comfortably on top there as well.