Advertisement
Guest User

Untitled

a guest
Mar 19th, 2018
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.25 KB | None | 0 0
  1. # This class represents the state of a board at a point in time.
  2. # The class implements functions for basic manipulation of the board
  3. # such as playing moves and doing captures. The board is not aware whose turn it is.
  4. # The Baord class does *not* contain the move history or the prisoner counts,
  5. # by design. These things are contained in a Game object intead, which
  6. # uses the board class as a utility.
  7.  
  8. class Board(object):
  9.    
  10.     def __init__(self, width):
  11.         self.grid = list()
  12.         self.width = width
  13.         for i in range(0,self.width):
  14.             self.grid.append(list())
  15.             for j in range(0,self.width):
  16.                 self.grid[-1].append(".")
  17.  
  18.     def to_string(self):
  19.         s = ""
  20.         for i in range(0,self.size):
  21.             for j in range(0,self.size):
  22.                 s += self.board.grid[i][j]
  23.             s += "\n"
  24.         return s
  25.  
  26.     def clear(self):
  27.         for i in range(0,self.width):
  28.             for j in range(0,self.width):
  29.                 self.grid[i][j] = '.'
  30.  
  31.  
  32.     # Plays a move on the board and returns the intersections that had stones
  33.     # that were captures as a set (possibly empty). Raises an exception in case
  34.     # of an illegal move
  35.     def play_stone(self, row, column, color):
  36.         if self.grid[row][col] != '.':
  37.             raise Exception("Can't play on top of another stone")
  38.        
  39.         captured = self.get_captured_stones(row,col,color)
  40.        
  41.         # Try to place the stone
  42.         self.grid[row][col] = color
  43.  
  44.         if len(self.get_liberties(row,col)) == 0:
  45.             if len(captured) == 0:
  46.                 self.grid[row][col] = '.' # undo
  47.                 raise Exception("Suicide is not allowed")
  48.  
  49.         # Move is legal. Remove captured stones from the board
  50.         for pos in captured:
  51.             self.grid[pos[0]][pos[1]] = '.'
  52.  
  53.         return captured
  54.  
  55.     # Returns the list of coordinates of the intersections that are adjacent
  56.     # to the given position
  57.     def get_neighbors(self,row,col):
  58.         neighbors = set()
  59.         if row > 0: neighbors.add((row-1,col))
  60.         if row < self.width-1: neighbors.add((row+1,col))
  61.         if col > 0: neighbors.add((row,col-1))
  62.         if col < self.width-1: neighbors.add((row,col+1))  
  63.         return neighbors    
  64.        
  65.     # Returns the set of positions of stones which are captured by
  66.     # placing a stone to (row,col) of the given color
  67.     # Assumes the intersection at (row,col) is empty
  68.     def get_captured_stones(self,row,col,color):
  69.         assert(self.grid[row][col] == '.')
  70.         captured = set()
  71.         enemy = ('W' if color == 'B' else 'B')
  72.         for neighbor in self.get_neighbors(row,col):
  73.             r,c = neighbor[0], neighbor[1]
  74.             if self.grid[r][c] == enemy:
  75.                 liberties = self.get_liberties(r,c)
  76.                 if len(liberties) == 1: # Was in atari?
  77.                     captured = captured.union(self.get_group(r,c))
  78.         return captured
  79.        
  80.     # Returns the set of coordinates which correspond to the liberties of the group that
  81.     # contains the the position (row,col).
  82.     # If there is no stone at (row,col), returns an empty set
  83.     def get_liberties(self,row,col):
  84.         group = self.get_group(row,col)
  85.         liberties = set()
  86.         for pos in group:
  87.             for neighbor in self.get_neighbors(pos[0],pos[1]):
  88.                 if self.grid[neighbor[0]][neighbor[1]] == '.':
  89.                     liberties.add(neighbor)
  90.         return liberties
  91.        
  92.     # Returns set set of coordinates that correspond to the group that contains the given position
  93.     # If the given position is empty, returns an empty set
  94.     def get_group(self, row, col):
  95.    
  96.         if self.grid[row][col] == '.': return set()
  97.    
  98.         color = self.grid[row][col]
  99.         # Run a depth first search from the starting position
  100.         visited = set()
  101.         stack = [(row,col)] # DFS stack
  102.         while len(stack) != 0:
  103.             pos = stack.pop()
  104.             r, c = pos[0], pos[1]
  105.            
  106.             if pos in visited or self.grid[r][c] != color: continue
  107.             visited.add(pos)
  108.  
  109.             for neighbor in self.get_neighbors(r,c):
  110.                 stack.append(neighbor)
  111.        
  112.         return visited
  113.  
  114.     def score_game(self, komi):
  115.         black_score = 0
  116.         white_score = 0
  117.         stack = [] # DFS stack containing triples (row, column, color)
  118.         # In effect we have two DFS searches going on at the same time, one from black stones,
  119.         # one from white stones. I use only one stack to run both at the same time
  120.  
  121.         # Initialize the stack with the empty neighbors of all points
  122.         for r in range(0,self.size):
  123.             for c in range(0,self.size):
  124.                 if self.grid[r][c] == 'B': black_score += 1
  125.                 if self.grid[r][c] == 'W': white_score += 1
  126.                 for neighbor in self.get_neighbors(r,c):
  127.                     if self.grid[neighbor[0]][neighbor[1]] == 'B':
  128.                         stack.append((r,c,'B'))
  129.                     if self.grid[neighbor[0]][neighbor[1]] == 'W':
  130.                         stack.append((r,c,'W'))
  131.  
  132.         point_owners = list() # 2d array of dicts {'W': True/False, 'B': True/False}
  133.         for i in range(0,self.size):
  134.             point_owners.append(list())
  135.             for j in range(0,self.size):
  136.                 point_owners[-1].append({'W': False, 'B': False})    
  137.  
  138.         # Run a depth first search
  139.         visited = set() # Triples (row, column, color)
  140.  
  141.         while len(stack) != 0:
  142.             r,c,color = stack.pop()
  143.            
  144.             if self.grid[r][c] != '.' or (r,c,color) in visited: continue
  145.  
  146.             visited.add((r,c,color))
  147.             point_owners[r][c][color] = True
  148.  
  149.             for neighbor in self.get_neighbors(r,c):
  150.                 stack.append((neighbor[0], neighbor[1], color))
  151.  
  152.         for r in range(0,self.size):
  153.             for c in range(0,self.size):
  154.                 if point_owners[r][c]['W'] == True and point_owners[r][c]['B'] == True:
  155.                     continue # Dame
  156.                 if point_owners[r][c]['B'] == True: black_score += 1
  157.                 if point_owners[r][c]['W'] == True: white_score += 1
  158.  
  159. return black_score, white_score + komi, point_owners
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement