GPT-4はどこまで進化したのか?オセロで戦うことができるのか検証してみた

GPT-4とオセロで遊ぶことができないか、様々なプロンプトを試してみた検証記事です。
2023.03.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。CX 事業本部 Delivery 部のきんじょーです。

先日、TwitterでGPT-3.5とオセロをする実験する興味深いツイートを見ました。

上記実験では、初手で左角を取ってくるという自由奔放さを見せていたChatGPTでしたが、昨日公開されたGPT-4ならば可能なのではないかと期待を抱き試してみました!

試してみた

以下のように、徐々に与える情報を増やして検証していきます.

  1. 事前情報を与えずにオセロを開始する
  2. オセロのルールを伝えた上でゲームを開始する
  3. オセロのルールを伝えた上で、裏返す処理をより詳細に伝えてゲームを開始する
  4. オセロのルールを伝えた上で、裏返す処理をTypeScriptのサンプルコードで伝えてゲームを開始する

1. 事前情報を与えずにオセロを開始する

入力するプロンプト

「オセロを開始すること」、「GPTとの入出力のルール」の2つの情報与えて、ゲームを開始します。

あなたはオセロ専用のAI、GPTReverciでAIエンジンとして使われるGPTモデルです。
オセロを始めましょう。

GPTへの入力は2つです。

1. 現在の盤面状態
2. プレイヤーが次に置く場所

GPTは入力を受けて、以下の3つを出力してください。

1. プレイヤーが置いた後の盤面状態
2. GPTが次に置く場所
3. GPTが置いた後の盤面状態

それでは私の番から、私の石はの色は黒(B)で先にスタートします。

1.  現在の盤面状態
  a b c d e f g h
1 - - - - - - - - 
2 - - - - - - - - 
3 - - - - - - - - 
4 - - - W B - - - 
5 - - - B W - - - 
6 - - - - - - - - 
7 - - - - - - - - 
8 - - - - - - - - 

2. プレイヤー次に置く場所

c4

GPT-4の出力

1. プレイヤーが置いた後の盤面状態

  a b c d e f g h
1 - - - - - - - -
2 - - - - - - - -
3 - - - - - - - -
4 - - B B B - - -
5 - - - B W - - -
6 - - - - - - - -
7 - - - - - - - -
8 - - - - - - - -

2. GPTが次に置く場所

e6

3. GPTが置いた後の盤面状態

  a b c d e f g h
1 - - - - - - - -
2 - - - - - - - -
3 - - - - - - - -
4 - - B B B - - -
5 - - - B W - - -
6 - - - - W - - -
7 - - - - - - - -
8 - - - - - - - -

惜しいです! 初手でa1には置かなくなったので、進化しているとは言えますが、e6は白で挟める石がないので置いてはいけない場所です。

次に、「石を置くことのできる場所」と、「裏返す際のルール」について説明を加えて試してみます。

2. オセロのルールを伝えた上でゲームを開始する

ChatGPTに教えてもらったオセロのルールを、少し加筆してプロンプトに加えました。

入力するプロンプト

あなたはオセロ専用のAI、GPTReverciでAIエンジンとして使われるGPTモデルです。

まず初めにオセロのルールを説明します。

## オセロのルールについて
オセロ(別名リバーシ)は、2人用のボードゲームで、8x8マスの盤と、黒と白の両面がある64個の石で遊びます。ゲームの開始時に、プレイヤーは白と黒どちらの石を使うかを選びます。最後に盤上に自分の色の石がより多くある方が勝ちです。以下に、簡単なルールを説明します。

1. ゲーム開始時、盤の中央に黒と白の石が交互に配置されます。
2. プレイヤーは交互に石を置きます。石を置く際、自分の色の石で相手の石を挟むことができる場所に置かなければなりません。
  - 挟む方向は「縦」「横」「斜め」です。この8方向に挟める相手の石がある場合(つまり、隣接した相手の石があり、その先に自分の石がある場合)は、そのマスに自分の石を置く事ができますが、そうでない場合は石を置くことができません。
3. 石を置いた後、既に置いてあった自分の石と、今回おいた石の間で、挟んでいる相手の石を、自分の色の石で置き換えます。
4. 盤上に石が置ける場所がない場合、そのプレイヤーはPASSをします。両プレイヤーが連続してPASSした場合、ゲームは終了します。
5. ゲーム終了時に、盤上に自分の色の石がより多いプレイヤーが勝ちです。
6. このオセロでは黒の石を「B」、白の石を「W」と言う記号で表します。

## GPTへの入出力について

GPTへの入力は2つです。

1. 現在の盤面状態
2. プレイヤーが次に置く場所

GPTは入力を受けて、以下の3つを出力してください。

1. プレイヤーが置いた後の盤面状態
2. GPTが次に置く場所
3. GPTが置いた後の盤面状態

それでは私の番から、私の石はの色は黒(B)で先にスタートします。

1.  現在の盤面状態
  a b c d e f g h
1 - - - - - - - - 
2 - - - - - - - - 
3 - - - - - - - - 
4 - - - W B - - - 
5 - - - B W - - - 
6 - - - - - - - - 
7 - - - - - - - - 
8 - - - - - - - - 

2. プレイヤー次に置く場所

c4

GPT-4の出力

1. プレイヤーが置いた後の盤面状態

  a b c d e f g h
1 - - - - - - - -
2 - - - - - - - -
3 - - - - - - - -
4 - - B B B - - -
5 - - - B W - - -
6 - - - - - - - -
7 - - - - - - - -
8 - - - - - - - -

2. GPTが次に置く場所

c5

3. GPTが置いた後の盤面状態

  a b c d e f g h
1 - - - - - - - -
2 - - - - - - - -
3 - - - - - - - -
4 - - B B B - - -
5 - - W B W - - -
6 - - - - - - - -
7 - - - - - - - -
8 - - - - - - - -

先ほどよりも惜しいです! 置く場所はあっていますが、挟んだら裏返すというルールを反映できなかったようです。

次は、裏返すルールについてさらに詳細の情報を与えてみます。

3. オセロのルールを示した上で、裏返す処理をより詳細に伝えた上でゲームを開始する

入力するプロンプト

裏返すルールを伝えました。試しているうちに「裏返す」という表現が伝わりづらいように感じたため「石を置き換える」という表現に変えています。

あなたはオセロ専用のAI、GPTReverciでAIエンジンとして使われるGPTモデルです。

まず初めにオセロのルールを説明します。

## オセロのルールについて
オセロ(別名リバーシ)は、2人用のボードゲームで、8x8マスの盤と、黒と白の両面がある64個の石で遊びます。ゲームの開始時に、プレイヤーは白と黒どちらの石を使うかを選びます。最後に盤上に自分の色の石がより多くある方が勝ちです。以下に、簡単なルールを説明します。

1. ゲーム開始時、盤の中央に黒と白の石が交互に配置されます。
2. プレイヤーは交互に石を置きます。石を置く際、自分の色の石で相手の石を挟むことができる場所に置かなければなりません。
  - 挟む方向は「縦」「横」「斜め」です。この8方向に挟める相手の石がある場合(つまり、隣接した相手の石があり、その先に自分の石がある場合)は、そのマスに自分の石を置く事ができますが、そうでない場合は石を置くことができません。
3. 石を置いた後、既に置いてあった自分の石と、今回おいた石の間で、挟んでいる相手の石を、自分の色の石で置き換えます。
4. 盤上に石が置ける場所がない場合、そのプレイヤーはPASSをします。両プレイヤーが連続してPASSした場合、ゲームは終了します。
5. ゲーム終了時に、盤上に自分の色の石がより多いプレイヤーが勝ちです。
6. このオセロでは黒の石を「B」、白の石を「W」と言う記号で表します。

## 挟んだ石を置き換えるルールについて

石を置き換えるルールは重要なので、より詳細に説明します。


初期状態を以下の状態とします。

  a b c d e f g h
1 - - - - - - - -
2 - - - - - - - -
3 - - - - - - - -
4 - - B B B - - -
5 - - - B W - - -
6 - - - - - - - -
7 - - - - - - - -
8 - - - - - - - -

初期状態にc5に石を置くと以下の状態になります。

  a b c d e f g h
1 - - - - - - - -
2 - - - - - - - -
3 - - - - - - - -
4 - - B B B - - -
5 - - W B W - - -
6 - - - - - - - -
7 - - - - - - - -
8 - - - - - - - -

c5のWとe5のWで、d5のBを挟んでいるため、d5はWで置き換える必要があります。
置き換えた後の盤面状態は以下の通りです。

  a b c d e f g h
1 - - - - - - - -
2 - - - - - - - -
3 - - - - - - - -
4 - - B B B - - -
5 - - W W W - - -
6 - - - - - - - -
7 - - - - - - - -
8 - - - - - - - -

## GPTへの入出力について

GPTへの入力は2つです。

1. 現在の盤面状態
2. プレイヤーが次に置く場所

GPTは入力を受けて、以下の3つを出力してください。

1. プレイヤーが置いた後の盤面状態
2. GPTが次に置く場所
3. GPTが置いた後の盤面状態

それでは私の番から、私の石はの色は黒(B)で先にスタートします。

1.  現在の盤面状態
  a b c d e f g h
1 - - - - - - - - 
2 - - - - - - - - 
3 - - - - - - - - 
4 - - - W B - - - 
5 - - - B W - - - 
6 - - - - - - - - 
7 - - - - - - - - 
8 - - - - - - - - 

2. プレイヤー次に置く場所

c4

GPT-4の出力

1. プレイヤーが置いた後の盤面状態

  a b c d e f g h
1 - - - - - - - -
2 - - - - - - - -
3 - - - - - - - -
4 - - B B B - - -
5 - - - B W - - -
6 - - - - - - - -
7 - - - - - - - -
8 - - - - - - - -

2. GPTが次に置く場所

c3

3. GPTが置いた後の盤面状態

  a b c d e f g h
1 - - - - - - - -
2 - - - - - - - -
3 - - W - - - - -
4 - - B B B - - -
5 - - - B W - - -
6 - - - - - - - -
7 - - - - - - - -
8 - - - - - - - -

やはり裏返すことができません。。 自然言語でダメなら、コードで例を示してみてはどうだろうと考えました。

4. オセロのルールを示した上で、裏返す処理をTypeScriptのコードで伝えた上でゲームを開始する

挟んだ石を裏返すコードはもちろんChatGPTに書いてもらいます。 設計情報を書きながら、今後コーディング作業がこのように置き換わるのではないかと感じながら、プロンプトを組み立てていきます。

挟んだ石を裏返すコードをChatGPTに依頼したプロンプト

オセロゲームを作ろうとしています。
TypeScriptでオセロの盤面状態の保存と、石を置いた後にひっくり返すロジックを実装したいです。

以下の要件に従い、オセロの盤面状態を更新して返却する関数のコードを出力してください。

1. 引数
  1. オセロの盤面状態
    - 8x8の2次元配列で表現します
  2. 次に置く場所
    - x, y座標のtupleで表現します
  3. 自分の色
2. 処理概要
  1. 引数で渡されてきた「オセロの盤面状態」と「次に石を置く場所」を比較して、「次に石を置く場所」に石を置くことができるかバリデーションしてください。
    - 石を置くことができるのは、自分の色の石で相手の石を挟むことができる場所だけです。
  2. 石を置くことができる場合、挟んだ相手の石を、自分の石で置き換えてください。
    - 2次元配列上で、既に存在する自分の石と、縦横斜めで挟んでいる相手の石が置き換えの対象です。

出力されたコード

type Board = number[][];
type Position = [number, number];

const EMPTY = 0;
const BLACK = 1;
const WHITE = 2;

function updateBoard(board: Board, position: Position, myColor: number): Board {
  const [x, y] = position;
  const opponentColor = myColor === BLACK ? WHITE : BLACK;

  if (board[y][x] !== EMPTY) {
    throw new Error("Invalid move: The cell is not empty.");
  }

  const directions = [
    [-1, -1], [-1, 0], [-1, 1],
    [0, -1],           [0, 1],
    [1, -1], [1, 0], [1, 1],
  ];

  let updatedBoard = JSON.parse(JSON.stringify(board));
  let validMove = false;

  for (const [dx, dy] of directions) {
    let xCurrent = x + dx;
    let yCurrent = y + dy;
    let flippedStones: Position[] = [];

    while (xCurrent >= 0 && xCurrent < 8 && yCurrent >= 0 && yCurrent < 8) {
      if (updatedBoard[yCurrent][xCurrent] === EMPTY) {
        break;
      } else if (updatedBoard[yCurrent][xCurrent] === opponentColor) {
        flippedStones.push([xCurrent, yCurrent]);
      } else if (updatedBoard[yCurrent][xCurrent] === myColor) {
        if (flippedStones.length > 0) {
          validMove = true;
          for (const [fx, fy] of flippedStones) {
            updatedBoard[fy][fx] = myColor;
          }
        }
        break;
      }
      xCurrent += dx;
      yCurrent += dy;
    }
  }

  if (!validMove) {
    throw new Error("Invalid move: No stones can be flipped.");
  }

  updatedBoard[y][x] = myColor;
  return updatedBoard;
}

出力されたコードを読むと、directionsで定義した8方向に対して走査を行い、隣接するopponentColorがある場合は、裏返す石を保持する配列flippedStonesに格納して裏返す処理が記載されています。
あくまでサンプルとして使うため、試してはいませんが動きそうなコードです!

入力するプロンプト

それでは「挟んだ場合の石の置き換えについて」の説明をTypeScriptのコードに置き換えてレスポンスを検証してみます。 検証する中で、入出力もTypeScriptのサンプルコードと対応する形の方が精度が出るとGPT-4から回答があったので、プロンプトもそれに合わせて修正をしています。

あなたはオセロ試合専用のAI、GPTReverciでAIエンジンとして使われるGPTモデルです。

まず初めにオセロのルールを説明します。

## オセロのルール
オセロ(別名リバーシ)は、2人用のボードゲームで、8x8マスの盤と、黒と白の両面がある64個の石で遊びます。ゲームの開始時に、プレイヤーは白と黒どちらの石を使うかを選びます。最後に盤上に自分の色の石がより多くある方が勝ちです。以下に、簡単なルールを説明します。

1. ゲーム開始時、盤の中央に黒と白の石が交互に配置されます。
2. プレイヤーは交互に石を置きます。石を置く際、自分の色の石で相手の石を挟むことができる場所に置かなければなりません。
3. 石を置いた後、既に置いてあった自分の石と、今回おいた石の間で、挟んでいる相手の石を、自分の色の石で置き換えます。
4. 盤上に石が置ける場所がない場合、そのプレイヤーはPASSをします。両プレイヤーが連続してPASSした場合、ゲームは終了します。
5. ゲーム終了時に、盤上に自分の色の石がより多いプレイヤーが勝ちです。
6. このオセロでは黒の石を「2」、白の石を「1」と言う記号で表します。

### 挟んだ場合の石の置き換えについて

オセロの重要なルールのため、TypeScriptのサンプルコードを用いてより詳しく説明します。

```
~先ほど出力したコード~
```

## GPTの入力と出力について

GPT への入力は 2 つです。

1. 現在の盤面状態(board)
2. プレイヤーが次に置く場所(position)
3. プレイヤーの石の色

  - board[行][列]とした時の[行,列]の座標

GPT は入力を受けて、以下の 3 つを出力してください。

1. プレイヤーが置いた後の盤面状態(board)

  - 「プレイヤーが次に置く場所」で与えられた position と、現在の盤面状態で与えられた board を元に、石を置いた後に、「挟んだ場合の石の置き換えについて」で示した updateBoard()関数を利用して、石の置き換えを行った後の状態を出力してください
  - 石の置き換えがとても重要なので、`flippedStones`を用いて必ず石の置き換えを実施してください。

2. GPT が次に置く場所(position)

  - 最初に説明したルールの範囲で次に置く場所を考えてください
  - board[行][列]とした時の[行,列]の座標
  - 置くことができない場合は「PASS」と言ってください

3. GPT が置いた後の盤面状態(board)
  - プレイヤーが置いた後の盤面状態(board)で出力した最新の盤面状態と、「GPT が次に置く場所」で与えられた position を利用して「挟んだ場合の石の置き換えについて」で示した updateBoard()関数を利用して、石の置き換えを行った後の状態を出力してください

それでは私の番から、私の石はの色は黒(2)で先にスタートします。

1.  現在の盤面状態

```
[
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 2, 1, 0, 0, 0],
  [0, 0, 0, 1, 2, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
]
```

2. プレイヤーが次に置く場所

```
board[4][2]
```

3. プレイヤーが置く石の色

黒(2)

GPT4-の出力

1. プレイヤーが置いた後の盤面状態

[
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 2, 1, 0, 0, 0],
  [0, 0, 2, 1, 2, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
]

2. GPT が次に置く場所(position)

board[5][3]

3. GPT が置いた後の盤面状態(board)

[
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 2, 1, 0, 0, 0],
  [0, 0, 2, 1, 2, 0, 0, 0],
  [0, 0, 0, 1, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
]

やはり、挟んだ石を裏返すことができません。。

この他には「石を置いた直後の状態」、「挟んだ石を裏返した後の状態」など細かいステップで思考内容を出力することで、改善がみられるかを試してみましたが、やはり石を置く場所と裏返す処理が安定せず、GPT-4とオセロを楽しむことはできませんでした。

まだGPT-4にオセロは早かった?

戦略的な思考はできなくても、オセロのルールに従いランダムに石を置く程度であればできるのではないかと期待して検証してみました。
今回の検証では、現時点で事前にオセロAIとしての設定を吹き込んでそのまま利用することは出来なさそう、という結果に終わりました。

GPT-5がもう準備中との話も聞こえてきます。次のモデルではGPTとオセロができるようになっていると嬉しいですね。

以上。CX 事業本部 Delivery 部のきんじょーでした。