Advertisement
Guest User

london_bolt_sim

a guest
Oct 17th, 2020 (edited)
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.07 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Sun Oct 11 15:11:05 2020
  4.  
  5. @author: Alex Majlaton
  6. """
  7.  
  8. import random, copy
  9. import pandas as pd
  10. from statistics import mean
  11. from time import process_time
  12.  
  13. ##### MULLIGAN ENGINES #####
  14. # Here I'm writing a few functions that implement various mulligan strategies.
  15. # Note: The way these functions are implemented, the cards you remove from
  16. # your mulligan hands are never actually put on the bottom of your deck.
  17. # I don't expect this to matter for these simulations, but it's
  18. # important to note in case this code gets reused again somewhere.
  19.  
  20. # This function is what it sounds like - you never mulligan.
  21.  
  22. def neverMull(deck):
  23.     starting_deck = copy.copy(deck)
  24.     random.shuffle(starting_deck)
  25.     opening_hand = starting_deck[:7]
  26.     starting_deck = starting_deck[7:]
  27.     return starting_deck, opening_hand
  28.  
  29. # This function takes a starting deck, a starting hand size, and a starting
  30. # number of bolts as an input and generates that starting hand.
  31. # The purpose is to use it in a series of loops to simulate games with
  32. # every possible opening hand.
  33.    
  34. def startingHandSize(deck, n, b):
  35.     starting_deck = copy.copy(deck)
  36.     opening_hand = []
  37.     for i in range(b):
  38.         starting_deck.remove(2)
  39.         opening_hand.append(2)
  40.     for j in range(n-b):
  41.         starting_deck.remove(1)
  42.         opening_hand.append(1)
  43.     random.shuffle(starting_deck)
  44.     return starting_deck, opening_hand
  45.  
  46. # This was the original policy I wrote, before I simulated every hand.
  47. # It was based only on my intuition after considering every hand.
  48. # A rough description is this:
  49. #
  50. # 7 cards: Keep 4, 5, or 6 bolts.
  51. # 6 cards: Keep 4, 5, or 6 bolts and start 4/2 if possible, then 5/1.
  52. # 5 cards: Keep 3, 4, 5, or 6 bolts and start 4/1 if possible, then 3/2.
  53. # 4 cards: Keep 2-6 bolts and start 3/1 if possible, then 2/2.
  54. # 3 cards: Keep 2-7 bolts and start 2/1 if possible, then 3/0.
  55. # 2 cards: Keep 1-7 bolts and start 1/1, if possible, then 2/0.
  56. # 1 card: Keep and start a bolt if you have one.
  57.  
  58. def londonMull(deck):
  59.     mulls = 0
  60.     keep = 0
  61.     while (keep == 0):
  62.         starting_deck = copy.copy(deck)
  63.         random.shuffle(starting_deck)
  64.         opening_hand = starting_deck[:7]
  65.         starting_deck = starting_deck[7:]
  66.         OHB = opening_hand.count(2)
  67.         if mulls == 0:
  68.             if OHB in range(4,7):
  69.                 keep = 1
  70.             else:
  71.                 mulls += 1
  72.         elif mulls == 1:
  73.             if OHB == 4:
  74.                 keep = 1
  75.                 opening_hand = [2,2,2,2,1,1]
  76.             elif OHB in range(5,7):
  77.                 keep = 1
  78.                 opening_hand = [2,2,2,2,2,1]
  79.             else:
  80.                 mulls += 1
  81.         elif mulls == 2:
  82.             if OHB in range(4,7):
  83.                 keep = 1
  84.                 opening_hand = [2,2,2,2,1]
  85.             elif OHB == 3:
  86.                 keep = 1
  87.                 opening_hand = [2,2,2,1,1]
  88.             else:
  89.                 mulls += 1
  90.         elif mulls == 3:
  91.             if OHB in range(3,7):
  92.                 keep = 1
  93.                 opening_hand = [2,2,2,1]
  94.             elif OHB == 2:
  95.                 keep = 1
  96.                 opening_hand = [2,2,1,1]
  97.             else:
  98.                 mulls += 1
  99.         elif mulls == 4:
  100.             if OHB in range(2,7):
  101.                 keep = 1
  102.                 opening_hand = [2,2,1]
  103.             elif OHB == 7:
  104.                 keep = 1
  105.                 opening_hand = [2,2,2]
  106.             else:
  107.                 mulls += 1
  108.         elif mulls == 5:
  109.             if OHB == 7:
  110.                 keep = 1
  111.                 opening_hand = [2,2]
  112.             elif OHB >= 1:
  113.                 keep = 1
  114.                 opening_hand = [2,1]
  115.             else:
  116.                 mulls += 1
  117.         elif mulls == 6:
  118.             keep = 1
  119.             if OHB == 7:
  120.                 opening_hand = [2]
  121.             else:
  122.                 opening_hand = [1]
  123.     return starting_deck, opening_hand    
  124.  
  125. # This is the policy described in the blog post.
  126.  
  127. def mullPolicyTest(deck):
  128.     mulls = 0
  129.     keep = 0
  130.     while (keep == 0):
  131.         starting_deck = copy.copy(deck)
  132.         random.shuffle(starting_deck)
  133.         opening_hand = starting_deck[:7]
  134.         starting_deck = starting_deck[7:]
  135.         OHB = opening_hand.count(2)
  136.         if mulls == 0:
  137.             # here is where you can adjust the range of 7 card keeps.
  138.             # 4 and 5 represent number of bolts.
  139.             # to keep 6 bolts, add a 6 to the list.
  140.             if OHB in [4,5]:
  141.                 keep = 1
  142.             else:
  143.                 mulls += 1
  144.         elif mulls == 1:
  145.             if OHB in [4,5,6]:
  146.                 keep = 1
  147.                 if OHB == 6:
  148.                     opening_hand = [2,2,2,2,2,1]
  149.                 else:
  150.                     opening_hand = [2,2,2,2,1,1]
  151.             else:
  152.                 mulls += 1
  153.         elif mulls == 2:
  154.             if OHB in [3,4,5,6]:
  155.                 keep = 1
  156.                 if OHB == 3:
  157.                     opening_hand = [2,2,2,1,1]
  158.                 else:
  159.                     opening_hand = [2,2,2,2,1]
  160.             else:
  161.                 mulls += 1
  162.         elif mulls == 3:
  163.             keep = 1
  164.             if OHB in [3,4,5,6]:
  165.                 opening_hand = [2,2,2,1]
  166.             elif OHB == 2:
  167.                 opening_hand = [2,2,1,1]
  168.             else:
  169.                 # even though you've kept 4 cards you're adding 1 to the
  170.                 # mulls counter to signify that you've kept a "bad" 4 card
  171.                 # hand as a way to track how often they occur
  172.                 mulls += 1
  173.                 if OHB == 7:
  174.                     opening_hand = [2,2,2,2]
  175.                 elif OHB == 1:
  176.                     opening_hand = [2,1,1,1]
  177.                 elif OHB == 0:
  178.                     opening_hand = [1,1,1,1]
  179.     return starting_deck, opening_hand
  180.                    
  181. # create empty lists for scorekeeping
  182. boltsInDeck = []
  183. avgKillTurn = []
  184. # use these if you're simulating every hand
  185. # numStartingCards = []
  186. # numStartingBolts = []
  187.  
  188. # timekeeping
  189. total_time = float(0)
  190.  
  191. # If you're simulating every hand, uncomment these lines and use them to
  192. # loop with the startingHandSize function.
  193.  
  194. # for cards in range(8):
  195. #     for spells in range(cards+1):
  196.  
  197. # The big loop begins here.
  198. # Looping through desired values of lands and bolts in the deck.
  199. # These ranges can be adjusted.
  200.  
  201. for i in range(8,25):
  202.     t1_start = process_time()
  203.     # create empty starting deck list
  204.     deck = []
  205.     lands = i
  206.     # adjust deck size here. 60 = regular constructed deck, 99 = EDH, etc.
  207.     bolts = 60 - i
  208.     # populate the deck with lands and bolts
  209.     for l in range(lands):
  210.         deck.append(1)
  211.     for b in range(bolts):
  212.         deck.append(2)
  213.  
  214.     # create empty list for scorekeeping
  215.     scores = []
  216.    
  217.     # choose number of iterations to run here
  218.     for j in range(10000):
  219.        
  220.         # this is where you decide what mulligan policy you're testing
  221.         starting_deck, opening_hand = mullPolicyTest(deck)
  222.         #starting_deck, opening_hand = startingHandSize(deck, cards, spells)
  223.         #starting_deck, opening_hand = londonMull(deck)
  224.         #starting_deck, opening_hand = neverMull(deck)
  225.        
  226.         turn = 0
  227.         # adjustable to any life total
  228.         oppLife = 20
  229.         # adjustable to any damage spell - Shock would be 2 for ex.
  230.         boltDmg = 3
  231.        
  232.         # using the lists to define the starting gameplay values
  233.         landsInPlay = 0
  234.         landsInHand = opening_hand.count(1)
  235.         boltsInHand = opening_hand.count(2)
  236.        
  237.         while oppLife > 0:
  238.             turn += 1
  239.             # strategy for turn 1:
  240.             # if you have a land, play it
  241.             # if did and you have a bolt, cast it
  242.             if turn == 1:
  243.                 if landsInHand >= 1:
  244.                     landsInPlay += 1
  245.                     landsInHand -= 1
  246.                 manaLeft = landsInPlay
  247.                 if boltsInHand >= 1 and manaLeft == 1:
  248.                     oppLife -= boltDmg
  249.                     manaLeft -= 1
  250.                     boltsInHand -= 1
  251.  
  252.             # general strategy after turn 1:
  253.             # play a land if you have one
  254.             # then play every single bolt you have mana for
  255.             if turn > 1:
  256.                 # pop(0) pulls from the front of the list
  257.                 drawStep = starting_deck.pop(0)
  258.                 if drawStep == 1:
  259.                     landsInHand += 1
  260.                 if drawStep == 2:
  261.                     boltsInHand += 1
  262.                 if landsInHand > 0:
  263.                     landsInPlay += 1
  264.                     landsInHand -= 1
  265.                 manaLeft = landsInPlay
  266.                
  267.                 if boltsInHand >= manaLeft:
  268.                     boltsInHand -= manaLeft
  269.                     oppLife -= (manaLeft * boltDmg)
  270.                 elif boltsInHand < manaLeft:
  271.                     oppLife -= (boltsInHand * boltDmg)
  272.                     boltsInHand = 0
  273.                
  274.                 # discard to hand size
  275.                 if boltsInHand > 7:
  276.                     boltsInHand = 7
  277.                    
  278.         # add the score (i.e. the turn you killed on) to the scores list
  279.         scores.append(turn)
  280.     # append the results to two lists, use to make a dataframe
  281.     # if you want CSV output
  282.     boltsInDeck.append(bolts)
  283.     avgKillTurn.append(mean(scores))
  284.     # use these if you're simulating every hand
  285.     #numStartingCards.append(cards)
  286.     #numStartingBolts.append(spells)
  287.     t1_stop = process_time()
  288.     total_time += (t1_stop - t1_start)
  289.     print("Split time:", t1_stop - t1_start)
  290.     print("Elapsed time:", total_time)
  291.    
  292. print("Total time:", total_time)
  293.  
  294. # if you want a dataframe & CSV output
  295. results = pd.DataFrame(
  296.     {'bolts in deck': boltsInDeck,
  297.      'average kill turn': avgKillTurn
  298.      # use these if you're simulating every hand, don't forget the comma above
  299.      #'starting hand size': numStartingCards,
  300.      #'starting bolts': numStartingBolts
  301.     })
  302.    
  303. results.to_csv("YOUR DIRECTORY HERE/bolt_sim_allhands_60_100k.csv", index=False)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement