Code viewer for World: Connect 4 AI battle
document.addEventListener('DOMContentLoaded', function () {
  document.write(`
  <!DOCTYPE HTML>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Connect 4 AI Battle</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        text-align: center;
        margin: 20px;
      }
      #game-board {
        display: grid;
        grid-template-columns: repeat(7, 50px);
        grid-gap: 5px;
        justify-content: center;
        margin-top: 20px;
      }
      .cell {
        width: 50px;
        height: 50px;
        border: 1px solid #000;
        border-radius: 50%;
        background-color: #ddd;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      .cell.player1 {
        background-color: red;
      }
      .cell.player2 {
        background-color: yellow;
      }
      #teams, #results {
        margin-top: 20px;
      }
      .button {
        margin-top: 20px;
        padding: 10px 20px;
        font-size: 16px;
        background-color: #007BFF;
        color: white;
        border: none;
        border-radius: 5px;
        cursor: pointer;
      }
      .button:disabled {
        background-color: #aaa;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Connect 4 AI Battle</h1>
    <div id="teams">
      <p><strong>Teams:</strong></p>
      <p>Red: Player 1 (Cohere AI)</p>
      <p>Yellow: Player 2 (Hugging Face AI)</p>
    </div>
    <div id="game-board"></div>
    <button id="start-button" class="button">Start Game</button>
    <button id="restart-button" class="button" style="display: none;">Restart Game</button>
    <div id="results"></div>
  </body>
  </html>
  `);

  const rows = 6;
  const cols = 7;
  let board;
  let currentPlayer;
  let gameActive = false;
  
  
  // MH edit 
  const COHERE_API_KEY          =   "7v8CzI8JYfSUaCtS91GhhyPbAs4qOsAonlCS5JYT";
  const HUGGINGFACE_API_KEY     =   "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";



  const gameBoard = document.getElementById("game-board");
  const startButton = document.getElementById("start-button");
  const restartButton = document.getElementById("restart-button");
  const resultsDiv = document.getElementById("results");

  function initializeGame() {
    board = Array.from({ length: rows }, () => Array(cols).fill(0));
    gameBoard.innerHTML = "";

    for (let r = 0; r < rows; r++) {
      for (let c = 0; c < cols; c++) {
        const cell = document.createElement("div");
        cell.classList.add("cell");
        cell.dataset.row = r;
        cell.dataset.col = c;
        gameBoard.appendChild(cell);
      }
    }

    currentPlayer = Math.random() < 0.5 ? 1 : 2;
    gameActive = true;

    resultsDiv.textContent = `Player ${currentPlayer} (${currentPlayer === 1 ? "Cohere" : "Hugging Face"}) starts!`;
  }

  function isColumnFull(col) {
    return board[0][col] !== 0;
  }

  function dropPiece(col, player) {
    for (let r = rows - 1; r >= 0; r--) {
      if (board[r][col] === 0) {
        board[r][col] = player;
        updateBoardUI(r, col, player);
        return r;
      }
    }
    return -1;
  }

  function updateBoardUI(row, col, player) {
    const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
    cell.classList.add(player === 1 ? "player1" : "player2");
  }

  function checkWinner(player) {
    const directions = [
      { dr: 0, dc: 1 },
      { dr: 1, dc: 0 },
      { dr: 1, dc: 1 },
      { dr: 1, dc: -1 }
    ];

    for (let r = 0; r < rows; r++) {
      for (let c = 0; c < cols; c++) {
        if (board[r][c] === player) {
          for (const { dr, dc } of directions) {
            let count = 0;
            for (let i = 0; i < 4; i++) {
              const nr = r + dr * i;
              const nc = c + dc * i;
              if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && board[nr][nc] === player) {
                count++;
              }
            }
            if (count === 4) return true;
          }
        }
      }
    }
    return false;
  }

  function makeMove() {
    if (!gameActive) return;

    const currentAPI = currentPlayer === 1 ? "Cohere" : "Hugging Face";
    const fetchAI = currentPlayer === 1 ? fetchFromCohere : fetchFromHuggingFace;

    fetchAI(board).then(col => {
      if (!gameActive) return;

      if (isColumnFull(col)) {
        resultsDiv.textContent = `Player ${currentPlayer} (${currentAPI}) tried an invalid move. Skipping.`;
        return setTimeout(switchPlayer, 250);
      }

      dropPiece(col, currentPlayer);

      if (checkWinner(currentPlayer)) {
        gameActive = false;
        resultsDiv.textContent = `Player ${currentPlayer} (${currentAPI}) wins!`;
        startButton.style.display = "none";
        restartButton.style.display = "inline-block";
        return;
      }

      setTimeout(switchPlayer, 250);
    });
  }

  function switchPlayer() {
    currentPlayer = 3 - currentPlayer;
    makeMove();
  }

  async function fetchFromCohere(boardState) {
    try {
        
        // MH edit
        console.log ( "Cohere send " + `Current board state:\n${JSON.stringify(boardState)}\nChoose a valid column (0-6) for your Connect 4 move:` );
        
      const response = await fetch("https://api.cohere.ai/v1/generate", {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${COHERE_API_KEY}`,
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          prompt: `Current board state:\n${JSON.stringify(boardState)}\nChoose a valid column (0-6) for your Connect 4 move:`,
          max_tokens: 1,
          temperature: 0.7
        })
      });
      const result = await response.json();
      
        // MH edit
        console.log ( "Cohere response " ); console.log ( result );
 
      const col = parseInt(result.generations[0]?.text.trim(), 10);

      if (isNaN(col) || col < 0 || col > 6) {
        throw new Error("Invalid move generated by Cohere");
      }

      return col;
    } catch (error) {
      console.error("Cohere error:", error);
      return getRandomValidColumn();
    }
  }

  async function fetchFromHuggingFace(boardState) {
    try {
        
        // MH edit
        console.log ( "Hugging send " + `Current board state:\n${JSON.stringify(boardState)}\nChoose a valid column (0-6) for your Connect 4 move:` );
         
      const response = await fetch("https://api-inference.huggingface.co/models/gpt2", {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${HUGGINGFACE_API_KEY}`,
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ inputs: `Current board state:\n${JSON.stringify(boardState)}\nChoose a valid column (0-6) for your Connect 4 move:` })
      });
      const result = await response.json();

        // MH edit
        console.log ( "Hugging response " ); console.log ( result );
        console.log ( result.generated_text );
        console.log ( result[0].generated_text );

      const col = parseInt(result.generated_text.trim(), 10);

      if (isNaN(col) || col < 0 || col > 6) {
        throw new Error("Invalid move generated by Hugging Face");
      }

      return col;
    } catch (error) {
      console.error("Hugging Face error:", error);
      return getRandomValidColumn();
    }
  }


  function getRandomValidColumn() {
      
      // MH edit
      console.log ("calling getRandomValidColumn");
      
    const validColumns = [];
    for (let c = 0; c < cols; c++) {
      if (!isColumnFull(c)) validColumns.push(c);
    }
    return validColumns[Math.floor(Math.random() * validColumns.length)];
  }

  startButton.addEventListener("click", function () {
    startButton.style.display = "none";
    restartButton.style.display = "inline-block";
    resultsDiv.textContent = "";
    gameActive = true;
    makeMove();
  });

  restartButton.addEventListener("click", function () {
    gameActive = false;
    startButton.style.display = "inline-block";
    restartButton.style.display = "none";
    initializeGame();
  });

  initializeGame();
});