def connect_lonely_people(player, board, distances, game_state): aims = [] moves = [] my_groups = [] for tile in board: if board[tile]["player"] == player: g = group(tile, board) if g not in my_groups: my_groups.append(g) for my_group in my_groups: libs = liberties(my_group[0], board) for l in libs: for n in board[l]["neighbours"]: for mg in my_groups: if n in mg: if mg != my_group: aims.append(l) if n in liberties(mg[0], board): if mg != my_group: aims.append(l) for i in aims: if board[i]["player"] == None and is_suicidal(player, i, board) == False: if is_ko == False or game_state["last_ko"] == False: good = False for n in board[i]["neighbours"]: a = is_alive(n, board) if a == False: good = True if good == True: moves.append(i) return moves
def is_ko(player, move, board): #default response is false, and if the move isn't a valid position then return false. response = False if move not in board: return response #play in the position and find the neighbouring groups for that position. if move in board: board[move]["player"] = player g = group(move, board) n_g = neighbouring_groups(move, board) #takens stores the number of pieces that have been captured by the input move takens = 0 #if the move is not part of a larger group (only solitary pieces can commit ko) then loop through neighbouring groups if len(g) == 1: for n in n_g: #if the neighbouring group is owned by the enemy then calculate it's liberties if board[n[0]]["player"] is not None: t = n[0] l = liberties(t, board) #if the piece has no liberties left then it will be captured so add 1 to takens if the group consists of only one piece, or 5 (an arbitrary number) if the group is larger than 1 if len(l) == 0: if len(n) == 1: takens = takens + 1 elif len(n) > 1: takens = takens + 5 #if only one piece has been taken (the second condition for ko) then set response to true. Undo the move and return response if takens == 1: response = True board[move]["player"] = None return response
def find_friends(board): groups = [] friends = [] #loop through the board, if the tile is not empty then add it's group to the list of groups, if not already in there for tile in board: if board[tile]["player"] is not None: g = group(tile, board) if g not in groups: groups.append(g) #loop through groups and find the player who own's them and a list of tiles that could be played to make the group "alive" if it isn't already for g in groups: player = board[g[0]]["player"] s = saviours(g[0], board) #if the group has only one saviour place then add that place to friends (if there are two or more then it is unnecessary to play in the spot because if attacked it can be saved by one of the other places) if len(s) == 1: friends.append(s[0]) #or if there are no saviour tiles then loop through the liberties of the group elif len(s) == 0: for tile in liberties(g[0], board): #pretend to play in the position and look for saviours then undo the move board[tile]["player"] = player t = saviours(g[0], board) board[tile]["player"] = None #if there are now two or more saviours then add the original position to friends if len(t) >= 2: friends.append(tile) return friends
def ladder(tile, player, board, distances, game_state): v = False #if the tile is unowned... if board[tile]["player"] is None: enemies = [] frees = 0 #loop through the tile's neighbours, if the neighbour is unowned then add 1 to frees for n in board[tile]["neighbours"]: if board[n]["player"] is None: frees += 1 #or if the neighbour is owned by the enemy then add the neighbour's position to the enemies lists elif board[n]["player"] != player: enemies.append(n) #if there is only 1 enemy then find the groups that neighbour on the enemy group if len(enemies) == 1: ng = neighbouring_groups(enemies[0], board) safe = True #loop through all the neighbouring groups, if the group is owned by the player and the group is in atari then the ladder is no longer safe for g in ng: if board[g[0]]["player"] == player: if is_in_atari(g, board) == True: safe = False #if the ladder is safe then calculate the liberties of the enemy group. If it only has 2 liberties and we have one less free than the number of neighbours that surround the original tile then return True if safe == True: libs = liberties(enemies[0], board) if len(libs) == 2: if frees + 1 == len(board[tile]["neighbours"]): v = True return v
def is_in_atari(group, board): #calculate the liberties of the group, if it's equal to 1 then return true, otherwise return false l = liberties(group[0], board) q = len(l) if q == 1: return True else: return False
def save_from_probable_death(tile, player, board, distances, game_state): v = False #if the tile is unoccupied then loop through all of it's neighbours if board[tile]["player"] == None: for n in board[tile]["neighbours"]: #if the neighbour is owned by me then calculate its liberties if board[n]["player"] == player: libs = liberties(n, board) #if there is only one liberty then pretend to play in the tile and calculate liberties again. if len(libs) == 1: board[tile]["player"] = player newlibs = liberties(n, board) #undo the move and if there are now more than 2 liberties then it is a good move board[tile]["player"] = None if len(newlibs) > 2: v = True return v
def is_suicidal(player, move, board): #default response is false. response = False #play in the position and calculate its liberties board[move]["player"] = player l = liberties(move, board) #if it has no liberties then set the response to true if len(l) == 0: response = True #but loop through neighbouring groups n_g = neighbouring_groups(move, board) for g in n_g: g_l = liberties(g[0], board) #and if a group has 0 liberties then it would be captured so the move is legal and set response to true if len(g_l) == 0: response = False #undo the move board[move]["player"] = None return response
def capture(tile, player, board, distances, game_state): v = False if board[tile]["player"] == None: x = is_eye_candidate(tile, board) if x is not None: if x["owner"] == player: return False for n in board[tile]["neighbours"]: if board[n]["player"] is not None and board[n]["player"] != player: l = liberties(n, board) if len(l) == 1: v = True return v
def saviours(tile, board): player = board[tile]["player"] saviours = [] if player == None: return [] else: first = is_alive(tile, board) if first == True: return [] if first == False: libs = liberties(tile, board) for l in libs: board[l]["player"] = player second = is_alive(tile, board) board[l]["player"] = None if second == True: saviours.append(l) return saviours
def check_captures(t, board, capture_points): #find all neighbouring groups and the player who owns the input piece n_g = neighbouring_groups(t, board) player = board[t]["player"] #loop through all neighbouring groups and find their player. for h in n_g: j = h[0] p = board[j]["player"] #if the groups are owned by a player then they must be owned by the enemy player (as if they were owned by the same player then it would be part of the original group). Calculate liberties of enemy group if p is not None: l = liberties(j, board) q = len(l) #if the group has no liberties then loop through all of it's peices and remove them, adding capture points. if q == 0: for i in h: board[i]["player"] = None capture_points[player] = capture_points[player] + 1 return board
def save_from_certain_death(player, board, distances, game_state): moves = [] my_groups = [] for tile in board: if board[tile]["player"] == player: g = group(tile, board) if g not in my_groups: my_groups.append(g) for my_group in my_groups: if is_alive(my_group[0], board) == False: libs = liberties(my_group[0], board) for l in libs: board[l]["player"] = player if is_alive(my_group[0], board) == True: moves.append(l) board[l]["player"] = None for n in board[l]["neighbours"]: if board[n]["player"] == None: board[n]["player"] = player if is_alive(my_group[0], board) == True: moves.append(n) board[n]["player"] = None return moves
def play(player,board): #this is a territorial player my_groups=[] enemy_groups=[] my_territory=[] enemy_territory=[] loosely_mine=[] loosely_enemy=[] neutral_space=[] allowed_moves=[] stupid_moves=[] fight_points=[] distances=distances_from_edge(board) #work out what's what for tile in board: if board[tile]["player"]==player: g=group(tile,board) if g not in my_groups: my_groups.append(g) elif board[tile]["player"] is None: if is_ko(player, tile, board)==False or game_state["last_ko"]==False: if is_suicidal(player, tile, board)==False: allowed_moves.append(tile) sort_of_owner=loosely_territory(tile,board) if sort_of_owner==player: loosely_mine.append(tile) elif sort_of_owner=="Neutral": neutral_space.append(tile) elif sort_of_owner=="Nobody": fight_points.append(tile) else: loosely_enemy.append(tile) actual_owner=territory(tile,board) if actual_owner==player: my_territory.append(tile) elif actual_owner=="Neutral": pi=3.14 else: enemy_territory.append(tile) else: h=group(tile,board) if h not in enemy_groups: enemy_groups.append(h) #forget about stuff inside other people's eyes for enemy_group in enemy_groups: rep=enemy_group[0] libs=liberties(rep,board) is_deaded=False eyeness=is_eye_candidate(libs[0],board) if eyeness==None: break else: if eyeness["owner"]==player: enemy_groups.remove(enemy_group) for l in eyeness["group"]: if l in allowed_moves: stupid_moves.append(l) if l in fight_points: fight_points.remove(l) for my_group in my_groups: rep=my_group[0] libs=liberties(rep,board) is_deaded=False eyeness=is_eye_candidate(libs[0],board) if eyeness==None: break else: if eyeness["owner"]!=player: my_groups.remove(my_group) for l in eyeness["group"]: if l in allowed_moves: stupid_moves.append(l) if l in fight_points: fight_points.remove(l) #1: if possible, make a non-alive group of mine be an alive group #2: make a nearly_alive group of the enemy's be a deaded group #3: seal off some loosely territory into proper territory (multiple seal points??) #4: claim some new loosely territory close-ish to the edge (row 3 or 4) #We do these in reverse order so that more important things overwrite the move variable move="pass" #So without further ado: Number 4: break_new_ground=[] for i in allowed_moves: if i in distances[2] or (i in distances[3] and i not in distances[5]): if i in neutral_space: break_new_ground.append(i) #Cool. Now let's try Number 3, securing loose territory: fight_moves=[] for i in fight_points: if i in allowed_moves: fight_moves.append(i) #Before we do that, let's kill dangerous people, 2.5: saviours=[] for my_group in my_groups: a=is_in_atari(my_group,board) if a==True: n_g=neighbouring_groups(my_group[0],board) for nnn in n_g: b=is_in_atari(nnn,board) if b==True and nnn[0] in allowed_moves: saviours.append(liberties(nnn[0],board)[0]) feedback="I'm not doing anything" if len(fight_moves)>0: move=random.choice(fight_moves) feedback="I'm fighting" if len(break_new_ground)>0: move=random.choice(break_new_ground) feedback="I'm breaking new ground" if len(saviours)>0: move=random.choice(saviours) feedback="I'm saving people" #print(feedback) return move
def play_game(player1, player2, graphics=True): #make a board and set all the default values board = make_a_board() game_state = { "in_progress": True, "last_pass": False, "last_ko": False, "capture points": { "Black": 0, "White": 0 }, "moves_made": 0, "history": [] } x = "pass" y = "pass" #if drawing graphics then remove all the current screen drawings and redraw the screen in size 9x9 if graphics == True: delete() setupDrawing(9) #while the game is still in progress... while game_state["in_progress"] == True: #take a move from player1, if it's pass then set last_pass to true and if the previous move was a pass as well then end the game x = player1("Black", board, game_state) if x == "pass": print("black passed") if game_state["last_pass"] == True: game_state["in_progress"] = False print("game over") game_state["last_pass"] = True #if x is not a move that exists on the board then pass instead elif x not in board: print("Black was really really stupid") game_state["last_pass"] = True #if x is already occupied then pass instead elif x in board and board[x]["player"] != None: print("Black was Stupid") game_state["last_pass"] = True #otherwise so long as the move is not pass and the tile is unowned then play there else: if x != "pass": game_state["last_pass"] = False if board[x]["player"] is None: board[x]["player"] = "Black" #check if any captures have happened, and check if the new board state is ko or not board = check_captures(x, board, game_state["capture points"]) k = is_ko(board, game_state["history"]) #if the move is ko then return the board to it's previous state and set last_pass to true if k == True: board = unstring(board, game_state["history"][-1]) game_state["last_pass"] = True print("Black attempted ko") #calculate the liberties of the group containing the piece that was just played in l = liberties(x, board) q = len(l) #if the piece has no liberties then undo the move and set last pass to true if q == 0: #print ("Black was suicidal") board[x]["player"] = None game_state["last_pass"] = True #add one to moves made (even pass counts as a move in this case) and add the hash of board state to history game_state["moves_made"] = game_state["moves_made"] + 1 game_state["history"].append(stringy(board)) #if graphics is true then draw the new board and then check if game is still in progress if graphics == True: update(board) if game_state["in_progress"] == True: #take a move from player1, if it's pass then set last_pass to true and if the previous move was a pass as well then end the game y = player2("White", board, game_state) if y == "pass": print("white passed") if game_state["last_pass"] == True: game_state["in_progress"] = False print("game over") game_state["last_pass"] = True #if y is not a move that exists on the board then pass instead elif y not in board: print("White was really really stupid") game_state["last_pass"] = True #if y is already occupied then pass instead elif y in board and board[y]["player"] != None: print("White was Stupid") game_state["last_pass"] = True #otherwise so long as the move is not pass and the tile is unowned then play there else: if y != "pass": game_state["last_pass"] = False if board[y]["player"] is None: board[y]["player"] = "White" #check if any captures have happened, and check if the new board state is ko or not board = check_captures(y, board, game_state["capture points"]) k = is_ko(board, game_state["history"]) #if the move is ko then return the board to it's previous state and set last_pass to true if k == True: board = unstring(board, game_state["history"][-1]) game_state["last_pass"] = True print("Black attempted ko") #calculate the liberties of the group containing the piece that was just played in l = liberties(y, board) q = len(l) #if the piece has no liberties then undo the move and set last pass to true if q == 0: #print ("Black was suicidal") board[y]["player"] = None game_state["last_pass"] = True #add one to moves made (even pass counts as a move in this case) game_state["moves_made"] = game_state["moves_made"] + 1 game_state["history"].append(stringy(board)) #if graphics is true then draw the new board and then check if game is still in progress if graphics == True: update(board) #at the end of the game score the board and then return this dictionary. points = score(board, game_state["capture points"], { "Black": 0, "White": 5.5 }) return points
def play(player, board, game_state): #find how far each tile is from the end of the board distances = greatest_distance(board) #patterns is the list of functiosn (declared below) that return true or false when given a move, according to certain criteria. These are in priority order. patterns = [ capture, save_from_probable_death, ladder, invade_large_empty_space, seal_off_territory, seal_the_edges, sneak ] #default move is pass, allowed moves stores all moves that aren't illegal and decisions is a dictionary mapping from pattern to movs that the patern wants to make move = "pass" allowed_moves = [] decisions = {} #friends is a list of tiles that are essential to the life of a group. f is the list of friend moves friends = find_friends(board) f = [] #loop through friends, if any of the moves are allowed then add them to f for i in friends: if is_allowed(i, board, player, game_state) == True: f.append(i) #if there are any moves in f, then pick a random f to return (because friends is the most important patern and is run across the entire board if len(f) > 0: return random.choice(f) #loop through the board, if the move is allowed (not occupied and not suicidal) and is not ko then pretend to play there for tile in board: if board[tile]["player"] == None and is_suicidal(player, tile, board) == False: if check_ko(player, tile, board, game_state) == False: board[tile]["player"] = player #check whether the group is in atari after the move a = is_in_atari(group(tile, board), board) b = False #loop through the board and if the move makes any captures then set b = True for n in board[tile]["neighbours"]: if board[n]["player"] is not None and board[n][ "player"] != player: l = liberties(n, board) if len(l) == 0: b = True #if we are not putting ourselves in atari or we make captures despite this then add the tile to allowed moves if a == False or b == True: allowed_moves.append(tile) #undo the hypothetical move board[tile]["player"] = None #loop through patterns, adding a new empty list for each pattern (these will store the moves that this pattern wants to make) for p in patterns: decisions[p] = [] #loop through all allowed moves and all patterns. for tile in allowed_moves: for pat in patterns: #call the pattern's function on the tile and if the pattern wants to play there, add it to it's corresponding decisions list verdict = pat(tile, player, board, distances, game_state) if verdict == True: decisions[pat].append(tile) #loop through patterns again and if there are any moves for that pattern then choose a random one of them to return for i in patterns: if len(decisions[i]) > 0: move = random.choice(decisions[i]) return move #this will return pass if none of the patterns decide on any moves return move