できるだけChatGPTだけで作るリバーシ(オセロ)ソフト その1
はじめに
オセロはツクダオリジナルの商標のため、以降はリバーシで統一します。
今回は検索用にタイトルに入れました。
以前にも書いた、ChatGPTだけでリバーシを作るという話は頓挫していたわけではなく、優先度が落ちていただけで最近になって少しずつ活動を再開しました。
今回はまずは動くものを作ることを目標に書いていきます。
選定言語は、標準ライブラリでもGUIができるPythonとしました。
まずは、ChatGPTに記載するプロンプトを考えます。
出てきたコードは次の通り
import tkinter as tk
import random
class Reversi:
def __init__(self, root):
self.root = root
self.canvas = tk.Canvas(root, width=400, height=400)
self.canvas.pack()
self.board = [[0 for _ in range(8)] for _ in range(8)]
self.board[3][3] = 1
self.board[4][4] = 1
self.board[3][4] = -1
self.board[4][3] = -1
self.player = 1
self.score_label = tk.Label(root, text="Player 1: 2, Player 2: 2")
self.score_label.pack()
self.canvas.bind("<Button-1>", self.click)
self.draw_board()
def draw_board(self):
for i in range(8):
for j in range(8):
x, y = i * 50, j * 50
self.canvas.create_rectangle(x, y, x + 50, y + 50, fill="green")
if self.board[i][j] == 1:
self.canvas.create_oval(x + 5, y + 5, x + 45, y + 45, fill="white")
elif self.board[i][j] == -1:
self.canvas.create_oval(x + 5, y + 5, x + 45, y + 45, fill="black")
self.update_score()
def click(self, event):
x, y = event.x // 50, event.y // 50
if self.place_piece(x, y, self.player, True):
self.player *= -1
self.draw_board()
self.computer_move()
def computer_move(self):
if self.player == -1:
valid_moves = [(x, y) for x in range(8) for y in range(8) if self.place_piece(x, y, self.player, False)]
if valid_moves:
move = random.choice(valid_moves)
self.place_piece(move[0], move[1], self.player, True)
self.player *= -1
self.draw_board()
def place_piece(self, x, y, player, actual=False):
if x < 0 or x >= 8 or y < 0 or y >= 8 or self.board[x][y] != 0:
return False
directions = [(0, 1), (1, 0), (0, -1), (-1, 0), (1, 1), (-1, -1), (1, -1), (-1, 1)]
to_flip = []
for dx, dy in directions:
i, j, flips = x + dx, y + dy, []
while 0 <= i < 8 and 0 <= j < 8 and self.board[i][j] == -player:
flips.append((i, j))
i += dx
j += dy
if 0 <= i < 8 and 0 <= j < 8 and self.board[i][j] == player and flips:
to_flip.extend(flips)
if not to_flip:
return False
if actual:
self.board[x][y] = player
for i, j in to_flip:
self.board[i][j] = player
return True
def update_score(self):
scores = [sum(row.count(player) for row in self.board) for player in [1, -1]]
self.score_label.config(text=f"Player 1: {scores[0]}, Player 2: {scores[1]}")
root = tk.Tk()
reversi = Reversi(root)
root.mainloop()
見た目はちゃんとした感じのものが表示されました。
が、その後に出てきた説明文に不穏なことが書いてありまして・・・
プレイヤーは先手(白ピース)としてスタートします。
クリックすることでピースを配置できます。
コンピュータは合法手からランダムにピースを配置します。
スコアがラベルとして表示されます。
その他、リバーシの基本的なルールが実装されています。
いや、先手は黒なので。
終了判定などが入っていなかったので、いくつか質問を繰り返し、最終的に次のコードができあがりました。
import tkinter as tk
import random
from tkinter import messagebox
class Reversi:
def __init__(self, root):
self.root = root
self.choose_color()
self.canvas = tk.Canvas(root, width=400, height=400)
self.canvas.pack()
self.board = [[0 for _ in range(8)] for _ in range(8)]
self.board[3][3] = -1
self.board[4][4] = -1
self.board[3][4] = 1
self.board[4][3] = 1
self.player = 1 # Player starts with black pieces
self.score_label = tk.Label(root, text="Player 1: 2, Player 2: 2")
self.score_label.pack()
self.canvas.bind("<Button-1>", self.click)
self.draw_board()
self.move_count = 0
def choose_color(self):
self.color_choice = tk.Toplevel(self.root)
tk.Label(self.color_choice, text="Choose your color:").pack()
tk.Button(self.color_choice, text="Black", command=lambda: self.start_game(1)).pack()
tk.Button(self.color_choice, text="White", command=lambda: self.start_game(-1)).pack()
def start_game(self, color):
self.color_choice.destroy()
self.canvas = tk.Canvas(self.root, width=400, height=400)
self.canvas.pack()
self.initialize_board()
self.player = color # Player chooses the color
self.score_label = tk.Label(self.root, text="Player 1: 2, Player 2: 2")
self.score_label.pack()
self.canvas.bind("<Button-1>", self.click)
self.draw_board()
if self.player == -1:
self.computer_move()
def initialize_board(self):
self.board = [[0 for _ in range(8)] for _ in range(8)]
self.board[3][3] = -1
self.board[4][4] = -1
self.board[3][4] = 1
self.board[4][3] = 1
self.move_count = 0
def draw_board(self):
for i in range(8):
for j in range(8):
x, y = i * 50, j * 50
self.canvas.create_rectangle(x, y, x + 50, y + 50, fill="green")
if self.board[i][j] == 1:
self.canvas.create_oval(x + 5, y + 5, x + 45, y + 45, fill="black")
elif self.board[i][j] == -1:
self.canvas.create_oval(x + 5, y + 5, x + 45, y + 45, fill="white")
self.update_score()
def click(self, event):
x, y = event.x // 50, event.y // 50
if self.place_piece(x, y, self.player, True):
self.move_count += 1
self.player *= -1
self.draw_board()
self.check_game_end()
def computer_move(self):
if self.player == -1:
valid_moves = [(x, y) for x in range(8) for y in range(8) if self.place_piece(x, y, self.player, False)]
if valid_moves:
move = random.choice(valid_moves)
self.place_piece(move[0], move[1], self.player, True)
self.move_count += 1
self.player *= -1
self.draw_board()
else:
self.player *= -1 # No valid moves, switch turn to the other player
self.check_game_end()
def place_piece(self, x, y, player, actual=False):
if x < 0 or x >= 8 or y < 0 or y >= 8 or self.board[x][y] != 0:
return False
directions = [(0, 1), (1, 0), (0, -1), (-1, 0), (1, 1), (-1, -1), (1, -1), (-1, 1)]
to_flip = []
for dx, dy in directions:
i, j, flips = x + dx, y + dy, []
while 0 <= i < 8 and 0 <= j < 8 and self.board[i][j] == -player:
flips.append((i, j))
i += dx
j += dy
if 0 <= i < 8 and 0 <= j < 8 and self.board[i][j] == player and flips:
to_flip.extend(flips)
if not to_flip:
return False
if actual:
self.board[x][y] = player
for i, j in to_flip:
self.board[i][j] = player
return True
def update_score(self):
scores = [sum(row.count(player) for row in self.board) for player in [1, -1]]
self.score_label.config(text=f"Player 1: {scores[0]}, Player 2: {scores[1]}")
def check_game_end(self):
player_moves = [(x, y) for x in range(8) for y in range(8) if self.place_piece(x, y, self.player, False)]
opponent_moves = [(x, y) for x in range(8) for y in range(8) if self.place_piece(x, y, -self.player, False)]
if not player_moves and not opponent_moves or self.move_count >= 60:
self.show_game_end()
elif not player_moves: # No valid moves for the current player, switch turn
self.player *= -1
def show_game_end(self):
scores = [sum(row.count(player) for row in self.board) for player in [1, -1]]
winner = "Draw"
if scores[0] > scores[1]:
winner = "Player 1 wins"
elif scores[1] > scores[0]:
winner = "Player 2 wins"
messagebox.showinfo("Game Over", f"{winner}! Final Score - Player 1: {scores[0]}, Player 2: {scores[1]}")
self.canvas.destroy()
self.score_label.destroy()
self.choose_color()
root = tk.Tk()
reversi = Reversi(root)
root.mainloop()
初期配置は白黒逆だし、まだ先手後手の選択もできませんし、コンピュータの手番にならない(プレイヤーが相手側の石を置ける)など、まだまだ問題点は多いです。
これを見て作ってみようと思った方は、この辺りのことも最初の指示にしっかり書いた方がいいでしょう。いい感じにやってくれそうで、やってくれないです。
それでは、今日はここまで。また次回に。
次回は、バグ修正と、評価関数、探索関数の簡易的なものを作っていきます。
この記事が気に入ったらサポートをしてみませんか?