Adding Your Own Games to the LLM Game Simulation



This guide will instruct you on how to add games to the LLM Benchmark.

The example code in this guide is based on our Tic-Tac-Toe implementation.

You can copy/paste the code examples provided in this guide into your IDE and modify them as instructed.

  1. Implementing the Game Board
    In this section, you will be modifying the "index.html" file for the Game Simulation page.

    1. Within the "game-type" select element, add an option for your game.
      <select id="game-type" name="game-type">
      <option value="tic-tac-toe">Tic-Tac-Toe</option>
      <option value="connect-four">Connect Four</option>
      <option value="gomoku">Gomoku</option>
      <!-- Add an option for your game here. -->
      </select>
    2. Within the "board-container" div, add the HTML necessary to display your game (we will discuss styling in the next section.)
      The ID of your game board should be the value you set for your game in the select dropdown above with "-board" appended to it.
      <div id="board-container">
      <div id="tic-tac-toe-board">
        <div class="board-row">
         <div class="board-cell" id="tic-tac-toe-1-1"></div>
         <div class="board-cell" id="tic-tac-toe-1-2"></div>
         <div class="board-cell" id="tic-tac-toe-1-3"></div>
        </div>
        <div class="board-row">
         <div class="board-cell" id="tic-tac-toe-2-1"></div>
         <div class="board-cell" id="tic-tac-toe-2-2"></div>
         <div class="board-cell" id="tic-tac-toe-2-3"></div>
        </div>
        <div class="board-row">
         <div class="board-cell" id="tic-tac-toe-3-1"></div>
         <div class="board-cell" id="tic-tac-toe-3-2"></div>
         <div class="board-cell" id="tic-tac-toe-3-3"></div>
        </div>
      </div>

      <!-- Code lines skipped for this guide... -->
        <div class="board-row">
         <div class="board-cell" id="gomoku-15-14"></div>
         <div class="board-cell" id="gomoku-15-15"></div>
        </div>
      </div>
      <!-- Add HTML for your game here. -->
      </div>


  2. Styling Your Game Board
    In this section, you will be modifying the "game-simulation.css" file.

    Note that your game's styling may vary significantly compared to the styles used in our study. We have provided our tic-tac-toe board's styling for your review.

    Your game board's height (and ideally, width) should total 60vh.

    1. Styling for entire game board div:
      #tic-tac-toe-board,
      #connect-four-board,
      #gomoku-board {
       display: table;
       width: 60vh;
       height: 60vh;
       margin-right: 1vh;
       margin-left: 1vh;
      }
    2. Styling for game board rows:
      #tic-tac-toe-board .board-row,
      #connect-four-board .board-row,
      #gomoku-board .board-row {
       display: table-row;
      }
    3. Styling for game board cells:

      We are aiming for a width/height of 60vh. Therefore, accounting for the 3vh of total borders for each row/column, the width/height of each cell in our 3x3 tic-tac-toe board should be (60 - 3) / 3 = 19vh.
      #tic-tac-toe-board .board-cell {
       display: table-cell;
       text-align: center;
       vertical-align: middle;
      } #tic-tac-toe-board .board-cell {
       width: 19vh;
       height: 19vh;
       font-size: 13vh;
       background-color: white;
      } #tic-tac-toe-1-1 {
       border-left: 0.5vh solid white;
       border-top: 0.5vh solid white;
       border-right: 0.5vh solid black;
       border-bottom: 0.5vh solid black;
      } #tic-tac-toe-1-2 {
       border-left: 0.5vh solid black;
       border-top: 0.5vh solid white;
       border-right: 0.5vh solid black;
       border-bottom: 0.5vh solid black;
      }

      ...
      /* Other lines are omitted for this guide, but a unique set of borders is applied to each cell to create a tic-tac-toe board. */


  3. Implementing the Game Class
    1. Create a JavaScript file for your game in the "game-simulation" folder.

      For the rest of this section, you will be modifying the file you've just created.

    2. At the top of your game flass file, import the Move class using this line:
      import { Move } from "./classes.js";
    3. Create a class for your game and be sure to use the "export" keyword so that your game can be accessed in other JavaScript files.
      export class TicTacToe {
      ...
      (Internal methods (discussed below.)
      ...
      }
    4. Implement the static explainGame() method. This method should return your game explanation prompt, ending with a space and a newline character \n.
      static explainGame() {
      return "Tic-Tac-Toe is a two-player game played on a 3 by 3 grid. The first player uses X symbols, and the second player uses O symbols. Players take turns placing their symbols in an empty cell on the grid. The objective is to align three of your symbols either horizontally, vertically, or diagonally. The player who first aligns three of their symbols wins the game. Strategic placement is crucial; besides aiming to align their symbols, players must also block their opponent's potential alignments to avoid defeat. \n";
      }
    5. Implement the static formatNextMove() method. This method should return your move formatting prompt, starting with a space and ending with a space and a newline character \n. You should ask the LLM to request the move in a JSON format.
      static formatNextMove() {
      return " Suggest your next move in the following JSON format: {'row': RowNumber, 'column': ColumnNumber}. Do not include any additional commentary in your response. Replace RowNumber and ColumnNumber with the appropriate numbers for your move. Both RowNumber and ColumnNumber start at 1 (top left corner is {'row': 1, 'column': 1}). The maximum value for RowNumber and ColumnNumber is 3, as the grid is 3 by 3. \n";
      }
    6. Implement the static systemPrompt() method. This method should return the system prompt for your LLM.

      Note that none of the LLMs in our study required a "system prompt" parameter, but you may use/modify this method in case any LLMs you use require a system prompt.
      static systemPrompt() {
      return this.formatNextMove();
      }
    7. Implement the static invalidMoveWarning() method. This method should return a warning to the LLM about disqualification after they make a certain number of invalid moves, starting with a space and ending with a space and a newline character \n.

      Note that this warning calls the getMaxInvalidMoves() method in your class to obtain the maximum number of invalid moves.
      static invalidMoveWarning() {
      return " Please note that your move will be considered invalid if your response does not follow the specified format, or if you provide a RowNumber or ColumnNumber that is out of the allowed range, or already occupied by a previous move. Making more than " + this.getMaxInvalidMoves() + " invalid moves will result in disqualification. \n";
      }
    8. Implement the static promptVersion() method. This method should return the date that the prompts in your game class were last modified in YYYY-MM-DD format.
      static promptVersion() {
      return "2024-06-12";
      }
    9. Implement the static getMaxMoves() method. This method should return the maximum total number of moves allowed in the game. The game will be cancelled if the total number of moves made during the game (from both LLMs combined) reaches this amount.
      static getMaxMoves() {
      return 20;
      }
    10. Implement the static getMaxInvalidMoves() method. This method should return the maximum total number of moves allowed in the game. If a player's invalid move count goes above this number, they will be disqualified.

      For this study, this figure was calculated as the average number of cells in a row/column of the board, but this may be modified for your game.
      static getMaxInvalidMoves() {
      return 3;
      }
    11. Implement the static listPlayerMoves(player) method. For the grid-based games used in this study, this method accepts the current player number and returns a string list of coordinates where they have placed moves in the format (row, column). This method may be modified for non-grid-based games.

      For example, if player 1 (X) in tic-tac-toe has placed in the first row/column and the last (3rd) row/column, the list returned from listPlayerMoves(1) would be [“1,1”, “3,3”].
      static listPlayerMoves(player) {
      let movesList = [];
      let playerSymbol = (player === 1) ? "X" : "O";
      for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
         if (document.getElementById("tic-tac-toe-" + (i + 1) + "-" + (j + 1)).innerText === playerSymbol) {
          movesList.push((i + 1) + "," + (j + 1));
         }
        }
       }
      return movesList;
      }
    12. Implement the static listBoard() method, which will be called when using the "list" prompt type or progress display type. To obtain a list of the player moves, we call the listPlayerMoves() method defined above for each player, but your implementation cna be modified.

      This method should return a string consisting of the following, in order:
      1. An explanation of how the state of the game will be provided in this prompt, starting with a space and ending with a space and a newline character \n.
      2. The following string: “ The current state of the game is as follows: \n”
      3. The following string: “ The locations occupied by the first player: “
      4. A string list of moves made (or locations occupied) by the first player, formatted as described in your explanation, ending with a space and a newline character \n.
      5. The following string: “ The locations occupied by the second player: “
      6. A string list of moves made (or locations occupied) by the second player, formatted as described in your explanation, ending with a space and a newline character \n.
      static listBoard() {
      let gameStatus = "";
      let firstPlayerMoves = this.listPlayerMoves(1);
      let secondPlayerMoves = this.listPlayerMoves(2);
       gameStatus += " The current state of the game is recorded in a specific format: each occupied location is delineated by a semicolon (';'), and for each occupied location, the row number is listed first, followed by the column number, separated by a comma (','). If no locations are occupied by a player, 'None' is noted. Both the row and column numbers start from 1, with the top left corner of the grid indicated by 1,1. \n";
       gameStatus += " The current state of the game is as follows: \n";
       gameStatus += " The locations occupied by the first player: ";
       gameStatus += (firstPlayerMoves.length ? firstPlayerMoves.join("; ") : "None") + " \n";
       gameStatus += " The locations occupied by the second player: ";
       gameStatus += (secondPlayerMoves.length ? secondPlayerMoves.join("; ") : "None") + " \n";
      return gameStatus;
      }
    13. Implement the static imagePrompt() method, which will be called when using the "image" prompt type. This method should return a string describing the board screenshots that will be provided to the LLMs, starting with a space and ending with a newline character \n.
      static drawBoard() {
      let gameStatus = "";
       gameStatus += " The current state of the game is illustrated on a 3 by 3 grid. 'X' represents positions taken by the first player and 'O' represents positions taken by the second player, while '.' indicates an available position. \n";
       gameStatus += " The current state of the game is as follows: \n";
      for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
         gameStatus += (document.getElementById("tic-tac-toe-" + (i + 1) + "-" + (j + 1)).innerText === "") ? "." : document.getElementById("tic-tac-toe-" + (i + 1) + "-" + (j + 1)).innerText;
       }
       gameStatus += " \n";
       }
      return gameStatus;
      }
    14. Implement the static imagePrompt() method, which will be called when using the "image" prompt type. This method should return a string describing the board screenshots that will be provided to the LLMs, starting with a space and ending with a space and a newline character \n.
      static imagePrompt() {
      return " The current state of the game is depicted in an image showing a 3 by 3 grid, where 'X' represents positions taken by the first player and 'O' represents positions taken by the second player. \n";
      }
    15. Implement the static screenshotBoard() method, which which will be called when using the “image” prompt type or progress display type. You should simply change the ID in the query selector below to match the HTML ID of your game board.

      To maintain consistency with our study, you should also modify the parameters of the html2canvas() call as necessary to ensure that your screenshots are 512px by 512px in size. However, this may need to be modified for games that do not use square boards.
      static async screenshotBoard() {
      return new Promise((resolve, reject) => {
        html2canvas(document.querySelector("#tic-tac-toe-board"), { width: 512, height: 512, windowWidth: 1677, windowHeight: 854, scale: 1, logging: false }).then((canvas) => {
         return canvas.toDataURL("image/png;base64");
        }).then(data => {
         resolve(data);
        }).catch(error => {
         reject(error);
        });
      });
      }
    16. Implement the static randomMove() method, which will return a randomly-generated move according to the JSON format requested by your prompt.
      static randomMove() {
        let row = Math.floor(Math.random() * 3) + 1; // Obtain a random row number between 1 and 3.
        let col = Math.floor(Math.random() * 3) + 1; // Obtain a random column number between 1 and 3.
        return "{\"row\": " + row + ", \"column\": " + col + "}";
      }
    17. Implement the static processMove() method, which will check that an LLM’s move was valid, display the move on the board if possible, and return a Move object. Begin by checking whether each JSON value you requested from the LLM exists and is of the correct type; if not, throw an error. After that, validate the move according to the rules of your game. If the move is valid, update your game board accordingly and return a new Move object with the “Valid” outcome. If the move is invalid, determine the type of invalid move and return a new Move object with an outcome matching the type of invalid move.

      The "classes.js" file in the "game-simulation" folder contains the Move class implementation if you'd like to view the constructor parameters and their meanings.
      static processMove(response, currentPlayer, model, currentMoveCount, currentStatus, useConsoleLogging) {
      let row;
      let col;
      let symbol = (currentPlayer === 1) ? "X" : "O";

      if (response.row !== undefined && typeof response.row === "number") {
        row = response.row;
       } else {
        return new Move(currentMoveCount, currentPlayer, -1, -1, "Invalid Format", currentStatus, JSON.stringify(response));
       }

      if (response.column !== undefined && typeof response.column === "number") {
        col = response.column;
       } else {
        return new Move(currentMoveCount, currentPlayer, -1, -1, "Invalid Format", currentStatus, JSON.stringify(response));
       }

      if (row >= 1 && row <= 3 && col >= 1 && col <= 3) {
        if (document.getElementById("tic-tac-toe-" + row + "-" + col).innerText === "") {
         document.getElementById("tic-tac-toe-" + row + "-" + col).innerText = symbol;

         document.getElementById("tic-tac-toe-" + row + "-" + col).style.color = (symbol === "X") ? "blue" : "red";

         if (useConsoleLogging) console.log("Move " + currentMoveCount + ": " + model.getName() + " (" + symbol + ") places at space (" + row + ", " + col + ").");
         return new Move(currentMoveCount, currentPlayer, row, col, "Valid", currentStatus, JSON.stringify(response));
        } else {
         if (useConsoleLogging) console.log("Move " + currentMoveCount + ": " + model.getName() + " (" + symbol + ") tried to place at space (" + row + ", " + col + ") which is already taken.");
         return new Move(currentMoveCount, currentPlayer, row, col, "Already Taken", currentStatus, JSON.stringify(response));
        }
       } else {
        console.log("Move " + currentMoveCount + ": " + model.getName() + " (" + symbol + ") tried to place at space (" + row + ", " + col + ") which is out of bounds.");
        return new Move(currentMoveCount, currentPlayer, row, col, "Out of Bounds", currentStatus, JSON.stringify(response));
       }
      }
    18. Implement the static visualizeBoardState() function, which will be used to generate the board visualizations for the text file logs. This should return a text-based visualization of the board, with each line of the visualization followed by a newline character \n. Append another \n to the visualization for proper spacing in the text file log.

      Note that this method is very similar to the drawBoard method, with the main difference being that we add vertical separators | between each space here, while we do not add separators in the drawBoard() method. If you’d like your text file logs to be the same as your “illustration” prompts, you can replace the logic in the function below with the same board visualization logic from your drawBoard() implementation.
      1. Example drawBoard() board state:
        .O.
        X..
        X..
      2. Example visualizeBoardState() output:
        .|O|.
        X|.|.
        X|.|.

      static visualizeBoardState() {
      let boardState = "";
      for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
         let cellValue = document.getElementById("tic-tac-toe-" + (i + 1) + "-" + (j + 1)).innerText;
         boardState += (cellValue === "") ? "." : cellValue;
         if (j < 2) {
          boardState += "|";
         }
        }
        boardState += "\n";
       }
      return boardState + "\n";
      }
    19. Implement the static checkForWin() function, which will return ‘true’ if a player has won the game, and false otherwise.
      static checkForWin() {
      let field = new Array(3);
      for (let i = 0; i < 3; i++) {
        field[i] = new Array(3);
       }

      for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
         field[i][j] = document.getElementById("tic-tac-toe-" + (i + 1) + "-" + (j + 1)).innerText;
        }
       }

      for (let i = 0; i < 3; i++) {
        // Check rows
        if (field[i][0] !== "") {
         let firstMark = field[i][0];
         let allSame = true;
         for (let j = 1; j < 3; j++) {
          if (firstMark !== field[i][j]) {
           allSame = false;
          }
         }
         if (allSame) return true;
        }

        // Check columns
        if (field[0][i] !== "") {
         let firstMark = field[0][i];
         let allSame = true;
         for (let j = 1; j < 3; j++) {
          if (firstMark !== field[j][i]) {
           allSame = false;
          }
         }
         if (allSame) return true;
        }
       }

      // Check top-left to bottom-right diagonal
      if (field[0][0] !== "") {
         let firstMark = field[0][0];
         let allSame = true;
         for (let i = 1; i < 3; i++) {
          if (firstMark !== field[i][i]) {
           allSame = false;
          }
         }
         if (allSame) return true;
       }

      // Check top-right to bottom-left diagonal
      if (field[0][3 - 1] !== "") {
        let firstMark = field[0][3 - 1];
        let allSame = true;
        for (let i = 1; i < 3; i++) {
         if (firstMark !== field[i][3 - i - 1]) {
          allSame = false;
         }
        }
        if (allSame) return true;
       }
      return false;
      }
    20. Implement the static checkForFullBoard() method, which will return true if the board is full, or false otherwise.

      If your game’s board cannot be full, you may simply return ‘false’ here.
      static checkForFullBoard() {
      for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
         if (document.getElementById("tic-tac-toe-" + (i + 1) + "-" + (j + 1)).innerText === "") {
          return false;
         }
        }
       }
      return true;
      }
    21. Implement the static resetBoard() method, which will clear the board of moves.
      static resetBoard() {
      for (let i = 0; i < 3; i++) {
        for(let j = 0; j < 3; j++) {
         document.getElementById("tic-tac-toe-" + (i + 1) + "-" + (j + 1)).innerText = "";
        }
       }
      }


  4. Importing and Adding Your Game Class
    In this section, you will be modifying the "game-simulation.js" file in the "game-simulation" folder.

    1. Import your completed game class at the top of the "game-simulation.js" file.
      import { TicTacToe } from "./tic-tac-toe.js";
      import { ConnectFour } from "./connect-four.js";
      import { Gomoku } from "./gomoku.js";
      // Add imports for future game classes here.
    2. Once your game’s class is imported, add a line to the “get game class” conditional under the playGame() function to add your game. The “gameType” you’re checking for should match the “value” you set for your game in the select element in Section 1 Part a.
      let game;
      if (gameType === "tic-tac-toe")
       game = TicTacToe;
      else if (gameType === "connect-four")
       game = ConnectFour;
      else if (gameType === "gomoku")
       game = Gomoku;
      // Add conditions for future games here.


  5. Updating the Game Details and Prompt List for Your Game
    Now that your game is fully implemented, you should update the "Game Details" and "Prompt list" popup contents with the details of your new game and examples of your game's prompts, respectively.

    1. Update the “gameDetails.json” file with information for your new game, following the format used for the existing games:
      [
       {
        "Game type": "Tic-Tac-Toe",
        "Details": "Tic-Tac-Toe is a two-player game and is played on a 3 by 3 grid. The objective is to align three of your symbols, Xs for the first player and Os for the second, either horizontally, vertically, or diagonally. Strategic placement is crucial; besides aiming for three in a row, players must also block their opponent's potential alignments to avoid defeat. Players take turns placing their symbols in an empty cell on the grid. Please see here for more details: https://en.wikipedia.org/wiki/Tic-tac-toe"
       },
      ... (Extra lines omitted for this guide.) ...
      (Your game’s details here.)
      ]
    2. Update the “promptList.json” file with information for your new game’s prompts, following the format used for the existing games:
      [
       {
        "Game Type": "Tic-Tac-Toe",
        "Prompt Type": "list",
        "Prompt Example": "Tic-Tac-Toe is a two-player game played on a 3 by 3 grid. The first player uses X symbols, and the second player uses O symbols. Players take turns placing their symbols in an empty cell on the grid. The objective is to align three of your symbols either horizontally, vertically, or diagonally. The player who first aligns three of their symbols wins the game. Strategic placement is crucial; besides aiming to align their symbols, players must also block their opponent's potential alignments to avoid defeat. <br> The current state of the game is recorded in a specific format: each occupied location is delineated by a semicolon (';'), and for each occupied location, the row number is listed first, followed by the column number, separated by a comma (','). If no locations are occupied by a player, 'None' is noted. Both the row and column numbers start from 1, with the top left corner of the grid indicated by 1,1. <br> The current state of the game is as follows: <br> The locations occupied by the first player: 1,1; 2,1; 3,2; 3,3 <br> The locations occupied by the second player: 1,2; 2,2; 3,1 <br> You are an adept strategic player, aiming to win the game in the fewest moves possible. You are the second player. What would be your next move? <br> Suggest your next move in the following JSON format: {'row': RowNumber, 'column': ColumnNumber}. Do not include any additional commentary in your response. Replace RowNumber and ColumnNumber with the appropriate numbers for your move. Both RowNumber and ColumnNumber start at 1 (top left corner is {'row': 1, 'column': 1}). The maximum value for RowNumber and ColumnNumber is 3, as the grid is 3 by 3. <br> Please note that your move will be considered invalid if your response does not follow the specified format, or if you provide a RowNumber or ColumnNumber that is out of the allowed range, or already occupied by a previous move. Making more than 3 invalid moves will result in disqualification. <br> You currently have 1 invalid move(s). 3 more invalid moves will result in disqualification."
       },
       {
        "Game Type": "Connect-Four",
        "Prompt Type": "list",
        "Prompt Example": ... (Omitted for this guide) ...
       },
       {
        "Game Type": "Gomoku",
        "Prompt Type": "list",
        "Prompt Example": ... (Omitted for this guide) ...
       },
      (Your game’s list prompt example here.)
       {
        "Game Type": "Tic-Tac-Toe",
        "Prompt Type": "illustration",
        "Prompt Example": "Tic-Tac-Toe is a two-player game played on a 3 by 3 grid. The first player uses X symbols, and the second player uses O symbols. Players take turns placing their symbols in an empty cell on the grid. The objective is to align three of your symbols either horizontally, vertically, or diagonally. The player who first aligns three of their symbols wins the game. Strategic placement is crucial; besides aiming to align their symbols, players must also block their opponent's potential alignments to avoid defeat. <br> The current state of the game is illustrated on a 3 by 3 grid. 'X' represents positions taken by the first player and 'O' represents positions taken by the second player, while 'e' indicates an empty (available) position. <br> The current state of the game is as follows: <br>OXX <br>eeO <br>OXe <br> You are an adept strategic player, aiming to win the game in the fewest moves possible. You are the first player. What would be your next move? <br> Suggest your next move in the following JSON format: {'row': RowNumber, 'column': ColumnNumber}. Do not include any additional commentary in your response. Replace RowNumber and ColumnNumber with the appropriate numbers for your move. Both RowNumber and ColumnNumber start at 1 (top left corner is {'row': 1, 'column': 1}). The maximum value for RowNumber and ColumnNumber is 3, as the grid is 3 by 3. <br> Please note that your move will be considered invalid if your response does not follow the specified format, or if you provide a RowNumber or ColumnNumber that is out of the allowed range, or already occupied by a previous move. Making more than 3 invalid moves will result in disqualification. <br> You currently have 0 invalid move(s). 4 more invalid moves will result in disqualification."
       },
       {
        "Game Type": "Connect4",
        "Prompt Type": "illustration",
        "Prompt Example": ... (Omitted for this guide) ...
       },
       {
        "Game Type": "Gomoku",
        "Prompt Type": "illustration",
        "Prompt Example": ... (Omitted for this guide) ...
       },
      (Your game’s illustration prompt example here.)
       {   "Game Type": "Tic-Tac-Toe",
        "Prompt Type": "image",
        "Prompt Example": "Tic-Tac-Toe is a two-player game played on a 3 by 3 grid. The first player uses X symbols, and the second player uses O symbols. Players take turns placing their symbols in an empty cell on the grid. The objective is to align three of your symbols either horizontally, vertically, or diagonally. The player who first aligns three of their symbols wins the game. Strategic placement is crucial; besides aiming to align their symbols, players must also block their opponent's potential alignments to avoid defeat. <br> The current state of the game is depicted in an image showing a 3 by 3 grid, where 'X' represents positions taken by the first player and 'O' represents positions taken by the second player. <br> The current state of the game is given in the attached image. <br> You are an adept strategic player, aiming to win the game in the fewest moves possible. You are the second player. What would be your next move? <br> Suggest your next move in the following JSON format: {'row': RowNumber, 'column': ColumnNumber}. Do not include any additional commentary in your response. Replace RowNumber and ColumnNumber with the appropriate numbers for your move. Both RowNumber and ColumnNumber start at 1 (top left corner is {'row': 1, 'column': 1}). The maximum value for RowNumber and ColumnNumber is 3, as the grid is 3 by 3. <br> Please note that your move will be considered invalid if your response does not follow the specified format, or if you provide a RowNumber or ColumnNumber that is out of the allowed range, or already occupied by a previous move. Making more than 3 invalid moves will result in disqualification. <br> You currently have 0 invalid move(s). 4 more invalid moves will result in disqualification. [THE IMAGE IS SENT SEPARATELY IN BASE64 FORMAT]"
       },
       {
        "Game Type": "Connect-Four",
        "Prompt Type": "image",
        "Prompt Example": ... (Omitted for this guide) ...
       },
       {
        "Game Type": "Gomoku",
        "Prompt Type": "image",
        "Prompt Example": ... (Omitted for this guide) ...
       },
      (Your game’s image prompt example here.)
      ]