text: import argparse
  import json
  import socket
  import random
  from .random_bot import RandomBot
  import time
  
  class ExploreExploitBot(RandomBot):
  
      # TODO: Add cooling schedule
      # TODO: Make the bidding function a monotonically decreasing then increasing function
  
      DATA_SIZE = 8192
  
      def __init__(self, name, server_address):
          self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          self.socket.connect(server_address)
          self.__send_json({'name': name})
          self.name = name
  
          init_status = self.receive_init()
          self.current_round = 0
          # print(init_status)
          self.artists_types = init_status['artists_types']
          self.required_count = init_status['required_count']
          self.auction_items = init_status['auction_items']
          self.current_wealth = init_status['init_wealth']
          self.player_count = init_status['player_count']
          self.painting_times = {}
          for i in range(len(self.auction_items)):
              artist = self.auction_items[i]
              if artist not in self.painting_times:
                  self.painting_times[artist] = []
              self.painting_times[artist].append(i)
          self.player_paintings = {}
          self.player_paintings[self.name] = {}
          for artist in self.auction_items:
              self.player_paintings[self.name][artist] = 0
          self.max_value_left_single_artist = {}
          for artist in range(self.artists_types):
              self.max_value_left_single_artist["t"+str(artist)] = -1
          self.player_wealth = {}
          self.game_state = None
          self.temperature = 0.4
          self.cooling_parameter = 0.75
          self.change_flag = 1
          self.focus = 0
          self.items_bought = [0 for _ in range(self.artists_types)]
  
      def __send_json(self, json_object):
          self.socket.sendall(bytes(json.dumps(json_object), 'utf-8'))
  
      def make_bid(self, bid_item, bid_amount):
          print("bidding: ", bid_amount)
          self.__send_json({'bid_item': bid_item, 'bid_amount': bid_amount})
  
      def receive_round(self):
          return json.loads(self.socket.recv(self.DATA_SIZE).decode('utf-8'))
  
      def receive_init(self):
          return json.loads(self.socket.recv(self.DATA_SIZE).decode('utf-8'))
  
      def close(self):
          self.socket.close()
  
      def __del__(self):
          self.close()
  
      def get_bid(self):
          return random.randint(0, self.current_wealth)
  
      def get_winning_bid(self, cur_item):
          items_left = 0
          low_point = self.required_count//2
          additional = low_point*(low_point+1)
          try:
              items_left = self.required_count - self.player_paintings[self.name][cur_item]
          except KeyError:
              items_left = self.required_count
          if items_left > self.required_count//2:
              additional += (items_left - self.required_count//2)*(items_left - self.required_count//2+1)
          else:
              additional -= (self.required_count//2 - items_left)*(self.required_count//2 - items_left + 1)
          price = (self.current_wealth - additional)//items_left
          price += 2*abs(items_left - self.required_count//2)
          print("Bidding price ", price)
          return min(price, self.current_wealth - items_left + 1)
  
      def get_bid(self):
          cur_item = self.auction_items[self.current_round]
          try:
              if self.player_paintings[self.name][cur_item] == self.required_count - 1:
                  return self.current_wealth
          except KeyError:
              pass
          try:
              max_value = self.max_value_left_single_artist[cur_item]
              if max_value != -1:
                  print("sleeping now and then bidding ", max_value + 1)
                  time.sleep(2)
                  return min(max_value + 1, self.player_wealth[self.name])
          except KeyError:
              pass
          try:
              required_paintings = self.required_count - self.player_paintings[self.name][cur_item]
              if len(self.painting_times[cur_item]) < required_paintings:
                  return 0
          except KeyError:
              pass
          min_painting = 1000
          painting_name = -1
          if self.change_flag == 1:
              try:
                  for painting in self.player_paintings[self.name]:
                      required_paintings = self.required_count - self.player_paintings[self.name][painting]
                      if len(self.painting_times[painting]) < required_paintings:
                          continue
                      
                      if self.painting_times[painting][required_paintings-1] < min_painting:
                          min_painting = self.painting_times[painting][required_paintings-1]
                          painting_name = painting
              except KeyError:
                  painting_name = cur_item
              self.focus = painting_name
              self.change_flag = 0
          print(self.focus, cur_item)
          # print(self.painting_times[painting_name][self.required_count - self.player_paintings[self.name][painting_name]])
          # print(self.painting_times[cur_item][self.required_count - self.player_paintings[self.name][cur_item]])
  
          if self.focus == cur_item:
              random_num = random.randint(1, 10)
              if random_num != 10:
                  return self.get_winning_bid(cur_item)
              else:
                  return 0
          else:
              random_num = random.uniform(0,1)
              self.temperature *= self.cooling_parameter
              if random_num < self.temperature:
                  return int(0.4*self.get_winning_bid(cur_item))
              else:
                  return 0
          return random.randint(0, self.current_wealth)
  
      def check_game_status(self):
          if self.game_state['bid_winner'] is not None:
              print('Player {} won {} on this round {} with bid amount {}.'
                    .format(self.game_state['bid_winner'],
                            self.game_state['bid_item'],
                            self.game_state['auction_round'],
                            self.game_state['winning_bid']))
              self.painting_times[self.game_state['bid_item']].pop(0)
              if self.game_state['bid_winner'] == self.name:
                  self.current_wealth -= self.game_state['winning_bid']
                  self.items_bought[int(self.game_state['bid_item'][1:])] += 1
              else:
                  if self.game_state['bid_item'] == self.focus:
                      self.change_flag = 1
              player_name = self.game_state['bid_winner']
              if player_name not in self.player_paintings:
                  self.player_paintings[player_name] = {}
              bid_item = self.game_state['bid_item']
              if bid_item not in self.player_paintings[player_name]:
                  self.player_paintings[player_name][bid_item] = 0
              self.player_paintings[player_name][bid_item] += 1
              if player_name not in self.player_wealth:
                  self.player_wealth[player_name] = 100 - self.game_state['winning_bid']
              else:
                  self.player_wealth[player_name] -= self.game_state['winning_bid']
              if self.player_paintings[player_name][bid_item] == self.required_count-1:
                  self.max_value_left_single_artist[bid_item] = max(self.max_value_left_single_artist[bid_item], self.player_wealth[player_name])
          else:
              print('No bidders in this round {}.'.format(self.game_state['auction_round']))
  
          print('-------------------------------')
  
          if self.game_state['finished']:
              print('Game over\n{}\n'.format(self.game_state['reason']))
              return False
          return True
  
      def play(self):
          self.current_round = 0
          while True:
              print("")
              print(self.current_round)
              bid_amt = self.get_bid()
              self.make_bid(self.auction_items[self.current_round], bid_amt)
              try:
                  print(self.player_paintings[self.name])
              except KeyError:
                  pass
              print("Current wealth: ", self.current_wealth)
              for painting in self.painting_times:
                  required_paintings = self.required_count - self.player_paintings[self.name][painting]
                  print(painting, self.painting_times[painting][required_paintings-1])
              # after sending bid, wait for other player
              self.game_state = self.receive_round()
              if not self.check_game_status():
                  break
              self.current_round += 1
  
  
  if __name__ == "__main__":
      random.seed(time.time())
  
      parser = argparse.ArgumentParser()
      parser.add_argument('--host', default='localhost', type=str)
      parser.add_argument('--port', default=9000, type=int)
      parser.add_argument('--name', default='CO2', type=str)
      args = parser.parse_args()
  
      bot = ExploreExploitBot(args.name, (args.host, args.port))
      bot.play()
  