frankkarsten

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