File size: 3,482 Bytes
c4367ba
6ad4064
edf941b
b8ed266
edf941b
 
 
 
 
 
 
 
 
 
 
c4367ba
 
34d6098
 
c4367ba
 
 
 
 
 
 
 
 
 
 
 
 
 
b8ed266
c4367ba
 
 
 
 
 
b8ed266
c4367ba
b8ed266
c4367ba
 
6ad4064
b8ed266
6ad4064
 
c4367ba
 
b8ed266
 
 
 
6ad4064
c4367ba
 
b8ed266
 
 
c4367ba
b8ed266
c4367ba
b8ed266
 
 
 
 
 
 
 
 
 
 
c4367ba
b8ed266
 
 
 
 
 
 
 
 
 
 
34d6098
b8ed266
 
 
 
 
 
c4367ba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import gradio as gr
from PIL import Image, ImageDraw
import random
time

def choose_move(board, player):
    valid_moves = []
    for r in range(8):
        for c in range(8):
            if get_flips(board, r, c, player):
                valid_moves.append((r, c))
    if not valid_moves:
        return None
    return random.choice(valid_moves)

def initialize_board():
    board = [[0 for _ in range(8)] for _ in range(8)]
    board[3][3], board[4][4] = 1, 1
    board[3][4], board[4][3] = -1, -1
    return board

DIRECTIONS = [(-1, -1), (-1, 0), (-1, 1),
              (0, -1),           (0, 1),
              (1, -1),  (1, 0),  (1, 1)]

def get_flips(board, row, col, player):
    if board[row][col] != 0:
        return []
    flips = []
    for dr, dc in DIRECTIONS:
        r, c = row + dr, col + dc
        buffer = []
        while 0 <= r < 8 and 0 <= c < 8 and board[r][c] == -player:
            buffer.append((r, c)); r += dr; c += dc
        if buffer and 0 <= r < 8 and 0 <= c < 8 and board[r][c] == player:
            flips.extend(buffer)
    return flips

def apply_move(board, row, col, player):
    flips = get_flips(board, row, col, player)
    if not flips: return False
    board[row][col] = player
    for r, c in flips: board[r][c] = player
    return True

def board_to_image(board, img_size=320):
    cell = img_size // 8
    img = Image.new('RGB', (img_size, img_size), 'green')
    draw = ImageDraw.Draw(img)
    for r in range(8):
        for c in range(8):
            x0, y0 = c*cell, r*cell; x1, y1 = x0+cell, y0+cell
            draw.rectangle([x0,y0,x1,y1], outline='black')
            if board[r][c]==1: draw.ellipse([x0+4,y0+4,x1-4,y1-4], fill='white')
            elif board[r][c]==-1: draw.ellipse([x0+4,y0+4,x1-4,y1-4], fill='black')
    return img

def count_score(board):
    b = sum(cell==-1 for row in board for cell in row)
    w = sum(cell==1 for row in board for cell in row)
    return b, w

def click_handler(evt: gr.SelectData, state):
    board, player = state
    x, y = evt.index
    cell = 320/8
    r, c = int(y//cell), int(x//cell)
    if not (0<=r<8 and 0<=c<8):
        yield board_to_image(board), "ボード上をクリックしてください。", state
        return
    if not apply_move(board, r, c, player):
        yield board_to_image(board), f"({r+1},{c+1})には置けません。", state
        return
    b,w = count_score(board)
    commentary = f"あなたは({r+1},{c+1})に石を置きました。\n現在:黒{b} - 白{w}。AIの思考中…"
    player = -player
    yield board_to_image(board), commentary, (board, player)
    time.sleep(2)
    ai_mv = choose_move(board, player)
    if ai_mv:
        apply_move(board, ai_mv[0], ai_mv[1], player)
        b,w = count_score(board)
        commentary = f"AIは({ai_mv[0]+1},{ai_mv[1]+1})に石を置きました。\n現在:黒{b} - 白{w}{'あなた' if player==-1 else 'AI'}の番です。"
    else:
        commentary = "AIはパスしました。あなたの番です。"
    player = -player
    yield board_to_image(board), commentary, (board, player)

with gr.Blocks() as demo:
    gr.HTML("<h2>オセロ(リバーシ)</h2>")
    state = gr.State((initialize_board(), -1))
    board_img = gr.Image(value=board_to_image(initialize_board()), interactive=True)
    commentary = gr.Markdown("黒2 - 白2。黒の番です。")
    board_img.select(click_handler, inputs=[state], outputs=[board_img, commentary, state])
    demo.launch()