One comment on the Expected Gain. As far as I see it, the winning outcomes are not mutually exclusive and the Expected Gain calculation assumes they are.
Therefore I think an adjustment could be made by defining a pay strategy for cases when more than one winning combination occurs --for example by assigning the highest prize among all realized winning outcomes. This of course requires the calculation of the probabilities of all possible winning-outcome combinations (such as all 1's).
It seems to me that the current calculation of the Expected Gain follows a pay strategy that assigns $0 to boards where multiple winning outcomes occur, which does not really make sense to the player. The good news is that, under the current probability layout, multiple winning outcomes have very low probability so this adjustment should not affect the Expected Gain value by much.

On the other hand, the simulation step might already be taking the multiple winning-outcome situation into account. In fact, the calculation of the "win" amount does not involve calculation of probabilities, but just counting the number of winning outcomes in a particular realization. The question I have here is: how is the TestWinner() function taking into account multiple winning outcomes to compute the "win" amount returned by the function? Is it giving the win amount that corresponds to the highest-prize winning outcome or is it summing the win amount of all realized winning-outcomes?

Conclusion: if I am not making any incorrect reasoning, the conclusion is that the theoretical and the practical approaches described above are not in line, and this will cause a divergence between the two expected gain values that is not only due to chance.