def print_board(board, size=9):
    # Column letters A-J skipping I
    cols = 'ABCDEFGHJK'
    print('  ' + ' '.join(cols[:size]))
    for i in range(size):
        row_str = f"{size - i:2d} "
        for j in range(size):
            if board[i][j] == 0:
                row_str += '. '
            elif board[i][j] == 1:  # Black
                row_str += '● '
            else:  # White
                row_str += '○ '
        print(row_str.strip())

def get_neighbors(i, j, size=9):
    neighbors = []
    for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
        ni, nj = i + di, j + dj
        if 0 <= ni < size and 0 <= nj < size:
            neighbors.append((ni, nj))
    return neighbors

def get_group(board, i, j, size=9):
    """Get the group of connected stones of the same color starting from (i,j)"""
    color = board[i][j]
    if color == 0:
        return set(), set()
    
    group = set()
    liberties = set()
    stack = [(i, j)]
    visited = set()
    
    while stack:
        ci, cj = stack.pop()
        if (ci, cj) in visited:
            continue
        visited.add((ci, cj))
        group.add((ci, cj))
        
        for ni, nj in get_neighbors(ci, cj, size):
            if board[ni][nj] == 0:
                liberties.add((ni, nj))
            elif board[ni][nj] == color and (ni, nj) not in visited:
                stack.append((ni, nj))
    
    return group, liberties

def count_liberties(board, i, j, size=9):
    """Count liberties for the group containing (i,j)"""
    group, liberties = get_group(board, i, j, size)
    return len(liberties)

def check_capture(board, size=9):
    """Check for captured groups and return list of groups to remove"""
    captured = []
    visited = set()
    
    for i in range(size):
        for j in range(size):
            if board[i][j] != 0 and (i, j) not in visited:
                group, liberties = get_group(board, i, j, size)
                visited.update(group)
                if len(liberties) == 0:
                    captured.append(group)
    
    return captured

def place_stone(board, i, j, color, size=9):
    """Place a stone and handle captures. Returns True if move is valid, False otherwise"""
    if board[i][j] != 0:
        return False
    
    # Place the stone temporarily
    board[i][j] = color
    
    # Check for opponent captures
    opponent = 2 if color == 1 else 1
    captured_groups = check_capture(board, size)
    
    # Check if this move results in suicide (no liberties for own group and no captures)
    own_group, own_liberties = get_group(board, i, j, size)
    if len(own_liberties) == 0 and len(captured_groups) == 0:
        # Undo the move
        board[i][j] = 0
        return False
    
    # Remove captured opponent groups
    for group in captured_groups:
        for ci, cj in group:
            board[ci][cj] = 0
    
    return True

def parse_move(move_str, size=9):
    """Parse move string like 'E5' to (row, col) indices"""
    if move_str.lower() == 'pass':
        return 'pass'
    
    if len(move_str) < 2:
        return None
    
    col_char = move_str[0].upper()
    row_str = move_str[1:]
    
    # Column letters A-J skipping I
    cols = 'ABCDEFGHJK'
    if col_char not in cols:
        return None
    
    try:
        row = int(row_str)
    except ValueError:
        return None
    
    col_idx = cols.index(col_char)
    row_idx = size - row  # Convert 1-based row to 0-based index (1 -> 8, 9 -> 0)
    
    if row < 1 or row > size or col_idx < 0 or col_idx >= size:
        return None
    
    return row_idx, col_idx

def score_game(board, size=9):
    """Score using area scoring (stones on board + territory)"""
    # Simple area scoring: count stones on board
    black_stones = sum(1 for i in range(size) for j in range(size) if board[i][j] == 1)
    white_stones = sum(1 for i in range(size) for j in range(size) if board[i][j] == 2)
    
    # For simplicity, no territory calculation (real Go scoring is complex)
    # This is stones-only scoring, but area scoring typically includes territory
    # We'll use stones count as a simple proxy for area scoring
    return black_stones, white_stones

def play_go(size=9):
    # Initialize empty board (0 = empty, 1 = black, 2 = white)
    board = [[0 for _ in range(size)] for _ in range(size)]
    current_player = 1  # Black starts
    consecutive_passes = 0
    
    print("Welcome to 9x9 Go!")
    print("Black (●) plays first. Enter moves as column+row (e.g., E5) or 'pass'.")
    print("Column letters: A-H, J (no I). Row numbers: 1-9 (1 is bottom).")
    
    while consecutive_passes < 2:
        print_board(board, size)
        print(f"Player {'Black' if current_player == 1 else 'White'}'s turn")
        
        move_str = input("Enter move: ").strip()
        move = parse_move(move_str, size)
        
        if move == 'pass':
            consecutive_passes += 1
            current_player = 2 if current_player == 1 else 1
            continue
        
        if move is None:
            print("Invalid move format. Try again (e.g., E5 or pass).")
            continue
        
        i, j = move
        
        if place_stone(board, i, j, current_player, size):
            consecutive_passes = 0
            current_player = 2 if current_player == 1 else 1
        else:
            print("Invalid move. Try again.")
    
    print_board(board, size)
    black_score, white_score = score_game(board, size)
    
    print("\nGame Over!")
    print(f"Final Score:")
    print(f"Black: {black_score}")
    print(f"White: {white_score}")
    
    if black_score > white_score:
        print("Black wins!")
    elif white_score > black_score:
        print("White wins!")
    else:
        print("It's a tie!")

if __name__ == "__main__":
    play_go()
