A ChatGPT experiment by someone who is definitely not a coder
This post documents a ChatGPT coding experiment. The goal was to get ChatGPT to output usable JavaScript code for a simple rock, paper, scissors “battle royale” game that could be embedded on a WordPress or other site. The (imperfect) result is below. Following that, I share some of the process and the prompts.
What I learned
- It’s not as easy as we might assume
- ChatGPT fights back
- Instructions need to be explicit and unambiguous
- Try, try again
All told, I spent about eight hours on this project. I documented the first few interactions but skipped several of the failed attempts in the middle. Along the way, I was learning, and refining my prompt to finally reach a result that’s close enough to what I had in mind.

In the end, I was nowhere near satisfied… what I was going for was this:
Original prompt:
I want you to create a paper, rock, scissors battle as embeddable code I can paste on my wordpress site.
It should start with the user selecting how many players there are in the battle increments of 3 (i.e. 3 = 1 rock, 1 paper, 1 scissors. 6= 2 rocks, 2 papers, 2 scissors etc.). Each player is represented by the emoji so rock = rock emoji, paper = paper emoji, scissors = scissors emoji.
The behavior of the players is to float around on the screen randomly and when two players collide, standard paper, rock, scissors rules apply. The winner of the collision remains unchanged, the loser of the collision becomes the same player type as the winner. For example, if a rock collides with a paper, the rock loses and becomes paper both in look and behavior.
The game ends when only one player type remains. At that point, display WINNER! and immediately below that, the emoji representation of the winning player type.
In addition, display some stats from the game. For example, the number of collisions that occurred, the number of times rock won a collision, the number of times paper won a collision, the total time elapsed from the start to the end of the match.
Result
Collisions: 0
Rock Wins: 0
Paper Wins: 0
Scissors Wins: 0
Total Time: 0 seconds
Output:
# Since the user requested an embeddable code for a Rock, Paper, Scissors game to be used on a WordPress site,
# we need to write a JavaScript program that can be embedded as HTML.
# This code snippet will include the HTML, CSS, and JavaScript necessary for the game to function.
# The JavaScript code will handle the game logic, including:
# - Taking user input for the number of players
# - Representing players as emojis
# - Moving players around the screen
# - Handling collisions based on Rock, Paper, Scissors rules
# - Determining and displaying the winner
# - Displaying game stats
# The code will be designed as a standalone HTML snippet that can be embedded directly into a WordPress page.
game_code = """
<div id="rpsGameContainer" style="position: relative; width: 100%; height: 500px; border: 1px solid #000;"></div>
<p id="winnerNotice" style="display: none;">WINNER! <span id="winnerEmoji"></span></p>
<p>Collisions: <span id="statsCollisions">0</span></p>
<p>Rock Wins: <span id="statsRockWins">0</span></p>
<p>Paper Wins: <span id="statsPaperWins">0</span></p>
<p>Scissors Wins: <span id="statsScissorsWins">0</span></p>
<p>Total Time: <span id="statsTotalTime">0</span> seconds</p>
<script>
// Define player emojis
const emojis = {
rock: '\\u270A', // โ
paper: '\\u270B', // โ
scissors: '\\u270C' // โ๏ธ
};
// Player class to represent each emoji player
class Player {
constructor(type) {
this.type = type;
this.element = document.createElement('div');
this.element.innerHTML = emojis[type];
this.element.style.position = 'absolute';
this.element.style.fontSize = '30px';
this.updatePosition();
document.getElementById('rpsGameContainer').appendChild(this.element);
}
// Randomly update the position of the player on the screen
updatePosition() {
const container = document.getElementById('rpsGameContainer');
this.x = Math.random() * (container.offsetWidth - 30);
this.y = Math.random() * (container.offsetHeight - 30);
this.element.style.left = this.x + 'px';
this.element.style.top = this.y + 'px';
}
// Collision logic based on RPS rules
collide(opponent) {
if (this.type === opponent.type) return;
if ((this.type === 'rock' && opponent.type === 'scissors') ||
(this.type === 'scissors' && opponent.type === 'paper') ||
(this.type === 'paper' && opponent.type === 'rock')) {
opponent.changeType(this.type);
document.getElementById('stats' + this.type.charAt(0).toUpperCase() + this.type.slice(1) + 'Wins').innerText++;
}
}
// Change the type of the player after losing a collision
changeType(newType) {
this.type = newType;
this.element.innerHTML = emojis[newType];
}
}
// Initialize players based on user input
function initPlayers(playerCount) {
const playerTypes = ['rock', 'paper', 'scissors'];
const players = [];
for (let i = 0; i < playerCount; i++) {
players.push(new Player(playerTypes[i % 3]));
}
return players;
}
// Check for collisions between players
function checkCollisions(players) {
for (let i = 0; i < players.length; i++) {
for (let j = i + 1; j < players.length; j++) {
if (Math.abs(players[i].x - players[j].x) < 30 && Math.abs(players[i].y - players[j].y) < 30) {
players[i].collide(players[j]);
document.getElementById('statsCollisions').innerText++;
}
}
}
}
// Check if there is a winner
function checkWinner(players) {
const types = players.map(p => p.type);
if (new Set(types).size === 1) {
document.getElementById('winnerEmoji').innerText = emojis[types[0]];
document.getElementById('winnerNotice').style.display = 'block';
return true;
}
return false;
}
// Main game loop
function gameLoop(players) {
const startTime = Date.now();
const gameInterval = setInterval(() => {
players.forEach(player => player.updatePosition());
checkCollisions(players);
if (checkWinner(players)) {
clearInterval(gameInterval);
const totalTime = ((Date.now() - startTime) /
Refinement:
Changes:
- The user should select the number of players before the game starts (in increments of 3)
- The game should be confined to a window that is 600px square
- The emojis should be rock, paper, and scissors. Not hands representing rock, paper, scissors.
- The players should slow down a bit and the motion should be much smoother as they move. They should float, not flash.
- Add a click sound when players collide
Output
# Modifying the game code according to the requested changes.
updated_game_code = """
<div id="rpsGameContainer" style="position: relative; width: 600px; height: 600px; border: 1px solid #000; margin: auto;"></div>
<label for="playerCount">Select number of players (in increments of 3):</label>
<input type="number" id="playerCount" min="3" step="3" value="3">
<button onclick="startGame()">Start Game</button>
<p id="winnerNotice" style="display: none;">WINNER! <span id="winnerEmoji"></span></p>
<p>Collisions: <span id="statsCollisions">0</span></p>
<p>Rock Wins: <span id="statsRockWins">0</span></p>
<p>Paper Wins: <span id="statsPaperWins">0</span></p>
<p>Scissors Wins: <span id="statsScissorsWins">0</span></p>
<p>Total Time: <span id="statsTotalTime">0</span> seconds</p>
<script>
const emojis = {
rock: '๐ชจ',
paper: '๐',
scissors: 'โ๏ธ'
};
class Player {
constructor(type, container) {
this.type = type;
this.element = document.createElement('div');
this.element.innerHTML = emojis[type];
this.element.style.position = 'absolute';
this.element.style.transition = 'top 0.5s, left 0.5s'; // smooth transition for movement
this.container = container;
this.container.appendChild(this.element);
this.updatePosition();
}
updatePosition() {
this.x = Math.random() * (this.container.offsetWidth - 30);
this.y = Math.random() * (this.container.offsetHeight - 30);
this.element.style.left = this.x + 'px';
this.element.style.top = this.y + 'px';
}
collide(opponent) {
if (this.type === opponent.type) return;
if ((this.type === 'rock' && opponent.type === 'scissors') ||
(this.type === 'scissors' && opponent.type === 'paper') ||
(this.type === 'paper' && opponent.type === 'rock')) {
opponent.changeType(this.type);
document.getElementById('stats' + this.type.charAt(0).toUpperCase() + this.type.slice(1) + 'Wins').innerText++;
playSound();
}
}
changeType(newType) {
this.type = newType;
this.element.innerHTML = emojis[newType];
}
}
function initPlayers(playerCount, container) {
const playerTypes = ['rock', 'paper', 'scissors'];
const players = [];
for (let i = 0; i < playerCount; i++) {
players.push(new Player(playerTypes[i % 3], container));
}
return players;
}
function checkCollisions(players) {
players.forEach((player, i) => {
players.slice(i + 1).forEach(opponent => {
if (Math.abs(player.x - opponent.x) < 30 && Math.abs(player.y - opponent.y) < 30) {
player.collide(opponent);
document.getElementById('statsCollisions').innerText++;
}
});
});
}
function checkWinner(players) {
const types = players.map(p => p.type);
if (new Set(types).size === 1) {
document.getElementById('winnerEmoji').innerText = emojis[types[0]];
document.getElementById('winnerNotice').style.display = 'block';
return true;
}
return false;
}
function playSound() {
const clickSound = new Audio('https://www.soundjay.com/button/sounds/button-16.mp3');
clickSound.play();
}
function startGame() {
const container = document.getElementById('rpsGameContainer');
container.innerHTML = ''; // Clear previous game
const playerCount = parseInt(document.getElementById('playerCount').value, 10);
const players = initPlayers(playerCount, container);
const startTime = Date.now();
const gameInterval = setInterval(() => {
players.forEach(player => player.updatePosition());
checkCollisions(players);
if (checkWinner(players)) {
clearInterval(gameInterval);
const totalTime = ((Date.now() - startTime) / 1000).toFixed(2);
document.getElementById('statsTotalTime').innerText = totalTime;
}
}, 1000); // Slowing down movement
}
</script>
"""
# Writing the updated code to a new .html file which can be provided to the user for download.
updated_file_path = '/mnt/data/updated_rps_game.html'
with open(updated_file_path, 'w') as file:
file.write(updated_game_code)
updated_file_path
Result
Refinement
Changes:
- The emoji should be in constant motion


Result
Lots of different things breaking. Several more attempts. In the end, saying:
OK, that doesn't work. The start button doesn't work, the players don't change when they collide. The sound doesn't work. Let's start again. Take everything I've said in this chat and start from scratch.

I understand that we need to start from scratch and create a working version of the Rock, Paper, Scissors game with the following requirements:
A selection field for the number of players, which should be in increments of 3.
A selection field for the speed of the emojis, ranging from 1 to 10.
A 600px square game area where the emojis will move around.
Emojis should be in constant motion.
Collision detection between emojis with the standard Rock, Paper, Scissors rules applied.
When a collision occurs, the losing emoji changes to the type of the winning emoji and a click sound should play.
The game ends when only one type of emoji remains, displaying a winner message and some game statistics.
I'll write the code to meet these specifications, ensuring that the game logic and functionalities are correctly implemented and that the start button and collision logic are operational. Please allow me some time to write and test the code.

After a bunch of failed attempts, I decided to start again in a new chat using some of the directions ChatGPT generated in response to my previous feedback.
Final (?) Attempt
The Prompt
I want you to create code that I can embed on a wordpress site. The game is called Paper, Rock, Scissors Royale. A bunch of paper, rock, scissors emoji will float around the screen and when they collide, a winner is determined and the loser of the match becomes another player for the winner. For example, if rock and paper collide, the rock turns into paper and the game continues.
paper beats rock
rock beats scissors
scissors beat paper
Here are some parameters:
A user interface to select the number of players (in increments of 3) and the speed of the emojis (in increments of 1 from 1 to 10).
A 600px square game area where the emojis will float around in constant motion.
The emojis for rock, paper, and scissors are the actual emojis ๐ชจ, ๐, and โ๏ธ, respectively.
The motion of the emojis will be smooth and they will make a click sound when they collide.
Standard rock-paper-scissors rules will apply when emojis collide: the loser changes to the type of the winner.
The game ends when only one type of emoji remains, displaying "WINNER!" and the emoji of the winning type.
Game statistics for the number of collisions, wins per type, and total time elapsed will be shown
Success! – Final_final_FINAL attempt
This is the prompt that ultimately worked out. I took stuff that ChatGPT had spit back at me across various interactions with varying degrees of success.
You are an expert javascript and HTML developer. I want you to create the code for a complete paper, rock, scissors battle game as HTML that I can play directly in a web browser. I will share the parameters for the game below.
It should start with the user selecting how many players there are in the battle increments of 3 (i.e. 3 = 1 rock, 1 paper, 1 scissors. 6= 2 rocks, 2 papers, 2 scissors etc.). Each player is represented by the emoji so rock = rock emoji, paper = paper emoji, scissors = scissors emoji.
The behavior of the players is to float around on the screen on a straight trajectory at a constant speed. When two players collide they battle using, standard paper, rock, scissors rules apply. The winner of the collision remains unchanged, the loser of the collision becomes the same player type as the winner. For example, if a rock collides with a paper, the rock loses and becomes paper both in look and behavior. When players collide, they should also bounce off each other and continue moving at the same speed but on a new trajectory. When players collide, play the sound at this URL: https://amc.ink/wp-content/uploads/2023/11/button-16.mp3
The game ends when only one player type remains. At that point, all the players freeze and a button appears that says "rematch" Hitting the rematch button starts a new match.
The game should be in a container that is 400px square.
Below the game, include text fields with up and down input buttons for the user to change some parameters as follows:
Players - Sets the number of players in increments of three, ensuring that there's always an even number of paper, rock, scissors players at the start of each game
Speed - Sets the speed of the players movement from 1 (slowest) to 10 (fastest)
Output
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rock Paper Scissors Battle</title>
<style>
#game-container {
width: 400px;
height: 400px;
position: relative;
border: 1px solid #000;
overflow: hidden;
}
.player {
position: absolute;
user-select: none;
}
button, input[type=number] {
margin-top: 10px;
}
</style>
</head>
<body>
<div id="game-container"></div>
<input type="number" id="player-count" min="3" step="3" value="3">
<input type="number" id="speed-control" min="1" max="10" value="5">
<button onclick="initializeGame()">Start Game</button>
<audio id="collision-sound" src="https://amc.ink/wp-content/uploads/2023/11/button-16.mp3"></audio>
<script>
const gameContainer = document.getElementById('game-container');
const collisionSound = document.getElementById('collision-sound');
let players = [];
let interval;
let speed = 5;
function initializeGame() {
gameContainer.innerHTML = ''; // Clear previous game
const playerCount = document.getElementById('player-count').value;
const playerTypes = ['โ', 'โ', 'โ๏ธ'];
players = [];
for (let i = 0; i < playerCount; i++) {
const player = document.createElement('div');
player.textContent = playerTypes[i % 3];
player.className = 'player';
player.style.left = `${Math.random() * (gameContainer.offsetWidth - 20)}px`;
player.style.top = `${Math.random() * (gameContainer.offsetHeight - 20)}px`;
player.dataset.type = i % 3; // 0: Rock, 1: Paper, 2: Scissors
player.dataset.dx = Math.random() < 0.5 ? 1 : -1;
player.dataset.dy = Math.random() < 0.5 ? 1 : -1;
gameContainer.appendChild(player);
players.push(player);
}
speed = document.getElementById('speed-control').value;
clearInterval(interval);
interval = setInterval(movePlayers, 50);
}
function movePlayers() {
for (const player of players) {
let x = parseInt(player.style.left);
let y = parseInt(player.style.top);
x += speed * player.dataset.dx;
y += speed * player.dataset.dy;
// Check for collisions with walls
if (x <= 0 || x >= gameContainer.offsetWidth - 20) {
player.dataset.dx *= -1;
x = Math.max(0, Math.min(gameContainer.offsetWidth - 20, x));
}
if (y <= 0 || y >= gameContainer.offsetHeight - 20) {
player.dataset.dy *= -1;
y = Math.max(0, Math.min(gameContainer.offsetHeight - 20, y));
}
// Check for collisions with other players
for (const otherPlayer of players) {
if (player !== otherPlayer && isColliding(player, otherPlayer)) {
resolveCollision(player, otherPlayer);
}
}
player.style.left = `${x}px`;
player.style.top = `${y}px`;
}
// Check for end of game
if (isGameOver()) {
clearInterval(interval);
// Show rematch button
const rematchButton = document.createElement('button');
rematchButton.textContent = 'Rematch';
rematchButton.onclick = initializeGame;
gameContainer.appendChild(rematchButton);
}
}
function isColliding(player1, player2) {
const rect1 = player1.getBoundingClientRect();
const rect2 = player2.getBoundingClientRect();
return !(rect1.right < rect2.left ||
rect1.left > rect2.right ||
rect1.bottom < rect2.top ||
rect1.top > rect2.bottom);
}
function resolveCollision(player1, player2) {
const type1 = parseInt(player1.dataset.type);
const type2 = parseInt(player2.dataset.type);
const winningType = (3 + type1 - type2) % 3;
collisionSound.play();
if (winningType === 1) {
// player1 wins
player2.textContent = player1.textContent;
player2.dataset.type = type1;
} else if (winningType === 2) {
// player2 wins
player1.textContent = player2.textContent;
player1.dataset.type = type2;
}
// Bounce off each other
player1.dataset.dx *= -1;
player1.dataset.dy *= -1;
player2.dataset.dx *= -1;
player2.dataset.dy *= -1;
}
function isGameOver() {
const aliveTypes = new Set();
players.forEach(player => aliveTypes.add(player.dataset.type));
return aliveTypes.size === 1;
}
document.getElementById('player-count').addEventListener('change', (event) => {
const value = parseInt(event.target.value);
// Ensure the number of players is a multiple of 3
event.target.value = value - value % 3;
});
document.getElementById('speed-control').addEventListener('change', (event) => {
const value = parseInt(event.target.value);
// Ensure the speed is between 1 and 10
event.target.value = Math.max(1, Math.min(10, value));
speed = event.target.value;
});
// Initialize the game with default values on load
window.onload = initializeGame;
</script>
</body>
</html>
Result
It’s janky as hell but it’s there, at the top of the page
Update and improve?
After a few days away, I decided to try to more closely replicate the inspiration above. I noticed that the players in the video kinda pursued or evaded each other. So I asked ChatGPT to add behavior like that into the code.
The Prompt
Improve the following code. Instead of player movement being random, make it so that player types pursue other players if they'd win the battle.
- Scissors should pursue paper and try to evade rock
- Rock should pursue scissors and try to evade paper
- Paper should pursue rock and try to evade scissors
The output
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... [your existing head content] ... -->
</head>
<body>
<!-- ... [your existing body content] ... -->
<script>
// ... [your existing script content up to movePlayers function] ...
function getTarget(player, players) {
let target = null;
let minDistance = Infinity;
players.forEach(otherPlayer => {
if (player !== otherPlayer) {
const distance = Math.hypot(
otherPlayer.offsetLeft - player.offsetLeft,
otherPlayer.offsetTop - player.offsetTop
);
if (distance < minDistance) {
minDistance = distance;
target = otherPlayer;
}
}
});
return target;
}
function moveTowards(player, target) {
const dx = target.offsetLeft - player.offsetLeft;
const dy = target.offsetTop - player.offsetTop;
const angle = Math.atan2(dy, dx);
player.dataset.dx = Math.cos(angle);
player.dataset.dy = Math.sin(angle);
}
function moveAway(player, target) {
const dx = player.offsetLeft - target.offsetLeft;
const dy = player.offsetTop - target.offsetTop;
const angle = Math.atan2(dy, dx);
player.dataset.dx = Math.cos(angle);
player.dataset.dy = Math.sin(angle);
}
function movePlayers() {
players.forEach(player => {
const target = getTarget(player, players);
if (target) {
const playerType = parseInt(player.dataset.type);
const targetType = parseInt(target.dataset.type);
const winningType = (3 + playerType - targetType) % 3;
if (winningType === 1) {
// Player would win, move towards target
moveTowards(player, target);
} else if (winningType === 2) {
// Player would lose, move away from target
moveAway(player, target);
} // If it's a tie, keep the current direction
}
// ... [rest of the original movePlayers function] ...
});
// ... [rest of the original movePlayers function] ...
}
// ... [rest of your existing script content] ...
</script>
</body>
</html>
The result
After filling in the parts that ChatGPT left out, this is the result. It doesn’t work… but I’m over this idea now.