philRG

Bot philRG Connect4

Mar 2nd, 2022
672
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.81 KB | None | 0 0
  1. import random
  2. import sys
  3. import math
  4. from copy import deepcopy
  5.  
  6.  
  7. def idebug(*args):
  8.     return
  9.     print(*args, file=sys.stderr)
  10.  
  11.  
  12. def debug(*args):
  13.     # return
  14.     print(*args, file=sys.stderr)
  15.  
  16.  
  17. WIDTH, HEIGHT = 9, 7
  18. ALIGNEMENT = 4
  19.  
  20.  
  21. def get_valid_actions(board: list):
  22.     actions = []
  23.     for action in range(WIDTH):
  24.         room = [i for i in range(HEIGHT) if board[i][action] == '.']
  25.         if room:
  26.             actions.append(action)
  27.     return actions
  28.  
  29.  
  30. def poids_cases():
  31.     """Calcule le poids des cases en fonction de la dimension de la grille et du nombre de pions à aligner pour gagner"""
  32.     """[3,4,5,7,5,4,3,4,6,8,10,8,6,4,5,8,11,13,11,8,5,5,8,11,13,11,8,5,4,6,8,10,8,6,4,3,4,5,7,5,4,3] pour une grille 7x6 avec 4 pions à aligner"""
  33.     poids = [0] * WIDTH * HEIGHT
  34.     # Sur les horizontales
  35.     for j in range(HEIGHT):
  36.         for i in range(WIDTH - ALIGNEMENT + 1):
  37.             for k in range(ALIGNEMENT):
  38.                 poids[WIDTH * j + i + k] += 1
  39.     # Sur les verticales
  40.     for j in range(HEIGHT - ALIGNEMENT + 1):
  41.         for i in range(WIDTH):
  42.             for k in range(ALIGNEMENT):
  43.                 poids[WIDTH * j + i + k * WIDTH] += 1
  44.     # Sur les diagonales montantes
  45.     for j in range(HEIGHT - ALIGNEMENT + 1):
  46.         for i in range(WIDTH - ALIGNEMENT + 1):
  47.             for k in range(ALIGNEMENT):
  48.                 poids[WIDTH * j + i + k * WIDTH + k] += 1
  49.     # Sur les diagonales descendantes
  50.     for j in range(ALIGNEMENT - 1, HEIGHT):
  51.         for i in range(WIDTH - ALIGNEMENT + 1):
  52.             for k in range(ALIGNEMENT):
  53.                 poids[WIDTH * j + i - k * WIDTH + k] += 1
  54.     return poids
  55.  
  56.  
  57. # Drop chips in the columns.
  58. # Connect at least 4 of your chips in any direction to win.
  59.  
  60. def display_board(board: list):
  61.     board_print = ""
  62.     for i in range(HEIGHT):
  63.         for j in range(WIDTH):
  64.             board_print += board[i][j] + " "
  65.         board_print += "\n"
  66.     debug(board_print)
  67.  
  68.  
  69. def update_board(board: list, col: int, player_id: int):
  70.     row = max([i for i in range(HEIGHT) if board[i][col] == '.'])
  71.     board[row][col] = str(player_id)
  72.  
  73.  
  74. def three_check(p: str, board: list):
  75.     for i in range(HEIGHT):
  76.         for j in range(WIDTH):
  77.             if board[i][j] == p:
  78.                 if i + 2 < HEIGHT and j + 2 < WIDTH and board[i + 1][j + 1] == p and board[i + 2][j + 2] == p:  # Diagonal Right Down Check
  79.                     debug(f'Diagonal Right Down Check')
  80.                     return p
  81.                 elif j + 2 < WIDTH and board[i][j + 1] == p and board[i][j + 2] == p:  # Horizontal Check
  82.                     debug(f'Horizontal Check')
  83.                     return p
  84.                 elif i >= 2 and i - 2 < HEIGHT and j + 3 < WIDTH and board[i - 1][j + 1] == p and board[i - 2][j + 2] == p:  # Diagonal Right Up Check
  85.                     debug(f'Diagonal Right Up Check')
  86.                     return p
  87.                 elif i + 2 < HEIGHT and board[i + 1][j] == p and board[i + 2][j] == p:  # Vertical Check
  88.                     debug(f'Vertical Check')
  89.                     return p
  90.  
  91.  
  92. def win_check(p: str, board: list):
  93.     for i in range(HEIGHT):
  94.         for j in range(WIDTH):
  95.             if board[i][j] == p:
  96.                 if i + 3 < HEIGHT and j + 3 < WIDTH and board[i + 1][j + 1] == p and board[i + 2][j + 2] == p and board[i + 3][j + 3] == p:  # Diagonal Right Down Check
  97.                     debug(f'Diagonal Right Down Check')
  98.                     return p
  99.                 elif j + 3 < WIDTH and board[i][j + 1] == p and board[i][j + 2] == p and board[i][j + 3] == p:  # Horizontal Check
  100.                     debug(f'Horizontal Check')
  101.                     return p
  102.                 elif i >= 3 and i - 3 < HEIGHT and j + 3 < WIDTH and board[i - 1][j + 1] == p and board[i - 2][j + 2] == p and board[i - 3][j + 3] == p:  # Diagonal Right Up Check
  103.                     debug(f'Diagonal Right Up Check')
  104.                     return p
  105.                 elif i + 3 < HEIGHT and board[i + 1][j] == p and board[i + 2][j] == p and board[i + 3][j] == p:  # Vertical Check
  106.                     debug(f'Vertical Check')
  107.                     return p
  108.  
  109.  
  110. def count_three_chips(p: str, board: list):
  111.     count = 0
  112.     for i in range(HEIGHT):
  113.         for j in range(WIDTH):
  114.             if board[i][j] == p:
  115.                 if i + 2 < HEIGHT and j + 2 < WIDTH and board[i + 1][j + 1] == p and board[i + 2][j + 2] == p:  # Diagonal Right Down Check
  116.                     # debug(f'Diagonal Right Down Check')
  117.                     count += 1
  118.                 if j + 2 < WIDTH and board[i][j + 1] == p and board[i][j + 2] == p:  # Horizontal Check
  119.                     # debug(f'Horizontal Check')
  120.                     count += 1
  121.                 if i >= 2 and i - 2 < HEIGHT and j + 3 < WIDTH and board[i - 1][j + 1] == p and board[i - 2][j + 2] == p:  # Diagonal Right Up Check
  122.                     # debug(f'Diagonal Right Up Check')
  123.                     count += 1
  124.                 if i + 2 < HEIGHT and board[i + 1][j] == p and board[i + 2][j] == p:  # Vertical Check
  125.                     # debug(f'Vertical Check')
  126.                     count += 1
  127.     return count
  128.  
  129.  
  130. def count_two_chips(p: str, board: list):
  131.     count = 0
  132.     for i in range(HEIGHT):
  133.         for j in range(WIDTH):
  134.             if board[i][j] == p:
  135.                 if i + 1 < HEIGHT and j + 1 < WIDTH and board[i + 1][j + 1] == p:  # Diagonal Right Down Check
  136.                     # debug(f'Diagonal Right Down Check')
  137.                     count += 1
  138.                 if j + 1 < WIDTH and board[i][j + 1] == p:  # Horizontal Check
  139.                     # debug(f'Horizontal Check')
  140.                     count += 1
  141.                 if i >= 1 and i - 1 < HEIGHT and j + 3 < WIDTH and board[i - 1][j + 1] == p:  # Diagonal Right Up Check
  142.                     # debug(f'Diagonal Right Up Check')
  143.                     count += 1
  144.                 if i + 1 < HEIGHT and board[i + 1][j] == p:  # Vertical Check
  145.                     # debug(f'Vertical Check')
  146.                     count += 1
  147.     return count
  148.  
  149.  
  150. '''    poids = [3, 4, 5, 7, 7, 7, 5, 4, 3,
  151.             4, 6, 8, 10, 10, 10, 8, 6, 4,
  152.             5, 8, 11, 13, 13, 13, 11, 8, 5,
  153.             7, 10, 13, 16, 16, 16, 13, 10, 7,
  154.             5, 8, 11, 13, 13, 13, 11, 8, 5,
  155.             4, 6, 8, 10, 10, 10, 8, 6, 4,
  156.             3, 4, 5, 7, 7, 7, 5, 4, 3]
  157.             '''
  158.  
  159. '''     3   4   5   7   5   4   3
  160.         4   6   8   10  8   6   4
  161.         5   8   11  13  11  8   5
  162.         5   8   11  13  11  8   5
  163.         4   6   8   10  8   6   4
  164.         3   4   5   7   5   4   3
  165.        '''
  166.  
  167.  
  168. def get_action_score(player_id: int, action: int, board: list):
  169.     row = max([i for i in range(HEIGHT) if board[i][action] == '.'])
  170.     weight = poids[row * WIDTH + action]
  171.     p = str(player_id)
  172.     two_chips_count = count_two_chips(p, board)
  173.     three_chips_count = count_three_chips(p, board)
  174.     score = 1
  175.     new_board = deepcopy(board)
  176.     update_board(new_board, action, player_id)
  177.     if win_check(p, new_board) == p:
  178.         return math.inf
  179.     else:
  180.         three_chips_new_count = count_three_chips(p, new_board)
  181.         new_three_chips = three_chips_new_count - three_chips_count
  182.         score += new_three_chips * 100
  183.         two_chips_new_count = count_two_chips(p, new_board)
  184.         new_two_chips = two_chips_new_count - two_chips_count
  185.         score += new_two_chips * 10
  186.     return score + weight
  187.  
  188.  
  189. # my_id: 0 or 1 (Player 0 plays first)
  190. # opp_id: if your index is 0, this will be 1, and vice versa
  191. my_id, opp_id = [int(i) for i in input().split()]
  192. idebug(my_id, opp_id)
  193. is_start = True
  194. poids = poids_cases()
  195.  
  196. # game loop
  197. while True:
  198.     board = []
  199.     actions = []
  200.  
  201.     turn_index = int(input())  # starts from 0; As the game progresses, first player gets [0,2,4,...] and second player gets [1,3,5,...]
  202.     idebug(turn_index)
  203.     for i in range(7):
  204.         board_row = input()  # one row of the board (from top to bottom)
  205.         idebug(board_row)
  206.         board.append(list(board_row))
  207.     num_valid_actions = int(input())  # number of unfilled columns in the board
  208.     idebug(num_valid_actions)
  209.  
  210.     valid_actions = []
  211.     for i in range(num_valid_actions):
  212.         action = int(input())  # a valid column index into which a chip can be dropped
  213.         idebug(action)
  214.         valid_actions.append(action)
  215.     opp_previous_action = int(input())  # opponent's previous chosen column index (will be -1 for first player in the first turn)
  216.     idebug(opp_previous_action)
  217.  
  218.     player_wins = False
  219.     opponent_wins = False
  220.  
  221.     best_action = None
  222.     action = None
  223.  
  224.     if is_start:
  225.         if opp_previous_action in range(3, 6):
  226.             action = 'STEAL'
  227.         else:
  228.             action = random.choice([3, 4, 5])
  229.         is_start = False
  230.     else:
  231.         # check if player wins
  232.         for action in valid_actions:
  233.             new_board = deepcopy(board)
  234.             # debug(f'action = {action}')
  235.             update_board(new_board, action, my_id)
  236.             p = str(my_id)
  237.             if win_check(p, new_board) == p:
  238.                 best_action = action
  239.                 player_wins = True
  240.                 break
  241.  
  242.         if player_wins:
  243.             action = best_action
  244.         else:
  245.             # check if opponent wins
  246.             for action in valid_actions:
  247.                 new_board = deepcopy(board)
  248.                 update_board(new_board, action, opp_id)
  249.                 p = str(opp_id)
  250.                 if win_check(p, new_board) == p:
  251.                     debug(f'Player #{opp_id} wins with action {action}!')
  252.                     display_board(new_board)
  253.                     best_action = action
  254.                     opponent_wins = True
  255.                     break
  256.             if opponent_wins:
  257.                 action = best_action
  258.             else:
  259.                 actions_candidates = []
  260.                 debug(f'valid_actions: {valid_actions}')
  261.                 debug(f'board = {board}')
  262.                 for max_action in valid_actions:
  263.                     opponent_wins = False
  264.                     max_board = deepcopy(board)
  265.                     update_board(max_board, max_action, my_id)
  266.                     min_valid_actions = get_valid_actions(max_board)
  267.                     # debug(f'opp_valid_actions after p action {action} = {opp_valid_actions}')
  268.                     for min_action in min_valid_actions:
  269.                         min_board = deepcopy(max_board)
  270.                         update_board(min_board, min_action, opp_id)
  271.                         p = str(opp_id)
  272.                         if win_check(p, min_board) == p:
  273.                             debug(f'Opp WINS after action {min_action}!!!')
  274.                             opponent_wins = True
  275.                             break
  276.                     if not opponent_wins:
  277.                         actions_candidates.append(max_action)
  278.  
  279.                 ''' Easiest way '''
  280.                 op_actions = [(action, get_action_score(opp_id, action, board)) for action in actions_candidates]
  281.                 op_best_action, op_best_score = max(op_actions, key=lambda x: x[1])
  282.                 debug(f'op_best_action = {op_best_action}')
  283.                 player_actions = [(action, get_action_score(my_id, action, board)) for action in actions_candidates]
  284.                 player_best_action, player_best_score = max(op_actions, key=lambda x: x[1])
  285.                 debug(f'op_best_action = {op_best_action}')
  286.  
  287.                 ''' Other way '''
  288.                 # debug(f'actions_candidates: {actions_candidates}')
  289.                 # player_actions = [(action, get_action_score(my_id, action, board)) for action in actions_candidates]
  290.                 # best_score = max(player_actions, key=lambda x: x[1])[1]
  291.                 # actions_candidates = [action for action, score in player_actions if score == best_score]
  292.                 # player_best_action = random.choice(actions_candidates)
  293.                 # # player_best_action, player_best_score = max(player_actions, key=lambda x: x[1])
  294.                 # debug(f'player_best_action = {player_best_action}')
  295.  
  296.                 ''' Set action '''
  297.                 action = player_best_action if player_best_score > op_best_score else op_best_action
  298.                
  299.     if action != 'STEAL':
  300.         row = max([i for i in range(HEIGHT) if board[i][action] == '.'])
  301.         weight = poids[row * WIDTH + action]
  302.         debug(f'score action {action}, weight {weight} = {get_action_score(my_id, action, board)}')
  303.     # debug(poids)
  304.     # display_board(board)
  305.     # Output a column index to drop the chip in. Append message to show in the viewer.
  306.     print(f'{action}')
  307.  
  308.     '''    poids = [3, 4, 5, 7, 7, 7, 5, 4, 3,
  309.             4, 6, 8, 10, 10, 10, 8, 6, 4,
  310.             5, 8, 11, 13, 13, 13, 11, 8, 5,
  311.             7, 10, 13, 16, 16, 16, 13, 10, 7,
  312.             5, 8, 11, 13, 13, 13, 11, 8, 5,
  313.             4, 6, 8, 10, 10, 10, 8, 6, 4,
  314.             3, 4, 5, 7, 7, 7, 5, 4, 3]
  315.             '''
  316.  
Advertisement
Add Comment
Please, Sign In to add comment