// Created by Jamie Kavanagh on 23 Nov 2023
// This world is a game show where the player tries to rack up the highest score using questions supplied by chatGPT
const token = "";
const url = "https://api.openai.com/v1/chat/completions";
function getQuestion() {
const userScore = document.getElementById('userScore');
const score = parseInt(userScore.textContent);
const chaserScore = document.getElementById('chaser');
const Cscore = parseInt(chaserScore.textContent);
if (score === Cscore) {
document.getElementById('category-div').style.display = 'none'
document.getElementById('gameIntro').style.display = 'none'
document.getElementById('gameOver').style.display = 'block'
return
}
// Simulated backend response with question and answers
document.getElementById('category-div').style.display = 'none'; // Hide the selection box
document.getElementById('loadingbox').style.display = 'block'; // Show the loading screen
value = document.getElementById("categorySelect").value
// fetch method adapted from https://www.freecodecamp.org/news/javascript-post-request-how-to-send-an-http-post-request-in-js/
// MH edit
console.log ( "I need you to give me a random trivia question based on " + value + ", i want you to return a json of the question a string and a list called answers with 4 possible answers, the head of the list will always be the correct answer" );
fetch(url, {
method: 'POST',
// found in https://ancientbrain.com/world.php?world=2850716357
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token,
},
body: JSON.stringify({
'model': 'gpt-3.5-turbo',
'messages': [{"role": "user", "content": "I need you to give me a random trivia question based on " + value + ", i want you to return a json of the question a string and a list called answers with 4 possible answers, the head of the list will always be the correct answer"}]
})
})
.then(response => {
return response.json(); // Return JSON from the response
})
.then(data => {
console.log("data:", data);
// https://rollbar.com/blog/chatgpt-api-with-javascript/
let apiResponse = data["choices"][0].message.content;
console.log("test:", apiResponse);
// Find the JSON string within the API response
// https://stackoverflow.com/questions/58564271/looking-for-the-easiest-way-to-extract-an-unknown-substring-from-within-a-string
let jsonStartIndex = apiResponse.indexOf('{');
let jsonEndIndex = apiResponse.lastIndexOf('}') + 1; // Get indexes
if (jsonStartIndex !== -1 && jsonEndIndex !== -1) { // Check there is json to parse
let jsonString = apiResponse.slice(jsonStartIndex, jsonEndIndex); //Extract the json from the message
let triviaJSON = JSON.parse(jsonString); // parse the json
console.log("Extracted JSON object:", triviaJSON);
const question = triviaJSON.question;
const answers = triviaJSON.answers;
//const randomNum =triviaJSON.rand;
// Check if the json worked
console.log("Question:", question);
console.log("Answers:", answers);
//console.log("Num:", randomNum);
displayAnswer(question, answers); // pass to the next function
} else {
console.log("JSON data not found in the API response.");
}
})
.catch(error => {
console.error('Error:', error);
});
}
function displayAnswer(question, answers) {
console.log("Recieved", question);
window.headWord = answers[0]; // Make the first element of a list a global variable
console.log("Head", headWord);
//https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
for (let i = 0; i < answers.length; i++) { // Mix up the list
const j = Math.floor(Math.random() * (i + 1));
[answers[i], answers[j]] = [answers[j], answers[i]];
}
console.log("Swapped Array", answers);
document.getElementById('question').textContent = question;
const answerElements = document.getElementsByClassName('answer'); // Display each answer in html
for (let i = 0; i < answerElements.length; i++) {
answerElements[i].textContent = answers[i];
}
document.getElementById('loadingbox').style.display = 'none'; //Hide the load screen
document.getElementById('questiondiv').style.display = 'block'; // Show the answer card
}
function checkAnswer(selectedIndex) {
// Simulated correct answer text for testing
//const correctAnswerText = "Correct Answer";
const answerElements = document.getElementsByClassName('answer'); // Get all the answers
for (let i = 0; i < answerElements.length; i++) {
const answerText = answerElements[i].textContent.trim(); // Check what answer is correct
if (answerText === headWord) {
answerElements[i].style.backgroundColor = 'green'; // Highlight the correct one green
} else {
answerElements[i].style.backgroundColor = 'red'; // Highlight the wrong ones red
}
answerElements[i].style.pointerEvents = 'none'; // Disable clicks on answers
}
const userScore = document.getElementById('userScore');
const score = parseInt(userScore.textContent);
const isCorrect = answerElements[selectedIndex].textContent.trim() === headWord;
userScore.textContent = isCorrect ? score + 1 : score; // Increase users score if correct
const rand = Math.floor(Math.random() * 4); // Generate a random number
console.log("Chaser", rand)
const chaserScore = document.getElementById('chaser');
const Cscore = parseInt(chaserScore.textContent);
const check = answerElements[rand].textContent.trim() === headWord; // if the number is the index where the correct answer is
chaserScore.textContent = check ? Cscore + 1 : Cscore; // Increase chasers score if correct
}
function nextQuestion() {
document.getElementById('category-div').style.display = 'block'; // Display the category boxes
document.getElementById('questiondiv').style.display = 'none';
const answerElements = document.getElementsByClassName('answer');
for (let i = 0; i < answerElements.length; i++) {
answerElements[i].style.backgroundColor = ''; // Reset answer box colors
answerElements[i].style.pointerEvents = 'auto'; // Enable answer selection
}
}
document.write ( `
<!DOCTYPE html>
<html>
<head>
<title>Trivia Game</title>
<style>
/*All Animated css is influenced from https://uiverse.io/ */
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0; /* Background color of the body */
color: blue;
}
.center-screen {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.matte-black-card {
background-color: #000;
color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
width: calc(43.75vw - 40px); /* 7/16 of viewport width minus padding */
height: calc(43.75vh - 40px); /* One-third of viewport height minus padding */
max-width: 900px; /* Adjust the maximum width as needed */
max-height: 900px; /* Adjust the maximum height as needed */
}
.wrapper {
width: 200px;
height: 60px;
position: relative;
z-index: 1;
}
.circle {
width: 20px;
height: 20px;
position: absolute;
border-radius: 50%;
background-color: #fff;
left: 15%;
transform-origin: 50%;
animation: circle7124 .5s alternate infinite ease;
}
@keyframes circle7124 {
0% {
top: 60px;
height: 5px;
border-radius: 50px 50px 25px 25px;
transform: scaleX(1.7);
}
40% {
height: 20px;
border-radius: 50%;
transform: scaleX(1);
}
100% {
top: 0%;
}
}
.circle:nth-child(2) {
left: 45%;
animation-delay: .2s;
}
.circle:nth-child(3) {
left: auto;
right: 15%;
animation-delay: .3s;
}
.shadow {
width: 20px;
height: 4px;
border-radius: 50%;
background-color: rgba(0,0,0,0.9);
position: absolute;
top: 62px;
transform-origin: 50%;
z-index: -1;
left: 15%;
filter: blur(1px);
animation: shadow046 .5s alternate infinite ease;
}
@keyframes shadow046 {
0% {
transform: scaleX(1.5);
}
40% {
transform: scaleX(1);
opacity: .7;
}
100% {
transform: scaleX(.2);
opacity: .4;
}
}
.shadow:nth-child(4) {
left: 45%;
animation-delay: .2s
}
.shadow:nth-child(5) {
left: auto;
right: 15%;
animation-delay: .3s;
}
.centered-div {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.title {
position: absolute;
top: 20px; /* Adjust the distance from the top as needed */
left: 50%; /* Align the element horizontally */
transform: translateX(-50%); /* Center the element horizontally */
color: blue;
}
#score {
position: absolute;
top: 50px; /* Adjust the distance from the top as needed */
left: 20%; /* Align the element horizontally */
transform: translateX(-50%); /* Center the element horizontally */
color: blue;
}
.container {
height: 294px;
width: 240px;
color: red;
perspective: 800px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.card {
width: 100%;
height: 100%;
background: black;
border-radius: 2rem;
position: relative;
transition: transform 1500ms;
transform-style: preserve-3d;
}
.card-top {
display: flex;
align-items: center;
justify-content: center;
height: 10%;
position: absolute;
width: 50%;
background-color: transparent;
border: 2px solid black;
top: 0;
border-top: none;
border-radius: 0 0 1rem 1rem;
box-shadow: 0px 0px 10px 5px rgba(255, 0, 0, 0.7);
}
.card-top-para {
font-size: 16px;
font-weight: bold;
}
.container:hover > .card {
cursor: pointer;
transform: rotateX(180deg) rotateZ(-180deg);
}
.front,
.back {
height: 100%;
width: 100%;
border-radius: 2rem;
box-shadow: 0px 0px 10px 5px rgba(255, 0, 0, 0.7);
position: absolute;
backface-visibility: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
}
.back {
background-color: black;
transform: rotateX(180deg) rotateZ(-180deg);
}
.heading {
font-size: 22px;
font-weight: bold;
}
.follow {
font-size: 16px;
font-weight: 500;
}
#category-div {
position: absolute;
top: 130px; /* Adjust the distance from the top as needed */
left: 50%; /* Align the element horizontally */
transform: translateX(-50%); /* Center the element horizontally */
color: blue;
}
#categoryBox {
display: flex;
flex-direction: column;
align-items: center;
}
#categorySelect {
margin-bottom: 30px; /* Adjust as needed for space between select and button */
}
select {
-webkit-appearance:none;
-moz-appearance:none;
-ms-appearance:none;
appearance:none;
outline:0;
box-shadow:none;
border:0!important;
background: #5c6664;
background-image: none;
flex: 1;
padding: 0 .5em;
color:black;
cursor:pointer;
font-size: 1em;
font-family: 'Open Sans', sans-serif;
}
select::-ms-expand {
display: none;
}
.select {
position: relative;
display: flex;
width: 20em;
height: 3em;
line-height: 3;
background: #5c6664;
overflow: hidden;
border-radius: .25em;
}
/*
MH edit
original below looked like:
content: '(backslash)25BC';
but this caused console error:
Uncaught SyntaxError: Octal escape sequences are not allowed in template strings.
think this is downward pointing triangle
so can I use
content: '▼';
needs some debug
*/
.select::after {
/* content: '25BC'; */
position: absolute;
top: 0;
right: 0;
padding: 0 1em;
background: #2b2e2e;
cursor:pointer;
pointer-events:none;
transition:.25s all ease;
}
.select:hover::after {
color: #23b499;
}
button {
height: 50px;
margin: 5px;
width: 120px;
background: #333;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
font-family: Consolas, Courier New, monospace;
border: solid #404C5D 1px;
font-size: 16px;
color: #4d5354;
-webkit-transition: 500ms;
transition: 500ms;
border-radius: 5px;
background: linear-gradient(
#292929, black, #292929);
-webkit-box-shadow: -1px -5px 15px #41465B,
5px 5px 15px #41465B,
inset 5px 5px 10px #212121,
inset -5px -5px 10px #212121;
box-shadow: -1px -5px 15px red,
5px 5px 15px red,
inset 5px 5px 10px black,
inset -5px -5px 10px black;
}
button:hover {
-webkit-box-shadow: 1px 1px 13px blue,
-1px -1px 13px grey;
box-shadow: 1px 1px 13px #20232e,
-1px -1px 13px #545b78;
color: green;
-webkit-transition: 500ms;
transition: 500ms;
}
button:active {
-webkit-box-shadow: 1px 1px 13px green,
-1px -1px 33px green;
box-shadow: 1px 1px 13px green,
-1px -1px 33px green;
color: black;
-webkit-transition: 100ms;
transition: 100ms;
}
</style>
</head>
<body style="background-image: url('/uploads/jayk49/vanishing-stripes.png');">
<div class="title">
<h1 id="gameIntro">Welcome to TriviaGPT</h1>
<div id="gameOver" style="display: none;">
<h1>Game Over</h1>
<p>You've Been Caught!!</p>
</div>
</div>
<div id="score">
<h2>Score: <span id="userScore">0</span></h1>
<h2>Chaser: <span id="chaser">-1</span></h1>
</div>
<div id="category-div">
<div id="categoryBox">
<div class"select">
<select id="categorySelect">
<option value="science">Science</option>
<option value="history">History</option>
<option value="sports">Sports</option>
<option value="geography">Geography</option>
<option value="music">Music</option>
<option value="movies">Movies</option>
<option value="general knowledge">General Knowledge</option>
<option value="entertainment">Entertainment</option>
</select>
</div>
<button onclick="getQuestion()">Get Question</button>
</div>
</div>
<div class="container">
<div class="card" id="questiondiv" style="display: none;">
<div class="front">
<div class="card-top">
<p class="card-top-para">Question</p>
</div>
<center><p class="heading"></p></center>
<center><p class="follow" id="question"></p></center>
<p id="question"></p>
</div>
<div class="back">
<div class="card-top">
<p class="card-top-para">Answers</p>
</div>
<div id="questionBox"
<div id="answers">
<div class="answer" onclick="checkAnswer(0)"></div>
<div class="answer" onclick="checkAnswer(1)"></div>
<div class="answer" onclick="checkAnswer(2)"></div>
<div class="answer" onclick="checkAnswer(3)"></div>
</div>
<button onclick="nextQuestion()">Next Question</button>
</div>
</div>
</div>
</div>
<div class="wrapper centered-div" id="loadingbox" style="display: none;">
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="shadow"></div>
<div class="shadow"></div>
<div class="shadow"></div>
</div>
</body>
</html>
`);