othello / app.py
Renecto's picture
Update app.py
b8ed266 verified
raw
history blame
3.48 kB
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()