見出し画像

AIが作るAI対戦基盤


AI同士が対戦するプラットフォームって、いざ実装するぞー、となると案外面倒なものでして。それならいっそ、その部分からChatGPTに作ってもらったらよくない?というお話。

※今日はプログラミング色強めの話になります。
 明日はプログラミング色弱めの話にするので、
 今日だけちょっとがまんして。

対戦基盤

まずは、
「人工知能同士を戦わせるプラットフォームをJavascriptで実装して」
とお願いしてみる。

// ゲームのルール
const gameRules = {
  // ルールの定義
};

// AIプログラム例
class AIPlayer {
  constructor() {
    // AIの初期化
  }

  // 行動を決定するメソッド
  makeMove() {
    // 行動のロジック
  }
}

// プラットフォームの実装
class GamePlatform {
  constructor(player1, player2) {
    this.player1 = player1;
    this.player2 = player2;
    this.gameState = null;
  }

  // ゲームの進行を管理するメソッド
  playGame() {
    // ゲームの進行ロジック
  }
}

// 使用例
const aiPlayer1 = new AIPlayer();
const aiPlayer2 = new AIPlayer();

const platform = new GamePlatform(aiPlayer1, aiPlayer2);
platform.playGame();

じゃんけんでよくない?

「ゲームルールはじゃんけんで」という条件を追加

// ジャンケンの手の定義
const HANDS = ['rock', 'paper', 'scissors'];

// ランダムに手を選択するAIプレイヤー
class RandomAI {
  makeMove() {
    const randomIndex = Math.floor(Math.random() * HANDS.length);
    return HANDS[randomIndex];
  }
}

// ジャンケンゲームのプラットフォーム
class RockPaperScissorsGame {
  constructor(player1, player2) {
    this.player1 = player1;
    this.player2 = player2;
  }

  playRound() {
    const move1 = this.player1.makeMove();
    const move2 = this.player2.makeMove();

    console.log(`Player 1 plays ${move1}`);
    console.log(`Player 2 plays ${move2}`);

    // 勝敗の判定
    if (move1 === move2) {
      console.log('It\'s a tie!');
    } else if (
      (move1 === 'rock' && move2 === 'scissors') ||
      (move1 === 'paper' && move2 === 'rock') ||
      (move1 === 'scissors' && move2 === 'paper')
    ) {
      console.log('Player 1 wins!');
    } else {
      console.log('Player 2 wins!');
    }
  }

  playGame(rounds) {
    for (let round = 1; round <= rounds; round++) {
      console.log(`\n--- Round ${round} ---`);
      this.playRound();
    }
  }
}

// 使用例
const randomAI1 = new RandomAI();
const randomAI2 = new RandomAI();

const game = new RockPaperScissorsGame(randomAI1, randomAI2);
game.playGame(3); // 3ラウンドのゲームをプレイ

そうだよね。とりあえずAIプレイヤーを定義する時は、やっぱりランダムに手を選択するよね。ChatGPTとわかり合えた気がするのはなぜだろう。

やっぱり遺伝的アルゴリズム(GA)でしょ。

何が「やっぱり」なのか分からないと思うんですけれども。私は遺伝的アルゴリズムが大好きなんです。ロンデルじゃないとゲームを遊んだ気にならない、というような話と同じなんです。(?!)

というわけで「AI1を遺伝的アルゴリズムで」という指示を追加

// 遺伝子の長さ(ジャンケンの手の数)
const GENES_LENGTH = 3;

// ランダムな遺伝子を生成する関数
function generateRandomGenes() {
  const genes = [];
  for (let i = 0; i < GENES_LENGTH; i++) {
    const randomIndex = Math.floor(Math.random() * HANDS.length);
    genes.push(HANDS[randomIndex]);
  }
  return genes;
}

// 遺伝子から手を選択するAIプレイヤー
class GeneticAI {
  constructor(genes) {
    this.genes = genes || generateRandomGenes();
  }

  makeMove() {
    // 遺伝子から手を選択
    return this.genes[Math.floor(Math.random() * GENES_LENGTH)];
  }

  // 適応度の計算(勝利回数を基準に)
  calculateFitness(wins) {
    this.fitness = wins;
  }

  // 交叉(クロスオーバー)処理
  crossover(partner) {
    const newGenes = [];
    const midpoint = Math.floor(Math.random() * GENES_LENGTH);

    for (let i = 0; i < GENES_LENGTH; i++) {
      if (i > midpoint) {
        newGenes.push(this.genes[i]);
      } else {
        newGenes.push(partner.genes[i]);
      }
    }

    return new GeneticAI(newGenes);
  }

  // 突然変異処理
  mutate() {
    const mutationRate = 0.1; // 突然変異率

    for (let i = 0; i < GENES_LENGTH; i++) {
      if (Math.random() < mutationRate) {
        const randomIndex = Math.floor(Math.random() * HANDS.length);
        this.genes[i] = HANDS[randomIndex];
      }
    }
  }
}

// 遺伝的アルゴリズムに基づくジャンケンゲームのプラットフォーム
class GeneticGamePlatform extends RockPaperScissorsGame {
  constructor(player1, player2) {
    super(player1, player2);
  }

  evolveAI(generationSize, numGenerations) {
    let population = [];

    for (let i = 0; i < generationSize; i++) {
      population.push(new GeneticAI());
    }

    for (let generation = 1; generation <= numGenerations; generation++) {
      console.log(`\n--- Generation ${generation} ---`);

      for (let i = 0; i < population.length; i++) {
        const player1 = population[i];

        for (let j = 0; j < population.length; j++) {
          if (i !== j) {
            const player2 = population[j];
            const game = new RockPaperScissorsGame(player1, player2);
            const wins = game.playAndGetWins(100); // 100ラウンドのゲームをプレイ

            player1.calculateFitness(wins);
          }
        }
      }

      population.sort((a, b) => b.fitness - a.fitness);

      const newPopulation = [];

      for (let i = 0; i < generationSize / 2; i++) {
        const parent1 = population[i];
        const parent2 = population[i + 1];
        const child = parent1.crossover(parent2);
        child.mutate();
        newPopulation.push(parent1, parent2, child);
      }

      population = newPopulation;
    }

    // 最終的な最も適応度の高いAIを取得
    const bestAI = population[0];
    console.log('\n--- Best AI ---');
    console.log('Genes:', bestAI.genes);
    console.log('Fitness:', bestAI.fitness);
  }
}

// 使用例
const geneticAIPlayer = new GeneticAI();
const randomAIPlayer = new RandomAI();

const geneticGamePlatform = new GeneticGamePlatform(geneticAIPlayer, randomAIPlayer);
geneticGamePlatform.evolveAI(10, 5); // 10個体の集団を5世代進化させる

いろんなこと考えながら(忘れてる構文とかGoogleで検索しながら…)3時間くらいかけて実施する作業が、まさかの数分で完了ですわ。商売あがったりですわ。(AIに職を追われる、追われないみたいな話がよくあるけれど、こういうことかと目の当たりにした気がする)

コードを読めない人にはさっぱりだと思うので、遺伝的アルゴリズムについては、そのうち遺伝的アルゴリズム愛をこれでもか!と語る時に仕組みを聞いてもらうとして、プログラミングとかよくわからないんだよなぁ、という人でもAIプレイヤーを使ったテストプレイができるかもしれないレベルまでは来ているんだなということが上の実験でわかってもらえたかと。

明日は誰が読んでもなんとなくわかる話にすることを誓い、今日はこのあたりで。ほなね。

いただいたサポートは、きっと、ドイツアマゾンからの送料に変わると思います。 温かいご支援、お待ちしております。