SoFunction
Updated on 2024-11-10

python implementation of backgammon using minimax algorithm

This is a backgammon program for the command line environment. The minimax algorithm is used.

All code is my own except for the scoring method of each Baidu chess type. The structure of this program is exactly the same as the previous Tic-Tac-Toe and Othello.

There's a little problem. I don't have time to mess with it. That's it.

I. Rendering

(omitted)

II. Complete code

from functools import wraps
import time
import csv

'''
Backgammon Gobang
Author: hhh5460
Time: 20181213
'''


#1. Initialize the board
#------------
def init_board():
  '''
  Initializing the board

  Board size 15*15

  As shown below:
  board = [[. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .] ,
       [. . . . . . . . . . . . . . .]]

  Where: .
    . - unoccupied
    X - occupied by black
    O - occupied by white
  '''
  print('Init board...')
  (0.5)
  n = 15
  board = [['.' for _ in range(n)] for _ in range(n)]
  
  return board

#2. Determine the player, Black goes first.
#--------------------
def get_player():
  '''
  The human player chooses the color of the pieces (black 'X'Go first)
  '''
  humancolor = input("Enter your color. (ex. 'X' or 'O'):").upper()
  computercolor = ['X', 'O'][humancolor == 'X']
  
  return computercolor, humancolor

#3. Enter the loop
#----------

#4. Printing the board, prompting moves
#------------------------------
def print_board(board): #ok
  '''
  Print boards, scores

  Opening:
   1 2 3 4 5 6 7 8 9 a b c d e f
  1 . . . . . . . . . . . . . . .
  2 . . . . . . . . . . . . . . .
  3 . . . . . . . . . . . . . . .
  4 . . . . . . . . . . . . . . .
  5 . . . . . . . . . . . . . . .
  6 . . . . . . . . . . . . . . .
  7 . . . . . . . . . . . . . . .
  8 . . . . . . . . . . . . . . .
  9 . . . . . . . . . . . . . . .
  a . . . . . . . . . . . . . . .
  b . . . . . . . . . . . . . . .
  c . . . . . . . . . . . . . . .
  d . . . . . . . . . . . . . . .
  e . . . . . . . . . . . . . . .
  f . . . . . . . . . . . . . . .
  '''
  axises = list('123456789abcdef')
  print(' ', ' '.join(axises))
  for i, v in enumerate(axises): 
    print(v, ' '.join(board[i]))

#5. Think walks, abandonment termination
#--------------------
def get_human_move(board, color): #ok
  '''
  Taking Human Player Walks
  '''
  giveup = True # Give up the sign
  
  legal_moves = _get_legal_moves(board, color)
  
  #print(','.join([translate_move(move) for move in legal_moves]), len(legal_moves))
  
  while True:
    _move = input("Enter your move.(ex.'cd' means row=c col=d): ").lower()
    
    move = translate_move(_move)
    
    if move in legal_moves:
      giveup = False # Don't give up
      break
  
  return move, giveup

def _get_all_lianxin(board, move, color): #ok
  '''
  Taking the current point to drop and then connecting the stars

  1. According to the number of double, triple and quadruple quadra penta on the board double triple quadra penta
  '''
  n = len(board)
  uncolor = ['X', 'O'][color == 'X'] # Reverse color
  
  lianxin = [] # number of stars in a row, len(lianxin) == 4
  
  directions = ((0,1),(1,0),(1,1),(1,-1)) # East, south, southeast, southwest #
  for direction in directions:
    dr, dc = direction   # Steps
    #r, c = move # Starting point
    
    count = 1         # Number of stars in a row, counting the starting point.
    jump_count = [0, 0]    # of stars after jumping one space in the forward and backward direction
    jump_flag = [False, False] # A sign that jumps one space in the clockwise or reverse direction
    block = [False, False]   # Plugged in one direction or the other
    #name = ['','']
    
    for i,v in enumerate([1, -1]): # 1, -1 for clockwise and anticlockwise directions, respectively
      dr, dc = v*dr, v*dc      # Steps
      r, c = move[0]+dr, move[1]+dc # One step ahead
      while True:
        if not _is_on_board(board, [r, c]) or board[r][c] == uncolor: # Not on the board, or the opposing piece
          block[i] = True # Blocked
          break
        if board[r][c] == '.':                           # is empty
          if not _is_on_board(board, [r+dr, c+dc]) or board[r+dr][c+dc] != color: # And the next square, which is not on the board, or is not a piece of your side.
            break
          if jump_flag[i] == True: # One frame ahead, terminate
            break        # Ability to not think about jumping another frame!!!!
          else:
            jump_flag[i] = True
        elif board[r][c] == color:
          if jump_flag[i] == True:
            jump_count[i] += 1
          else:
            count += 1
        
        r, c = r + dr, c + dc # Stepping
        
      
    
    ([count, jump_count, block])
  
  return lianxin
  
def _move_score(board, move): #ok
  '''
  "Score" this drop position

  This logic is too complicated, and the code is long and smelly! I won't consider simplifying it for now.

  Chess type score:
  0. Live five +100000
  1.dead five +100000
  2.Live four +10000
  3.Dead Four +1000
  4.Live three +1000
  5. Dead three +100
  6. Live 2 +100
  7. Dead 2 +10
  8. Live 1 +10
  9.Dead 1 +2

  Special Notes:
  10.Jump N Adding both sides of the pattern score * 20% of the previous level's score? debatable


  lianxin == [[2,[0,0],[True,False]], [1,[0,0],[True,False]]
        [1,[0,0],[True,False]], [3,[1,0]]
        [3,[1,0],[False,False]], [3,[2,1],[True,False]], [3,[2,1],[True,False]]
        [3,[2,1],[True,False]]]
  '''
  # Dead one, alive one, dead two, alive two, dead three, alive three, dead four, alive four, dead five, alive five #
  scores = [   2,  10,  10,  100,  100, 1000, 1000, 10000,100000,100000]
  sum_score = 0
  for color in ['X','O']:
    for lianxin in _get_all_lianxin(board, move, color):
      count, jump_count, block = lianxin
      if jump_count[0] > 0 and jump_count[1] > 0: # Scenario one: jumping both ways
        if block[0] == True and block[1] == True:
          if count + jump_count[0] + jump_count[1] + 2 < 5: continue
        else:
          # This way jumps
          if block[0] == True: # There's jumping, add up the points first (check the table for points) #
            sum_score += scores[jump_count[0]*2-2] # Plus the points of death #
            sum_score += min(scores[(jump_count[0]+count)*2-2] * 0.2, 200) # 20% of the previous level
          else:
            sum_score += scores[jump_count[0]*2-1] # Plus the points of living
            sum_score += min(scores[(jump_count[0]+count)*2-1] * 0.2, 200) # 20% of the previous level
          
          # This way too
          if block[1] == True: # There's jumping, add up the points first (check the table for points) #
            sum_score += scores[jump_count[1]*2-2] # Plus the points of death #
            sum_score += min(scores[(jump_count[1]+count)*2-2] * 0.2, 200) # 20% of the previous level
          else:
            sum_score += scores[jump_count[1]*2-1] # Plus the points of living
            sum_score += min(scores[(jump_count[1]+count)*2-1] * 0.2, 200) # 20% of the previous level
          
          # In the middle #
          sum_score += scores[count*2-1] # With a live score in the middle
        
      elif jump_count[0] > 0 and jump_count[1] == 0: # Scenario two: one side jumps
        if block[0] == True and block[1] == True:
          if count + jump_count[0] + jump_count[1] + 1 < 5: continue
        else:
          # Jumping this way
          if block[0] == True: # Let's add up the scores on the jump side first (look up the table and add up the scores)
            sum_score += scores[jump_count[0]*2-2] # Plus the points of death #
            sum_score += min(scores[(jump_count[0]+count)*2-2] * 0.2, 200) # 20% of the previous level
          else:
            sum_score += scores[jump_count[0]*2-1] # Plus the points of living
            sum_score += min(scores[(jump_count[0]+count)*2-1] * 0.2, 200) # 20% of the previous level
          
          # The side that didn't jump
          if block[1] == True:
            sum_score += scores[count*2-2] # Plus the points of death #
          else:
            sum_score += scores[count*2-1] # Plus the points of living
          
      elif jump_count[1] > 0 and jump_count[0] == 0: # Scenario three: jump on the other side
        if block[0] == True and block[1] == True:
          if count + jump_count[0] + jump_count[1] + 1 < 5: continue
        else:
          # Jumping this way
          if block[1] == True: # Let's add up the scores on the jump side first (look up the table and add up the scores)
            sum_score += scores[jump_count[1]*2-2] # Plus the points of death #
            sum_score += min(scores[(jump_count[1]+count)*2-2] * 0.2, 200) # 20% of the previous level
          else:
            sum_score += scores[jump_count[1]*2-1] # Plus the points of living
            sum_score += min(scores[(jump_count[1]+count)*2-1] * 0.2, 200) # 20% of the previous level
          
          # The side that didn't jump
          if block[0] == True:
            sum_score += scores[count*2-2] # Plus the points of death #
          else:
            sum_score += scores[count*2-1] # Plus the points of living
          
      elif jump_count[0] == 0 and jump_count[1] == 0: # Scenario four: neither side jumps
        if block[0] and block[1]: # Both sides are blocked
          if count == 5: # Add only if it equals 5, otherwise don't add
            sum_score += scores[count*2-2] # - 1,-2 the same
        elif block[0] or block[1]: # Blocking only one side
          sum_score += scores[count*2-2] # Plus the points of death #
        else:
          sum_score += scores[count*2-1] # Plus the points of living

  return sum_score
  
def _get_center_enmpty_points(board): #ok
  '''
  Take the empty space near the center point

  Scan clockwise from the center circle by circle, if there is no piece in two consecutive circles, then stop.
  '''
  n = len(board)
  
  center_point = [n//2, n//2] # Center point [7,7], i.e. '88'
  
  c1 = 0   # Empty lap count
  legal_moves = [] # Save empty spaces
  for i in range(8): # Scanning eight times from the inside out
    c2 = True  # Empty circle sign
    
    if i == 0:
      points = [[n//2, n//2]]
    else:
      # points = [rows 7-i] + [columns 7+i] + [rows 7+i] + [columns 7-i] # Starting at the top left, one turn clockwise
      points = [[7-i,c] for c in range(7-i,7+i)] + \
           [[r,7+i] for r in range(7-i,7+i)] + \
           [[7+i,c] for c in range(7+i,7-i,-1)] + \
           [[r,7-i] for r in range(7+i,7-i,-1)]
           
    for point in points:
      if board[point[0]][point[1]] == '.': # When an empty space is encountered, the
        legal_moves.append(point) # Save points
      else:
        c2 = False        # This circle is not empty
    
    if c2 == True: # If this circle is empty, the empty circle counter is increased by 1
      c1 += 1
      if c1 == 2: break
    else:    # Otherwise, clear
      c1 = 0
  
  return legal_moves # The further ahead, the higher the board point score!

def minimax(board, color, maximizingPlayer, depth):
  '''
  maxima-minima algorithm
  
  included among these:
  maximizingPlayer = True #From your side
  
  use case:
  _, move = minimax(board, 'X', True, 4) # Suppose the computer plays 'X' #
  
  # See: /wiki/Minimax
  function minimax(node, depth, maximizingPlayer) is
    if depth = 0 or node is a terminal node then
      return the heuristic value of node
    if maximizingPlayer then
      value := −∞
      for each child of node do
        value := max(value, minimax(child, depth − 1, FALSE))
      return value
    else (* minimizing player *)
      value := +∞
      for each child of node do
        value := min(value, minimax(child, depth − 1, TRUE))
      return value

  (* Initial call *)
  minimax(origin, depth, TRUE)
  '''
  pass
  
def get_computer_move(board, color):
  '''
  Taking computerized player walks

  Computer move strategy:
    1. "Score" all legal move positions one by one (how it is "scored" determines the level of the computer's play)
    2. Take all the squares with the highest score.
  '''
  print('Computer is thinking...', end='')
  legal_moves = _get_legal_moves(board, color)
  
  scores = [_move_score(board, move) for move in legal_moves]
  
  max_score = max(scores) # Maximum score
  best_move = legal_moves[(max_score)]
  
  print("'{}'".format(translate_move(best_move)))
  return best_move
  
def  _is_legal_move(board, move): #ok
  '''
  Determine whether the drop position is legal or not

  Explanation: As long as it is inside the board and empty, it is legal.

  '''
  if _is_on_board(board, move) and board[move[0]][move[1]] == '.': 
    return True
  
  return False
  
def  _get_legal_moves(board, color): #ok
  '''
  Takes all legal moves of the current color.

  Return format: [[x1,y1], [x2,y2], ...]
  '''
  legal_moves = _get_center_enmpty_points(board)
  
  return legal_moves
  
def _is_on_board(board, move): #ok
  '''
  Determining whether a point is within the range of the board
  '''
  n = len(board)
  
  return move[0] in range(n) and move[1] in range(n)
  
def translate_move(move): #ok
  '''
  Converting coordinates

  such as '1a' can be converted to [0,9]; also [9,10] is converted to 'ab'

  This function, just for convenience, is not necessary
  '''
  axises = list('123456789abcdef')

  if type(move) is str: # As in 'cd'
    row = (move[0]) 
    col = (move[1])
    _move = [row, col] # Get [2,3]
  elif type(move) is list: # As [2,3]
    row = axises[move[0]]
    col = axises[move[1]]
    _move = '{}{}'.format(row, col) # Get 'cd'

  return _move
  
#6.
#----------
def do_move(board, move, color): #ok
  '''
  Drop the ball in the current position
  '''
  assert board[move[0]][move[1]] == '.'
  
  board[move[0]][move[1]] = color
 
#7. Judging the situation, termination or not
#------------------------------
def check_board(board, color): #ok
  '''
  Checking the board

  Returns: whether you won or not
  '''
  n = len(board)
  
  directions = ((0,1),(1,0),(1,1),(1,-1)) # East, south, southeast, southwest #
  # Starting points (coordinates) for the four search directions in four groups.
  # e.g. [[Points in column 1], [Points in row 1], [Points in column 1 + row 1], [Points in row 1 + column n]]
  all_start_points = [[[i, 0] for i in range(n)],
            [[0, j] for j in range(n)],
            [[i, 0] for i in range(n-4)] + [[0, j] for j in range(1,n-4)], # Excludes lengths less than 5, and duplicates
            [[0, j] for j in range(4,n)] + [[i, n-1] for i in range(1,n-4)]]
  
  for direction, start_points in zip(directions, all_start_points):
    dr, dc = direction   # Steps
    for start_point in start_points:
      r, c = start_point # Starting point
      count = 0
      while _is_on_board(board, [r, c]):
        if board[r][c] == color:
          count += 1
          if count == 5:
            return True
        else:
          count = 0
        
        r, c = r + dr, c + dc # Stepping
  
  return False

def check_board__(board, color): # Abandoned!
  '''
  Check the board (not as succinct as the above)

  Returns whether you won or not
  '''
  n = len(board)
  uncolor = ['X', 'O'][color == 'X'] # Reverse color
  
  # 1. Line search
  for i in range(n):
    count = 0
    for j in range(n):
      if board[i][j] == color:
        count += 1
        if count == 5:
          return True # 'Winner is ' + color
      elif board[i][j] == uncolor:
        count = 0
  
  # 2. Column search
  for j in range(n):
    count = 0
    for i in range(n):
      if board[i][j] == color:
        count += 1
        if count == 5:
          return True # 'Winner is ' + color
      elif board[i][j] == uncolor:
        count = 0
  
  # 3. diagonal search k=1 top left bottom right
  #=1 above the diagonal
  for j in range(n-4):   # Termination column n-4
    count = 0
    for i in range(n-j): # Terminate lines n-j
      if board[i][j+i] == color:
        count += 1
        if count == 5:
          return True
      elif board[i][j+i] == uncolor:
        count = 0
        
  #=1 Below the diagonal
  for i in range(1, n-4):   # Termination line n-4
    count = 0
    for j in range(n-i): # Termination columns n-i
      if board[i+j][j] == color:
        count += 1
        if count == 5:
          return True
      elif board[i+j][j] == uncolor:
        count = 0
        
  # 4. diagonal search k=-1 left down right up
  #=-1 below the diagonal
  for j in range(n-4):   # Termination column n-4
    count = 0
    for i in range(n-j): # Terminate lines n-j
      if board[n-i-1][j+i] == color:
        count += 1
        if count == 5:
          return True
      elif board[n-i-1][j+i] == uncolor:
        count = 0
  
  #=-1 above the diagonal
  for j in range(4, n):
    count = 0
    for i in range(n-1):
      if board[i][j-i] == color:
        count += 1
        if count == 5:
          return True
      elif board[i][j-i] == uncolor:
        count = 0
  return False
  



#8. Game over, return message
#--------------------

  
def logging(func): #ok
  '''
  Record game-related information (decorator)

  Includes:
  Start time, game time, board size, black players, white players, game score, game moves

  Save to file
  '''
  @wraps(func)
  def wrap(*args, **kwargs):
    try:
      start = ("%Y%m%d %H:%M:%S", ()) # Start time
      
      t1 = ()
      info = func(*args,**kwargs) # Board size, black players, white players, game scores, game plan (main program)
      t2 = ()
      t = int(t2 - t1) # Competition time consuming
      
      line = [start, t, *info]
      
      with open('', 'a') as f:
        writer = (f, lineterminator='\n')
        (line) # Write
    except Exception as e:
      pass
  
  return wrap

#==========================================
# main function
#==========================================
#@logging
def main(): #ok
  '''
  main program

  Man vs. Machine

  Procedure:
  1. Initialize the board
  2. Determine the players, black first
  3. Enter the cycle
   4. Print the board and prompt for moves.
   5. Think about moves, give up and terminate
   6. Drop discs
   7.Check board, terminate or not
   8. Switch players
  9. Game over, return message
  '''
  # 1. Initialize the board
  board = init_board()
  
  # 2. Determine the players. Black goes first.
  computer_color, human_color = get_player()
  current_color = 'X'
  
  record = '' # Chess games, e.g. 'X:ab O:aa X:ba ...'
  # 3. Enter the loop
  while True:
    # 4. Printing the board, prompting moves
    print_board(board)
    print("Now turn to '{}'...".format(current_color))
    
    # 5. Thinking about moves and recording the game
    if current_color == computer_color:
      move = get_computer_move(board, current_color)
    elif current_color == human_color:
      move, giveup = get_human_move(board, current_color)
      if giveup == True: break # Terminated by waiver
    
    record = record + ' {}:{}'.format(current_color, translate_move(move)) # Entering a game
    
    # 6. Drop
    do_move(board, move, current_color)
    
    # 7. Judging the situation
    done = check_board(board, current_color) # Return the termination flag
    
    # 7_1. Termination
    if done == True:
      print_board(board)
      print("Game over! Winner is '{}'".format(current_color))
      break
    
    # 8. Switching players
    current_color = ['X', 'O'][current_color == 'X']


#Testing
def test_get_center_enmpty_points():
  '''
  #     1 2 3 4 5 6 7 8 9 a b c d e f
  board = [[. . . . . . . . . . . . . . .],#1
       [. . . . . . . . . . . . . . .],#2
       [. . . . . . . . . . . . . . .],#3
       [. . . . . . . . . . . . . . .],#4
       [. . . . . . . . . . . . . . .],#5
       [. . . . . . . . . . . . . . .],#6
       [. . . . . . . . . . . . . . .],#7
       [. . . . . . . . . . . . . . .],#8
       [. . . . . . . . . . . . . . .],#9
       [. . . . . . . . . . . . . . .],#a
       [. . . . . . . . . . . . . . .],#b
       [. . . . . . . . . . . . . . .],#c
       [. . . . . . . . . . . . . . .],#d
       [. . . . . . . . . . . . . . .],#e
       [. . . . . . . . . . . . . . .]]#f
       
  #     1 2 3 4 5 6 7 8 9 a b c d e f
  board = [[. . . . . . . . . . . . . . .],#1
       [. . . . . . . . . . . . . . .],#2
       [. . . . . . . . . . . . . . .],#3
       [. . . . . . . . . . . . . . .],#4
       [. . . . . . . . . X . . . . .],#5
       [. . . . . . X . . . . . . . .],#6
       [. . . . . O . . X O . . . . .],#7
       [. . . . . X X O X . . . . . .],#8
       [. . . . . X O X . . . . . . .],#9
       [. . . . . . . . . . X . . . .],#a
       [. . . X . . . . . . . . . . .],#b
       [. . X . . . . . . . . . . . .],#c
       [. O . . . . . . . . . . . . .],#d
       [. . . . . . . . . . . . . . .],#e
       [. . . . . . . . . . . . . . .]]#f
  '''
  print('Testing _get_center_enmpty_points()...')
  
  #     1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
  board = [['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#1
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#2
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#3
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#4
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#5
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#6
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#7
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#8
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#9
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#a
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#b
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#c
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#d
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#e
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]#f
  empty_points = _get_center_enmpty_points(board)
  
  translate_points = [translate_move(move) for move in empty_points]
  #print(translate_points)
  assert translate_points == ['77','78','79','89','99','98','97','87', '66','67','68','69','6a','7a','8a','9a','aa','a9','a8','a7','a6','96','86','76']
  
  #     1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
  board = [['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#1
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#2
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#3
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#4
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#5
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#6
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#7
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#8
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#9
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#a
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#b
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#c
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#d
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#e
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]#f
  empty_points = _get_center_enmpty_points(board)
  
  translate_points = [translate_move(move) for move in empty_points]
  print(translate_points)
  assert '11' in translate_points
  
  #     1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
  board = [['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#1
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#2
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#3
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#4
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#5
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#6
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#7
       ['.','.','.','.','.','.','.','X','.','.','.','.','.','.','.'],#8
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#9
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#a
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#b
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#c
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#d
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#e
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]#f
  empty_points = _get_center_enmpty_points(board)
  
  translate_points = [translate_move(move) for move in empty_points]
  print(translate_points)
  assert '11' in translate_points
  
  print('ok')
  
def test_move_score():
  '''
  _move_score(board, move, color)
  #     1 2 3 4 5 6 7 8 9 a b c d e f
  board = [[. . . . . . . . . . . . . . .],#1
       [. . . . . . . . . . . . . . .],#2
       [. . . . . . . . . . . . . . .],#3
       [. . . . . . . . . . . . . . .],#4
       [. . . . . . . . . . . . . . .],#5
       [. . . . . . . . . . . . . . .],#6
       [. . . . . . . . . . . . . . .],#7
       [. . . . . . . . . . . . . . .],#8
       [. . . . . . . . . . . . . . .],#9
       [. . . . . . . . . . . . . . .],#a
       [. . . . . . . . . . . . . . .],#b
       [. . . . . . . . . . . . . . .],#c
       [. . . . . . . . . . . . . . .],#d
       [. . . . . . . . . . . . . . .],#e
       [. . . . . . . . . . . . . . .]]#f
       
  #     1 2 3 4 5 6 7 8 9 a b c d e f
  board = [[. . . . . . . . . . . . . . .],#1
       [. . . . . . . . . . . . . . .],#2
       [. . . . . . . . . . . . . . .],#3
       [. . . . . . . . . . . . . . .],#4
       [. . . . . . . . . X . . . . .],#5
       [. . . . . . X . . . . . . . .],#6
       [. . . . . O . . X O . . . . .],#7
       [. . . . . X X O X . . . . . .],#8
       [. . . . . X O X . . . . . . .],#9
       [. . . . . . . . . . X . . . .],#a
       [. . . X . . . . . . . . . . .],#b
       [. . X . . . . . . . . . . . .],#c
       [. O . . . . . . . . . . . . .],#d
       [. . . . . . . . . . . . . . .],#e
       [. . . . . . . . . . . . . . .]]#f
  '''
  print('Testing _move_score()...')
  
  #     1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
  board = [['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#1
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#2
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#3
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#4
       ['.','.','.','.','.','.','.','.','.','X','.','.','.','.','.'],#5
       ['.','.','.','.','.','.','X','.','.','.','.','.','.','.','.'],#6
       ['.','.','.','.','.','O','.','.','X','O','.','.','.','.','.'],#7
       ['.','.','.','.','.','X','X','O','X','.','.','.','.','.','.'],#8
       ['.','.','.','.','.','X','O','X','.','.','.','.','.','.','.'],#9
       ['.','.','.','.','.','.','.','.','.','.','X','.','.','.','.'],#a
       ['.','.','.','X','.','.','.','.','.','.','.','.','.','.','.'],#b
       ['.','.','X','.','.','.','.','.','.','.','.','.','.','.','.'],#c
       ['.','O','.','.','.','.','.','.','.','.','.','.','.','.','.'],#d
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#e
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]#f
  #[count, jump_count, block] # East, south, southeast, southwest #
  lianxin = _get_all_lianxin(board, [6,7], 'X')
  #print(lianxin)
  assert lianxin == [[2,[0,0],[True,False]],
            [1,[0,0],[True,False]],
            [3,[1,0],[False,False]],
            [3,[2,1],[True,False]]]
  # Dead one, alive one, dead two, alive two, dead three, alive three, dead four, alive four, dead five, alive five #
  scores = [   2,  10,  10,  100,  100, 1000, 1000, 10000,100000,100000]
  assert _move_score(board, [6,7], 'X') == 10 + 2 + (1000 + 10 + 200) + (1000 + 10 + 10 + 200 + 200)
  
  print('ok')
  
def test_get_all_lianxin():
  '''
  get_all_lianxin(board, move, color)
  #     1 2 3 4 5 6 7 8 9 a b c d e f
  board = [[. . . . . . . . . . . . . . .],#1
       [. . . . . . . . . . . . . . .],#2
       [. . . . . . . . . . . . . . .],#3
       [. . . . . . . . . . . . . . .],#4
       [. . . . . . . . . . . . . . .],#5
       [. . . . . . . . . . . . . . .],#6
       [. . . . . . . . . . . . . . .],#7
       [. . . . . . . . . . . . . . .],#8
       [. . . . . . . . . . . . . . .],#9
       [. . . . . . . . . . . . . . .],#a
       [. . . . . . . . . . . . . . .],#b
       [. . . . . . . . . . . . . . .],#c
       [. . . . . . . . . . . . . . .],#d
       [. . . . . . . . . . . . . . .],#e
       [. . . . . . . . . . . . . . .]]#f
       
  #     1 2 3 4 5 6 7 8 9 a b c d e f
  board = [[. . . . . . . . . . . . . . .],#1
       [. . . . . . . . . . . . . . .],#2
       [. . . . . . . . . . . . . . .],#3
       [. . . . . . . . . . . . . . .],#4
       [. . . . . . . . . X . . . . .],#5
       [. . . . . . X . . . . . . . .],#6
       [. . . . . O . . X O . . . . .],#7
       [. . . . . X X O X . . . . . .],#8
       [. . . . . X O X . . . . . . .],#9
       [. . . . . . . . . . X . . . .],#a
       [. . . X . . . . . . . . . . .],#b
       [. . X . . . . . . . . . . . .],#c
       [. O . . . . . . . . . . . . .],#d
       [. . . . . . . . . . . . . . .],#e
       [. . . . . . . . . . . . . . .]]#f
  '''
  print('Testing _get_all_lianxin()...')
  #     1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
  board = [['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#1
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#2
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#3
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#4
       ['.','.','.','.','.','.','.','.','.','X','.','.','.','.','.'],#5
       ['.','.','.','.','.','.','X','.','.','.','.','.','.','.','.'],#6
       ['.','.','.','.','.','O','.','.','X','O','.','.','.','.','.'],#7
       ['.','.','.','.','.','X','X','O','X','.','.','.','.','.','.'],#8
       ['.','.','.','.','.','X','O','X','.','.','.','.','.','.','.'],#9
       ['.','.','.','.','.','.','.','.','.','.','X','.','.','.','.'],#a
       ['.','.','.','X','.','.','.','.','.','.','.','.','.','.','.'],#b
       ['.','.','X','.','.','.','.','.','.','.','.','.','.','.','.'],#c
       ['.','O','.','.','.','.','.','.','.','.','.','.','.','.','.'],#d
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],#e
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]#f
  #[count, jump_count, block] # East, south, southeast, southwest #
  lianxin = _get_all_lianxin(board, [6,7], 'X')
  #print(lianxin)
  assert lianxin == [[2,[0,0],[True,False]],
            [1,[0,0],[True,False]],
            [3,[1,0],[False,False]],
            [3,[2,1],[True,False]]]
  
  #     1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
  board = [['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'], #1
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'], #2
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'], #3
       ['.','.','.','.','.','.','.','.','.','X','.','.','.','.','.'], #4
       ['.','.','.','.','.','.','X','.','.','.','.','.','.','.','.'], #5
       ['.','.','.','.','.','O','.','.','X','O','.','.','.','.','.'], #6
       ['.','.','.','.','.','X','X','O','X','.','.','.','.','.','.'], #7
       ['.','.','.','.','.','X','O','X','.','.','.','.','.','.','.'], #8
       ['.','.','.','.','.','.','.','.','.','.','X','.','.','.','.'], #9
       ['.','.','.','X','.','.','.','.','.','.','.','.','.','.','.'], #a
       ['.','.','X','.','.','.','.','.','.','.','.','.','.','.','.'], #b
       ['.','O','.','.','.','.','.','.','.','.','.','.','.','.','.'], #c
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'], #d
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'], #e
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']] #f
  #[count, jump_count, block] # East, south, southeast, southwest #
  lianxin = _get_all_lianxin(board, [5,7], 'X')
  #print(lianxin)
  assert lianxin == [[2,[0,0],[True,False]],
            [1,[0,0],[True,False]],
            [3,[1,0],[False,False]],
            [3,[2,1],[True,False]]]
  
  
  print('ok')
  
def test_check_board():
  '''
  
  '''
  print('Testing check_board()...')
  board = [['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]
  assert check_board(board, 'X') == False
  
  board = [['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['X','X','X','X','X','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]
  assert check_board(board, 'X') == True
  
  board = [['X','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['X','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['X','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['X','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['X','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]
  assert check_board(board, 'X') == True

  board = [['.','.','.','.','.','.','.','.','.','.','X','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','X','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','X','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','X','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','X'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]
  assert check_board(board, 'X') == True
  
  board = [['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['X','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','X','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','X','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','X','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','X','.','.','.','.','.','.','.','.','.','.']]
  assert check_board(board, 'X') == True
  
  board = [['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','X'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','X','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','X','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','X','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','X','.','.','.','.']]
  assert check_board(board, 'X') == True
  
  board = [['.','.','.','.','X','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','X','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','X','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','X','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['X','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'],
       ['.','.','.','.','.','.','.','.','.','.','.','.','.','.','.']]
  assert check_board(board, 'X') == True
  
  print('ok')
  
if __name__ == '__main__':
  main()
  #test_check_board()
  #test_get_all_lianxin()
  #test_move_score()
  #test_get_center_enmpty_points()

This is the whole content of this article.