frankkarsten

Finding the best Hatebear deck

Jul 31st, 2018
339
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package hatebears;
  2.  
  3. import java.util.Random;
  4. import java.util.Arrays.*;
  5.  
  6. public class Hatebears {
  7.  
  8.     public static void main(String[] args) {
  9.        
  10.         Deck Hatedeck=new Deck();
  11.         //CardType 1 is a Leyline of Sanctity
  12.         //CardType 2 is a Nourishing Shoal
  13.         //CardType 3 is a Bassara Tower Archer
  14.         //CardType 4 is a Forest
  15.        
  16.         double BestWinProb=0;
  17.         for (int NrLeyline=10; NrLeyline<=20; NrLeyline++){
  18.             for (int NrShoal=15; NrShoal<=25; NrShoal++){
  19.                 for (int NrArcher=10; NrArcher<=20; NrArcher++){
  20.                     int NrForest=60-NrLeyline-NrShoal-NrArcher;
  21.                     if (NrForest>0){
  22.                         Hatedeck.SetDeck(NrLeyline,NrShoal,NrArcher,NrForest,0);
  23.                         double ProbabilityVsChancellor=ProbabilityForRandomHand(Hatedeck,7,100000,true);
  24.                         double ProbabilityVsRipple=ProbabilityForRandomHand(Hatedeck,7,100000,false);
  25.                         double Probability=0.5*ProbabilityVsChancellor+0.5*ProbabilityVsRipple;
  26.                         if (Probability>BestWinProb){
  27.                             System.out.print("A new best deck! For a deck with "+NrLeyline+" Leylines, "+NrShoal+" Shoals, "+NrArcher+" Archers, and "+NrForest+" Forests: win probability is ");
  28.                             System.out.println(Math.round(Probability*10000)/100.0+". Vs Chancellor: "+ProbabilityVsChancellor+". Vs Ripple: "+ProbabilityVsRipple);
  29.                             BestWinProb=Probability;
  30.                         }
  31.                     }
  32.                 }
  33.             }
  34.         }
  35.                
  36.     }//end of main
  37.  
  38.     public static double ProbabilityForRandomHand(Deck deck, int StartingCards, int NumberOfIterations, boolean PlayVsChancellor){
  39.         double NumberOfGamesWithfavorableOutcome=0;
  40.         double NumberOfGames=0;
  41.         Deck remainingdeck=new Deck();
  42.         for (int IterationCounter=1; IterationCounter<=NumberOfIterations; IterationCounter++){
  43.             remainingdeck.SetDeck(deck.NumberOfCardType1,deck.NumberOfCardType2,deck.NumberOfCardType3,deck.NumberOfCardType4,deck.NumberOfCardType5);
  44.             int Outcome=0;
  45.             if (!PlayVsChancellor) {Outcome=SimulateGameVsFlame(remainingdeck);}
  46.             if (PlayVsChancellor) {Outcome=SimulateGameVsChancellor(remainingdeck);}
  47.             if (Outcome==0) {NumberOfGamesWithfavorableOutcome++; NumberOfGames++;}
  48.             if (Outcome==1) {NumberOfGames++;}
  49.         }
  50.         return NumberOfGamesWithfavorableOutcome/(NumberOfGames+0.0);
  51.     }//end of AverageKillTurnForRandomHand
  52.    
  53.  
  54.     static int SimulateGameVsFlame(Deck HateDeck) {
  55.         int TypeOfCardDrawn=1;
  56.         int Outcome=1; //1 corresponds to a loss; 0 corresponds to a win
  57.         int NrShoal=0;
  58.         int NrArcher=0;
  59.         int NrForest=0;
  60.         int NrLeyline=0;
  61.         int ForestInPlay=0;
  62.         int ArcherInPlay=0;  
  63.         int HatePlayerLife=20;
  64.         for (int CardsDrawn=0; CardsDrawn<7; CardsDrawn++){
  65.             TypeOfCardDrawn=HateDeck.DrawCard();
  66.             if (TypeOfCardDrawn==1) {NrLeyline++;}
  67.             if (TypeOfCardDrawn==2) {NrShoal++;}
  68.             if (TypeOfCardDrawn==3) {NrArcher++;}
  69.             if (TypeOfCardDrawn==4) {NrForest++;}
  70.         }
  71.        
  72.         boolean WeHaveLeyline=false;
  73.         if (NrLeyline>=1) {WeHaveLeyline=true;}
  74.        
  75.         Random generator = new Random();
  76.         boolean OnThePlay=generator.nextBoolean(); //This refers to whether the Hate player is on the play or not
  77.        
  78.         Deck FlameDeck=new Deck();
  79.         FlameDeck.SetDeck(31,29,0,0,0);
  80.         int NrFlames=0;
  81.         int NrSSG=0;
  82.         int ApesInPlay=0;
  83.         int FlamePlayerLife=20;
  84.         //CardType 1 is a SSG
  85.         //CardType 2 is a SurgFlame
  86.         //CardType 3-5 are not used
  87.         for (int CardsDrawn=0; CardsDrawn<7; CardsDrawn++){
  88.             TypeOfCardDrawn=FlameDeck.DrawCard();
  89.             if (TypeOfCardDrawn==1) {NrSSG++;}
  90.             if (TypeOfCardDrawn==2) {NrFlames++;}
  91.         }
  92.        
  93.         boolean FlamePlayerWon=false;
  94.         boolean HatePlayerWon=false;
  95.        
  96.         if (WeHaveLeyline) {
  97.  
  98.             if (!OnThePlay) {
  99.                 for (int Turn=1; Turn<=53; Turn++){
  100.                     if (!FlamePlayerWon && !HatePlayerWon){
  101.                         //FlamePlayerTurn
  102.                         int NrTrades=Math.min(ApesInPlay, ArcherInPlay);
  103.                         ArcherInPlay=ArcherInPlay-NrTrades;
  104.                         ApesInPlay=ApesInPlay-NrTrades;
  105.                         HatePlayerLife=HatePlayerLife-2*ApesInPlay;
  106.                         if (HatePlayerLife<=0) {FlamePlayerWon=true;}
  107.                         if (Turn>1){
  108.                             TypeOfCardDrawn=FlameDeck.DrawCard();
  109.                             if (TypeOfCardDrawn==1) {NrSSG++;}
  110.                         }
  111.                         if (NrSSG>=4) {ApesInPlay++; NrSSG=NrSSG-4;}
  112.                         //HatePlayerTurn
  113.                         NrTrades=Math.min(ApesInPlay, ArcherInPlay);
  114.                         ArcherInPlay=ArcherInPlay-NrTrades;
  115.                         ApesInPlay=ApesInPlay-NrTrades;
  116.                         FlamePlayerLife=FlamePlayerLife-2*ArcherInPlay;
  117.                         if (FlamePlayerLife<=0) {HatePlayerWon=true;}
  118.                         TypeOfCardDrawn=HateDeck.DrawCard();
  119.                         if (TypeOfCardDrawn==2) {NrShoal++;}
  120.                         if (TypeOfCardDrawn==3) {NrArcher++;}
  121.                         if (TypeOfCardDrawn==4) {NrForest++;}
  122.                         if (NrForest>=1) {ForestInPlay++; NrForest--;}
  123.                         ArcherInPlay=ArcherInPlay+Math.min(ForestInPlay/2, NrArcher);
  124.                         NrArcher=NrArcher-Math.min(ForestInPlay/2, NrArcher);
  125.                         if (NrShoal>=2) {HatePlayerLife=HatePlayerLife+2; NrShoal=NrShoal-2;}
  126.                     }
  127.                 }
  128.                 if (HatePlayerWon) {Outcome=0;} else {Outcome=1;}
  129.                 //In case neither player's life total was reduced to 0 after all those turns (because everything traded) then the hate player, who was on the draw, loses to decking
  130.             }
  131.  
  132.             if (OnThePlay) {
  133.                 for (int Turn=1; Turn<=53; Turn++){
  134.                     if (!FlamePlayerWon && !HatePlayerWon){
  135.                         //HatePlayerTurn
  136.                         int NrTrades=Math.min(ApesInPlay, ArcherInPlay);
  137.                         ArcherInPlay=ArcherInPlay-NrTrades;
  138.                         ApesInPlay=ApesInPlay-NrTrades;
  139.                         FlamePlayerLife=FlamePlayerLife-2*ArcherInPlay;
  140.                         if (FlamePlayerLife<=0) {HatePlayerWon=true;}
  141.                         if (Turn>1){
  142.                             TypeOfCardDrawn=HateDeck.DrawCard();
  143.                             if (TypeOfCardDrawn==2) {NrShoal++;}
  144.                             if (TypeOfCardDrawn==3) {NrArcher++;}
  145.                             if (TypeOfCardDrawn==4) {NrForest++;}
  146.                         }
  147.                         if (NrForest>=1) {ForestInPlay++; NrForest--;}
  148.                         ArcherInPlay=ArcherInPlay+Math.min(ForestInPlay/2, NrArcher);
  149.                         NrArcher=NrArcher-Math.min(ForestInPlay/2, NrArcher);
  150.                         if (NrShoal>=2) {HatePlayerLife=HatePlayerLife+2; NrShoal=NrShoal-2;}
  151.                         //FlamePlayerTurn
  152.                         NrTrades=Math.min(ApesInPlay, ArcherInPlay);
  153.                         ArcherInPlay=ArcherInPlay-NrTrades;
  154.                         ApesInPlay=ApesInPlay-NrTrades;
  155.                         HatePlayerLife=HatePlayerLife-2*ApesInPlay;
  156.                         if (HatePlayerLife<=0) {FlamePlayerWon=true;}
  157.                         TypeOfCardDrawn=FlameDeck.DrawCard();
  158.                         if (TypeOfCardDrawn==1) {NrSSG++;}
  159.                         if (NrSSG>=4) {ApesInPlay++; NrSSG=NrSSG-4;}
  160.                     }
  161.                 }
  162.                 if (FlamePlayerWon) {Outcome=1;} else {Outcome=0;}
  163.                 //In case neither player's life total was reduced to 0 after all those turns (because everything traded) then the Flame player, who was on the draw, loses to decking
  164.             }
  165.            
  166.         }
  167.        
  168.         if (!WeHaveLeyline) {
  169.             //We'll assume for convenience that the Flame player never hardcasts Simian Spirit Guide. This need not be optimal but it's a close approximation.
  170.             if (!OnThePlay) {
  171.                 for (int Turn=1; Turn<=53; Turn++){
  172.                     if (!FlamePlayerWon && !HatePlayerWon){
  173.                         if (NrShoal>=2) {HatePlayerLife=HatePlayerLife+2; NrShoal=NrShoal-2;}
  174.                         //FlamePlayerTurn
  175.                         if (Turn>1){
  176.                             if (FlameDeck.NrOfCards()>0) {TypeOfCardDrawn=FlameDeck.DrawCard();} else {TypeOfCardDrawn=1;} //SSGs are rippled to the bottom
  177.                             if (TypeOfCardDrawn==1) {NrSSG++;}
  178.                             if (TypeOfCardDrawn==2) {NrFlames++;}
  179.                         }
  180.                         int CastableFlames=Math.min(NrSSG/2,NrFlames);
  181.                         int TotDMG=0;
  182.                         NrSSG=NrSSG-2*CastableFlames;
  183.                         NrFlames=NrFlames-CastableFlames;
  184.                         if (CastableFlames>0){
  185.                             do {
  186.                                 CastableFlames--; TotDMG=TotDMG+2;
  187.                                 for (int i=1; i<=4; i++){
  188.                                     if (FlameDeck.NrOfCards()>0){TypeOfCardDrawn=FlameDeck.DrawCard();}
  189.                                     if (TypeOfCardDrawn==2) {CastableFlames++;}
  190.                                 }
  191.                             } while (CastableFlames>0 && TotDMG<20);
  192.                         }
  193.                         HatePlayerLife=HatePlayerLife-TotDMG;
  194.                         if (HatePlayerLife<=0) {FlamePlayerWon=true;}
  195.                         //HatePlayerTurn
  196.                         FlamePlayerLife=FlamePlayerLife-2*ArcherInPlay;
  197.                         if (FlamePlayerLife<=0) {HatePlayerWon=true;}
  198.                         TypeOfCardDrawn=HateDeck.DrawCard();
  199.                         if (TypeOfCardDrawn==2) {NrShoal++;}
  200.                         if (TypeOfCardDrawn==3) {NrArcher++;}
  201.                         if (TypeOfCardDrawn==4) {NrForest++;}
  202.                         if (NrForest>=1) {ForestInPlay++; NrForest--;}
  203.                         ArcherInPlay=ArcherInPlay+Math.min(ForestInPlay/2, NrArcher);
  204.                         NrArcher=NrArcher-Math.min(ForestInPlay/2, NrArcher);
  205.                         //System.out.println("Turn "+Turn+": HatePlayerLife "+HatePlayerLife+", FlamePlayerLife "+FlamePlayerLife);
  206.                     }
  207.                 }
  208.             if (FlamePlayerWon){Outcome=1;} else if (HatePlayerWon){Outcome=0;}
  209.             }
  210.            
  211.             if (OnThePlay) {
  212.                 for (int Turn=1; Turn<=53; Turn++){
  213.                     if (!FlamePlayerWon && !HatePlayerWon){
  214.                         if (NrShoal>=2) {HatePlayerLife=HatePlayerLife+2; NrShoal=NrShoal-2;}
  215.                         //HatePlayerTurn
  216.                         FlamePlayerLife=FlamePlayerLife-2*ArcherInPlay;
  217.                         if (FlamePlayerLife<=0) {HatePlayerWon=true;}
  218.                         if (Turn>1){
  219.                             TypeOfCardDrawn=HateDeck.DrawCard();
  220.                             if (TypeOfCardDrawn==2) {NrShoal++;}
  221.                             if (TypeOfCardDrawn==3) {NrArcher++;}
  222.                             if (TypeOfCardDrawn==4) {NrForest++;}
  223.                         }
  224.                         if (NrForest>=1) {ForestInPlay++; NrForest--;}
  225.                         ArcherInPlay=ArcherInPlay+Math.min(ForestInPlay/2, NrArcher);
  226.                         NrArcher=NrArcher-Math.min(ForestInPlay/2, NrArcher);
  227.                         //FlamePlayerTurn
  228.                         if (FlameDeck.NrOfCards()>0) {TypeOfCardDrawn=FlameDeck.DrawCard();} else {TypeOfCardDrawn=1;} //SSGs are rippled to the bottom
  229.                         if (TypeOfCardDrawn==1) {NrSSG++;}
  230.                         if (TypeOfCardDrawn==2) {NrFlames++;}
  231.                         int CastableFlames=Math.min(NrSSG/2,NrFlames);
  232.                         int TotDMG=0;
  233.                         NrSSG=NrSSG-2*CastableFlames;
  234.                         NrFlames=NrFlames-CastableFlames;
  235.                         if (CastableFlames>0){
  236.                             do {
  237.                                 CastableFlames--; TotDMG=TotDMG+2;
  238.                                 for (int i=1; i<=4; i++){
  239.                                     if (FlameDeck.NrOfCards()>0){TypeOfCardDrawn=FlameDeck.DrawCard();}
  240.                                     if (TypeOfCardDrawn==2) {CastableFlames++;}
  241.                                     //We'll assume for convenience that the other cards remain exiled rather than going to the bottom, but this shouldn't realistially matter
  242.                                 }
  243.                             } while (CastableFlames>0 && TotDMG<20);
  244.                         }
  245.                         HatePlayerLife=HatePlayerLife-TotDMG;
  246.                         if (HatePlayerLife<=0) {FlamePlayerWon=true;}
  247.                     }
  248.                 }
  249.             if (HatePlayerWon){Outcome=0;} else if (FlamePlayerWon){Outcome=1;}
  250.             }
  251.          
  252.         }
  253.        
  254.         return Outcome;
  255.     }
  256.    
  257.     static int SimulateGameVsChancellor(Deck fulldeck) {
  258.         int TypeOfCardDrawn;
  259.         int Outcome=1; //1 corresponds to a loss; 0 corresponds to a win
  260.         int NrShoal=0;
  261.         int NrArcher=0;
  262.         int NrForest=0;
  263.         int ForestInPlay=0;
  264.         int ArcherInPlay=0;      
  265.         for (int CardsDrawn=0; CardsDrawn<7; CardsDrawn++){
  266.             TypeOfCardDrawn=fulldeck.DrawCard();
  267.             if (TypeOfCardDrawn==2) {NrShoal++;}
  268.             if (TypeOfCardDrawn==3) {NrArcher++;}
  269.             if (TypeOfCardDrawn==4) {NrForest++;}
  270.         }
  271.        
  272.         boolean WeCanGain2=false;
  273.         if (NrShoal>=2) {
  274.             WeCanGain2=true;
  275.         }
  276.         else if (NrShoal==1 && NrArcher>=1){
  277.             NrArcher--;
  278.             WeCanGain2=true;
  279.         }
  280.        
  281.         if (WeCanGain2) {
  282.             Random generator = new Random();
  283.             boolean OnThePlay=generator.nextBoolean();
  284.             if (OnThePlay) {Outcome=0;} //If we survive the Chancellors then we'll eventually deck our opponent
  285.             if (!OnThePlay) {
  286.                 int OppLife=20+3*7;
  287.                 for (int Turn=1; Turn<=53; Turn++){
  288.                     OppLife=OppLife-2*ArcherInPlay;
  289.                     TypeOfCardDrawn=fulldeck.DrawCard();
  290.                     if (TypeOfCardDrawn==3) {NrArcher++;}
  291.                     if (TypeOfCardDrawn==4) {NrForest++;}
  292.                     if (NrForest>=1) {ForestInPlay++; NrForest--;}
  293.                     ArcherInPlay=ArcherInPlay+Math.min(ForestInPlay/2, NrArcher);
  294.                     NrArcher=NrArcher-Math.min(ForestInPlay/2, NrArcher);
  295.                 }
  296.                 if (OppLife<0) {Outcome=0;}
  297.             }
  298.         }
  299.        
  300.         //In other cases (we weren't able to gain 2 in response, or our deck had so few Archers that we got decked) Outcome remains at 1, i.e., a loss
  301.        
  302.         return Outcome;
  303.     }//end of SimulateGame
  304.    
  305. }
  306.  
  307. class OpeningHand {
  308.     int NumberOfLands;
  309.     int NumberOfCardType2;
  310.     int NumberOfCardType3;
  311.     int NumberOfCardType4;
  312.     int NumberOfSpells;
  313.  
  314.     int NrOfCards(){
  315.         return NumberOfLands+NumberOfCardType2+NumberOfCardType3+NumberOfCardType4+NumberOfSpells;
  316.     }
  317.  
  318.     void SetHand (int Nr1, int Nr2, int Nr3, int Nr4, int Nr5) {
  319.         NumberOfLands=Nr1;
  320.         NumberOfCardType2=Nr2;
  321.         NumberOfCardType3=Nr3;
  322.         NumberOfCardType4=Nr4;
  323.         NumberOfSpells=Nr5;
  324.     }
  325.  
  326. }//end of OpeningHand
  327.  
  328. class Deck {
  329.     int NumberOfCardType1;
  330.     int NumberOfCardType2;
  331.     int NumberOfCardType3;
  332.     int NumberOfCardType4;
  333.     int NumberOfCardType5;
  334.    
  335.     void SetDeck (int Nr1, int Nr2, int Nr3, int Nr4, int Nr5) {
  336.         NumberOfCardType1=Nr1;
  337.         NumberOfCardType2=Nr2;
  338.         NumberOfCardType3=Nr3;
  339.         NumberOfCardType4=Nr4;
  340.         NumberOfCardType5=Nr5;
  341.     }
  342.    
  343.     int NrOfCards(){
  344.         return NumberOfCardType1+NumberOfCardType2+NumberOfCardType3+NumberOfCardType4+NumberOfCardType5;
  345.     }
  346.    
  347.     int DrawCard (){
  348.         Random generator = new Random();
  349.         int CardType=0;
  350.         int RandomIntegerBetweenOneAndDeckSize=generator.nextInt( this.NrOfCards() )+1;
  351.         int OneCutoff=NumberOfCardType1;
  352.         int TwoCutoff=OneCutoff+NumberOfCardType2;
  353.         int ThreeCutoff=TwoCutoff+NumberOfCardType3;
  354.         int FourCutoff=ThreeCutoff+NumberOfCardType4;
  355.         int FiveCutoff=FourCutoff+NumberOfCardType5;
  356.  
  357.         if (RandomIntegerBetweenOneAndDeckSize<=OneCutoff) {CardType=1; this.NumberOfCardType1--;}
  358.         if (RandomIntegerBetweenOneAndDeckSize>OneCutoff && RandomIntegerBetweenOneAndDeckSize<=TwoCutoff) {CardType=2; this.NumberOfCardType2--;}
  359.         if (RandomIntegerBetweenOneAndDeckSize>TwoCutoff && RandomIntegerBetweenOneAndDeckSize<=ThreeCutoff) {CardType=3; this.NumberOfCardType3--;}
  360.         if (RandomIntegerBetweenOneAndDeckSize>ThreeCutoff && RandomIntegerBetweenOneAndDeckSize<=FourCutoff) {CardType=4; this.NumberOfCardType4--;}
  361.         if (RandomIntegerBetweenOneAndDeckSize>FourCutoff && RandomIntegerBetweenOneAndDeckSize<=FiveCutoff) {CardType=5; this.NumberOfCardType5--;}
  362.         return CardType;
  363.     }
  364.    
  365. }//end of Deck
RAW Paste Data