Observations and Ending the Experiment
In this closing chapter of my experiment to have ChatGPT write all code for a turn-based strategy game, I part with a better understanding of the limitations of the current version 4 of OpenAI.com‘s ChatGPT. Part 3 ended with a partially functional checker-style board with movable game units, after a mess of refactoring into JavaScript classes in Part 2. In this session I took a radical and informative change, which also ends the experiment.
Experiments are meant to test theories and hypotheses, which this effort did. I also learned a lot in the process, which is another purpose for experimentation. My experiment was to not write any of the code myself, only ask the AI to write it, based on simple requests and comments on errors. Game development gave a purpose, learning the limitations was the objective.
What I learned from ChatGPT in Trying to Coax it to Write Code
- If you word your requests carefully, and descriptively, the reply can be a useful, educational tutorial, much better than any previous internet search. Sorry Google, there are new kids on the block.
- ChatGPT can be creative while iterating through revisions on a small amount of text or code
- ChatGPT can generate some interesting and useful code, and even debug parts.
Despite these strengths, I choose to end the experiment because ChatGPT, for lack of a better description, loses focus. It lacks a concept of a vision a person may have, which a human keeps in their thoughts going forward in action without having to continually articulate it. Unless you are into affirmations, which is great if you don’t have to remind ChatGPT of them every other moment.
In starting this session, having learned from previous sessions, I decided to start over and restate my initial request. In my first session (Part 1) my starting requests were short and not detailed, and went like this:
"Are you familiar with the game Antiyoy?"
In which ChatGPT provided a nice summary of the game that could have come from a dry version of Wikipedia. Then I made my request.
"Write p5.js code for Antiyoy I want to use my own textures for the objects."
The rest of that process is told in the earlier posts (Part 1, Part 2, Part 3).
Starting over, and with a better understanding of how to interact with Chat, I began with the following request and exchange. What I got back was much more useful than earlier sessions and is why I say ChatGPT can be a powerful educational tutorial tool.
I need your help creating a web-based locally hosted game. I want to use an open-source free code base and game engine. I want ChatGPT to write the code based on my requests. The game should be a turn-based hex-tile resource strategy game, supporting at least two players and more if desired. The game should be similar to Anityoy.
ChatGPT replied with:
I understand your requirements and will help you create a turn-based hex-tile resource strategy game similar to Antiyoy using an open-source, free game engine. I recommend using Phaser, a popular and well-documented HTML5 game engine. First, make sure you have the following prerequisites: Node.js (https://nodejs.org/) installed on your computer. A text editor like Visual Studio Code (https://code.visualstudio.com/). A web browser to test your game.
Chat outlined the required code files with stubbed functions and little else before continuing. The code stubs were otherwise unremarkable. On the other hand, the instructions and pointers Chat combined in its response are helpful and remarkable.
To get you started with a hex-tile based strategy game, you may find these resources helpful: Hexagonal grids tutorial (https://www.redblobgames.com/grids/hexagons/): This tutorial will help you understand hexagonal grids and how to work with them in your game. Phaser 3 Hex Map Example (https://github.com/luizbills/phaser3-hexmap-example): This GitHub repository contains a Phaser 3 example of creating a hexagonal tile map. By referring to these resources and the Phaser documentation, you can customize the game mechanics, graphics, and interactions to fit your requirements. Good luck and happy coding!
Note, ChatGPT still has a dated training set, so sometimes provided links are bad. This is a link to the Phaser 3 site, https://phaser.io, as the one listed above is a dead end.
Now armed with some references, particularly for hexagonal grids tutorial (https://www.redblobgames.com/grids/hexagons) and Phaser.io, I can ask better questions and receiving more meaningful replies. Things like, “create a class and code for a game board, hex tiles flat-top double coordinates”, and “the gameboard looks incomplete. I need it to be 15 tiles wide and 20 tall. The tiles should be a random mix of ‘land’ tiles and ‘water’ tiles.”
Up to this point I got a good set of mostly working code, not having writen a single line myself. As I mentioned in earlier posts, while I am a software engineer, I tend to specialize in databases and development of infrastructure and cybersecurity management tools. I am not a gamer, game designer, or user-interface specialist.
What impressed me from ChatGPT was code like this drawHexagon() function. To me, this is cool and knowing for me to try writing it from whole cloth would have taken time to research as I am not versed in the referenced graphics library.
function drawHexagon(graphics, tileSize) {
for (let i = 0; i < 6; i++) {
const angleDeg = 60 * i + 30;
const angleRad = (Math.PI / 180) * angleDeg;
const x = tileSize * Math.cos(angleRad);
const y = tileSize * Math.sin(angleRad);
if (i === 0) {
graphics.moveTo(x, y);
} else {
graphics.lineTo(x, y);
}
}
graphics.closePath();
graphics.strokePath();
graphics.fillPath();
}
While I don’t have a functional game as a result, I have learned a lot in trying, and that was the point.
As I continued down the road to get a working gameboard, ChatGPT started to fall into the loss-of-focus well. Time can get seriously wasted in explaining a problem to Chat, followed by a proposed fix that either undoes a previous fix or creates a new problem. Rinse and repeat and you start to see you are going in circles reverting the one change while making another.
The gameboard I was aiming for was a flat-top double coordinate hexagonal grid. ChatGPT always produced a point-top grid. I never could get ChatGPT to get that change, nor properly deal with the tile overlap.
Nevertheless, what it did create, concisely, was a gameboard like what I described. In making changes to functions, I found debugging code was a stretch for ChatGPT, but it did make corrections when I pointed out errors.
Most importantly, from these sessions, I learned a little about how to ask ChatGPT for what I want. Then use unrelated Chat sessions to expand on suggestions to gain a little more personal knowledge. With new knowledge in hand, I had the tools to go back and ask for specific results.
I can see where integrating ChatGPT in real time with real development tools like Visual Studio Code, or other development environments, will be exceptional. Being able to ask ChatGPT to help craft a function like the ‘drawHexagon()’ method, while framing it with full knowledge of the code and code-intelligence tools will be a game changer for software developers. Expect in the coming months and years to see revolutionary advances in applications and online tools.
In my professional work, at least for now, these AI integrations are blocked. This is for security and intellectual property reasons. Companies will need to address this. Consider, everything a person feeds into ChatGPT is retained by ChatGPT and can be exposed or leveraged by anyone else. For example, see: ChatGPT Users Report Seeing Other People’s Conversation Histories | PCMag. Your knowledge becomes part of everyone’s library.
This is where the power of integrated AI will shine, at least until we reach “the singularity” with AI taking over the world and leaving us all as meat puppets to oil the machinery.
This is the last version of the code ChatGPT suggested. Enjoy.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'game',
scene: {
preload: preload,
create: create,
update: update,
},
};
const game = new Phaser.Game(config);
function preload() {
// Load tile textures here
}
function drawHexagon(graphics, tileSize) {
for (let i = 0; i < 6; i++) {
const angleDeg = 60 * i - 30;
const angleRad = (Math.PI / 180) * angleDeg;
const x = tileSize * Math.cos(angleRad);
const y = tileSize * Math.sin(angleRad);
if (i === 0) {
graphics.moveTo(x, y);
} else {
graphics.lineTo(x, y);
}
}
graphics.closePath();
graphics.strokePath();
graphics.fillPath();
}
function create() {
// Create hexagonal tile textures
const tileSize = 32;
const landTexture = createHexTileTexture(this, tileSize, 0x228B22, 0x006400); // Forest green, Dark green
const waterTexture = createHexTileTexture(this, tileSize, 0x4169E1, 0x000080); // Royal blue, Navy
// Create game objects and setup the game world here
const gameBoard = new GameBoard(this, tileSize, landTexture, waterTexture); // Pass the textures as arguments
// Generate a 15x20 game board with random land and water tiles
gameBoard.generateBoard(15, 20);
}
function createHexTileTexture(scene, tileSize, fillColor, lineColor) {
const hexGraphics = new Phaser.GameObjects.Graphics(scene);
hexGraphics.fillStyle(fillColor, 1);
hexGraphics.lineStyle(2, lineColor);
hexGraphics.beginPath();
for (let i = 0; i < 6; i++) {
const angleDeg = 60 * i - 30;
const angleRad = (Math.PI / 180) * angleDeg;
const x = tileSize + tileSize * Math.cos(angleRad);
const y = tileSize + tileSize * Math.sin(angleRad);
if (i === 0) {
hexGraphics.moveTo(x, y);
} else {
hexGraphics.lineTo(x, y);
}
}
hexGraphics.closePath();
hexGraphics.strokePath();
hexGraphics.fillPath();
const textureName = `tile_${fillColor}_${lineColor}`;
scene.add.existing(hexGraphics); // Add the graphics object to the scene
hexGraphics.generateTexture(textureName, tileSize * 2, tileSize * 2);
hexGraphics.destroy();
return textureName;
}
function update() {
// Update game logic and handle user input here
}
class HexTile {
constructor(x, y, size, texture) {
this.x = x;
this.y = y;
this.size = size;
this.texture = texture;
}
getCorner(offset) {
const angleDeg = 60 * offset - 30;
const angleRad = (Math.PI / 180) * angleDeg;
return {
x: this.x + this.size * Math.cos(angleRad),
y: this.y + this.size * Math.sin(angleRad),
};
}
draw(scene) {
const hexSprite = scene.add.sprite(this.x, this.y, this.texture);
hexSprite.setOrigin(0.5, 0.5);
}
}
class GameBoard {
constructor(scene, tileSize, landTexture, waterTexture) { // Add landTexture and waterTexture as arguments
this.scene = scene;
this.tileSize = tileSize;
this.tiles = [];
this.landTexture = landTexture; // Store the landTexture as an instance variable
this.waterTexture = waterTexture; // Store the waterTexture as an instance variable
}
generateBoard(width, height) {
const tileSize = this.tileSize;
const tileHeight = tileSize * Math.sqrt(3);
const tileWidth = tileSize * 1.5;
for (let row = 0; row < height; row++) {
for (let col = 0; col < width; col++) {
const offsetY = (col % 2 === 0) ? 0 : tileHeight / 2;
const x = col * tileWidth + tileSize;
const y = row * tileHeight * 0.75 + offsetY + tileSize;
const texture = (Math.random() < 0.5) ? this.landTexture : this.waterTexture;
this.addTile(x, y, texture);
}
}
}
addTile(x, y, texture) {
const hexTile = new HexTile(x, y, this.tileSize, texture);
this.tiles.push(hexTile);
hexTile.draw(this.scene);
}
// Add your custom methods for game board logic here
}