Solving a gamebook : revenge of the Haskell solver

This post is part of the "Gamebook solver" serie:

Last time I rewrote the Haskell solver in Rust, and it was so much faster that it became possible to solve the second book from zero. That was very satisfying, but I had misgivings.

First, the Haskell version was better tested, and supported more features (such as the hunting discipline). Secondly, for Haskell I used a standard memoizer, whereas in Rust I wrote my own memoization system. I decided to do the same with the Haskell version, and it turned out it runs sufficiently fast to be usable! It is also much more confortable to add features in such a high level language.

I also tweaked the book description a bit to remove graph loops (unfortunately, this is currently a manual process), and introduced a topological sort approach to state exploration that prevents exploration loops.

To cut things short, here are updated numbers, that have been checked more toroughly than in the previous post, and should be much more accurate. In particular, a lot of bugs have been found in the chapters descriptions, and the combat escape mechanism did not work. This means that win probabilities are now much better, as fights can actually be avoided!

Starting conditions

In the following examples, the starting conditions are:

  • a short sword (yes, even when having other weapon disciplines)
  • the Seal of Hammerdal
  • a shield
  • 15 gold coins

In the previous instalments, I chose the pair of meals over the shield, but the shield is in fact the most effective item to choose at the beginning of the story. All other items would be quickly lost, but for some reason the shield can be kept.

It would be better to choose a weapon that matches selected weapon specialties, but this will be for another episode :)

Number of states

First of all, what is interesting is how many game states need to be traversed in order to find the solution, depending on the starting disciplines. The time it takes to compute a solution is generally proportional to the amount of states that must be searched. Here is a quick chart that should be illustrative:

Tracking
Spear
ShortSword
Healing
MindBlast
MindShield
AnimalKinship
Camouflage
MindOverMatter
SixthSense
Hunting
Tracking29855572625361271171029024172985249309985431506963204877319866931981459314661
Spear262536152363165819251506042752308675323102551909055125946073541617111212612684
ShortSword271171058192515297698512324152936135420292556185855671585860453594291013092512
Healing290241750604275123241551433555108995705421581223858618805862985591776114926638
MindBlast298524952308675293613551089956543955845481595792059836696102573617476615263336
MindShield309985453231025420292570542158454815847823614238661888756303044645637715507739
AnimalKinship315069655190905561858581223859579206142386595446063008636405337643811915776351
Camouflage320487755125945567158586188059836696188875630086359860116460004653018916144572
MindOverMatter319866960735415860453586298561025736303044640533764600046105302617756615883371
SixthSense319814561711125942910591776161747666456377643811965301896177566617756715826247
Hunting931466112612684130925121492663815263336155077391577635116144572158833711582624715129259

It turns out hunting makes the number of states explode. I believe it is because it allows you to keep more meals, creating more decisions when the character does not have to hunt.

On the other hand, tracking does reduce the amount of states generated. The reason is that at chapter 231, you get to choose between two huge branches, but tracking forces you into a given path.

Success probability

Strong character

A strong character starts with maxed out endurance and combat skill (respectively 29 and 19).

AnimalKinship
MindShield
Hunting
Spear
Healing
MindBlast
ShortSword
Camouflage
MindOverMatter
SixthSense
Tracking
AnimalKinship89.29%89.29%89.55%89.49%89.56%89.54%89.54%89.29%89.29%84.83%89.29%
MindShield89.29%50.24%78.73%67.31%64.28%52.69%52.20%50.24%50.24%47.96%49.34%
Hunting89.55%78.73%42.43%63.95%55.95%46.79%44.86%42.43%42.43%40.31%42.43%
Spear89.49%67.31%63.95%29.24%43.05%31.47%31.37%29.24%29.24%27.89%28.51%
Healing89.56%64.28%55.95%43.05%24.54%24.54%24.34%24.54%24.54%23.52%24.18%
MindBlast89.54%52.69%46.79%31.47%24.54%17.26%17.91%17.26%17.26%16.42%15.62%
ShortSword89.54%52.20%44.86%31.37%24.34%17.91%16.79%16.79%16.79%16.00%15.62%
Camouflage89.29%50.24%42.43%29.24%24.54%17.26%16.79%15.89%15.89%15.11%14.10%
MindOverMatter89.29%50.24%42.43%29.24%24.54%17.26%16.79%15.89%15.89%15.11%14.10%
SixthSense84.83%47.96%40.31%27.89%23.52%16.42%16.00%15.11%15.11%15.11%13.40%
Tracking89.29%49.34%42.43%28.51%24.18%15.62%15.62%14.10%14.10%13.40%14.10%

Average character

A strong character starts with everage endurance and combat skill (respectively 25 and 15).

AnimalKinship
MindShield
Hunting
Spear
Healing
MindBlast
ShortSword
Camouflage
MindOverMatter
Tracking
SixthSense
AnimalKinship84.92%84.92%85.38%84.78%85.22%87.09%86.94%84.92%84.92%84.53%80.73%
MindShield84.92%6.91%22.92%16.40%13.77%7.42%7.40%6.91%6.91%6.91%6.56%
Hunting85.38%22.92%3.96%11.10%7.82%4.25%4.24%3.96%3.96%3.96%3.76%
Spear84.78%16.40%11.10%2.41%5.28%2.61%2.56%2.41%2.41%2.29%2.29%
Healing85.22%13.77%7.82%5.28%1.66%1.70%1.70%1.66%1.66%1.66%1.57%
MindBlast87.09%7.42%4.25%2.61%1.70%0.73%0.85%0.73%0.73%0.73%0.69%
ShortSword86.94%7.40%4.24%2.56%1.70%0.85%0.73%0.73%0.73%0.73%0.69%
Camouflage84.92%6.91%3.96%2.41%1.66%0.73%0.73%0.67%0.67%0.67%0.64%
MindOverMatter84.92%6.91%3.96%2.41%1.66%0.73%0.73%0.67%0.67%0.67%0.64%
Tracking84.53%6.91%3.96%2.29%1.66%0.73%0.73%0.67%0.67%0.67%0.64%
SixthSense80.73%6.56%3.76%2.29%1.57%0.69%0.69%0.64%0.64%0.64%0.64%

Effect of skill and endurance on outcome

This table displays the effect of starting skill and endurance on the winning probability, for the animal kinship and mindblast choice of disciplines.

10
11
12
13
14
15
16
17
18
19
2068.63%71.42%77.10%78.11%80.31%81.80%85.20%85.65%86.88%87.04%
2170.60%73.48%79.06%80.04%82.11%83.46%86.36%86.70%87.69%87.82%
2272.35%75.27%80.69%81.61%83.53%84.73%87.14%87.39%88.26%88.34%
2373.96%76.87%82.09%82.93%84.67%85.72%87.69%87.87%88.67%88.72%
2475.42%78.26%83.25%84.01%85.59%86.47%88.10%88.21%88.97%89.01%
2576.80%79.53%84.25%84.92%86.35%87.09%88.42%88.49%89.18%89.21%
2678.10%80.69%85.10%85.68%86.99%87.59%88.69%88.74%89.34%89.35%
2779.33%81.76%85.81%86.31%87.53%88.01%88.92%88.96%89.43%89.45%
2880.46%82.71%86.40%86.82%87.99%88.36%89.12%89.14%89.49%89.50%
2981.51%83.57%86.90%87.25%88.37%88.66%89.27%89.29%89.53%89.54%

Discussion

As always, fair bit of warning : all those statistics might be completely wrong. They sure were previously, and while I reviewed the chapter descriptions toroughly, there still might be mistakes, especially in the decision heuristics.

As was well known, the animal kinship discipline is almost obligatory if one wishes to survive this book. If you do not have this discipline, you are forced through a route that involves acquiring the magic spear, which is a very dangerous fight. A descent substitute is the hunting and mindshield combination, but only for strong characters.

One huge surprise was that some disciplines decreases your probability of winning.

  • The first is sixth sense. This discipline is useful for a human, as it gives hints throughout the adventure, but not to a solver that already knowns the optimal path. Its drawback is observed in chapter 254 where it forces you thought a path that leads to chapter 183, where you have a 10% chance of instadeath.

  • The other low tier discipline is tracking, which is used in four chapters in order to give you a hint about where you should go next, and only opens a new path in chapter 334, but this chapter is not on the optimal solution path anyway. As previously discussed, it also forces you into a bad path, at chapter 231.

Chapter 200, and the choice of assassin

In chapter 200, you get to choose who you will attack. As noted in other walkthough, attacking Halvorc the merchant seems preferable as it is the easier fight. However, it also has a weak reward, so I wondered if it might make sense, sometimes, to have a harder fight in exchange for a better reward.

It turns out that this is indeed that case, but in a completely counter-intuitive way. It is sometimes better to attack the priest Parsion. I did a tiny bit of correlation, and it turns out that it is inversely correlated to the amount of meals one have (except for characters with the hunting discipline), and to the probability of actually winning that fight!

I suppose that the stronger characters do not need that reward to survive the rest of the adventure, which makes the harder fight only interesting for weaker characters.

For those interested, here are the raw correlation results between all tracked variables for average character with mindblast and animal kinship. Win chances and expected endurance are computed for the priest fight.

                    chapter  allmeals  winchance  expectedendurance  Laumspur      Meal
chapter            1.000000 -0.226461  -0.413484          -0.259957 -0.195328 -0.141111
allmeals          -0.226461  1.000000  -0.014969          -0.059701  0.640212  0.797655
winchance         -0.413484 -0.014969   1.000000           0.858334 -0.139976  0.090432
expectedendurance -0.259957 -0.059701   0.858334           1.000000 -0.183343  0.066315
Laumspur          -0.195328  0.640212  -0.139976          -0.183343  1.000000  0.047357
Meal              -0.141111  0.797655   0.090432           0.066315  0.047357  1.000000

Conclusion

I am much more confident in the current version numbers, but I will need to audit the choice heuristics to make sure nothing is wrong. The current software has a solution explorer, that let you run through the adventure and tells you your probability of winning at each choice, but it is still very crude. A browser version would be much nicer, but I can't really reuse all the Haskell machinery, as this project is GHC 9+ and GHCJs doesn't seem to be supported for this version :(


  • 2021-12-07 : fixed a bug in the way combat escapes were handled. Should work properly now!