Code viewer for World: Tic-Tac-Toe (2-Player) Game

// Cloned by Toma on 3 Dec 2023 from World "Chat with GPT model (clone by Toma)" by Toma 
// Please leave this clone trail here.
 


// Cloned by Toma on 1 Dec 2023 from World "Chat with GPT model" by Starter user 
// Please leave this clone trail here.
 


 
// default body is margin 0 and padding 0 
// give it more whitespace:

let currentPlayer = 'X';
let gameBoard = ['', '', '', '', '', '', '', '', ''];
let gameActive = true;
let apiKey;
let mediaRecorder;
let audioChunks = [];

  $('body').css( "margin", "20px" );
  $('body').css( "padding", "20px" );


 
document.write ( `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tic Tac Toe</title>
</head>
<body>
    <body>
   
        <h2 style="text-align: center">Tic Tac Toe</h2>
        <div
          id="gameBoard"
          style="
            /* color: white; */
            position: relative;
            margin: 0 auto;
            width: 304px;
            height: 304px;
            border: 3px solid #000;
          "
        >
          <div
            style="
              position: absolute;
              top: 0;
              left: 0;
              width: 100%;
              height: 100%;
              background: rgb(255, 255, 255);
              z-index: 1;
            "
          >
            <img
              id="myImage"
              src=""
              alt="No image"
              srcset=""
              style="
                opacity: 0.4;
                width: 300px;
                height: 300px;
                border: 2px solid black;
              "
            />
          </div>
    
          <div
            id="cell0"
            style="
              font-weight: bolder;
              position: absolute;
              z-index: 2;
              top: 0;
              left: 0;
              width: 100px;
              height: 100px;
              line-height: 100px;
              text-align: center;
              border: 1px solid #000;
            "
          ></div>
          <div
            id="cell1"
            style="
              font-weight: bolder;
              position: absolute;
              z-index: 2;
              top: 0;
              left: 100px;
              width: 100px;
              height: 100px;
              line-height: 100px;
              text-align: center;
              border: 1px solid #000;
            "
          ></div>
          <div
            id="cell2"
            style="
              font-weight: bolder;
              position: absolute;
              z-index: 2;
              top: 0;
              left: 200px;
              width: 100px;
              height: 100px;
              line-height: 100px;
              text-align: center;
              border: 1px solid #000;
            "
          ></div>
          <div
            id="cell3"
            style="
              font-weight: bolder;
              position: absolute;
              z-index: 2;
              top: 100px;
              left: 0;
              width: 100px;
              height: 100px;
              line-height: 100px;
              text-align: center;
              border: 1px solid #000;
            "
          ></div>
          <div
            id="cell4"
            style="
              font-weight: bolder;
              position: absolute;
              z-index: 2;
              top: 100px;
              left: 100px;
              width: 100px;
              height: 100px;
              line-height: 100px;
              text-align: center;
              border: 1px solid #000;
            "
          ></div>
          <div
            id="cell5"
            style="
              font-weight: bolder;
              position: absolute;
              z-index: 2;
              top: 100px;
              left: 200px;
              width: 100px;
              height: 100px;
              line-height: 100px;
              text-align: center;
              border: 1px solid #000;
            "
          ></div>
          <div
            id="cell6"
            style="
              font-weight: bolder;
              position: absolute;
              z-index: 2;
              top: 200px;
              left: 0;
              width: 100px;
              height: 100px;
              line-height: 100px;
              text-align: center;
              border: 1px solid #000;
            "
          ></div>
          <div
            id="cell7"
            style="
              font-weight: bolder;
              position: absolute;
              z-index: 2;
              top: 200px;
              left: 100px;
              width: 100px;
              height: 100px;
              line-height: 100px;
              text-align: center;
              border: 1px solid #000;
            "
          ></div>
          <div
            id="cell8"
            style="
              font-weight: bolder;
              position: absolute;
              z-index: 2;
              top: 200px;
              left: 200px;
              width: 100px;
              height: 100px;
              line-height: 100px;
              text-align: center;
              border: 1px solid #000;
            "
          ></div>
        </div>
        <div style="clear: both; text-align: center; margin-top: 20px;">
         <p
          id="gameStatus"
          style="text-align: center; font-size: 20px; font-weight: bolder"
        ></p>
          <button onclick="startGame()" style="padding: 10px 20px;">
            Start New Game
          </button>
          <button id="startRecording" style="padding: 10px 20px;">
            Change Image
          </button>
          <button id="stopRecording" disabled style="padding: 10px 20px;">
            Stop Recording
          </button>
          
          <button id="supriseMeButton" style="padding: 10px 20px;">Random Background</button>
          <!-- <br> -->
          <div
            style="
              display: flex;
              flex-direction: row;
              place-items: center;
              width: 100vw;
              justify-content: center;
              margin-top: 20px;
            "
          >
            <audio id="audioPlayback" controls style="margin-right: 20px"></audio>
            <button id="useAudioButton">Use Audio</button>
          </div>
     <p id="errorMessage" style="color: red; font-weight: bolder"></p>
          <h2 id="isLoading" style="margin-top: 20px"></h2>
        </div>
       
        <p id="transcribedText" style="text-align: center; font-size: 15px"></p>
    
    
    
        <input type="text" name="" id="apiKey" placeholder="API KEY">
        <button id="submitApiKey">Submit</button>
       
      </body>
</body>
</html>
` );

const myImage = document.getElementById("myImage");
const useAudioButton = document.getElementById("useAudioButton");
const startRecordingButton = document.getElementById("startRecording");
const stopRecordingButton = document.getElementById("stopRecording");
const isLoading = document.getElementById("isLoading");
const transcribedText = document.getElementById("transcribedText");
const errorMessage = document.getElementById("errorMessage");

useAudioButton.disabled = true;

startRecordingButton.addEventListener("click", startRecording);

stopRecordingButton.addEventListener("click", stopRecording);

document.getElementById("submitApiKey").addEventListener("click", function () {
  apiKey = document.getElementById("apiKey").value;
  if (apiKey) {
       errorMessage.innerHTML = "API KEY SET";
       errorMessage.style.color = 'green';
    alert("API KEY SET");
  } else {
    alert("Please enter an API key.");
    errorMessage.innerHTML = "API KEY NOT SET";
    errorMessage.style.color = 'red';
  }
});
useAudioButton.addEventListener("click", function () {
  isLoading.innerHTML = "Loading Image........";
  const audioBlob = new Blob(audioChunks, { type: "audio/mpeg" });
  transcribeAudio(audioBlob);
});
supriseMeButton.addEventListener("click", function () {
     isLoading.innerHTML = "Loading........";
  generateRandomPromptAndImage();
})

function handleCellPlayed(clickedCell, clickedCellIndex) {
  gameBoard[clickedCellIndex] = currentPlayer;
  clickedCell.innerHTML = currentPlayer;
}

function handlePlayerChange() {
  currentPlayer = currentPlayer === "X" ? "O" : "X";
}

function checkWin() {
  const winConditions = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8], // rows
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8], // columns
    [0, 4, 8],
    [2, 4, 6], // diagonals
  ];

  let roundWon = false;
  for (let i = 0; i < winConditions.length; i++) {
    const winCondition = winConditions[i];
    let a = gameBoard[winCondition[0]];
    let b = gameBoard[winCondition[1]];
    let c = gameBoard[winCondition[2]];
    if (a === "" || b === "" || c === "") {
      continue;
    }
    if (a === b && b === c) {
      roundWon = true;
      break;
    }
  }

  if (roundWon) {
    document.getElementById("gameStatus").innerHTML;
    document.getElementById(
      "gameStatus"
    ).innerHTML = `Player ${currentPlayer} has won!`;
    gameActive = false;
    return;
  }

  let roundDraw = !gameBoard.includes("");
  if (roundDraw) {
    document.getElementById("gameStatus").innerHTML = "Game ended in a draw!";
    gameActive = false;
    return;
  }

  handlePlayerChange();
}

function handleCellClick(clickedCellEvent) {
  const clickedCell = clickedCellEvent.target;
  const clickedCellIndex = parseInt(
    clickedCell.getAttribute("id").replace("cell", "")
  );

  if (gameBoard[clickedCellIndex] !== "" || !gameActive) {
    return;
  }

  handleCellPlayed(clickedCell, clickedCellIndex);
  checkWin();
}

function startGame() {
  gameActive = true;
  currentPlayer = "X";
  gameBoard = ["", "", "", "", "", "", "", "", ""];
  for (let i = 0; i < 9; i++) {
    document.getElementById(`cell${i}`).innerHTML = "";
  }
  document.getElementById("gameStatus").innerHTML = "";
}

document
  .querySelectorAll("#gameBoard div")
  .forEach((cell) => cell.addEventListener("click", handleCellClick));
startGame();

function startRecording() {
  navigator.mediaDevices
    .getUserMedia({ audio: true })
    .then((stream) => {
      mediaRecorder = new MediaRecorder(stream);
      mediaRecorder.ondataavailable = (event) => {
        audioChunks.push(event.data);
      };
      mediaRecorder.onstop = () => {
        const audioBlob = new Blob(audioChunks, { type: "audio/mpeg" });
        const audioUrl = URL.createObjectURL(audioBlob);
        document.getElementById("audioPlayback").src = audioUrl;
      };
      audioChunks = [];
      mediaRecorder.start();
      startRecordingButton.disabled = true;
      useAudioButton.disabled = true;
      stopRecordingButton.disabled = false;
    })
    .catch((e) => console.error(e));
}

function stopRecording() {
  mediaRecorder.stop();
  startRecordingButton.disabled = false;
  stopRecordingButton.disabled = true;
  useAudioButton.disabled = false;
}

function transcribeAudio(audioBlob) {
  const formData = new FormData();
  formData.append("file", audioBlob, "recording.mp3");
  formData.append("model", "whisper-1");
  formData.append("language", "en");

  fetch("https://api.openai.com/v1/audio/transcriptions", {
    method: "POST",
    body: formData,
    headers: {
      Authorization: `Bearer ${apiKey}`,
    },
  })
    .then((response) => response.json())
    .then((data) => {
      console.log("Transcription:", data);
      generateImage(data.text);
    })
    .catch((error) => {
      console.error("Error:", error);
      isLoading.innerHTML = "";
    });
}

function generateImage(text) {
  if (!apiKey) {
    isLoading.innerHTML = "";
    alert("API key is not set.");
    errorMessage.innerHTML = "API KEY NOT SET";
    errorMessage.style.color = 'red';
    return;
  }
  fetch("https://api.openai.com/v1/images/generations", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt: text,
    }),
  })
    .then((response) => response.json())
    .then((data) => {
      isLoading.innerHTML = "";
      errorMessage.innerHTML = "";
      transcribedText.innerHTML = "Transcribed Text - ".concat(text);
      var imageUrl = data.data[0].url;
      myImage.src = imageUrl;
    })
    .catch((error) => {
      console.error("Error calling DALLĀ·E API", error);
      isLoading.innerHTML = "";
      errorMessage.innerHTML = error.message || error;
      errorMessage.style.color = 'red';
    });
}
function generateRandomPromptAndImage() {
    if (!apiKey) {
    isLoading.innerHTML = "";
    alert("API key is not set.");
    errorMessage.innerHTML = "API KEY NOT SET";
    errorMessage.style.color = 'red';
    return;
  }
  const body = {
    model: "gpt-3.5-turbo",
    messages: [
      {
        role: "user",
        content:
          "Generate a prompt for dalle image generation no more than 20 words based on a game",
      },
    ],
  };
  
  
  fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    body: JSON.stringify(body),
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${apiKey}`,
    },
  })
    .then((response) => response.json())
    .then((data) => {
        generateImage(data.choices[0].message.content);
    })
    .catch((error) => {
      console.error("Error:", error.message);
       isLoading.innerHTML = "";
     
    });
}