Code viewer for World: New World
// Check if jQuery is already loaded before importing
if (typeof jQuery == 'undefined') {
    const jQueryScript = document.createElement('script');
    jQueryScript.src = 'https://code.jquery.com/jquery-3.6.4.min.js';
    document.head.appendChild(jQueryScript);
}

// Check if Three.js is already loaded before importing
if (typeof THREE == 'undefined') {
    const threeScript = document.createElement('script');
    threeScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js';
    document.head.appendChild(threeScript);
}

// talk to OpenAI GPT model (ChatGPT)
// adapted from: https://platform.openai.com/docs/api-reference/making-requests

const openaiURL = "https://api.openai.com/v1/chat/completions"; // can POST to this 3rd party URL
const themodel = "gpt-3.5-turbo"; // the OpenAI model we are going to talk to

// default API key and prompt:
var apikey = "";
var theprompt = "hello";

// default body is margin 0 and padding 0
// give it more whitespace:
$('body').css("margin", "20px");
$('body').css("padding", "20px");

document.write(`
    <h1> Chat with GPT model </h1>

    Running World:
    <a href='https://ancientbrain.com/world.php?world=2850716357'>Chat with GPT model</a>.
    <br> 
    Chat with
    <a href="https://platform.openai.com/docs/models/overview">GPT 3.5</a>
    using the
    <a href="https://en.wikipedia.org/wiki/OpenAI">OpenAI    </a>  API.
    <br> 
    This is the model
    <a href="https://en.wikipedia.org/wiki/ChatGPT">ChatGPT</a>   uses.

    <pre></pre>

    <h3> Enter API key </h3>

    The crucial thing is you need an "API key" to talk to OpenAI. <br>
    Register for free and get your API key  
    <a href='https://platform.openai.com/account/api-keys'>here</a>.
    <br>
    You enter your API key below and then chat away.
    Then communications to OpenAI come from your IP address using your API key. 
    <br>
    This World   will never  store your API key. 
    You can view the <a href='https://ancientbrain.com/viewjs.php?world=2850716357'> source code</a>  to see that is true!
    <p>

    <div id=enterkey>
        Enter API key: 
        <input style='width:25vw;' maxlength='2000' NAME="apikey" id="apikey" VALUE=''>  
        <button onclick='setkey();' class=ab-normbutton >Set API key</button>
    </div>

    <pre></pre>

    <div style="width:60vw; background-color:white;  border: 1px solid black; margin:20; padding: 20px;">
        <h3> Enter a "prompt" </h3>
        <input style="width:50vw;" id=me value="when did henry vii die?" >
        <button onclick="sendchat();" class=ab-normbutton > Send </button> 
    </div>

    <div style="width:60vw; background-color:#ffffcc;  border: 1px solid black; margin:20; padding: 20px;">
        <h3> GPT replies </h3>
        <div id=them> </div>
    </div>

    <button onclick="clearScreen();" class=ab-normbutton >Clear Screen</button>

    <p> <i> Be warned that GPT replies are often completely inaccurate.<br> 
    All LLM systems <a href="https://www.google.com/search?q=llm+hallucination"> "hallucinate"</a>.
    It is how they work. </i> </p>

    <pre></pre>

    <div id="drawing-section" style="width: 60vw; height: 400px; background-color: #ccffff; border: 1px solid black; margin: 20; padding: 20px;">
        <h3> Drawing Section </h3>
        <canvas id="drawingCanvas" width="600" height="400"></canvas>
    </div>
`);

// Enter will also send chat:
document.getElementById('me').onkeydown = function (event) { if (event.keyCode == 13) sendchat(); };

// --- Send my line of text ----------------------------------------------------------------
function sendchat() {
    theprompt = $("#me").val();

    // construct request as JSON
    var thedata = {
        "model": themodel,
        "temperature": 0.7,
        "messages": [{
            "role": "user",
            "content": theprompt
        }]
    };

    // then as a string representing that JSON:
    var thedatastring = JSON.stringify(thedata);

    // HTTP headers must be set up with API key:
    $.ajaxSetup({
        headers: {
            "Content-Type": "application/json",
            "Authorization": "Bearer " + apikey
        }
    });

    // POST to the 3rd party URL:
    $.ajax({
        type: "POST",
        url: openaiURL,
        data: thedatastring,
        dataType: "json",
        success: function (d, rc) { successfn(d, rc); },
        error: function () { errorfn(); }
    });
}


function setkey() {
    apikey = jQuery("input#apikey").val();
    apikey = apikey.trim();
    $("#enterkey").html("<b> API key has been set. </b>");
}

// Initialize variables for the game
var canvas, context;
var paddleWidth = 10, paddleHeight = 60;
var userPaddleY = 0, aiPaddleY = 0;
var ballX = 50, ballY = 50, ballSpeedX = 5, ballSpeedY = 2;

// Initialize the game
function gameInit() {
    canvas = document.getElementById("drawingCanvas");
    context = canvas.getContext("2d");

    // Set initial positions of paddles
    userPaddleY = canvas.height / 2 - paddleHeight / 2;
    aiPaddleY = canvas.height / 2 - paddleHeight / 2;

    // Start the game loop
    setInterval(update, 1000 / 60);
}

// Update the game state
function update() {
    move();
    draw();
}

// Move paddles and ball
function move() {
    // Move the user paddle with the mouse
    canvas.addEventListener('mousemove', function (event) {
        var mouseY = event.clientY - canvas.getBoundingClientRect().top;
        userPaddleY = mouseY - paddleHeight / 2;
    });

    // Move the AI paddle to track the ball
    aiPaddleY += (ballY - (aiPaddleY + paddleHeight / 2)) * 0.1;

    // Move the ball
    ballX += ballSpeedX;
    ballY += ballSpeedY;

    // Bounce the ball off the walls and paddles
    if (ballY < 0 || ballY > canvas.height) {
        ballSpeedY = -ballSpeedY;
    }

    if (ballX < 0) {
        if (ballY > userPaddleY && ballY < userPaddleY + paddleHeight) {
            ballSpeedX = -ballSpeedX;
        } else {
            // AI scores a point
            ballReset();
        }
    }

    if (ballX > canvas.width) {
        if (ballY > aiPaddleY && ballY < aiPaddleY + paddleHeight) {
            ballSpeedX = -ballSpeedX;
        } else {
            // User scores a point
            ballReset();
        }
    }
}

// Draw the paddles and ball
function draw() {
    // Clear the canvas
    context.clearRect(0, 0, canvas.width, canvas.height);

    // Draw the user paddle
    context.fillStyle = "white";
    context.fillRect(0, userPaddleY, paddleWidth, paddleHeight);

    // Draw the AI paddle
    context.fillRect(canvas.width - paddleWidth, aiPaddleY, paddleWidth, paddleHeight);

    // Draw the ball
    context.beginPath();
    context.arc(ballX, ballY, 5, 0, Math.PI * 2);
    context.fillStyle = "white";
    context.fill();
    context.closePath();
}

// Reset the ball to the center
function ballReset() {
    ballX = canvas.width / 2;
    ballY = canvas.height / 2;
}