2022年にOpen AI社からChatGPTが発表されて以来、わずか2年で生成AIは驚くほどの進化を遂げた。例えば、実際の人物のような画像を生成したり、作曲や動画制作までお手の物だ。簡単なゲームであればすぐにコードが生成され、遊ぶことができる。そこで生成AIに「オセロ風ゲームを作って」とお願いしたら作ってくれるのか試してみた。
オセロ風ゲームを作るために使った生成AIはGoogle社の「Gemini 1.5 Pro」が。AIにおこなった指示は「Pythonで動くオセロ風ゲームのコードを書いてください」というもの。そのコードの内容は記事の最後に添付しておく。
GoogleのColaboratoryを新規で開き、指示された通りにスクリプトエディタを動作させてコードを実行すると、見事にオセロ風の画面が生成された。このコードを実行すると人間同士でオセロ風ゲームを楽しむことができる。操作に慣れてしまえば、ほんの数分で制作完了する。
ゲーム制作の素人でもオセロ風ゲームが作れるのだから、プロがAIを活用すればもっと高度なゲームが作れるのではないだろうか。実際にValve社が提供しているゲームやストリーミングビデオなどをダウンロードできるプラットフォーム「Steam」では、すでに1000以上のゲームが生成AIによって制作されたものだ。
このあとも筆者は、Geminiに対して「テトリス風ゲームを作ってください」といった命令文を出し、さまざまなゲームのコードを生成させてみた。コードを実行させようとするとエラーが生じることもあったが、エラーの内容をGeminiに確認すると対処方法を教えてくれるので、プログラミングの勉強にもなる。
20年近く前にプログラマーとして働いていた筆者からすると、こんなに簡単に動くコードが生成されるとは驚きだ。間違いなく生成AIがプログラミングの世界を変えたといっていいだろう。もしも現役プログラマーだった当時、筆者が同じようにオセロ風ゲームを作れといわれていたら、環境設定からなにやらで1日以上の時間をかけることが予想される。
世間を騒がせた名作ゲームが実は生成AIによって作られていたなんて時代は、もうすぐそこまで迫っているのかもしれない。
<オセロ風ゲームのコード>
import copy
# 盤面のサイズ
BOARD_SIZE = 8
# プレイヤーの色
BLACK = 1
WHITE = 2
EMPTY = 0
# 方向
DIRECTIONS = [(0, 1), (1, 0), (0, -1), (-1, 0), (1, 1), (-1, -1), (1, -1), (-1, 1)]
def create_board():
"""盤面を初期化する"""
board = [[EMPTY for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
board[3][3] = board[4][4] = WHITE
board[3][4] = board[4][3] = BLACK
return board
def print_board(board):
"""盤面を表示する"""
print(" " + " ".join([str(i + 1) for i in range(BOARD_SIZE)]))
for i in range(BOARD_SIZE):
print(str(i + 1) + " " + " ".join(["." if cell == EMPTY else "●" if cell == BLACK else "○" for cell in board[i]]))
def is_valid_move(board, player, row, col):
"""指定された場所に石を置けるか判定する"""
if board[row][col] != EMPTY:
return False
opponent = 3 - player # 相手の色を取得
for dr, dc in DIRECTIONS:
r, c = row + dr, col + dc
flipped = False
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE:
if board[r][c] == opponent:
flipped = True
elif board[r][c] == player:
if flipped:
return True
break
else:
break
r += dr
c += dc
return False
def flip_stones(board, player, row, col):
"""石を置いて、挟まれた石をひっくり返す"""
board[row][col] = player
opponent = 3 - player
for dr, dc in DIRECTIONS:
r, c = row + dr, col + dc
stones_to_flip = []
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE:
if board[r][c] == opponent:
stones_to_flip.append((r, c))
elif board[r][c] == player:
for flip_row, flip_col in stones_to_flip:
board[flip_row][flip_col] = player
break
else:
break
r += dr
c += dc
def get_valid_moves(board, player):
"""有効な手のリストを取得する"""
valid_moves = []
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
if is_valid_move(board, player, row, col):
valid_moves.append((row, col))
return valid_moves
def count_stones(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 main():
"""ゲームのメインループ"""
board = create_board()
current_player = BLACK
while True:
print_board(board)
black_count, white_count = count_stones(board)
print(f"黒: {black_count}, 白: {white_count}")
valid_moves = get_valid_moves(board, current_player)
if not valid_moves:
print(f"{current_player}の手番ですが、置ける場所がありません。パスします。")
current_player = 3 - current_player
continue
print(f"{current_player}の手番です。")
while True:
try:
row, col = map(int, input("行と列を入力してください(例:1 2):").split())
row -= 1
col -= 1
if (row, col) in valid_moves:
break
else:
print("無効な入力です。もう一度入力してください。")
except (ValueError, IndexError):
print("無効な入力です。もう一度入力してください。")
flip_stones(board, current_player, row, col)
current_player = 3 - current_player
# ゲーム終了判定
if not get_valid_moves(board, current_player) and not get_valid_moves(board, 3 - current_player):
print("ゲーム終了です。")
black_count, white_count = count_stones(board)
print_board(board)
print(f"黒: {black_count}, 白: {white_count}")
if black_count > white_count:
print("黒の勝ちです!")
elif white_count > black_count:
print("白の勝ちです!")
else:
print("引き分けです!")
break
if __name__ == "__main__":
main()