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;
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();
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
105.                         HatePlayerLife=HatePlayerLife-2*ApesInPlay;
106.                         if (HatePlayerLife<=0) {FlamePlayerWon=true;}
107.                         if (Turn>1){
108.                             TypeOfCardDrawn=FlameDeck.DrawCard();
110.                         }
112.                         //HatePlayerTurn
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
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
155.                         HatePlayerLife=HatePlayerLife-2*ApesInPlay;
156.                         if (HatePlayerLife<=0) {FlamePlayerWon=true;}
157.                         TypeOfCardDrawn=FlameDeck.DrawCard();
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
178.                             if (TypeOfCardDrawn==2) {NrFlames++;}
179.                         }
181.                         int TotDMG=0;
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
230.                         if (TypeOfCardDrawn==2) {NrFlames++;}
232.                         int TotDMG=0;
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