Track first and last row and column at which each game object appears, and use this to narrow rule-checking loop bounds.
Detect loops through again turns for automated play.
Return backups of closed nodes into a pool from which new nodes and reopened closed nodes get their backup storage if possible. Speed is about the same, but maybe it will be less crashy.
Go back to expanding all of a node's actions at once, to simplify the code and get more nodes into the closed set to reduce memory usage. Also remove empty inner-sets from the open and closed sets, which increases churn but should make those data structures behave a little better; and avoid needlessly adding hash entries to those sets during searches. Expanding whole nodes at once means Atlas Shrank now finds results at about half speed, but search for Robot Arm is nearly 10 times faster, so it is a win overall.
Make hashKey2 an actually correct Jenkins hash function, and prevent needlessly adding hash entries to those sets during searches.