Pythonで、五目並べを作る

2024/09/10に公開

動作環境

Python:3.12.1 64bit
GoogleChrome:127.0.6533.120(Official Build)(64 ビット)
OS:Windows10
CPU:Core i5-1135G7
メモリ:16GB

すること

# 相手の盤面チェック
'''
相手が必ず勝つ場合、Trueを返す
相手が勝つケースがある場合、座標を返す
勝つケースがない場合、Falseを返す
'''
def check_enemy(board, N, player):
    enemy = "0"
    if player == "0":
        enemy = "1"

    # 相手の碁石が4つある場合をカウント
    horizontal_count = 0
    vertical_count = 0
    diagonal_count = 0
    win_case = []

    # 水平方向の碁石の数をチェック
    '''
    碁盤の水平方向で碁石が5個置ける範囲は、j(碁盤の横)がN - 5 + 1となる
    '''
    for i in range(N):
        for j in range(N - 4):
            row = board[i][j:j + 5]
            # 取得した5マスに相手の碁石が4つある、かつ空きマスがある場合
            if row.count(enemy) == 4 and "-1" in row:
                horizontal_count += 1
                # 座標をリストに保存しておく
                win_case.append(str(row.index("-1") + j + 1) + " " + str(i + 1))
                # 相手が必ず勝つケースのチェック
                # 4つ並んだ碁石の前後が空きマスの場合
                if (j > 0 and board[i][j - 1] == "-1" and row[-1] == "-1") or (j + 5 < N and board[i][j + 5] == "-1" and row[0] == "-1"):
                    return True

    # 垂直方向の碁石の数をチェック
    '''
    碁盤の垂直方向で碁石が5個置ける範囲は、i(碁盤の縦)がN - 5 + 1となる
    '''
    for i in range(N - 4):
        for j in range(N):
            column = [board[i + k][j] for k in range(5)]
            # 取得した5マスに相手の碁石が4つある、かつ空きマスがある場合
            if column.count(enemy) == 4 and "-1" in column:
                vertical_count += 1
                # 座標をリストに保存しておく
                win_case.append(str(j + 1) + " " + str(column.index("-1") + i + 1))
                # 相手が必ず勝つケースのチェック
                # 4つ並んだ碁石の前後が空きマスの場合
                if (i > 0 and board[i - 1][j] == "-1" and column[-1] == "-1") or (i + 5 < N and board[i + 5][j] == "-1" and column[0] == "-1"):
                    return True

    # 碁盤の左上から右下・右上から左下の斜め方向の碁石の数をチェックする
    '''
    碁盤の斜め方向で碁石が5個置けるスタート位置は、i(碁盤の縦)・j(碁盤の横)どちらもN - 4となる
    例えば、N = 8の場合、碁盤の左上・右上から4 × 4の範囲がチェックスタート範囲となる
    '''
    for i in range(N - 4):
        for j in range(N - 4):
            # 左上から右下方向に5マス取得する
            diagonal1 = [board[i + k][j + k] for k in range(5)]
            # 右上から左下方向に5マス取得する
            # Nがいかなる場合でも、横軸のスタートは左から5マス目となるため、j + 4となる
            diagonal2 = [board[i + k][j + 4 - k] for k in range(5)]
            # 取得した5マスに相手の碁石が4つある、かつ空きマスがある場合
            if diagonal1.count(enemy) == 4 and "-1" in diagonal1:
                diagonal_count += 1
                # 座標をリストに保存しておく
                win_case.append(str(diagonal1.index("-1") + j + 1) + " " + str(diagonal1.index("-1") + i + 1))
                # 相手が必ず勝つケースのチェック
                # 4つ並んだ碁石の前後が空きマスの場合
                if (i > 0 and j > 0 and board[i - 1][j - 1] == "-1" and diagonal1[-1] == "-1") or (i + 5 < N and j + 5 < N and board[i + 5][j + 5] == "-1" and diagonal1[0] == "-1"):
                    return True
            # 取得した5マスに相手の碁石が4つある、かつ空きマスがある場合
            if diagonal2.count(enemy) == 4 and "-1" in diagonal2:
                diagonal_count += 1
                # 座標をリストに保存しておく
                win_case.append(str(j + 1 + 4 - diagonal2.index("-1")) + " " + str(diagonal2.index("-1") + i + 1))
                # 相手が必ず勝つケースのチェック
                # 4つ並んだ碁石の前後が空きマスの場合
                if (i > 0 and j + 4 < N and board[i - 1][j + 4] == "-1" and diagonal2[-1] == "-1") or (i + 5 < N and j < N and board[i + 5][j] == "-1" and diagonal2[0] == "-1"):
                    return True

    # 相手が勝つケースが2つ以上ある場合
    if horizontal_count + vertical_count + diagonal_count > 1:
        win_case_tmp = set(win_case)
        # 相手が勝つケースが2種類以上の場合
        if len(win_case_tmp) > 1:
            return True
        # 相手が勝つケースが1種類の場合
        elif len(win_case_tmp) == 1:
            # 座標を返す
            return list(win_case_tmp)[0]
    # 相手が勝つケースが1つの場合
    elif horizontal_count + vertical_count + diagonal_count == 1:
        # 座標を返す
        return win_case[0]

    # 相手に勝つケースが無い場合
    return False


# プレイヤーの盤面チェック
'''
プレイヤーが勝つケースがある場合、座標を返す
勝つケースが無い場合、Falseを返す
'''
def check_player(board, N, player):
    # 水平方向の碁石の数をチェック(i=行数)
    for i in range(N):
        for j in range(N - 4):
            row = board[i][j:j + 5]
            # プレイヤーの碁石が4つある場合
            if row.count(player) == 4 and "-1" in row:
                # 座標を出力
                return str(row.index("-1") + j + 1) + " " + str(i + 1)
    
    # 垂直方向の碁石の数をチェック
    for i in range(N - 4):
        for j in range(N):
            column = [board[i + k][j] for k in range(5)]
            # プレイヤーの碁石が4つある場合
            if column.count(player) == 4 and "-1" in column:
                # 座標を出力
                return str(j + 1) + " " + str(column.index("-1") + i + 1)
                
    # 斜め方向の碁石の数をチェック
    for i in range(N - 4):
        for j in range(N - 4):
            diagonal1 = [board[i + k][j + k] for k in range(5)]
            diagonal2 = [board[i + k][j + 4 - k] for k in range(5)]
            if diagonal1.count(player) == 4 and "-1" in diagonal1:
                # 座標を出力
                return str(diagonal1.index("-1") + j + 1) + " " + str(diagonal1.index("-1") + i + 1)
            if diagonal2.count(player) == 4 and "-1" in diagonal2:
                # 座標を出力
                return str(j + 1 + 4 - diagonal2.index("-1")) + " " + str(diagonal2.index("-1") + i + 1)
    return False

# 盤面チェック
'''
盤面から空きマスを取得し、座標を返す
'''
def check_grid(board, N):
    for i in range(N):
        for j in range(N):
            grid = board[i][j]
            if grid == "-1":
                return str(j + 1) + " " + str(i + 1)


def main():
    input_list = input().split()
    N = int(input_list[0])
    player = input_list[1]

    board = []

    for _ in range(N):
        board.append(input().rstrip().split(' '))

    # 相手の状況をチェック
    enemy_win = check_enemy(board, N, str(player))
        
    # プレイヤーの状況をチェック
    player_win = check_player(board, N, str(player))
    
    # プレイヤーが勝つ場合
    if isinstance(player_win, str) == True and enemy_win == False:
        print(player_win)
    # プレイヤーも相手も勝つ場合
    elif isinstance(player_win, str) == True and isinstance(enemy_win, str) == True:
        print(player_win)
    # 相手が勝つ場合
    elif player_win == False and isinstance(enemy_win, str) == True:
        print(enemy_win)
    # プレイヤーが勝つかつ、相手が必ず勝つ場合
    elif isinstance(player_win, str) == True and enemy_win == True:
        print(player_win)
    # 相手が必ず勝つ場合
    elif player_win == False and enemy_win == True:
        print("LOSE")
    # ゲーム途中の場合
    elif player_win == False and enemy_win == False:
        grid = check_grid(board, N)
        print(grid)
    else:
        print("LOSE")

        
if __name__ == "__main__":
    main()

Discussion