I was not looking to write a full blown postmortem, since a lot has been mentioned already and my 3rd rank is too far from the top, so I doubt it has much if any relevance once they publish theirs. But anyway some asked, so here’s the gist.
- Draft phase
- Fixed number of turns.
- Learn first available spell unless the second spell is significantly better than the first.
- I was convinced draft should not be a distinct phase and be merged with the main game but failed to make it work.
- Spell score
- Determined by self-play for 50k games.
- Each game skips the draft phase by forcing the same spells to each player, with the exception of one different spell on each side selected by matchmaking, e.g. one random spell vs another one of similar ranking.
- Update the spell ranking according to game result.
- Tried to evaluate spell synergy, failed to give improvements.
- Main search
- Beam stack search. I don’t like vanilla beam search because it loses the completeness property.
- Use available recipes to give a value to each number of ingredients, as a heuristic to further guide the search.
- Nodes are pruned if the same key (inventory + potions brewed + spell learned) had been reached in a depth lower or equal.
- New nodes are also ‘manually’ pruned for more efficiency. A few examples:
- Learn before cast unless that cast allowed you to learn it (due to tax).
- Learn less taxed spells before the more taxed ones.
- Do not cast a spell after rest if it could have been cast before.
- Search opponent with same algorithm except 3x less time.
- Use opponent solution when searching for self to prohibit brewing any of their potions if they brew them faster.
- Perhaps the only CG game where better search is worse?
- Thanks to the random recipe drawn after a brew which has the property to mess up any plans and transform a lead or a win straight into a loss.
- Had to artificially limit the search depth to 15, any further decreased playing performance.
- Too much effort wasted on optimization as a result.
- Evaluation: Score, endgame reached, # of ingredients left according to tier, bonus for # of deliveries, bonus for faster brews.
- Endgame search
- During the main search, for each possible combination of potion brewed, keep the best path found to it. Also includes a path for maximizing score from ingredients.
- When main search is over, build a move tree for each player out of those paths.
- Perform simultaneous minimax on those trees with payoff matrix resolution to determine node value.
- Leaf node value is the end result win/draw/loss. If the game doesn’t complete, consider it as lost. Failed to find better values.
- If the root node value is good enough, override the search move with the minimax move.
- Contrary to game theory, I found using a mixed strategy is weaker in practice than a pure one.
- Works well for figuring out a game is won/lost and how up to 15 moves ahead.
- Too much effort wasted, the prediction is too often useless. The random recipe draw can mess everything up.
- Random thoughts
- I briefly tried training a NN to make some basic decisions but failed to converge anything meaningful, so gave up quickly.
- Random timeouts are a serious issue, there is no excuse if a language is not garbage collected.
- The game is fun at first but very frustrating and opaque to improve at beyond the obvious. Better/smarter planning is of little use with RNG possibly changing all optimal paths.
- Card draws are worse than fog of war, especially when that impactful. And I hate fog of war.
- Debugging with viewer is as painful as it’s ever been. Please consider simpler and alternate debug views again.
- Also please fix the scrolling, matching output with viewer should not be easier in a shared replay link.
- emil. was my smurf/alt
- I prefer playing anonymously these days, it’s much less stressful/pressure for me, and I can chat around without questions on my bot/performance.
- For disclosure, I have done so a few times in the past to mess around and give up soon after. I may keep doing so for the same reasons.
- This time was different when I unexpectedly ranked in the top early on and then decided to just play along until the last stretch.
- I used Rust to ‘hide’ better and also to internally put pressure on CG to keep parity between IDE and arena. They were made aware of it.
- The issue was raised months ago when they added Release mode only to arena, which very negatively affects local and batch testing, but was not addressed.
- If that failed, my plan was to switch to C++ later in the week.
- I apologize for the dead spot in legend, had no idea deleted accounts would not just disappear.
And obviously, many thanks to CG for organizing the contest, and the community for being so lively and fun during a challenge.