To imply I've just now begun work would be a bit of a lie. This project has had several incarnations over the last few months, but they all had their own problems so I've started from scratch again and taking what I've learned to make something pretty cool.
My goals here are to keep up posts about it on a semi-regular basis, even if the posts are on the short side, and also provide snippets of code that may be useful to people trying to do similar things.
Where do I start.
As mentioned I had worked on a few scripts before that sort of navigate the world but not in a particularly smart way... so I'm going to start by talking about them and why they didn't work. That seems as good a place as any.
"Wadjet" was my most successful script. It moved around the world in a winding, zig-zag pattern. Its logic was as follows:
- Advance towards the direction of progress, moving up and to the left
- Switch, advancing up and to the right
- Repeat 1-2 a certain number of times
- Retreat away from the direction of progress, moving down and to the left
- Switch, retreat down and to the right
- Repeat 4-5 a fewer number of times than the advance cycle
- Randomly insert a few A, B, and start commands for performing actions
- If an event flag is set (i.e. picking up oak's parcel, getting a badge), adjust the direction of progress
All movements were decided randomly and then filtered between the two allowed directions. I ran a few simulations at around 30-60x speed and the best Wadjet was able to do was beat Brock in around 56 hours, head east to Route 3, and then get stuck at the base of Mt. Moon. I brainstormed a few stupid ideas to try and make the script get into Mt. Moon, but at the end of the day there is only so much this method would be able to accomplish- the upper bound of which would probably be getting to Vermilion City on a really good day. Beyond that point, actions such as "use cut" start being involved, which would be nearly impossible for the script to trigger.
The other problem with this script is it had absolutely no idea if it was in battle or not, causing a lot of input inefficiencies, Moving up and to the left causes attacks to be selected, and down and to the right can end up running from wild encounters, but it was entirely up to chance.
Towards the end of this script's development I started reading from the game's memory to make decisions, such as flipping the direction of progress to east after getting the boulder badge, and I realized how powerful being able to read from memory can be when it comes to making decisions.
Where am I going?
Introducing project "Antidote". Where Wadjet was mostly blind to what is actually going on in the game, only aware of special interrupts, Antidote will always be on a specific mission and have better navigation technology. Here's the flow I'm anticipating:
- Determine the current goal (get a badge, collect an item, fight a specific trainer, etc)
- Locate the map on which that goal can be satisfied, backtracking if it gets lost
- Remain in that map until that goal is satisfied
- Should the player enter a battle, defeat the enemy
Antidote's goals will contain the following information:
- What kind of goal is this? (fight this trainer, pick up this item, get to a map, get to a tile, use cut, catch a pokemon... etc.)
- What map can this be satisfied on?
- Is there a fail condition for this goal? (i.e. leaving the map during a strength puzzle, running out of pokeballs, etc)
- If this goal fails, what goal do I start from?
I will continue to refine and trim out goals as Antidote's pathing and other technologies is upgraded, and will be aiming to be able to conquer the elite four with as few "goals" as possible. (I could tell it every turn it needs to make, but that stops being an AI and starts being a set of instructions)
By allowing these gradual improvements, I will be able to better iterate on different sections of Antidote's AI while still being able to test progress in the game.
That's all for now. Hoping to post updates and code snippets in the future!