Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bonus exercise (AtariGo) #33

Open
essepuntato opened this issue Dec 1, 2020 · 2 comments
Open

Bonus exercise (AtariGo) #33

essepuntato opened this issue Dec 1, 2020 · 2 comments
Labels

Comments

@essepuntato
Copy link
Contributor

Implement the function below in Python, that takes in input the colour of the player who has to play the turn (parameter colour), the sets of coordinates (i.e. sets of tuples) of all the black stones (parameter black) and white stones (parameter white) already positioned on the board, and returns the x, y coordinate (a tuple) of a free intersection where to place a new colour stone. The coordinates of the various positions of the board are those ones defined in "the board" as in the AlphaGo material available online.

def place_stone(colour, black, white):
    # study the board and calculate the
    # best place where to position the stone
    return x, y # the coordinates of the new stone

Additional information is available at https://doi.org/10.5281/zenodo.2204836.

@AlessandroBertozzi
Copy link

I don't really understand how to teach the machine to get the best solution. Nevertheless, my function return randomly one of the possibile position near to the opposite colour. The logic is to close the enemy stone.

import random


def place_stone(colour, black, white):
    if colour == "black":
        place = random.choice(possible_move("black", black, white))
        return place
    elif colour == "white":
        place = random.choice(possible_move("white", black, white))
        return place


def possible_move(colour, black, white): # check the free position near the opposite color
    if colour == "black":
        movement_list = []
        for position in white:
            list_single_move = single_stone(position, black, white)
            movement_list.extend(list_single_move)
        return movement_list
    elif colour == "white":
        movement_list = []
        for position in black:
            list_single_move = single_stone(position, black, white)
            movement_list.extend(list_single_move)
        return movement_list


def single_stone(position, black, white): # check the free position near the stone and return a list of free position
    list_movement = []
    if (position[0] - 1, position[1]) not in black and (position[0] - 1, position[1]) not in white and position[0] - 1 <= 6:
        list_movement.append((position[0] - 1, position[1]))
    if (position[0] + 1, position[1]) not in black and (position[0] + 1, position[1]) not in white and position[0] + 1 <= 6:
        list_movement.append((position[0] + 1, position[1]))
    if (position[0], position[1] - 1) not in black and (position[0], position[1] - 1) not in white and position[1] - 1 <= 6:
        list_movement.append((position[0], position[1] - 1))
    if (position[0], position[1] + 1) not in black and (position[0], position[1] + 1) not in white and position[1] + 1 <= 6:
        list_movement.append((position[0], position[1] + 1))
    return list_movement


print(place_stone("white", {(1, 5), (1, 4), (2, 6)}, {(2, 5), (2, 4)}))

@diegochillo
Copy link

diegochillo commented Dec 2, 2020

This function classifies all the free points on the board in these categories:

  • positions that expand current color's liberties;
  • positions that limit opponent's liberties;
  • positions that do both things;
  • neutral positions (others).

Then, to select the right move to return, it privileges:

  1. The first position that limits opponents and expand the current color, if one is found;
  2. Else, the first position that expands current color's liberties, if one is found;
  3. Else, the first position that limits opponent's liberties, if one is found;
  4. Else, a position that is not adjacent to anything.
    Otherwise there are no free positions to return.

Not a great strategy, but a lot of thoughts about liberties and groups and others and what is better to pursue.

def place_stone(color,black,white):
  
  if len(black & white)==0:     # Check that black and white sets don't have common elements
  
    range_x=range(7)            # Maximum number of columns
    range_y=range(7)            # Maximum number of rows
    occupied=black.union(white) # Defines a set with all the occupied cells regardless of the color
    
    expanding=list()  # Prepares the list of moves that expand the liberties
    limiting=list()   # Prepares the list of moves that limit opponent's liberties 
    others=list()     # Prepres the list of all other positions
    
    # Gets rid of the black/white dialectics and switches to current/opponent
    if color=="white":
      current=white
      opponent=black
    else:
      current=black
      opponent=white
    
    # Cycles all the positions of the board:
    for x in range_x:
      for y in range_y:
        
        if ((x,y) not in occupied): # if position is empty
          
          if check_neighbors(x,y,opponent): # if position limits opponent liberties
            limiting.append((x,y))
          if check_neighbors(x,y,current):  # if position expands current color liberties
            expanding.append((x,y))
          if ((x,y) not in limiting) and ((x,y) not in expanding): # if position has no neighbor stones
            others.append((x,y))
            
    bestpos=set(limiting) & set(expanding) # Finds the positons limiting the opponent and expanding the current group
    
    if len(bestpos)>0:
      return(list(bestpos)[0]) # Returns the first result that expand your liberty and limits the opponent
          
    if len(limiting)>0:
      return(limiting[0])      # Else returns the first result that limits the opponent
              
    if len(expanding)>0:
      return expanding[0]      # Else returns the first result that expands your liberties
            
    if len(others)>0:
      return (others[0])       # Else returns the first free position 
          
    return "No position available"  # Else no move can be done
    
  else:   
    return "Each point admits only one stone!"

# This ancillary function only returns if x,y position is adjacent to something in checking set
def check_neighbors(x,y,checking):
  return ((x-1,y) in checking) or ((x+1,y) in checking) or ((x,y-1) in checking) or ((x,y+1) in checking)


# TEST CASES  
  
color="white"
black={(2,2),(2,3),(2,4),(2,5)}
white={(2,1),(3,2),(3,3)}
print (place_stone(color,black,white)) # Answers (3,4)

color="black"
black={(4,3),(4,4),(4,5),(5,3),(5,5),(6,3),(6,5)}
white={(5,4)}
print (place_stone(color,black,white)) # Answers (6,4)... My boy!

color="black"
black={(4,3),(4,4),(4,5),(5,3),(5,5),(6,3),(6,5)}
white={(4,3)}
print (place_stone(color,black,white)) # Returns an error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants