ポンコツ夫婦のGame Trial Log Vol.1

Pythonでゲーム作成

カテゴリーの変更から

カテゴリー変更の説明がフォーマット化している点、ご容赦ください。今回は脱コロナをイメージしての変更ではなく、ゲームに関わる事柄を扱う新しい独立したカテゴリーとして「Game Trial Log」を立ち上げます。

Redkabagonはこれまで通り、G5Entertainmentの提供するアイテム探し&マッチ3を行い、その様子を録画・公開します。筆者Dr.takodemousは新たにゲームアプリを作成し、アプリのコード紹介と動作状況の録画公開に挑戦します

ゲームアプリ作成はGeminiのコーディングサポートを受けますが、時間がかかるため更新頻度は遅くなります。気長にお待ちください。また、機材に関わる内容は「The Gear」とクロスオーバーしますので、ゲームに興味はないけど機材には興味があるという方々のご来場もお待ちしております。

経歴の詳細は割愛しますが、2012年7月にサーティファイWEBクリエイター能力認定試験の上級(合格点65点に対し66点というブービー賞!)を45歳で取得。現在に至るまで、WEB業界で生計を立てられているとは言い難い状況です。他にIllustrator、Photoshop、Javascript、今では使われなくなったflashをかいつまんだ程度に理解している状況です。

Pythonのコード作成は未経験以前の無知。という状況でゲームを作成します。そこでR60世代に向けて是非ともメッセージしたい事があります。AI生成技術は産業革命に匹敵すると言われていますが、(筆者は産業革命を経験していないので匹敵するかどうかは不明!)AIは経験上、未知の世界へ飛び込むことに大いに役立ちます。R60世代の皆様も、一緒に飛び込みましょう!

【動画】AIと共同制作したオセロ、Dr.takodemousが勝利! Geminiと共同制作したオセロの完成版を、筆者がAI相手に打ち勝った動画です。ほぼ強制的に設置されたヒント表示を使用せず勝利したのは、ある程度のゲームのコツを知っていたからです。(コツは本ブログの趣旨と異なるため省略します。)

伝えたいのは、無知なレベルであってもAIを駆使すると、コーダーと言えるレベルのプログラムがつくれるという事です。ゲームやプログラムに興味がある方は是非参考にしてください。

プロンプトの参考になるように、最初に作成したオセロのコードから完成版までの道のりをフォルダに添付しておきます。プログラムに興味のある方は最初から順番に、ゲームに興味のある方は完全版を試してください。全てPythonのコードとなります。

redkabagonは今まで通り、G5Entertainmentの提供するアイテム探し&マッチ3をゲームしてもらい、その状況を録画そしてYou Tubeに投稿&本ブログにリンクする流れを行ってもらっています。

CapCutでの動画編集は現在のチャンネル登録分で最終となります。今後はCyberlinkの提供するPowerDirector 365を使用して作成していきます。PowerDirector 365についても、機材説明の機会に「The Gear」カテゴリーで紹介したいと思います。

映像作成に興味のある方は、是非ご来場ください。

pyramid of mahjong

前回まで五回にわたって記載してきたこの題目を、総括として終了したいと思います。コロナ禍が与えた影響は心身ともに、無意識下にダメージを与えていたと筆者は感じます。

漠然とした日々の不安や拠り所のない希望など、記載内容は意図的であれ無意識であれ、ネガティブな内容であった気がします。その当時はその状態が仕方ないとしても、現在の状況は自己選択が出来る状態です。

総じてカテゴリーの変更を行った後は、楽しみながら老いていくを実践しているようなものです。つまり最近のブログの内容は、R60のポンコツ夫婦が楽しみながら老いていく姿を紹介しているのです。やたら、参考にしてくださいというメッセージが多発するのは、自己選択の結果なような気がします。

やりがいや生きがいは、認知機能や肉体機能を維持するのに役立つと言われています。真意は不明といえばそれまでなのですが、信じてメッセージしていきたいと思います。

PR TIMESさんのサイトより”認知症予防の脳トレWebゲーム『Dr.脳トレ』をリリース。”のページを引用しています

今回からは、無知なAIコーダー(筆者)VSプロのコーダーの決戦の意味合いも含みます。脳科学には触れたことすらない筆者が「脳機能を鍛える」とプロンプトに指示して生まれたコードが、どこまでプロに肉薄できるか、自身でもウキウキしています。

第四回目も海馬を鍛えるシリーズになります。先ずはゲストモードで試してみて、効果を感じた場合アカウントを作成する感じで手軽に始めることが出来ます。このコナーのゲームは記憶の形成、空間学習、感情の制御を鍛えるというゲームとなっています。筆者も同類のアプリの作成にチャレンジするつもりです。

動画に登場しているバージョンは**プロンプト No.6です。DEPTH=4という設定で、レベルは中級者以上となっています。実行するには、Pythonを入手する必要があります。入手は自己責任ですが、世界中で使用されているプログラムを実行するためには必需品です。入手方法や設定方法などのリンクを貼っておきます。

どうぞGeminiのプロンプトの世界に、飛び込んでみてください。

プロンプトno1(外殻の設定と初期動作:相互手動)
# othello.py

# 1. ゲームボードの初期化
def create_board():
    board = []
    for i in range(8):
        row = [' '] * 8
        board.append(row)
    
    board[3][3] = 'W'
    board[3][4] = 'B'
    board[4][3] = 'B'
    board[4][4] = 'W'
    return board

# 2. ボードの表示
def print_board(board):
    print('  a b c d e f g h')
    print(' +-+-+-+-+-+-+-+-+')
    for i in range(8):
        print(f'{i+1}|', end='')
        for j in range(8):
            print(f'{board[i][j]}|', end='')
        print(f' {i+1}')
    print(' +-+-+-+-+-+-+-+-+')
    print('  a b c d e f g h')

# 3. 駒を置ける場所の判定と駒の反転
def is_valid_move(board, row, col, player, opponent):
    if not (0 <= row < 8 and 0 <= col < 8) or board[row][col] != ' ':
        return False

    directions = [
        (-1, -1), (-1, 0), (-1, 1),
        (0, -1),          (0, 1),
        (1, -1),  (1, 0),  (1, 1)
    ]
    
    found_flips = []

    for dr, dc in directions:
        r, c = row + dr, col + dc
        path = []
        while 0 <= r < 8 and 0 <= c < 8 and board[r][c] == opponent:
            path.append((r, c))
            r, c = r + dr, c + dc
        
        if 0 <= r < 8 and 0 <= c < 8 and board[r][c] == player and path:
            found_flips.extend(path)
            
    return found_flips

def flip_pieces(board, pieces_to_flip, player):
    for r, c in pieces_to_flip:
        board[r][c] = player

# 4. メインゲームループ
def main():
    board = create_board()
    player_turn = 'B'
    opponent_turn = 'W'

    while True:
        print_board(board)
        print(f'現在のターン: {player_turn}')

        try:
            move_str = input('駒を置く場所を入力してください (例: d3): ')
            col_char = move_str[0].lower()
            row_char = move_str[1:]
            
            # 入力を座標に変換
            col = 'abcdefgh'.index(col_char)
            row = int(row_char) - 1
            
            if not (0 <= row < 8 and 0 <= col < 8):
                print('無効な入力です。')
                continue
            
            # 有効な手か判定
            pieces_to_flip = is_valid_move(board, row, col, player_turn, opponent_turn)
            
            if pieces_to_flip:
                board[row][col] = player_turn
                flip_pieces(board, pieces_to_flip, player_turn)
                
                # ターンを交代
                player_turn, opponent_turn = opponent_turn, player_turn
            else:
                print('その場所には置けません。有効な手を打ってください。')
        
        except (ValueError, IndexError):
            print('無効な入力です。例: d3 のように入力してください。')

# プログラムの実行
if __name__ == '__main__':
    main()
プロンプトno2(GUIの設定1と初期動作:相互手動)
# 1. ゲームボードの初期化
# 盤面を表すための定数を定義します
# '・' : 空, '⚫' : 黒, '⚪' : 白
EMPTY = '・'
BLACK = '⚫'
WHITE = '⚪'

def create_board():
    """
    8x8の空の盤面を作成し、初期配置の石を配置します。
    """
    board = []
    for _ in range(8):
        row = [EMPTY] * 8
        board.append(row)
    
    board[3][3] = WHITE
    board[3][4] = BLACK
    board[4][3] = BLACK
    board[4][4] = WHITE
    return board

# 2. ボードの表示
def print_board(board):
    """
    現在の盤面をきれいに表示します。
    """
    # 列の表記を修正
    print('    a    b    c    d    e    f    g    h')
    # 罫線の表示
    print('  +---+---+---+---+---+---+---+---+---+---')
    for i in range(8):
        # 行の表示と升目の調整
        row_str = f'{i+1} |'
        for j in range(8):
            row_str += f' {board[i][j]} |'
        print(row_str)
        print('  +---+---+---+---+---+---+---+---+---+---')
    
# 3. 駒を置ける場所の判定と駒の反転
def is_valid_move(board, row, col, player, opponent):
    """
    指定された位置に石を置くことができるか判定し、
    ひっくり返せる石のリストを返します。
    """
    if not (0 <= row < 8 and 0 <= col < 8) or board[row][col] != EMPTY:
        return None

    # 8つの方向を定義 (行の変化, 列の変化)
    directions = [
        (-1, -1), (-1, 0), (-1, 1),
        (0, -1),            (0, 1),
        (1, -1),  (1, 0),  (1, 1)
    ]
    
    pieces_to_flip = []

    for dr, dc in directions:
        r, c = row + dr, col + dc
        path = []
        while 0 <= r < 8 and 0 <= c < 8 and board[r][c] == opponent:
            path.append((r, c))
            r, c = r + dr, c + dc
        
        # 挟み込んでいるかチェック
        if 0 <= r < 8 and 0 <= c < 8 and board[r][c] == player and path:
            pieces_to_flip.extend(path)
            
    return pieces_to_flip if pieces_to_flip else None

def flip_pieces(board, pieces_to_flip, player):
    """
    ひっくり返す石のリストを、指定されたプレイヤーの石に変換します。
    """
    for r, c in pieces_to_flip:
        board[r][c] = player

def get_valid_moves(board, player, opponent):
    """
    現在のプレイヤーが石を置けるすべての場所(有効な手)のリストを返します。
    """
    valid_moves = []
    for r in range(8):
        for c in range(8):
            if board[r][c] == EMPTY:
                if is_valid_move(board, r, c, player, opponent):
                    valid_moves.append((r, c))
    return valid_moves

def count_pieces(board):
    """
    盤面上の石の数を数え、勝敗を表示します。
    """
    black_count = 0
    white_count = 0
    for r in range(8):
        for c in range(8):
            if board[r][c] == BLACK:
                black_count += 1
            elif board[r][c] == WHITE:
                white_count += 1
    
    print(f"最終結果:黒 = {black_count}、白 = {white_count}")
    
    if black_count > white_count:
        print("黒の勝ちです!")
    elif white_count > black_count:
        print("白の勝ちです!")
    else:
        print("引き分けです。")

# 4. メインゲームループ
def main():
    """
    ゲームのメイン処理を実行します。
    """
    board = create_board()
    player_turn = BLACK
    opponent_turn = WHITE
    pass_count = 0  # 連続でパスした回数をカウント

    while True:
        print_board(board)
        
        valid_moves = get_valid_moves(board, player_turn, opponent_turn)
        
        if not valid_moves:
            pass_count += 1
            print(f'現在のターン: {"黒" if player_turn == BLACK else "白"}')
            print("置ける場所がありません。パスします。")
            
            if pass_count == 2:
                print("両プレイヤーがパスしました。ゲームを終了します。")
                break
            
            player_turn, opponent_turn = opponent_turn, player_turn
            continue
        else:
            pass_count = 0
            
        print(f'現在のターン: {"黒" if player_turn == BLACK else "白"}')
        
        try:
            move_str = input('駒を置く場所を入力してください (例: d3): ')
            
            if move_str.lower() == 'q':
                print("ゲームを終了します。")
                break

            col_char = move_str[0].lower()
            row_char = move_str[1:]
            
            col = 'abcdefgh'.index(col_char)
            row = int(row_char) - 1
            
            if (row, col) not in valid_moves:
                print('その場所には置けません。有効な手を打ってください。')
                continue
            
            pieces_to_flip = is_valid_move(board, row, col, player_turn, opponent_turn)
            board[row][col] = player_turn
            flip_pieces(board, pieces_to_flip, player_turn)
            
            player_turn, opponent_turn = opponent_turn, player_turn
        
        except (ValueError, IndexError):
            print('無効な入力です。例: d3 のように入力してください。')
    
    print("ゲーム終了!")
    count_pieces(board)
    
    input("結果を確認後、何かキーを押して終了してください...")

# プログラムの実行
if __name__ == '__main__':
    main()
プロンプトno3(GUIの設定2と初期動作:相互手動:盤面ほぼ完成)
import tkinter as tk
from tkinter import messagebox

# 盤面を表すための定数
EMPTY = '・'
BLACK = '⚫'
WHITE = '⚪'

# ウィンドウとキャンバスのサイズ
BOARD_SIZE = 400
CELL_SIZE = BOARD_SIZE // 8

# グローバル変数としてボードの状態を保持
game_board = None
canvas = None
current_player = BLACK
pass_count = 0

def create_board():
    """
    8x8の空の盤面を作成し、初期配置の石を配置します。
    """
    board = []
    for _ in range(8):
        row = [EMPTY] * 8
        board.append(row)
    
    board[3][3] = WHITE
    board[3][4] = BLACK
    board[4][3] = BLACK
    board[4][4] = WHITE
    return board

def is_valid_move(board, row, col, player, opponent):
    """
    指定された位置に石を置くことができるか判定し、
    ひっくり返せる石のリストを返します。
    """
    if not (0 <= row < 8 and 0 <= col < 8) or board[row][col] != EMPTY:
        return None

    directions = [
        (-1, -1), (-1, 0), (-1, 1),
        (0, -1),            (0, 1),
        (1, -1),  (1, 0),  (1, 1)
    ]
    
    pieces_to_flip = []

    for dr, dc in directions:
        r, c = row + dr, col + dc
        path = []
        while 0 <= r < 8 and 0 <= c < 8 and board[r][c] == opponent:
            path.append((r, c))
            r, c = r + dr, c + dc
        
        if 0 <= r < 8 and 0 <= c < 8 and board[r][c] == player and path:
            pieces_to_flip.extend(path)
            
    return pieces_to_flip if pieces_to_flip else None

def flip_pieces(board, pieces_to_flip, player):
    """
    ひっくり返す石のリストを、指定されたプレイヤーの石に変換します。
    """
    for r, c in pieces_to_flip:
        board[r][c] = player

def get_valid_moves(board, player, opponent):
    """
    現在のプレイヤーが石を置けるすべての場所(有効な手)のリストを返します。
    """
    valid_moves = []
    for r in range(8):
        for c in range(8):
            if board[r][c] == EMPTY:
                if is_valid_move(board, r, c, player, opponent):
                    valid_moves.append((r, c))
    return valid_moves

def count_pieces(board):
    """
    盤面上の石の数を数え、勝敗を決定します。
    """
    black_count = sum(row.count(BLACK) for row in board)
    white_count = sum(row.count(WHITE) for row in board)
    return black_count, white_count

def end_game_check():
    """
    ゲームが終了したかチェックし、終了していれば勝敗を表示します。
    """
    global pass_count
    
    black_count, white_count = count_pieces(game_board)
    
    if pass_count == 2 or (black_count + white_count) == 64:
        # ゲーム終了
        if black_count > white_count:
            message = f"ゲーム終了!\n黒の勝ちです!\n(黒: {black_count}, 白: {white_count})"
        elif white_count > black_count:
            message = f"ゲーム終了!\n白の勝ちです!\n(黒: {black_count}, 白: {white_count})"
        else:
            message = f"ゲーム終了!\n引き分けです!\n(黒: {black_count}, 白: {white_count})"
            
        messagebox.showinfo("ゲーム終了", message)
        return True
    return False

def draw_pieces():
    """
    Pythonのボード情報に基づいて、canvas上に石を描画します。
    """
    canvas.delete("all")
    
    # 盤面の升目を再描画
    for i in range(8):
        for j in range(8):
            x1 = j * CELL_SIZE
            y1 = i * CELL_SIZE
            x2 = x1 + CELL_SIZE
            y2 = y1 + CELL_SIZE
            canvas.create_rectangle(x1, y1, x2, y2, outline="black", fill="green")
            
    # 石を描画
    for row_idx in range(8):
        for col_idx in range(8):
            piece = game_board[row_idx][col_idx]
            if piece == BLACK:
                color = "black"
            elif piece == WHITE:
                color = "white"
            else:
                continue
            
            x1 = col_idx * CELL_SIZE + 5
            y1 = row_idx * CELL_SIZE + 5
            x2 = x1 + CELL_SIZE - 10
            y2 = y1 + CELL_SIZE - 10
            
            canvas.create_oval(x1, y1, x2, y2, fill=color, outline="black")

def on_click(event):
    """
    マウスがクリックされたときに呼び出される関数です。
    """
    global current_player, pass_count
    
    col = event.x // CELL_SIZE
    row = event.y // CELL_SIZE
    
    opponent_player = WHITE if current_player == BLACK else BLACK
    
    pieces_to_flip = is_valid_move(game_board, row, col, current_player, opponent_player)

    if pieces_to_flip:
        # 有効な手であれば、石を置く
        game_board[row][col] = current_player
        flip_pieces(game_board, pieces_to_flip, current_player)
        
        # プレイヤーを交代
        current_player = opponent_player
        pass_count = 0  # パスカウントをリセット

    else:
        # 無効な手の場合、何もしない
        return
        
    draw_pieces()
    
    # 相手プレイヤーに有効な手があるかチェック
    if not get_valid_moves(game_board, current_player, opponent_player):
        print(f'{current_player}は置ける場所がありません。パスします。')
        pass_count += 1
        current_player = opponent_player  # プレイヤーを再度交代
        
        # 連続パスの場合、ゲーム終了チェック
        if pass_count == 2:
            end_game_check()
        else:
            # パスしたので、盤面を再描画して次のプレイヤーの番
            draw_pieces()
            
    # ゲーム終了条件を常にチェック
    if not end_game_check():
        pass
    else:
        print("ゲームが終了しました。")

def create_gui_board():
    """
    tkinterのウィンドウとオセロ盤のGUIを作成します。
    """
    global game_board, canvas
    
    root = tk.Tk()
    root.title("オセロゲーム")

    canvas = tk.Canvas(root, width=BOARD_SIZE, height=BOARD_SIZE, bg="green")
    canvas.pack()
    
    canvas.bind("<Button-1>", on_click)
            
    game_board = create_board()
    draw_pieces()

    root.mainloop()

# プログラムの実行
if __name__ == "__main__":
    create_gui_board()
プロンプトno4(AI対戦相手のプログラムと初期動作)
import tkinter as tk
from tkinter import messagebox
import random # <--- ここを追加

# 盤面を表すための定数
EMPTY = '・'
BLACK = '⚫'
WHITE = '⚪'

# ウィンドウとキャンバスのサイズ
BOARD_SIZE = 400
CELL_SIZE = BOARD_SIZE // 8

# グローバル変数としてボードの状態を保持
game_board = None
canvas = None
current_player = BLACK
pass_count = 0

# AIの設定
AI_PLAYER = WHITE # AIを白のプレイヤーに設定
IS_AI_TURN = False # AIのターンかどうかを示すフラグ

def create_board():
    """
    8x8の空の盤面を作成し、初期配置の石を配置します。
    """
    board = []
    for _ in range(8):
        row = [EMPTY] * 8
        board.append(row)
    
    board[3][3] = WHITE
    board[3][4] = BLACK
    board[4][3] = BLACK
    board[4][4] = WHITE
    return board

# ----------------- AIロジックの追加 -----------------
def get_ai_move(valid_moves):
    """
    有効な手の中からランダムに手を選択します。
    """
    return random.choice(valid_moves)

def handle_ai_turn():
    """
    AIのターンを処理します。
    """
    global current_player, pass_count, IS_AI_TURN
    
    opponent_player = BLACK # AIは白なので、相手は黒
    
    valid_moves = get_valid_moves(game_board, AI_PLAYER, opponent_player)

    if not valid_moves:
        pass_count += 1
        print("AIは置ける場所がありません。パスします。")
        current_player = BLACK # プレイヤーを交代
        IS_AI_TURN = False
        end_game_check()
        draw_pieces()
    else:
        pass_count = 0
        
        # AIがランダムに手を選択
        row, col = get_ai_move(valid_moves)
        
        # 石を置く処理
        pieces_to_flip = is_valid_move(game_board, row, col, AI_PLAYER, opponent_player)
        game_board[row][col] = AI_PLAYER
        flip_pieces(game_board, pieces_to_flip, AI_PLAYER)
        
        current_player = BLACK # プレイヤーを交代
        IS_AI_TURN = False
        
        draw_pieces()
        
        if not end_game_check():
            pass
        else:
            print("ゲームが終了しました。")
            
def on_click(event):
    """
    マウスがクリックされたときに呼び出される関数です。
    """
    global current_player, pass_count, IS_AI_TURN
    
    if IS_AI_TURN:
        return # AIのターン中はプレイヤーの入力を無視
    
    col = event.x // CELL_SIZE
    row = event.y // CELL_SIZE
    
    opponent_player = WHITE # プレイヤーは黒なので、相手は白
    
    pieces_to_flip = is_valid_move(game_board, row, col, current_player, opponent_player)

    if pieces_to_flip:
        game_board[row][col] = current_player
        flip_pieces(game_board, pieces_to_flip, current_player)
        
        pass_count = 0
        current_player = opponent_player
        IS_AI_TURN = True # 次のターンはAI
        
        draw_pieces()
        
        if not end_game_check():
            canvas.after(500, handle_ai_turn) # 0.5秒後にAIを動かす
        else:
            print("ゲームが終了しました。")
    else:
        print("その場所には置けません。有効な手を打ってください。")


# ----------------- ここから下の関数は変更なし -----------------
def is_valid_move(board, row, col, player, opponent):
    if not (0 <= row < 8 and 0 <= col < 8) or board[row][col] != EMPTY:
        return None
    directions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]
    pieces_to_flip = []
    for dr, dc in directions:
        r, c = row + dr, col + dc
        path = []
        while 0 <= r < 8 and 0 <= c < 8 and board[r][c] == opponent:
            path.append((r, c))
            r, c = r + dr, c + dc
        if 0 <= r < 8 and 0 <= c < 8 and board[r][c] == player and path:
            pieces_to_flip.extend(path)
    return pieces_to_flip if pieces_to_flip else None

def flip_pieces(board, pieces_to_flip, player):
    for r, c in pieces_to_flip:
        board[r][c] = player

def get_valid_moves(board, player, opponent):
    valid_moves = []
    for r in range(8):
        for c in range(8):
            if board[r][c] == EMPTY:
                if is_valid_move(board, r, c, player, opponent):
                    valid_moves.append((r, c))
    return valid_moves

def count_pieces(board):
    black_count = sum(row.count(BLACK) for row in board)
    white_count = sum(row.count(WHITE) for row in board)
    return black_count, white_count

def end_game_check():
    global pass_count
    black_count, white_count = count_pieces(game_board)
    if pass_count == 2 or (black_count + white_count) == 64:
        if black_count > white_count:
            message = f"ゲーム終了!\n黒の勝ちです!\n(黒: {black_count}, 白: {white_count})"
        elif white_count > black_count:
            message = f"ゲーム終了!\n白の勝ちです!\n(黒: {black_count}, 白: {white_count})"
        else:
            message = f"ゲーム終了!\n引き分けです!\n(黒: {black_count}, 白: {white_count})"
        messagebox.showinfo("ゲーム終了", message)
        return True
    return False

def draw_pieces():
    canvas.delete("all")
    for i in range(8):
        for j in range(8):
            x1 = j * CELL_SIZE
            y1 = i * CELL_SIZE
            x2 = x1 + CELL_SIZE
            y2 = y1 + CELL_SIZE
            canvas.create_rectangle(x1, y1, x2, y2, outline="black", fill="green")
    for row_idx in range(8):
        for col_idx in range(8):
            piece = game_board[row_idx][col_idx]
            if piece == BLACK:
                color = "black"
            elif piece == WHITE:
                color = "white"
            else:
                continue
            x1 = col_idx * CELL_SIZE + 5
            y1 = row_idx * CELL_SIZE + 5
            x2 = x1 + CELL_SIZE - 10
            y2 = y1 + CELL_SIZE - 10
            canvas.create_oval(x1, y1, x2, y2, fill=color, outline="black")

def create_gui_board():
    global game_board, canvas
    root = tk.Tk()
    root.title("オセロゲーム")
    canvas = tk.Canvas(root, width=BOARD_SIZE, height=BOARD_SIZE, bg="green")
    canvas.pack()
    canvas.bind("<Button-1>", on_click)
    game_board = create_board()
    draw_pieces()
    root.mainloop()

if __name__ == "__main__":
    create_gui_board()
プロンプトno5(AI対戦相手のGUI改善:ヒント表示と初期動作)
import tkinter as tk
from tkinter import messagebox
import copy
import time 
import sys

# --- ゲーム定数 ---
BOARD_SIZE = 8
CELL_SIZE = 60
WINDOW_SIZE = BOARD_SIZE * CELL_SIZE
SIDE_PANEL_WIDTH = 150
AI_PLAYER = 2 # 2: 黒 (後攻) / 1: 白 (先攻)
SEARCH_DEPTH = 4 # AIの探索深さ

# --- グローバル変数 ---
root = None
canvas = None
board = None
current_player = 1 # 1:白, 2:黒
game_running = True
score_label = None
turn_label = None
history = [] 

# --- 初期化 ---

def create_initial_board():
    """初期盤面を作成 (0:空, 1:白, 2:黒)"""
    new_board = [[0] * BOARD_SIZE for _ in range(BOARD_SIZE)]
    new_board[3][3] = 1 # 白
    new_board[3][4] = 2 # 黒
    new_board[4][3] = 2 # 黒
    new_board[4][4] = 1 # 白
    return new_board

# --- ルールとAIロジック ---

def is_valid_move(r, c, player, current_board):
    """指定されたマスに駒を置けるかチェックし、裏返せる駒のリストを返す"""
    if current_board[r][c] != 0:
        return []

    opponent = 3 - player
    flips = []

    # 8方向をチェック
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]

    for dr, dc in directions:
        line_flips = []
        rr, cc = r + dr, c + dc

        # 相手の駒が続く限り進む
        while 0 <= rr < BOARD_SIZE and 0 <= cc < BOARD_SIZE and current_board[rr][cc] == opponent:
            line_flips.append((rr, cc))
            rr, cc = rr + dr, cc + dc
        
        # 終点が自分の駒で、間に裏返せる駒がある場合
        if line_flips and 0 <= rr < BOARD_SIZE and 0 <= cc < BOARD_SIZE and current_board[rr][cc] == player:
            flips.extend(line_flips)

    return flips

def get_valid_moves(player, current_board):
    """合法手の一覧を (r, c) のリストで返す"""
    valid_moves = []
    for r in range(BOARD_SIZE):
        for c in range(BOARD_SIZE):
            if is_valid_move(r, c, player, current_board):
                valid_moves.append((r, c))
    return valid_moves

def apply_move(r, c, player, current_board):
    """実際に駒を置き、盤面を更新する (新しい盤面を返す)"""
    new_board = [row[:] for row in current_board]
    flips = is_valid_move(r, c, player, current_board)
    
    if not flips:
        return new_board # 無効な手の場合は元の盤面を返す

    new_board[r][c] = player
    for fr, fc in flips:
        new_board[fr][fc] = player
        
    return new_board

def evaluate_board(current_board, player):
    """評価関数: 駒の数の差を計算"""
    p1_count = sum(row.count(1) for row in current_board)
    p2_count = sum(row.count(2) for row in current_board)
    
    if player == 1:
        return p1_count - p2_count
    else:
        return p2_count - p1_count

def minimax(current_board, depth, is_maximizing_player, alpha, beta):
    """Minimax with Alpha-Beta Pruning"""
    current_player_minimax = 2 if is_maximizing_player else 1
    
    # 終端条件
    valid_moves = get_valid_moves(current_player_minimax, current_board)
    if depth == 0 or (not valid_moves and not get_valid_moves(3 - current_player_minimax, current_board)):
        return evaluate_board(current_board, 2), None # AI(黒=2)視点の評価を返す

    best_move = None
    
    if is_maximizing_player: # AI (黒=2) の手番
        max_eval = -float('inf')
        for r, c in valid_moves:
            new_board = apply_move(r, c, 2, current_board)
            current_eval, _ = minimax(new_board, depth - 1, False, alpha, beta)
            
            if current_eval > max_eval:
                max_eval = current_eval
                best_move = (r, c)
            
            alpha = max(alpha, max_eval)
            if beta <= alpha:
                break
        return max_eval, best_move
        
    else: # プレイヤー (白=1) の手番
        min_eval = float('inf')
        for r, c in valid_moves:
            new_board = apply_move(r, c, 1, current_board)
            current_eval, _ = minimax(new_board, depth - 1, True, alpha, beta)
            
            if current_eval < min_eval:
                min_eval = current_eval
                best_move = (r, c)
                
            beta = min(beta, min_eval)
            if beta <= alpha:
                break
        return min_eval, best_move

def find_best_move(current_board, depth):
    start_time = time.time()
    _, best_move = minimax(current_board, depth, True, -float('inf'), float('inf'))
    end_time = time.time()
    print(f"Minimax探索時間: {end_time - start_time:.2f}秒 (深さ: {depth})")
    return best_move

# --- UIと描画 ---

def draw_board():
    """盤面を描画し、駒を配置する"""
    canvas.delete("all")
    
    # 盤面のグリッド線を描画
    for i in range(BOARD_SIZE + 1):
        # 垂直線
        canvas.create_line(i * CELL_SIZE, 0, i * CELL_SIZE, WINDOW_SIZE, fill="black")
        # 水平線
        canvas.create_line(0, i * CELL_SIZE, WINDOW_SIZE, i * CELL_SIZE, fill="black")

    # 駒の配置
    for r in range(BOARD_SIZE):
        for c in range(BOARD_SIZE):
            player = board[r][c]
            if player != 0:
                x1 = c * CELL_SIZE + 5
                y1 = r * CELL_SIZE + 5
                x2 = (c + 1) * CELL_SIZE - 5
                y2 = (r + 1) * CELL_SIZE - 5
                color = "white" if player == 1 else "black"
                canvas.create_oval(x1, y1, x2, y2, fill=color, outline="black")

    update_score_display()

def update_score_display():
    """スコアとターン表示を更新する"""
    p1_count = sum(row.count(1) for row in board)
    p2_count = sum(row.count(2) for row in board)
    
    score_text = f"白: {p1_count}\n黒: {p2_count}"
    turn_text = f"現在のターン: {'白' if current_player == 1 else '黒'}"
    
    if score_label and turn_label:
        score_label.config(text=score_text)
        turn_label.config(text=turn_text)

def show_hint():
    """合法手があるマスをハイライト表示する"""
    canvas.delete("hint")
    valid_moves = get_valid_moves(current_player, board)
    
    for r, c in valid_moves:
        x1 = c * CELL_SIZE + 2
        y1 = r * CELL_SIZE + 2
        x2 = (c + 1) * CELL_SIZE - 2
        y2 = (r + 1) * CELL_SIZE - 2
        canvas.create_rectangle(x1, y1, x2, y2, outline="yellow", width=3, tags="hint")

# --- イベントハンドラ ---

def handle_click(event):
    """マウスがクリックされたときの処理"""
    global board, current_player, game_running
    
    if not game_running or current_player == AI_PLAYER:
        return

    c = event.x // CELL_SIZE
    r = event.y // CELL_SIZE
    
    if not (0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE):
        return

    flips = is_valid_move(r, c, current_player, board)
    
    if flips:
        save_state() # 履歴保存
        
        board = apply_move(r, c, current_player, board)
        
        next_player = 3 - current_player
        end_turn(next_player)
    else:
        messagebox.showinfo("無効な手", "そこには置けません。")

def end_turn(next_player):
    """ターン終了時の処理"""
    global current_player, game_running
    current_player = next_player
    
    draw_board()
    
    p1_moves = get_valid_moves(1, board)
    p2_moves = get_valid_moves(2, board)
    
    if not p1_moves and not p2_moves:
        # 両者とも置けない = ゲーム終了
        game_running = False
        p1_count = sum(row.count(1) for row in board)
        p2_count = sum(row.count(2) for row in board)
        
        winner = "引き分け"
        if p1_count > p2_count: winner = "白の勝利"
        elif p2_count > p1_count: winner = "黒の勝利"
            
        messagebox.showinfo("ゲーム終了", f"最終スコア 白:{p1_count}, 黒:{p2_count}\n{winner}")
        return
        
    elif not get_valid_moves(current_player, board):
        # パス (合法手が無い場合は相手のターンに戻る)
        messagebox.showinfo("パス", f"{'白' if current_player == 1 else '黒'}は置く場所がないためパスします。")
        current_player = 3 - current_player
        draw_board() # プレイヤーが変わったことを表示

    show_hint()
    
    if current_player == AI_PLAYER and game_running:
        root.after(500, make_ai_move) # 0.5秒後にAIを起動

def make_ai_move():
    """AIが指し手を決定し、実行する"""
    global board, current_player, game_running
    
    if not game_running or current_player != AI_PLAYER:
        return

    save_state() # 履歴保存
    
    best_move = find_best_move(board, SEARCH_DEPTH)
    
    if best_move:
        r, c = best_move
        board = apply_move(r, c, AI_PLAYER, board)
        
        next_player = 3 - AI_PLAYER
        end_turn(next_player)
    else:
        # AIが置けない場合もパス処理で end_turn が実行される
        end_turn(3 - AI_PLAYER)

def save_state():
    """現在のゲーム状態を履歴に保存する (Undo用)"""
    global history
    state = (
        [row[:] for row in board],
        current_player
    )
    history.append(state)

def undo_move():
    """一手前の状態に戻す"""
    global board, current_player, game_running, history
    
    if current_player == AI_PLAYER:
        messagebox.showinfo("警告", "AIの手番中はUndoできません。")
        return
        
    if len(history) <= 1:
        messagebox.showinfo("警告", "初期状態のため、これ以上戻せません。")
        return
    
    # プレイヤーとAIの2手分を戻す
    if len(history) >= 2:
        history.pop() # AIの手
        history.pop() # プレイヤーの手
    else:
        # 初期盤面直後の履歴の場合
        history.pop() 

    prev_board, prev_player = history[-1]
    
    board = [row[:] for row in prev_board]
    current_player = prev_player
    game_running = True
    
    draw_board()
    show_hint()
    
    if current_player == AI_PLAYER and game_running:
        root.after(500, make_ai_move)
        
# --- GUIメイン関数 ---

def create_board_ui():
    global root, canvas, board, score_label, turn_label
    
    root = tk.Tk()
    root.title(f"オセロゲーム (AI深さ: {SEARCH_DEPTH})")
    
    # --- UI中央配置のための改善 ---
    
    # 1. すべての要素を保持するメインフレームを作成
    main_frame = tk.Frame(root)
    
    # 2. main_frameを親ウィンドウの中央に配置
    #    expand=True で利用可能なスペースを広げ、anchor='center' で中央に寄せます。
    main_frame.pack(expand=True, anchor='center') 
    
    # --------------------------------

    # 3. ボード(キャンバス)を main_frame の中に配置 (親を root から main_frame に変更)
    canvas = tk.Canvas(main_frame, width=WINDOW_SIZE, height=WINDOW_SIZE, bg="green")
    canvas.pack(side=tk.LEFT)
    
    # 4. スコアパネル(サイドパネル)を main_frame の中に配置 (親を root から main_frame に変更)
    score_frame = tk.Frame(main_frame, width=SIDE_PANEL_WIDTH)
    score_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=10, pady=10)
    
    # --- スコアとターン表示 ---
    
    score_label = tk.Label(score_frame, text="スコア", font=("Arial", 16))
    score_label.pack(pady=20)
    
    turn_label = tk.Label(score_frame, text="ターン", font=("Arial", 14))
    turn_label.pack(pady=10)

    # --- ボタン ---
    
    undo_button = tk.Button(score_frame, text="一手戻る (Undo)", command=undo_move, 
                            height=2, bg="#B0C4DE", fg="black")
    undo_button.pack(pady=20)
    
    hint_button = tk.Button(score_frame, text="ヒント表示", command=show_hint,
                            height=2, bg="#FFFACD", fg="black")
    hint_button.pack(pady=10)
    
    # --- ゲームの起動 ---
    
    board = create_initial_board()
    canvas.bind("<Button-1>", handle_click)
    
    # 初期状態を履歴に保存
    save_state()
    
    draw_board()
    show_hint()
    
    def on_closing():
        root.destroy()
        sys.exit()
        
    root.protocol("WM_DELETE_WINDOW", on_closing)
    root.mainloop()

if __name__ == "__main__":
    create_board_ui()
プロンプトno6(AI対戦相手の完全版ヒント表示の選択機能の追加と初期動作)
import tkinter as tk
from tkinter import messagebox
import copy
import time 
import sys

# --- ゲーム定数 ---
BOARD_SIZE = 8
CELL_SIZE = 60
WINDOW_SIZE = BOARD_SIZE * CELL_SIZE
SIDE_PANEL_WIDTH = 150
AI_PLAYER = 2 # 2: 黒 (後攻) / 1: 白 (先攻)
SEARCH_DEPTH = 4 # AIの探索深さ

# --- グローバル変数 ---
root = None
canvas = None
board = None
current_player = 1 # 1:白, 2:黒
game_running = True
score_label = None
turn_label = None
history = [] 

# --- 初期化 ---

def create_initial_board():
    """初期盤面を作成 (0:空, 1:白, 2:黒)"""
    new_board = [[0] * BOARD_SIZE for _ in range(BOARD_SIZE)]
    new_board[3][3] = 1 # 白
    new_board[3][4] = 2 # 黒
    new_board[4][3] = 2 # 黒
    new_board[4][4] = 1 # 白
    return new_board

# --- ルールとAIロジック ---

def is_valid_move(r, c, player, current_board):
    """指定されたマスに駒を置けるかチェックし、裏返せる駒のリストを返す"""
    if current_board[r][c] != 0:
        return []

    opponent = 3 - player
    flips = []

    # 8方向をチェック
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]

    for dr, dc in directions:
        line_flips = []
        rr, cc = r + dr, c + dc

        # 相手の駒が続く限り進む
        while 0 <= rr < BOARD_SIZE and 0 <= cc < BOARD_SIZE and current_board[rr][cc] == opponent:
            line_flips.append((rr, cc))
            rr, cc = rr + dr, cc + dc
        
        # 終点が自分の駒で、間に裏返せる駒がある場合
        if line_flips and 0 <= rr < BOARD_SIZE and 0 <= cc < BOARD_SIZE and current_board[rr][cc] == player:
            flips.extend(line_flips)

    return flips

def get_valid_moves(player, current_board):
    """合法手の一覧を (r, c) のリストで返す"""
    valid_moves = []
    for r in range(BOARD_SIZE):
        for c in range(BOARD_SIZE):
            if is_valid_move(r, c, player, current_board):
                valid_moves.append((r, c))
    return valid_moves

def apply_move(r, c, player, current_board):
    """実際に駒を置き、盤面を更新する (新しい盤面を返す)"""
    new_board = [row[:] for row in current_board]
    flips = is_valid_move(r, c, player, current_board)
    
    if not flips:
        return new_board # 無効な手の場合は元の盤面を返す

    new_board[r][c] = player
    for fr, fc in flips:
        new_board[fr][fc] = player
        
    return new_board

def evaluate_board(current_board, player):
    """評価関数: 駒の数の差を計算"""
    p1_count = sum(row.count(1) for row in current_board)
    p2_count = sum(row.count(2) for row in current_board)
    
    if player == 1:
        return p1_count - p2_count
    else:
        return p2_count - p1_count

def minimax(current_board, depth, is_maximizing_player, alpha, beta):
    """Minimax with Alpha-Beta Pruning"""
    current_player_minimax = 2 if is_maximizing_player else 1
    
    # 終端条件
    valid_moves = get_valid_moves(current_player_minimax, current_board)
    if depth == 0 or (not valid_moves and not get_valid_moves(3 - current_player_minimax, current_board)):
        return evaluate_board(current_board, 2), None # AI(黒=2)視点の評価を返す

    best_move = None
    
    if is_maximizing_player: # AI (黒=2) の手番
        max_eval = -float('inf')
        for r, c in valid_moves:
            new_board = apply_move(r, c, 2, current_board)
            current_eval, _ = minimax(new_board, depth - 1, False, alpha, beta)
            
            if current_eval > max_eval:
                max_eval = current_eval
                best_move = (r, c)
            
            alpha = max(alpha, max_eval)
            if beta <= alpha:
                break
        return max_eval, best_move
        
    else: # プレイヤー (白=1) の手番
        min_eval = float('inf')
        for r, c in valid_moves:
            new_board = apply_move(r, c, 1, current_board)
            current_eval, _ = minimax(new_board, depth - 1, True, alpha, beta)
            
            if current_eval < min_eval:
                min_eval = current_eval
                best_move = (r, c)
                
            beta = min(beta, min_eval)
            if beta <= alpha:
                break
        return min_eval, best_move

def find_best_move(current_board, depth):
    start_time = time.time()
    _, best_move = minimax(current_board, depth, True, -float('inf'), float('inf'))
    end_time = time.time()
    print(f"Minimax探索時間: {end_time - start_time:.2f}秒 (深さ: {depth})")
    return best_move

# --- UIと描画 ---

def draw_board():
    """盤面を描画し、駒を配置する"""
    canvas.delete("all")
    
    # 盤面のグリッド線を描画
    for i in range(BOARD_SIZE + 1):
        # 垂直線
        canvas.create_line(i * CELL_SIZE, 0, i * CELL_SIZE, WINDOW_SIZE, fill="black")
        # 水平線
        canvas.create_line(0, i * CELL_SIZE, WINDOW_SIZE, i * CELL_SIZE, fill="black")

    # 駒の配置
    for r in range(BOARD_SIZE):
        for c in range(BOARD_SIZE):
            player = board[r][c]
            if player != 0:
                x1 = c * CELL_SIZE + 5
                y1 = r * CELL_SIZE + 5
                x2 = (c + 1) * CELL_SIZE - 5
                y2 = (r + 1) * CELL_SIZE - 5
                color = "white" if player == 1 else "black"
                canvas.create_oval(x1, y1, x2, y2, fill=color, outline="black")

    update_score_display()

def update_score_display():
    """スコアとターン表示を更新する"""
    p1_count = sum(row.count(1) for row in board)
    p2_count = sum(row.count(2) for row in board)
    
    score_text = f"白: {p1_count}\n黒: {p2_count}"
    turn_text = f"現在のターン: {'白' if current_player == 1 else '黒'}"
    
    if score_label and turn_label:
        score_label.config(text=score_text)
        turn_label.config(text=turn_text)

def show_hint():
    """合法手があるマスをハイライト表示する"""
    canvas.delete("hint")
    valid_moves = get_valid_moves(current_player, board)
    
    for r, c in valid_moves:
        x1 = c * CELL_SIZE + 2
        y1 = r * CELL_SIZE + 2
        x2 = (c + 1) * CELL_SIZE - 2
        y2 = (r + 1) * CELL_SIZE - 2
        canvas.create_rectangle(x1, y1, x2, y2, outline="yellow", width=3, tags="hint")

# --- イベントハンドラ ---

def handle_click(event):
    """マウスがクリックされたときの処理"""
    global board, current_player, game_running
    
    if not game_running or current_player == AI_PLAYER:
        return

    c = event.x // CELL_SIZE
    r = event.y // CELL_SIZE
    
    if not (0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE):
        return

    flips = is_valid_move(r, c, current_player, board)
    
    if flips:
        save_state() # 履歴保存
        
        board = apply_move(r, c, current_player, board)
        
        next_player = 3 - current_player
        end_turn(next_player)
    else:
        messagebox.showinfo("無効な手", "そこには置けません。")

def end_turn(next_player):
    """ターン終了時の処理"""
    global current_player, game_running
    current_player = next_player
    
    draw_board()
    
    p1_moves = get_valid_moves(1, board)
    p2_moves = get_valid_moves(2, board)
    
    if not p1_moves and not p2_moves:
        # 両者とも置けない = ゲーム終了
        game_running = False
        p1_count = sum(row.count(1) for row in board)
        p2_count = sum(row.count(2) for row in board)
        
        winner = "引き分け"
        if p1_count > p2_count: winner = "白の勝利"
        elif p2_count > p1_count: winner = "黒の勝利"
            
        messagebox.showinfo("ゲーム終了", f"最終スコア 白:{p1_count}, 黒:{p2_count}\n{winner}")
        return
        
    elif not get_valid_moves(current_player, board):
        # パス (合法手が無い場合は相手のターンに戻る)
        messagebox.showinfo("パス", f"{'白' if current_player == 1 else '黒'}は置く場所がないためパスします。")
        current_player = 3 - current_player
        draw_board() # プレイヤーが変わったことを表示

    show_hint()
    
    if current_player == AI_PLAYER and game_running:
        root.after(500, make_ai_move) # 0.5秒後にAIを起動

def make_ai_move():
    """AIが指し手を決定し、実行する"""
    global board, current_player, game_running
    
    if not game_running or current_player != AI_PLAYER:
        return

    save_state() # 履歴保存
    
    best_move = find_best_move(board, SEARCH_DEPTH)
    
    if best_move:
        r, c = best_move
        board = apply_move(r, c, AI_PLAYER, board)
        
        next_player = 3 - AI_PLAYER
        end_turn(next_player)
    else:
        # AIが置けない場合もパス処理で end_turn が実行される
        end_turn(3 - AI_PLAYER)

def save_state():
    """現在のゲーム状態を履歴に保存する (Undo用)"""
    global history
    state = (
        [row[:] for row in board],
        current_player
    )
    history.append(state)

def undo_move():
    """一手前の状態に戻す"""
    global board, current_player, game_running, history
    
    if current_player == AI_PLAYER:
        messagebox.showinfo("警告", "AIの手番中はUndoできません。")
        return
        
    if len(history) <= 1:
        messagebox.showinfo("警告", "初期状態のため、これ以上戻せません。")
        return
    
    # プレイヤーとAIの2手分を戻す
    if len(history) >= 2:
        history.pop() # AIの手
        history.pop() # プレイヤーの手
    else:
        # 初期盤面直後の履歴の場合
        history.pop() 

    prev_board, prev_player = history[-1]
    
    board = [row[:] for row in prev_board]
    current_player = prev_player
    game_running = True
    
    draw_board()
    show_hint()
    
    if current_player == AI_PLAYER and game_running:
        root.after(500, make_ai_move)
        
# --- GUIメイン関数 ---

def create_board_ui():
    global root, canvas, board, score_label, turn_label
    
    root = tk.Tk()
    root.title(f"オセロゲーム (AI深さ: {SEARCH_DEPTH})")
    
    # --- UI中央配置のための改善 ---
    
    # 1. すべての要素を保持するメインフレームを作成
    main_frame = tk.Frame(root)
    
    # 2. main_frameを親ウィンドウの中央に配置
    #    expand=True で利用可能なスペースを広げ、anchor='center' で中央に寄せます。
    main_frame.pack(expand=True, anchor='center') 
    
    # --------------------------------

    # 3. ボード(キャンバス)を main_frame の中に配置 (親を root から main_frame に変更)
    canvas = tk.Canvas(main_frame, width=WINDOW_SIZE, height=WINDOW_SIZE, bg="green")
    canvas.pack(side=tk.LEFT)
    
    # 4. スコアパネル(サイドパネル)を main_frame の中に配置 (親を root から main_frame に変更)
    score_frame = tk.Frame(main_frame, width=SIDE_PANEL_WIDTH)
    score_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=10, pady=10)
    
    # --- スコアとターン表示 ---
    
    score_label = tk.Label(score_frame, text="スコア", font=("Arial", 16))
    score_label.pack(pady=20)
    
    turn_label = tk.Label(score_frame, text="ターン", font=("Arial", 14))
    turn_label.pack(pady=10)

    # --- ボタン ---
    
    undo_button = tk.Button(score_frame, text="一手戻る (Undo)", command=undo_move, 
                            height=2, bg="#B0C4DE", fg="black")
    undo_button.pack(pady=20)
    
    hint_button = tk.Button(score_frame, text="ヒント表示", command=show_hint,
                            height=2, bg="#FFFACD", fg="black")
    hint_button.pack(pady=10)
    
    # --- ゲームの起動 ---
    
    board = create_initial_board()
    canvas.bind("<Button-1>", handle_click)
    
    # 初期状態を履歴に保存
    save_state()
    
    draw_board()
    show_hint()
    
    def on_closing():
        root.destroy()
        sys.exit()
        
    root.protocol("WM_DELETE_WINDOW", on_closing)
    root.mainloop()

if __name__ == "__main__":
    create_board_ui()

次回はナンプレ(数独)のアプリを作成と動作確認を予定しています。楽しみにお待ちください。

ホーム » takodemous

ポンコツ夫婦のBIKE日記 with Insta360 Vol.4(後編)

「いつかは二人でツーリングコースを走る」という目標を掲げつつ、漢のロマンを語るDr.takodemousのBIKE日記です。今回Insta360 Ace Proが捉えたのは、筆者の青春の思い出が詰まった国営木曽三川公園138タワーパーク周辺。動画と合わせて、この地域の謎めいた歴史をお届けします。

一宮ヘリクラブ飛行場付近からスタート

vol.3では国営木曽三川公園 138タワーパーク周辺をツーリングし、青春時代の思い出などを紹介しました。実はVol.4(前編・後編)はVol.3と連動しています。正直に言うと動画を分割したに過ぎないのですが、R60世代が無理なく一日かけて過ごせる、ツーリング+αを提案できればと思い、敢えて別のナンバリングをしています。

動画の見どころは、蘇南公園 多目的グラウンド付近の堤防です。実はこのコースは、ロケ班のような下見をしていた時に筆者が偶然見つけた珍しい区間なのです。

【見逃し厳禁】全国でも稀な「二重堤防道路」

前回までのブログにも記載していますが、木曽川の堤防の歴史と相まって、堤防道路が木曽川左岸に対して二つ並行して存在する区間があるのです。筆者自身も調べ始めて気がつきました。このような構造は全国でも稀な存在です。皆さんも是非ツーリングして、この稀なコースを堪能してはいかがでしょうか。

木曽川左岸から川島堤防道路へ

本ブログVol.4(後編)と前回Vol.4(前編)を合わせると、木曽川左岸と川島堤防道路のツーリングが完成します。近郊に住む地元民でもあまり知られていない事実があります。それは、川島町が木曽川の中州に位置する地域であり、かつては全国で唯一、全域が川に囲まれた単独の町であった歴史があるということです。

中州でありながら広大な地形をしており、相当数の住居があることから、町(普通地方公共団体)として成立しました。現在は各務原市へと編入しています。

各務原市川島町の地理上の歴史

川島町は、以下のような非常に特異な地理的・歴史的背景を持っています。

  • 中州・河川島の集落: 木曽川の広大な流れの中にできた「川の島(河川島)」に集落が形成されました。
  • 治水との闘い(輪中): 度重なる木曽川の洪水に見舞われ、水害から集落を守るために、輪中(集落の周囲を堤防で囲む治水形態)の文化や技術が発達しました。
  • 渡船の歴史: かつては橋がなく、対岸との往来は渡し船に頼っていました(例:川島の渡し)。

各務原市川島町の魅力

  • 河川環境楽園(木曽川水園): 国営木曽三川公園の一部。広大な敷地内で水辺の生き物や植物を観察しながら、四季折々の美しい景色を楽しめます。
  • 水と共にある独特な文化の歴史: 輪中の文化や渡し船の歴史が深く根付いており、人々が水とどのように共生し、生活を守ってきたのかという、濃尾平野の治水の歴史を肌で感じることができます。
  • 複合レジャー施設としての利便性: 敷地が隣接する「オアシスパーク」は、高速道路(東海北陸自動車道)からも一般道からもアクセスできる複合レジャー施設です。
  • 国宝 犬山城と城下町:木曽川を遡った対岸、愛知県犬山市に位置します。現存する天守が国宝に指定されている犬山城は、木曽川のほとりの小高い山に建ち、その景観は圧巻です。城下町には、昔ながらの街並みが保存・整備されており、グルメや散策を楽しめます。川島町からは、木曽川沿いの道路をツーリングするルートとしても人気です。
  • 国営木曽三川公園 138タワーパーク:木曽川を下流(一宮市)方面に進んだところに位置します。公園のシンボルである「ツインアーチ138」は、遠くからでも目立つランドマークです。タワーの展望階からは、木曽三川の流れや濃尾平野の雄大な景色を一望でき、ツーリングの休憩や目的地として最適です。
  • 伊木山と伊木山城址:木曽川沿いにある山で、自然景観と歴史が融合したスポットです。頂上付近にはかつてのお城の跡があり、比較的低山ながらも、山頂からの眺めは木曽川の流れと周辺の平野を見下ろすことができ、清々しい気分になれます。ツーリング途中に少し汗を流すための軽いハイキングを楽しむのにも良いでしょう。
  • 岐阜かかみがはら航空宇宙博物館(そらはく):各務原市内にあり、日本の航空宇宙産業の歴史を学べる大規模な博物館です。実物の航空機やロケット関連の展示が豊富で、乗り物好きのツーリング客にとっては、知的好奇心を刺激される魅力的な立ち寄り先となります。

筆者のツーリングは、相変わらず一人のショートコースが中心です。Redkabagonさんの公道デビューは、どうやら「来年こそは!」というセリフが恒例行事になりそうな予感がしています。当ブログの名物企画として、公道デビューまでの道のり(の長さ)を、これからも気長に見届けてください。

次回は馬飼ビーチ周辺のバイク日記を投稿予定としています。お楽しみに。

ホーム » takodemous

ポンコツ夫婦のBIKE日記 with Insta360 Vol.4(前編)

「いつかは二人でツーリングコースを走る」という目標を掲げつつ、漢のロマンを語るDr.takodemousのBIKE日記です。今回Insta360 Ace Proが捉えたのは、筆者の青春の思い出が詰まった国営木曽三川公園138タワーパーク周辺。動画と合わせて、この地域の謎めいた歴史をお届けします。(なお、機材の詳細は今後「The Gear」カテゴリーでご紹介します。)

光明寺公園 球技場からスタート

vol.3では国営木曽三川公園 138タワーパーク周辺をツーリングし,青春時代の思い出などを紹介しました。実はVol.4(前編・後編)はVol.3と連動しています。正直に言うと動画を分割したに過ぎないのですが、R60世代が無理なく一日かけて過ごせる、ツーリング+αを提案できればと思い、敢えて別のナンバリングをしています。

動画の見どころは、ズバリ光明寺公園の駐車場をでた直後の堤防です。このコースは、筆者の青春時代にはまだ相互通行ができていました。ご覧になれば一目瞭然に、このコースのどこで自動車がすれ違えるのだろうと感じるくらい、道幅が狭くなっていて、現在では一方通行となっています。そして、旧極楽寺側からの一方通行と相対する事となります。動画では右折迂回路を経由していますが、左折をすると国営木曽三川公園 138タワーパークの駐車場へと向かいます。桜の季節には本コースも咲き乱れますので、読者の皆様もツーリングの一考にしてみてはいかがですか。

木曽川左岸から川島堤防道路へ

本ブログVol.4(前編)と次回Vol.4(後編)を合わせると、木曽川左岸と川島堤防道路のツーリングが完成します。近郊に住んでいる地元民でもあまり知られていない事実があります。それは、川島町は木曽川の中洲に位置する地域であり、木曽川の作る大小二つの島の中洲が一体となっており、その地形的特徴から、かつては単独の市町村で全域が川に囲まれた、全国で唯一の町であった歴史があります。

少し砕いて言うと、中州でありながら広大な地形をしており、相当数の住居がある事から、町(普通地方公共団体)の人口や都市的要件を満たしており、川島町として成立したという事になります。現在は各務原市へと編入しています。詳細はvol.4(後半)で紹介しますのでお待ちください。

自然を満喫しながらのサイクリング

木曽三川公園のサイクリングコースは、広大な敷地と河川沿いの景観を活かして整備されており、特に近年になってコースが延伸され、より広範囲を楽しめるようになりました。

歴史的経緯

  • 2016年(平成28年)2月13日に、138タワーパーク内のサイクリングロードが新たに開通しました。
  • この開通により、犬山市の木曽川犬山緑地から一宮市里小牧にある木曽川緑地公園まで、約18kmのコースがつながりました。
  • このコースは自転車用と歩行者用が色分けされており、安全にサイクリングやウォーキングを楽しめるように整備されています。

138タワーパーク 周辺のおすすめスポット

138タワーパークからのサイクリングで、気軽に立ち寄れるスポットをご紹介します。

1. 木曽川資料館(木曽川水系流域の歴史と治水)

木曽川をテーマにした資料館で、木曽三川分流工事(デ・レーケの治水事業)や、輪中の歴史、水との闘いに関する貴重な資料が展示されています。サイクリング休憩がてら、この地域の地理や歴史の深さを知るのに最適です。

2. 一宮市立尾西歴史民俗資料館(地域の文化と歴史)

旧尾西市(現一宮市の一部)の歴史や、かつて繊維産業で栄えた地域の文化を学べる施設です。機織り(はたおり)に関する展示などが充実しており、木曽川沿いの産業史に触れることができます。

3. 浅井山公園(休憩と自然)

一宮市北部にある自然豊かな公園です。大きな池があり、緑が多く、サイクリングの途中でベンチに座って休憩したり、静かな水辺の景色を楽しんだりするのに適しています。

4. 川島大橋・付近の河川敷(景観と開放感)

木曽川に架かる川島大橋の周辺は、特に河川敷の開放感があり、雄大な木曽川の流れを間近に感じることができます。休憩するのに適したスペースもあり、ゆったりとした景色を楽しむのに最適です。

木曽三川公園のサイクリングコースは、自然や歴史、そしてグルメを楽しみながら、自分のペースでゆっくりと散策するのにぴったりの場所です。

橋の歴史

vol.3では紹介していなかった橋の歴史シリーズを、vol4(前半)と併せて紹介いたします。また、次回vol.4(後半)についても本ブログと被っている動画を掲載することになりますので、併記としてご覧ください。

尾濃大橋の歴史(びのうおおはし)

  • 開通年: 1957年(昭和32年)
  • 建設の経緯: 尾濃大橋が架かる以前は、木曽川の渡船が利用されていました。しかし、交通量の増加と度重なる洪水のたびに渡し船が流されたり、運航が停止したりする事態が続いていました。地域の安全と交通の利便性を確保するため、橋の建設が強く求められるようになりました。
  • 特徴: 尾濃大橋の建設は、地域の発展に大きく貢献しました。特に、当時の自動車交通の増加に対応するため、重要な幹線道路として機能しました。

木曽川橋 (きそがわばし)

  • 開通: 1937年(昭和12年)に開通した道路橋です。
  • 特徴: 名古屋と岐阜を結ぶ主要な街道の要所に位置しており、日本の土木技術の発展を示す貴重な橋として知られています。
  • 現在の役割: 現在も交通量の多い幹線道路の一部として利用されています。

新木曽川橋(しんきそがわばし)

  • 1937年(昭和12年)10月: 最初に木曽川に架けられた橋は、現在の新木曽川橋よりも上流にある「木曽川橋」として開通しました。これは、現在の国道22号の旧道にあたる部分に位置していました。
  • 1969年(昭和44年): 高度経済成長期の交通量増大に対応するため、当時の木曽川橋の下流に、新たな橋として「新木曽川橋」が開通しました。この橋は、当初は名古屋方面から岐阜方面への下り線として使用されました。
  • 1975年(昭和50年): 上り線(岐阜方面から名古屋方面)の橋も完成し、上下線が分離した4車線道路として供用を開始しました。これにより、交通渋滞が大幅に緩和されました。

一宮川島線渡橋 (いちのみやかわしませんわたりばし)

  • 開通: 1964年(昭和39年)11月に開通しました。
  • 特徴: 以前は「渡船(わたしぶね)」がありましたが、度重なる洪水による欠航や、1959年(昭和34年)の伊勢湾台風で流失したことをきっかけに、橋の建設が進められました。
  • 歴史的背景: 橋の建設前には、木造の仮橋が何度か架けられましたが、その都度洪水で流されるなど、この地域が水害に悩まされてきた歴史を物語っています。

これらの橋は、それぞれの時代において、人々の生活や経済、そして地域の安全を守るために建設され、現在に至っています。

筆者のツーリングは、相変わらず一人のショートコースが中心です。Redkabagonさんの公道デビューは、どうやら「来年こそは!」というセリフが恒例行事になりそうな予感がしています。当ブログの名物企画として、公道デビューまでの道のり(の長さ)を、これからも気長に見届けてください。

次回は川島堤防道路から思いやり橋までのバイク日記を投稿予定としています。お楽しみに。

ホーム » takodemous

ポンコツ夫婦のBIKE日記with Insta 360 vol.3

昨年から「ポンコツ夫婦の旅日記」など、いくつかのカテゴリー変更を実施しています。今回は、MonkeyとZoomerのカテゴリーを統合し、「ポンコツ夫婦のBIKE日記」へと変更しました。

このカテゴリーは「The Gear」ともクロスオーバーさせ、今後は自動車(JimnyとEvery Wagon)関連の投稿にも広げていく予定です。まだ計画段階ですが、楽しみにしていてください。

「BIKE日記」のメッセージは、Dr.takodemousが①漢のロマンを語る、②熱血指導をする、③いつかは二人でツーリングコースを走る、の3つです。特に②は期待できると思います。

今回のテーマは「③いつかは二人でツーリングコースを走る」です。Insta360 Ace Proを搭載し、近所の堤防をツーリングした様子を掲載していきます。

岐阜県羽島市某所に住む筆者にとって、木曽川や長良川、揖斐川の堤防は、身近でツーリングに最適な環境です。

動画には、実際に乗車している感覚を伝えるため、あえてBGMを挿入していません。ただ、自動車学校のシミュレーターのように、自分が正面を向いているのに映像が傾くことがあります。苦手な方は、フル画面を避けたり、画質を下げたりしてご覧ください。

筆者は「R60仲良し夫婦コーディネーター」になることを目指しており、このブログはそのモチベーションで続けています。

これまではiPhoneで動画や画像を撮影していましたが、WordPressへのアップロード時に容量制限の問題がありました。

そこで、よりレベルの高い撮影と編集が可能な「Insta360 Ace Pro」を導入しました。このアイテムについては、別途「The Gear」カテゴリーで詳しくご紹介しますので、お楽しみに。

尾濃大橋からスタート

vol.3では筆者の青春時代を過ごした、現在の国営木曽三川公園 138タワーパーク周辺をツーリングします。高校時代は部活動でのランニングコース、大学時代はジムニーを駆ってのオフロードや、軟式野球のグランドとして過ごした思い出の場所です。

動画の見どころは、名鉄本線を超えた辺りから見えてくる、堤防越しの木曽川の風景です。現在、サイクリングロードを施工している最中です。総延長は、60kmに達するサイクリングコースになると広報されており、他の堤防では観る事とのできないコラボレーションを期待しながら、ツーリングができます。

木曽川左岸を上流へ

前回のポンコツ夫婦のBIKE日記でもご紹介したしまたが、新濃尾大橋と同様に尾濃大橋の知名度はまだまだ低いといえます。やはり、大垣側への道路が長良川で止まっているためだと推測します。

新濃尾大橋と周辺道路との違いは、羽島側と安八側での陸地部分の道路はほぼルートが整備されており、あとは新長良橋(仮名)の着工と羽島側の若干の土地買収が残されているだけという状況です。

日頃から一宮と大垣の間で渋滞に悩まされている住民としては、早期解消を願うばかりですが、若干尾濃大橋から大垣に抜けるルートの着工が早く、完成するのではと期待を寄せています。

国営木曽三川公園 138タワーパーク

現在の国営木曽三川公園 138タワーパークは、冒頭にも記載しておりますが、筆者の青春時代である大学生時代まで、ブログでは書けないような内容も含んだ思い出の地です。旧の名称は極楽寺公園という呼ばれ方をしていました。

そんな思い出の場所も、時代と共に姿を変え、現在は新しい魅力にあふれています。

国営公園としての誕生

138タワーパークは、木曽川・長良川・揖斐川の木曽三川が有する広大な河川敷を活用し、レクリエーション需要の増大に応えるために設置された「国営木曽三川公園」の一部です。特に、上流地区の拠点として位置づけられています。

開園と名称の由来

  • 開園: 1995年(平成7年)4月29日に開園しました。
  • 名称: 公園のシンボルである「ツインアーチ138」にちなんで名付けられました。
  • タワーの高さ: タワーの高さが138mであるのは、所在地である一宮市(いち=1、のみ=3、=8)の語呂合わせに由来しています。

特徴と役割

138タワーパークは、開園当時、広大な芝生広場や、四季折々の花を楽しめる庭園、そして展望タワーを備えた施設として、地域住民や観光客に親しまれてきました。タワーからは、木曽川の雄大な流れや濃尾平野の景色を一望できます。

このように、138タワーパークは、国営木曽三川公園のプロジェクトの一環として、地域のランドマークであり、レクリエーションと景観の拠点として整備されました。

地理上の歴史

vol.3では地理上の歴史にスポットを当てて紹介します。動画をご覧になると、堤防の内側(堤防より河川側)に住居が多数見受けられると思います。この現象は、日本の一級河川の最上位を誇る、長良川や揖斐川ですら見受けることができません。何故このような堤防の内側に住居が存在するのかと言うと、地理的条件と歴史背景が関係します。vol.4ではいつも通り橋の歴史をお伝えしますので、お待ちください。

愛知県一宮市木曽川町や川島町など、木曽川沿いの堤防よりも川側に住宅がある地域の歴史的背景は、この地域の特有な地理的条件と、度重なる洪水との闘いに深く関わっています。

「堤外地」という場所

堤防よりも川側の地域は、一般的に「堤外地(ていがいち)」と呼ばれます。ここは河川が氾濫した際に水が流れ込むことが想定されている場所です。にもかかわらず、なぜそこに人々が住み、家が建てられてきたのか、その理由にはいくつかの歴史的な背景があります。

1. 「御囲い堤」と「輪中」の歴史

  • 御囲い堤(おかいづつみ): 江戸時代、徳川家康が尾張(現在の愛知県)を治水するために築かせた強固な堤防です。この堤防は、尾張側を洪水から守る一方で、対岸の美濃(現在の岐阜県)側よりも堤防の高さを低くするよう定められていました。
  • 輪中(わじゅう): このため、美濃側の人々は自分たちの集落を守るため、集落の周りを堤防で囲む「輪中」という独自の治水システムを発達させました。

一宮市木曽川町や川島町は、この治水システムの境界に位置していました。尾張側にあるこの地域は、当初は御囲い堤によって守られていましたが、時代が下るにつれて、堤防の外側、つまり川側にも住宅や田畑が広がるようになりました。

2. 「二重堤防」の建設

堤防よりも川側に住宅ができた後も、この地域はたびたび水害に見舞われました。特に、昭和初期に発生した大洪水は大きな被害をもたらしました。

この水害を教訓として、一宮市木曽川町では、在来の堤防(御囲い堤)の内側に加えて、「二重堤防」が建設されました。これにより、堤防よりも川側の住宅地を囲む形で、もう一つの堤防が築かれ、水害から地域を守ろうとする取り組みが進められました。

3. 歴史的経緯と生活圏の拡大

このような地域に住宅ができたのは、以下のような経緯が考えられます。

  • 生活の場としての利用: 昔から、河川敷は生活に必要な資材(砂利など)の採取や、畑として利用されてきました。洪水が起きても、水が引けばまた生活に戻れるという考え方がありました。
  • 土地利用の拡大: 人口が増加するにつれて、限られた土地を有効活用するために、比較的土地の値段が安価な堤外地にも住宅が建てられるようになりました。
  • 近代的な治水工事: 明治以降に行われた大規模な治水工事(明治改修など)により、洪水の頻度が減り、堤外地でも生活が可能になるという認識が広まったことも一因です。

これらの歴史的背景から、一宮市木曽川町や川島町などの堤防よりも川側に住宅がある地域は、先人たちが度重なる洪水と闘い、独自の治水システムを築きながら生活の場を確保してきた、その努力の証と言えるでしょう。

筆者のツーリングは、相変わらず一人のショートコースが中心です。Redkabagonさんが公道デビューできるその日まで、この身近なコースを走り込み、技術と経験を磨いていきます。この日記を通して、二人の成長をぜひ見届けてください。

次回は国営木曽三川公園 138タワーパークから川島までのバイク日記を投稿予定としています。お楽しみに。

ホーム » takodemous

Stay in Fire TV Stick 第3世代VOL19

Prime Video Boxing13

今回のブログは前回からの継続である「Prime Video Boxing13」をご紹介いたします。モンスター井上尚弥選手の影響なのか、または帝拳ジムのプロモートの上手さなのか、6試合中3試合が帝拳ジム所属の選手が登場します。勿論「Prime Video Boxing」の国内戦では常にプロモートの中心人物である那須川天心選手も登場します。そして、今回のメインカードは第6試合の中谷潤人 vs 西田凌佑(WBC・IBF世界バンタム級王座統一戦)となります。冒頭からネタバレになってしまいますが、中谷潤人選手本当に「ビックバン」が炸裂炸裂しています。

R60世代にとってバンタム級といえば、薬師寺保栄VS辰吉丈一郎戦が思い起こされると思います。1994年に行われた試合は、営業の帰りにテレビ中継の画面に釘付けになって観ていたものです。

現在のバンタム級の選手群は史上最も層の厚い「ゴールデンエイジ」といっても過言ではなさそうです。世界タイトルの4団体を日本人のチャンピオンが独占しており、世界上位ランカーも多数存在しています。指名試合ですら日本人が選ばれている状況下においては、単にプロモート力だけが影響しているわけではなさそうです。

Prime Video Boxing13」においてもまさにその通りで、近々の他チャンネルを含めて王座統一戦が日本人同士で行われる事が、当たり前の感覚に陥ってしまいます。とても贅沢な環境ですね。皆様も是非手に汗を握ってご観戦ください。

対戦カード一覧

試合順 対戦カード階級
6中谷潤人(M.T)vs 西田凌佑(六島)WBC、IBF世界バンタム級王座統一戦
5那須川天心(帝拳)vsビクトル・サンティリャン(ドミニカ共和国)バンタム級10回戦
4坪井智也(帝拳)vs バン・タオ・トラン(ベトナム)WBOアジアパシフィック バンタム級王座決定戦10回戦
3増田陸(帝拳)vsミシェル・バンケス(ベネズエラ)ノンタイトル10回戦
2大久保るきあ(八王子中屋)vs米谷匠生(三迫)ミニマム級4回戦
1宮下陸(DANGAN越谷)vs大島冬也(T&T)スーパーフライ級4回戦

筆者はLIVE配信では観戦していません。便利な機能が備わっており、ストリームを使って観戦しています。配信時間帯に仕事などの都合がある場合やトイレなど用足しで見逃すことがなくなります。R60あるあるなのですが、内容が頭に入らない時に巻き戻しができます。これが結構なおすすめ機能となっております。必須条件としてはネタバレを防ぐことになるのですが。

Prime Video Boxing 13 試合展開と勝敗のポイント

第1試合:宮下陸 vs 大島冬也(スーパーフライ級4回戦)

  • 試合展開: デビュー戦に臨んだ宮下選手は、ダウンを奪うなど随所に奮闘を見せました。
  • 勝敗のポイント: 宮下選手が判定3-0で勝利し、プロデビュー戦を白星で飾りました。

第2試合:大久保るきあ vs 米谷匠生(ミニマム級4回戦)

  • 試合展開: 若手選手同士の試合で、大久保選手が序盤から積極的に攻め込み、ダウンを奪う見せ場を作りました。
  • 勝敗のポイント: 大久保選手が3ラウンドTKOで勝利を収めました。

第3試合:増田陸 vs ミシェル・バンケス(ノンタイトル10回戦)

  • 試合展開: 世界ランカーとの一戦で、増田選手は左右の強打と巧みな試合運びで圧倒しました。
  • 勝敗のポイント: 増田選手が1ラウンド1分27秒、KOで勝利。圧巻のパフォーマンスで世界へのアピールに成功しました。

第4試合:坪井智也 vs バン・タオ・トラン(WBOアジアパシフィック バンタム級王座決定戦)

  • 試合展開: 坪井選手は軽快なステップワークと卓越したハンドスピードで終始優位に立ち、相手に攻撃のチャンスを与えませんでした。
  • 勝敗のポイント: 坪井選手が判定3-0で勝利し、プロ2戦目にして地域タイトルを獲得しました。

第5試合:那須川天心 vs ビクトル・サンティリャン(バンタム級10回戦)

  • 試合展開: 世界挑戦に向けた重要な前哨戦。サンティリャン選手が粘りを見せる中、那須川選手はスピードと多彩なコンビネーションで試合を完全にコントロールしました。
  • 勝敗のポイント: 那須川選手が判定3-0で勝利。世界への道のりを着実に進める一戦となりました。

第6試合:中谷潤人 vs 西田凌佑(WBC・IBF世界バンタム級王座統一戦)

  • 試合展開: 無敗の王者同士による激しい打ち合い。ゴング直後から中谷選手が前に出て、西田選手も一歩も引かないスリリングな攻防が続きました。
  • 勝敗のポイント: 6ラウンド終了後、西田選手が右肩の脱臼により試合続行を断念。中谷選手が6R終了時TKOで勝利し、2団体統一王者となりました。

坪井智也選手はまたもや「ゴールデンエイジ」の一員です。そして、王座戦線に登場している選手群とは少し違う道のりを歩んで来ました。若干堤選手が歩んできた道のりと似ている部分もありますが、坪井智也 選手は大学でタイトルを独占したにもかかわらず、オリンピックに選出される機会を逸しています。おそらく、オリンピックに出場する機会を求めて、自衛隊体育学校に所属したのではないでしょうか。結果的には世界選手権で、二階級のゴールドを含む三つのメダルを獲得しています。ただし、リオオリンピック、東京オリンピック、パリオリンピックの出場を逃しアマチュアを引退しました。

その後、第二章という形でプロデビューすることになります。本大会では「遅れてきた大本命」と紹介され、プロデビュー2戦目で地域タイトルに挑戦しています。期待の大きさを表しているとおもいます。

筆者のような素人がうんちくを語るより、我が分身「Jr.takodemous」と命名したGoogle Geminiさんとの共同作業でR60世代に分かりやすく説明や解説、補足をいたします。

坪井智也選手の魅力は、その華々しいアマチュア実績だけでなく、プロのリングでも通用する卓越した技術と、クレバーな試合運びにあります。

彼の魅力を具体的に解説します。


1. 歴史的快挙に裏打ちされた確かな実力

坪井選手の最大の魅力は、日本男子ボクシング界に新たな歴史を刻んだアマチュアでの実績です。特に、2021年のAIBA世界ボクシング選手権(ベオグラード)でのバンタム級優勝は、日本人男子選手として史上初の快挙でした。

この偉業は、彼が単なる有望株ではなく、すでに世界基準のトップレベルのボクサーであることを証明しています。また、全日本選手権での4連覇も、国内における絶対的な強さを示しています。

2. 卓越したスピードとテクニック

アマチュア時代から培ってきた、教科書のような高い技術も魅力の一つです。

  • ハンドスピードとフットワーク: 驚異的な速さのパンチと、軽やかなステップワークで相手を翻弄します。常に最適な距離を保ちながら、正確なパンチを当てていきます。
  • ディフェンス技術: 攻守のバランスが非常に優れており、相手の攻撃を巧みにブロックしたり、かわしたりするディフェンス能力もトップクラスです。被弾が少なく、クリーンなボクシングを展開します。

3. プロのリングへのスムーズな適応力

アマチュアとプロでは求められるスタイルが異なりますが、坪井選手はプロ転向後、その変化にすぐさま適応しました。特に、プロ2戦目での地域タイトル獲得は、男子ボクサーとしては国内最速記録です。これは、彼の持つテクニックに加えて、プロの試合に勝つためのパンチのパワーやタイミングもすでに兼ね備えていることを示しています。

これらの点から、坪井智也選手は技術と実績、そして将来性をすべて持ち合わせた、日本のボクシング界を牽引する次世代のホープと言えるでしょう。

ここで筆者が補足いたします。ビックバン中谷潤人選手が一撃型、那須川天心選手が柔軟型、井上琢磨選手がヒットアンドアウェイ型とすると、坪井智也選手はラッシュ型といえるとおもいます。特にステップワークを使用した高速ラッシュは見ものです。つま先立ちで行う高速ラッシュは、言い換えると刺すようなボクシングと言えるのではないでしょうか。

しかしアマチュア時代のタイトルは調べることができます。前記の繰り返しにはなりますが、国内タイトルや世界タイトルを奪取(日本人初のゴールドメダル帝冠)しているにもかかわらず、出場機会のあった三度のオリンピックに選出漏れをしており、縁がなかったと推測します。

坪井智也選手 アマチュア時代の主な戦績

坪井智也選手は、プロ転向前にアマチュアボクシング界で輝かしい実績を残しました。通算戦績は131戦106勝(10RSC)25敗です。

特に以下の実績は特筆に値します。

  • 世界選手権優勝:2021年のAIBA世界ボクシング選手権(ベオグラード)バンタム級で優勝。これは日本男子ボクシング史上初の快挙でした。
  • 全日本選手権4連覇:全日本ボクシング選手権大会のライトフライ級で、2014年から2017年にかけて4連覇を達成しました。
  • 国民体育大会優勝:成年男子ライトフライ級で国民体育大会を2度制覇しています。

これらの実績が評価され、プロ入り後も大きな期待を集める存在となっています。

選手の戦績の他にprime videoでは独占密着取材という形式で、選手が試合に臨む前までの練習風景やインタビュー、その他の時事ネタを交えて紹介しています。

選手が育った人生や家族の誕生の瞬間、時には趣味などが紹介されています。試合の前の選手の心の中の状態が表現されていて、観戦する側としては感情移入することができます。この点は過去のTV放映と比較するとかなり多くの時間を使用しており、且つ番組自体が単独で配信されていますので、事後に気になった選手をフィーチャーすることも可能となっています。

Prime Video Boxing13密着取材
Prime Video Boxing13密着取材

昨年のブログで那須川天心選手の入場曲のyou tube動画埋め込みを試みたところ、対象動画がBAN扱いされていました。やはり著作権がらみなのでしょうね。今回も懲りずにご紹介いたします。

筆者主観の注目入場曲はズバリ増田陸選手です。筆者は観戦前、増田陸選手を注目の選手として紹介するつもりでした。割って入ってきたのが、遅れてきた大本命坪井智也選手です。そこで増田陸選手を注目の入場曲で登場してもらうことにしました。

少しだけ選手紹介をいたします。那須川天心選手坪井智也選手同様に帝拳ジム所属であり、かつバンタム級の階級に属しています。帝拳ジムは今後どのようにプロモートするのですかね。少し心配になるくらいの選手層の厚さです。増田陸選手は169cmと高身長なため、本命の階級はスーパーバンタムかフェザーなのだと思います

そんな増田陸選手の採用した入場曲は、 2Pacが歌う「I Ain’t Mad At Cha」です。他にはKodak Black「Transportin’」やEminem「Not Afraid」を使用していることから、きっと増田陸選手はヒップホップが好きなジャンルなんだと思われます。

「LIVE BOXING」のブログ投稿の際にはいつもお世話になっている、「渡嘉敷勝男&竹原慎二&畑山隆則 ぶっちゃけチャンネル」の中で、今回の「Prime Video Boxing13」の生解説している動画を埋め込みました。ご参照ください。

Prime Video Boxing13」については、中谷潤人 vs 西田凌佑(WBC・IBF世界バンタム級王座統一戦)戦を一本の動画配信、那須川天心 vs ビクトル・サンティリャン(バンタム級10回戦)を一本の動画で配信、合計二本立てで生配信されていました。

前回は竹原慎二さんが生配信の解説を欠席しており、少しばかり気にしていました。今回は三人とも揃って解説をしており、以前の通りボケ、ツッコミ、なだめとトークが役割分担されており、元気そうな様子にホッとしました。畑山隆則さんは前日の朝4:00迄約12時間飲んだそうで、そろそろ居酒屋トークを復活して欲しいものです。

さて今回の中谷潤人選手は、筆者が注目し始めてからの試合とは別人が試合をしているかのような印象を受けました。普段の中谷潤人選手は高長身と長いリーチを活かして、右手をセンサーのように使い、相手との距離感を測りながら序盤で試合を見極め、強烈な左のストレートを上下に打ちつけるスタイルが定番でした。特に上下に散らしたストレートの中でもボディストレートは圧巻です。距離感を見切ってのもだとおもいます。

後日譚で竹原慎二さんが詳細を解説していましたが、今回の中谷潤人選手は相手を壊しにいっているとの事でした。ガードの上から渾身のストレートを、初回から打ち続ける作戦を採用したようです。距離を見切る中には、相手が自分にしてくるであろう距離感も含んでいそうです。普段なら貰わないパンチを結構な数で被弾していました。途中からガードの上というより、西田凌佑選手の右手(肩付近)を攻撃の的にしていた展開も見受けられました。

是非皆さんも、その点を考慮して観戦してみてはいかがでしょうか。

渡嘉敷勝男&竹原慎二&畑山隆則 ぶっちゃけチャンネル
渡嘉敷勝男&竹原慎二&畑山隆則 ぶっちゃけチャンネル
Amazonでセール期間をチェック
Fire TV Stick 第3世代
ホーム » takodemous