# What’s the optimal mix of Rat Colonies and Swamps?

Apr 15th, 2018
542
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
1. package rats;
2.
3. import java.util.Arrays.*;
4. import java.util.Random;
5.
6. public class Rats{
7.
8. //We use stochastic dynamic programming to find an optimal mulligan strategy for every deck
9.
10. public static void main(String[] args) {
11.
12. Deck deck=new Deck();
13. boolean[][][] KeepOpeningHand = new boolean[8][8][8];
14. int NumberOfSimulationsPerDeck=1000000;
15. double FastestTurn=50;
16. double KillTurn;
17.
18. for (int RatCount=20; RatCount<=50; RatCount++){
19. deck.SetDeck(RatCount,60-RatCount);
20. KeepOpeningHand=GiveOptimalMulliganStrategy(deck);
21. KillTurn=AverageKillTurnForRandomHand(deck,7,KeepOpeningHand,NumberOfSimulationsPerDeck);
22. System.out.println("With "+RatCount+" Rats and "+(60-RatCount)+" Swamps, you win in expectation on turn "+KillTurn);
23. }
24. }//end of main
25.
26. public static boolean[][][] GiveOptimalMulliganStrategy(Deck deck) {
27. boolean[][][] KeepOpeningHand = new boolean[8][8][8];
28. OpeningHand openinghand=new OpeningHand();
29. int NumberOfSimulationsPerOpeningHandSize=100000;
30. int OriginalNrRats=deck.NumberOfRats;
31. int OriginalNrLands=deck.NumberOfLands;
32. double CutOffTurn = AverageKillTurnForRandomHand(deck,1,KeepOpeningHand,NumberOfSimulationsPerOpeningHandSize);
33. for (int StartingCards=2; StartingCards<=7; StartingCards++){
34. for (int RatCount=0; RatCount<=StartingCards; RatCount++){
35. int LandCount=StartingCards-RatCount;
36. //We assume that RatCount<=OriginalNrRats and LandCount<=OriginalNrLands but that should always be the case for our decks
37. openinghand.SetHand(RatCount, LandCount);
38. deck.SetDeck(OriginalNrRats,OriginalNrLands);
39. double AvgKillTurn=AverageKillTurnForSpecificHand(deck,openinghand);
40. if (AvgKillTurn<=CutOffTurn) { KeepOpeningHand[StartingCards][RatCount][LandCount]=true;}
41. if (AvgKillTurn>CutOffTurn) { KeepOpeningHand[StartingCards][RatCount][LandCount]=false;}
42. }
43. deck.SetDeck(OriginalNrRats,OriginalNrLands);
44. if (StartingCards<7) {CutOffTurn=AverageKillTurnForRandomHand(deck,StartingCards,KeepOpeningHand,NumberOfSimulationsPerOpeningHandSize);}
45. }
46. return KeepOpeningHand;
47. }
48.
49. public static double AverageKillTurnForSpecificHand(Deck deck, OpeningHand openinghand){
50. int NumberOfIterations=100000;
51. Deck remainingdeck=new Deck();
52. double AverageKillTurn=0;
53. for (int IterationCounter=1; IterationCounter<=NumberOfIterations; IterationCounter++){
54. remainingdeck.SetDeck(deck.NumberOfRats-openinghand.NumberOfRats,deck.NumberOfLands-openinghand.NumberOfLands);
55. AverageKillTurn=AverageKillTurn+TurnKill(remainingdeck,openinghand);
56. }
57. return (AverageKillTurn/(NumberOfIterations+0.0));
58. }//end of AverageKillTurnForSpecificHand
59.
60. public static double AverageKillTurnForRandomHand(Deck deck, int StartingCards, boolean[][][] KeepOpeningHand, int NumberOfIterations){
61. Deck remainingdeck=new Deck();
62. double AverageKillTurn=0;
63. for (int IterationCounter=1; IterationCounter<=NumberOfIterations; IterationCounter++){
64. OpeningHand openinghand=GiveOpeningHandAfterMulls(deck, StartingCards, KeepOpeningHand);
65. remainingdeck.SetDeck(deck.NumberOfRats-openinghand.NumberOfRats,deck.NumberOfLands-openinghand.NumberOfLands);
66. AverageKillTurn=AverageKillTurn+TurnKill(remainingdeck,openinghand);
67. }
68. return AverageKillTurn/(NumberOfIterations+0.0);
69. }//end of AverageKillTurnForRandomHand
70.
71. static OpeningHand GiveOpeningHandAfterMulls (Deck deck, int StartingCards, boolean[][][] KeepOpeningHand) {
72. Deck remainingdeck=new Deck();
73. OpeningHand openinghand=new OpeningHand();
74. int TypeOfCardDrawn;
75. boolean KeepHand=false;
76.
77. for (int OpeningHandSize=7; OpeningHandSize>=1; OpeningHandSize--){
78. if (KeepHand==false && StartingCards>=OpeningHandSize){
79. openinghand.ResetHand();
80. remainingdeck.SetDeck(deck.NumberOfRats,deck.NumberOfLands);
81. for (int CardsDrawn=0; CardsDrawn<OpeningHandSize; CardsDrawn++){
82. TypeOfCardDrawn=remainingdeck.DrawCard();
83. if (TypeOfCardDrawn==1) {openinghand.NumberOfRats++;}
84. if (TypeOfCardDrawn==2) {openinghand.NumberOfLands++;}
85. }
86. KeepHand=true;
87. if (OpeningHandSize>1) {
88. if (KeepOpeningHand[OpeningHandSize][openinghand.NumberOfRats][openinghand.NumberOfLands]==false) {KeepHand=false;}
89. }
90. }
91. }
92.
93. return openinghand;
94. }//end of GiveOpeningHandAfterMulls
95.
96. static int TurnKill(Deck remainingdeck, OpeningHand openinghand) {
97.
98. int Turn=0;
99. int OppLife=20;
100. int ManaLeft;
101. int TypeOfCardDrawn;
102.
103. int RatsInPlay=0;
104. int NonSickRats=0;
105. int SwampsInPlay=0;
106. int TotalPower=0;
107.
108. int RatsInHand=openinghand.NumberOfRats;
109. int SwampsInHand=openinghand.NumberOfLands;
110.
111. do {
112.
113. if (Turn>1) {
114.
115. TypeOfCardDrawn=remainingdeck.DrawCard();
116. if (TypeOfCardDrawn==1) {RatsInHand++;}
117. if (TypeOfCardDrawn==2) {SwampsInHand++;}
118. }
119.
120. //Play a land
121. if (SwampsInHand>=1) {SwampsInPlay++; SwampsInHand--;}
122. ManaLeft=SwampsInPlay;
123. NonSickRats=RatsInPlay;
124.
125. //Play Rats
126. if (RatsInHand>=3 && ManaLeft>=6) {RatsInPlay=RatsInPlay+3; RatsInHand=RatsInHand-3; ManaLeft=ManaLeft-6;}
127. if (RatsInHand>=2 && ManaLeft>=4) {RatsInPlay=RatsInPlay+2; RatsInHand=RatsInHand-2; ManaLeft=ManaLeft-4;}
128. if (RatsInHand>=1 && ManaLeft>=2) {RatsInPlay=RatsInPlay+1; RatsInHand=RatsInHand-1; ManaLeft=ManaLeft-2;}
129.
130. //Attack
131. TotalPower=NonSickRats*(2+RatsInPlay-1);
132. OppLife=OppLife-TotalPower;
133.
134. Turn++;
135.
136. } while (OppLife>0 &&Turn<=50);
137.
138. return Turn;
139. }//end of TurnKill
140.
141. }//end of OptimalAggroGoldfishDeck
142.
143. class OpeningHand {
144. int NumberOfRats;
145. int NumberOfLands;
146.
147. void ResetHand(){
148. NumberOfRats=0;
149. NumberOfLands=0;
150. }
151.
152. void SetHand (int NrRats, int NrLands) {
153. NumberOfRats=NrRats;
154. NumberOfLands=NrLands;
155. }
156.
157. }//end of OpeningHand
158.
159. class Deck {
160. int NumberOfRats;
161. int NumberOfLands;
162.
163. void SetDeck (int NrRats, int NrLands) {
164. NumberOfRats=NrRats;
165. NumberOfLands=NrLands;
166. }
167.
168. int NrOfCards(){
169. return NumberOfRats+NumberOfLands;
170. }
171.
172. int DrawCard (){
173. Random generator = new Random();
174. int RandomIntegerBetweenOneAndDeckSize=generator.nextInt( this.NrOfCards() )+1;
175. int CardType=0;
176. if (RandomIntegerBetweenOneAndDeckSize<=NumberOfRats) {CardType=1; this.NumberOfRats--;}
177. if (RandomIntegerBetweenOneAndDeckSize>NumberOfRats) {CardType=2; this.NumberOfLands--;}
178. return CardType;
179. }
180.
181. }//end of Deck
RAW Paste Data