Elec0

Untitled

Feb 17th, 2022 (edited)
53
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.34 KB | None | 0 0
  1. import requests
  2. import json
  3.  
  4.  
  5. class BlackjackPlayer:
  6.     URL = "https://mohsinq.com/blackjack/"
  7.     API = "https://mohsinq.com/api"
  8.  
  9.     def __init__(self, player_id=None):
  10.         self.debug = True
  11.         if player_id:
  12.             self.playerId = player_id
  13.         self.playerCredits = 0
  14.         self.betAmount = 0
  15.         self.lastBetAmount = 0
  16.         self.state = ""
  17.         self.message = ""
  18.         self.dealerHand = {}
  19.         self.playerHand = {}
  20.         self.games_played = 0
  21.         self.games_won = 0
  22.         self.throw = False
  23.  
  24.     def parse_game(self, r_json):
  25.         # Get the one we're given if we don't provide one
  26.         if not self.playerId:
  27.             self.playerId = r_json["id"]
  28.         self.playerCredits = r_json["playerCredits"]
  29.         self.betAmount = r_json["betAmount"]
  30.         self.state = r_json["state"]
  31.         self.message = r_json["message"]
  32.         self.dealerHand = r_json["dealerHand"]
  33.         self.playerHand = r_json["playerHand"]
  34.  
  35.         self.pdebug(r_json)
  36.  
  37.     def call_api(self, endpoint, method=requests.post) -> json:
  38.         r = method("{}/{}".format(self.API, endpoint), headers={'id': self.playerId})
  39.         if r.status_code != 200:
  40.             print(r.status_code, r.content)
  41.         return json.loads(r.content)
  42.  
  43.     def get_game(self):
  44.         """
  45.        endpoint: GET /game
  46.        """
  47.         r_json = self.call_api("game", requests.get)
  48.         self.parse_game(r_json)
  49.  
  50.     def place_bet(self, amt) -> json:
  51.         """
  52.        endpoint: POST /api/bet/betAmount
  53.        """
  54.         self.lastBetAmount = self.betAmount
  55.         return self.call_api("bet/{}".format(amt))
  56.  
  57.     def hit(self):
  58.         return self.call_api("hit")
  59.  
  60.     def stand(self):
  61.         return self.call_api("stand")
  62.  
  63.     def new_game(self):
  64.         return self.call_api("newGame")
  65.  
  66.     def replenish(self):
  67.         self.pdebug("Replenish credits")
  68.         return self.call_api("replenish")
  69.  
  70.     def determine_bet(self) -> int:
  71.         """
  72.        Figure out what to bet
  73.        """
  74.         self.pdebug("Player credits: ", self.playerCredits)
  75.  
  76.         to_make = min(int(self.playerCredits) // 4, 5000)
  77.         if self.throw:
  78.             to_make = int(self.playerCredits)
  79.  
  80.         self.pdebug("Bet: ", to_make)
  81.         return to_make
  82.  
  83.     def determine_action(self) -> bool:
  84.         """
  85.        The meat of this script
  86.        :return: true to hit, false to stand
  87.        """
  88.         self.print_hands()
  89.  
  90.         pv = self.get_player_val()
  91.         dv = self.get_dealer_val()
  92.         cond = []
  93.         if pv == 21:
  94.             return False
  95.  
  96.         if not self.player_num_ace():
  97.             # Always hit when below 12
  98.             cond.append(pv < 12)
  99.             cond.append(7 <= dv <= 10 and 12 <= pv <= 16)
  100.             cond.append(dv == 11 and 12 <= pv <= 15)
  101.  
  102.             cond.append(17 <= dv <= 20 and 12 <= pv <= 16)
  103.             cond.append(18 <= dv <= 20 and pv == 17)
  104.             cond.append(19 <= dv <= 20 and pv == 18)
  105.             cond.append(dv == 20 and pv == 19)
  106.  
  107.             dna = self.dealer_num_ace()
  108.             if dna:
  109.                 cond.append(pv < 12)
  110.                 cond.append(dna == 2 and 12 <= pv <= 15)
  111.                 if dna != 2:
  112.                     hc = lambda v: self.has_card(self.dealerHand, v)
  113.                     cond.append(hc(2) and 12 <= pv <= 14)
  114.                     cond.append((hc(3) or hc(4)) and 12 <= pv <= 13)
  115.                     cond.append(hc(5) and pv == 12)
  116.                     cond.append(hc(6) and 12 <= pv <= 16)
  117.         else:  # Player has at least one ace
  118.             # Value of player's cards that aren't aces
  119.             pva = self.cards_value({"cards": self.player_non_aces()})
  120.             cond.append(pva < 7)
  121.             cond.append(9 <= dv <= 10 and pva == 7)
  122.             cond.append(18 <= dv <= 20 and pva == 7)
  123.             cond.append(dv == 20 and pva == 7)
  124.  
  125.         return any(cond)
  126.  
  127.     def player_num_ace(self) -> int:
  128.         """ :returns: number of aces in hand"""
  129.         return self._has_ace(self.playerHand)
  130.  
  131.     def dealer_num_ace(self) -> int:
  132.         """ :returns: number of aces in hand"""
  133.         return self._has_ace(self.dealerHand)
  134.  
  135.     def player_non_aces(self) -> list:
  136.         return self._get_non_aces(self.playerHand)
  137.  
  138.     def dealer_non_aces(self) -> list:
  139.         return self._get_non_aces(self.dealerHand)
  140.  
  141.     @staticmethod
  142.     def cards_value(cards: dict) -> int:
  143.         return sum([int(c["cost"]) for c in cards["cards"]])
  144.  
  145.     @staticmethod
  146.     def has_card(cards, val):
  147.         return any([c for c in cards["cards"] if c["cost"] == val])
  148.  
  149.     @staticmethod
  150.     def _has_ace(v) -> int:
  151.         return sum([c["value"] == "A" for c in v["cards"]])
  152.  
  153.     @staticmethod
  154.     def _get_non_aces(v):
  155.         return [c for c in v["cards"] if c["value"] != "A"]
  156.  
  157.     def get_player_val(self):
  158.         return int(self.playerHand["value"])
  159.  
  160.     def get_dealer_val(self):
  161.         return int(self.dealerHand["value"])
  162.  
  163.     def print_hands(self):
  164.         if not self.debug:
  165.             return
  166.         print("Dealer hand: {}".format(["{} of {}".format(c["value"], c["suit"]) for c in self.dealerHand["cards"]]))
  167.         print("Dealer hand value: {}".format(self.dealerHand["value"]))
  168.         print("Player hand: {}".format(["{} of {}".format(c["value"], c["suit"]) for c in self.playerHand["cards"]]))
  169.         print("Player hand value: {}".format(self.playerHand["value"]))
  170.  
  171.     def handle_replenish(self):
  172.         """
  173.        If we get less than 1k credits, replenish will put us back up to that if we hit 0.
  174.        So start betting our entire pool. If we win, it'll give us a lot and if we lose we will get back up to 1k
  175.        """
  176.         if self.playerCredits == 0:
  177.             self.throw = False
  178.             self.replenish()
  179.             self.parse_game(self.new_game())
  180.             return True
  181.         elif self.playerCredits < 1000:
  182.             self.throw = True
  183.         elif self.playerCredits >= 1000:
  184.             # Abort the throw if we won because we probably won a lot
  185.             self.throw = False
  186.         return False
  187.  
  188.     def state_transition(self):
  189.         """
  190.        bet -> active -> (win | lose | tie)
  191.        Main screen is bet
  192.        """
  193.         self.pdebug("--- {} ---".format(self.state))
  194.  
  195.         if self.state == "bet":
  196.             bet = self.determine_bet()
  197.             self.parse_game(self.place_bet(bet))
  198.         elif self.state == "active":
  199.             act = self.determine_action()
  200.             if act:
  201.                 # If we hit the game continues
  202.                 self.pdebug("Player: hit")
  203.                 self.parse_game(self.hit())
  204.             else:
  205.                 self.pdebug("Player: stand")
  206.                 self.parse_game(self.stand())
  207.                 # Standing will end the game, no matter what, so go ahead and advance us one state automatically
  208.                 self.state_transition()
  209.         elif self.state == "win" or self.state == "lose" or self.state == "tie":
  210.             self.print_hands()
  211.             self.pdebug("You {}!".format(self.state))
  212.             sign = "+" if self.state == "win" else ("-" if self.state == "lose" else "=")
  213.             self.pdebug("Credits: {} ({}{})".format(self.playerCredits, sign, self.betAmount))
  214.             self.games_played += 1
  215.             if self.state == "win":
  216.                 self.games_won += 1
  217.  
  218.             self.pdebug("--- New Game (won {}/{} WR: {})---".format(self.games_won, self.games_played,
  219.                                                                     round((self.games_won/self.games_played)*100)))
  220.             print("Credits: {},  (won {}/{} WR: {})".format(self.playerCredits, self.games_won, self.games_played,
  221.                                                             round((self.games_won/self.games_played)*100)))
  222.             if not self.handle_replenish():
  223.                 self.parse_game(self.new_game())
  224.  
  225.     def state_runner(self):
  226.         """ Top level method to run the state methods """
  227.         # while self.games_played < 10:
  228.         while self.playerCredits < 50000:
  229.             self.state_transition()
  230.             # input("Press enter to progress to next state")
  231.  
  232.     def pdebug(self, *args):
  233.         if self.debug:
  234.             print(*args)
  235.  
  236.  
  237. if __name__ == '__main__':
  238.     bp = BlackjackPlayer("e3391243-45d6-4f43-9721-30d02ac665c3")
  239.     bp.get_game()
  240.     bp.state_runner()
  241.  
Add Comment
Please, Sign In to add comment