|
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() |
|
|