AI has been all the rage lately, with solutions like Stable Diffusion for image generation, GPT-3 for text generation, and CoPilot for code development becoming publicly available to the masses.
That excitement ramped up this week with the release of ChatGPT, an extremely impressive chat-based AI system leveraging the best GPT has to offer.
I decided last night to take ChatGPT for a spin, to test its code-generation capabilities. And I was astonished by the experience.
Together, we built a simulation of bugs foraging for food in a 100×100 grid world, tracking essentials like hunger and life, reproducing, and dealing with hardships involving seasonal changes, natural disasters, and predators. All graphically represented.
We’re going to explore this in detail, but I want to start off by showing you what we built:
Also, you can find out more on my GitHub repository
A Recap of my Experience
Before we dive into the collaborative sessions that resulted in a working simulation, let me share a few thoughts and tidbits about my experience:
- This absolutely feels like magic right now. I basically just discussed the project and requirements, and ChatGPT built it. I didn’t write any code for this.
- I felt more like I was working with a junior developer than a seasoned developer. The code works, but isn’t well-designed, isn’t future-proof, and was beginning to fall apart toward the end. I’m not worried about being put out of a job just yet.
- I worked across multiple AI sessions last night, as the ChatGPT service was struggling under load. I’d start by providing the code we had so far, and ask it to acknowledge what it does before continuing on. Each time, it accurately understood what we built!
- Each session felt unique, like passing the project off to a new developer with its own opinions about the code. They also brought their own ideas to the table.
- ChatGPT is not infallible. Some buggy code was generated. This was actually was fun to experience, because it meant cooperatively debugging this project together, trying new things, and in one case, giving up on an approach.
- Despite its ability to write code, and fix code, and suggest features, it really needs a human driving the experience in order to stay on track, find problems, and say no to things. AI doesn’t (yet) push back on ideas, and since it’s not actually testing what it writes, it doesn’t know when it’s gone down the wrong path.
- It often wanted to give me whole new copies of the source file, and I had to ask it not to do this. AI sessions eventually learned and gave me code in the form I wanted.
- I tried asking for Unified Diffs, but that only somewhat worked — the diffs often had changes I wouldn’t have expected, or lacked something.
- I’m absolutely using this for Rubber Duck Debugging and brainstorming from now on.
With that, let me take you on a journey.
Please note: What follows is long. Feel free to skip around.
There’s a lot of text here in image form, with code. I’m trying to transcribe it from screenshots using OCR and editing the results, but I may have missed some syntax errors here or there.
I’m also including both screenshots and text descriptions. I want this to be accessible, but I think some people might want to see the actual interactions.
Step 1: Let’s simulate hunger
This was the start of my experiment, before I even knew what I wanted to do. I gave it one prompt:
Prompt: “write some Python code for emulating hunger”
Answer:
Here is an example of Python code that could be used to simulate hunger:
import time hunger_level = 10 while hunger_level > 0: print("I'm feeling hungry!") hunger_level -= 1 time.sleep(1) print("I'm not hungry anymore.")In this code, we define a variable called
hunger_level
that represents the current hunger level of the person. We then use awhile
loop to repeatedly print a message and decrement thehunger_level
variable until it reaches 0. This simulates the process of feeling hungry and then gradually feeling less hungry over time. Thetime.sleep()
function is used to pause the program for one second between each iteration of the loop, so that the messages are printed at a more realistic pace. Of course, this is just a simple example, and there are many other ways that you could approach this problem in Python.
Step 2: Time to eat
I next wanted a concept of eating. The program was simple at this point, so I didn’t know how it would approach this, but I decided to be vague in giving it direction. I wanted to see what it came up with.
Prompt: “update that code to let the character eat to decrease hunger”
Answer:
Here is an updated version of the Python code that includes the ability for the character to eat and decrease their hunger level:
import time hunger_level = 10 while hunger_level > 0: print("I'm feeling hungry!") choice = input("Do you want to eat? (y/n)") if choice == 'y': print("Eating...") hunger_level -= 1 else: print("I'll wait.") time.sleep(1) print("I'm not hungry anymore.")In this updated version of the code, we use an
if
statement inside thewhile
loop to check whether the user wants to eat. If the user inputs ‘y’, the character will eat and their hunger level will decrease. Otherwise, the character will wait and their hunger level will remain the same. This allows the user to control the character’s hunger level by deciding when to eat. As before, thetime.sleep()
function is used to pause the program for one second between each iteration of the loop, so that the messages are printed at a more realistic pace.
Step 3: Bugs are hungry, too
Human input wasn’t good enough. Let’s make this a creature, a bug, that has to go find food.
I gave it the following prompt:
Prompt: “now update that to have hunger be part of an entity class for a bug, and allow the bug to move and find food”
Answer:
Here is an updated version of the Python code that includes a
Bug
class with ahunger
attribute and methods for moving and finding food:import time class Bug: def __init__(self): self.hunger = 10 self.position = (0, 0) def move(self): # Move the bug to a new random position self.position = (self.position[0] + randint(-1, 1), self.position[1] + randint(-1, 1)) def find_food(self): # Decrease the bug's hunger level if it finds food if random() < 0.1: self.hunger -= 1 bug = Bug() while bug.hunger > 0: print("I'm feeling hungry!") bug.move() bug.find_food() time.sleep(1) print("I'm not hungry anymore.")In this code, we define a
Bug
class that has ahunger
attribute to represent the bug’s hunger level, and aposition
attribute to represent its current location. The__init__()
method is used to initialize these attributes when a newBug
object is created. Themove()
method is used to move the bug to a new random position, and thefind_food()
method is used to decrease the bug’s hunger level if it finds food. Thewhile
loop is used to simulate the bug’s search for food. Each iteration of the loop, the bug moves to a new position and checks for food. If the bug finds food, its hunger level is decreased. If it doesn’t find food, its hunger level remains the same. This continues until the bug’s hunger level reaches 0, at which point it is no longer hungry.
Step 4: Let’s spawn some food
The above code made the act of finding food a random thing. On each random movement, it’d look for food, and based on the roll of a die, it’d find it.
I wanted more, so I told it to make a grid for the bug to live on and spawn food on it.
Prompt: “update the code to spawn food on a 100×100 grid for the bug to find”
Answer:
Here is an updated version of the Python code that includes a
spawn_food()
function that generates food items on a 100×100 grid for the bug to find:import time from random import randint, random class Bug: def __init__(self): self.hunger = 10 self.position = (0, 0) def move(self): # Move the bug to a new random position self.position = (self.position[0] + randint(-1, 1), self.position[1] + randint(-1, 1)) def find_food(self, food_grid): # Decrease the bug's hunger level if it finds food x, y = self.position if food_grid[x][y] > 0: self.hunger -= 1 food_grid[x][y] -= 1 def spawn_food(food_grid): # Spawn food on a 100x100 grid for i in range(100): for j in range(100): food_grid[i][j] += randint(0, 10) bug = Bug() food_grid = [[0] * 100 for _ in range(100)] while bug.hunger > 0: print("I'm feeling hungry!") bug.move() bug.find_food(food_grid) spawn_food(food_grid) time.sleep(1) print("I'm not hungry anymore.")In this updated version of the code, we define a
spawn_food()
function that generates food items on a 100×100 grid. Thespawn_food()
function uses twofor
loops to iterate over the grid and randomly assign food values to each cell. Thefind_food()
method of theBug
class is updated to check whether there is food at the bug’s current position, and to decrease the bug’s hunger level if there is. Thewhile
loop is updated to call thespawn_food()
function at each iteration, so that new food items are generated on the grid as the bug moves around. This allows the bug to search for food and find it as it moves around the grid.
Step 5: How about path finding?
That worked. Now I wanted it to actually search for the food. So I gave it a very simple request.
Prompt: “give it path finding to find the nearest food”
Answer:
Here is an updated version of the Python code that includes path finding for the bug to find the nearest food on the grid:
import time from random import randint, random from heap import heappop, heappush class Bug: def __init__(self): self.hunger = 10 self.position = (0, 0) def move(self): # Use path finding to move to the nearest food x, y = self.position distances = [(0, 1), (0, -1), (1, 0), (-1, 0)] heap = [(0, self.position)] visited = set() while heap: dist, pos = heappop(heap) if pos in visited: continue visited.add(pos) if food_grid[pos[0]][pos[1]] > o: # Found food, move to this position self.position = pos return for dx, dy in distances: new_pos = (pos[0] + dx, pos[1] + dy) if 0 <= new_pos[0] < 100 and 0 <= new_pos[1] < 100: heappush(heap, (dist + 1, new_pos)) def find_food(self, food_grid): # Decrease the bug's hunger level if it finds food x, y = self.position if food_grid[x][y] > o: self.hunger -= 1 food_grid[x][y] -= 1 def spawn_food(food_grid): # Spawn food on a 100x100 grid for i in range(100): for j in range(100): food_grid[i][j] += randint(0, 10) bug = Bug() food_grid = [[0] * 100 for _ in range(100)] while bug.hunger > 0: print("I'm feeling hungry!") bug.move() bug.find_food(food_grid) spawn_food(food_grid) time.sleep(1) print("I'm not hungry anymore.")In this updated version of the code, we use a path finding algorithm to help the bug find the nearest food on the grid. The
move()
method of theBug
class is updated to use a breadth-first search algorithm to find the nearest food. The algorithm uses a heap to store the distances and positions of the cells that the bug has visited, and it expands the search in increasing order of distance. When the algorithm finds a cell with food, the bug moves to that position and the search is terminated. This allows the bug to efficiently find the nearest food on the grid, even if the food is not directly adjacent to its current position. Thewhile
loop and the other parts of the code remain the same, so that the bug continues to move, find food, and spawn new food on the grid as before.
Step 6: Poor lonely bug. Let’s add more.
Editor’s note: I’m going to simplify the code samples from here on out, only show the changed areas instead of the whole files. Later, ChatGPT got better at doing this in our interactions. Also note, ChatGPT started dropping the descriptions of its changes for much of these interactions.
One bug wasn’t enough. We need more bugs!
Prompt: “add multiple bugs, all competing for the same food”
Answer:
Here is an updated version of the Python code that includes multiple bugs competing for the same food on the grid:
# ... num_bugs = 5 bugs = [Bug() for _ in range(num_bugs)] food_grid = [[0] * 100 for _ in range(100)] while any(bug.hunger > 0 for bug in bugs): for bug in bugs: if bug.hunger > 0: print("I'm feeling hungry!") bug.move() bug.find_food(food_grid) spawn_food(food_grid) time.sleep(1) print("I'm not hungry anymore.")
Step 7: Introducing bugs to life and death
The bugs were immortal, and nobody likes immortal bugs. We had to deal with this.
Now at this point, my session was acting up. Answers were being truncated prematurely. I eventually realized I needed to start a new session, so I copy/pasted what we had into a new AI session, and gave it my new prompt. It did.
Prompt: “Update this to add a concept of “life” to the bugs, decreasing if they can’t find food, and killing them if they hit 0”
Answer:
To add a concept of “life” to the bugs, we can add a new
life
attribute to theBug
class and decrease it by 1 every time the bug doesn’t find food. We can also check if the bug’slife
has reached 0 before moving and finding food, and stop the simulation if all bugs are dead.Here is one way to update the code to add “life” to the bugs:
# ... class Bug: def __init__(self): self.hunger = 10 self.life = 10 self.position = (0, 0) # ... def find_food(self, food_grid): # Decrease the bug's hunger and life levels if it finds food x, y = self.position if food_grid[x][y] > 0: self.hunger -= 1 self.life -= 1 food_grid[x][y] -= 1 # ... while any(bug.life > 0 for bug in bugs): for bug in bugs: if bug.life > 0: print("I'm feeling hungry!") bug.move() bug.find_food(food_grid) else: print("I'm dead :(") # Decrease the bug's life if it didn't find food if bug.hunger == 10: bug.life -= 1 spawn_food(food_grid) time.sleep(1) print("All bugs are dead.")Note that in the
find_food()
method, we decrease the bug’shunger
and increase itslife
by 1 if it finds food. In the main simulation loop, we decrease the bug’slife
by 1 if it didn’t find food (i.e. if itshunger
level is still 10 after moving and finding food). This means that
(At this point, we hit a limit on the response, and I never got to find out what that that ultimately meant. Oh well.)
Step 8: Let’s get visual! Visual!
How do I know any of this actually works? It could be full of lies. I needed to see what the bugs were doing. So I asked it for graphics, using Python’s turtle module.
Prompt: “Update the code to provide a visual reproduction of the simulation using Python’s turtle module.”
Answer:
# ... import turtle # ... num_bugs = 5 bugs = [Bug() for _ in range(num_bugs)] food_grid = [[0] * 100 for _ in range(100)] # Initialize the turtle screen screen = turtle.Screen) screen.title("Bug Simulation") # Create turtle objects for the bugs bug_turtles = [turtle.Turtle() for _ in range(num_bugs)] for t in bug_turtles: t.color("red") t.shape("turtle") while any(bug.life > 0 for bug in bugs): for bug, t in zip(bugs, bug_turtles) if bug.life > 0: print("I'm feeling hungry!") bug.move() bug.find_food(food_grid) # Update the turtle's position on the screen t.goto(bug.position[0] * 10, bug.position[1] * 10) else: print("I'm dead :(") # ...
Step 9: Randomize the bugs!
That actually worked! But all the bugs looked the same. They were all red, and all started at the same location, in the center of the screen at 0, 0. So let’s fix that.
Prompt: “Give each turtle a different color. Make sure they start at random locations.”
Answer:
# ... class Bug: def __init__(self): # ... self.position = (randint(0, 99), randint(0, 99)) # ... # Create turtle objects for the bugs bug_turtles = [turtle.Turtle() for _ in range(num_bugs)] colors = ["red", "blue", "green", "orange", "purple"] for t, color in zip(bug_turtles, colors): t.color(color) t.shape("turtle") # ...
Step 10: Debuggin’ bugs
It ran and it worked! Uhhhh kind of. It uncovered bugs. And not the ones I wanted. So we entered everyone’s favorite phase of software development: debugging.
First: The coordinate system was wrong. In Turtle, (0, 0)
is the center of the screen, not the top-left. The code wasn’t accounting for this. So I simply informed ChatGPT.
Note that at this point, the AI decided giving me more contextual code snippets was the way to go.
Prompt: “Fix the coordinate system. Turtle uses (0, 0) as the center of the screen, not the top-left.”
Answer:
To fix the coordinate system, we need to adjust the code so that the origin is at the center of the screen. This can be done by changing the values of the
x
andy
coordinates in thegoto
method of the turtle objects.Here is how the code should look after making the changes:
# Update the turtle's position on the screen t.goto(bug.position[0] * 10 - 500, bug.position[1] * 10 - 500)In the above code, the
x
andy
coordinates are multiplied by 10 to scale them up and then shifted by 50 units in the negative direction to move them to the center of the screen.
I hand-applied this to our code and verified the fix.
Step 11: Way too much food
I noticed a new problem: Food was spawning every tick! Bugs had no incentive to forage. I suggested we only spawn food every 200 ticks.
Prompt: Update the code to only spawn food every 200 cycles of the main loop.
Answer:
To update the code so that food is only spawned every 200 cycles of the main loop we can add a counter variable that keeps track of the number of iterations of the loop and then use the modulo operator
%
to determine if food should be spawned.Here is how the updated code should look:
# ... # Add a counter variable to keep track of the number of iterations counter = 0 while any(bug.life > 0 for bug in bugs): # ... # Only spawn food every 200 iterations if counter % 200 == 0: spawn_food(food_grid) counter += 1 time.sleep(1) # ...In the above code, the
counter
variable is initialized to 0 and then incremented by 1 at the end of each iteration of the main loop. Thespawn_food
function is only called if the counter variable is divisible by 200 (i.e., ifcounter % 200 = 0
isTrue
). This ensures that food is only spawned every 200 iterations of the main loop.
Step 12: Food is meant to be seen
I realized we had visuals for the bugs, but not the food. I could see the bugs moving around now, but couldn’t see what the food situation looked like. So, I asked for visuals.
Prompt: “Update the code to show a visual indicator of each food. Give it to me as a set of changes I should make.”
Answer:
To update the code to show a visual indicator of each food, we can use the turtle module to draw a small circle at the location of each food item on the grid. Here is how the updated code should look:
# ... # Create a turtle object for the food food_turtle = turtle.Turtle() food_turtle.color("yellow") food_turtle.shape("circle") # ... while any(bug.life > 0 for bug in bugs): # ... # Only spawn food every 200 iterations if counter % 200 == 0: spawn_food(food_grid) # Draw a circle at the location of each food item for i in range(100): for j in range(100): if food_grid[i][j] > 0: food_turtle.goto(i * 10 - 500, j * 10 - 500) food_turtle.stamp() # ... # ...In the above code, a new turtle object called
food_turtle
is created and initialized with thecircle
shape and theyellow
color. Then, in each iteration of the main loop, thefor
loops iterate over the entire food grid and draw a circle at the location of each food item using thestamp
method of thefood_turtle
object. This shows a visual indicator of each food item on the screen.
Step 13: Too much food! Too yellow! Fix it!
Oh no, food was everywhere! That random chance of food spawn was just too much. So I had it tone that down a bit. Also, I didn’t like the yellow circles for food, so I asked for a change there as well.
Prompt: “Update food spawning to make food more rare. At most, only about 2% of the board should ever have food. Also, make food pink squares instead of yellow circles. You can show me the lines to modify, instead of the full file.”
Answer:
To update the code to make food more rare and change its appearance, we can modify the
spawn_food
function and thefood_turtle
object. Here are the changes to make:def spawn_food(food_grid): # Spawn food on a 100x100 grid for i in range(100): for j in range(100): # Spawn food with probability 0.02 if random() < 0.02: food_grid[i][j] += 1 # Create a turtle object for the food food_turtle = turtle.Turtle() food_turtle.color("pink") food_turtle.shape("square")In the updated
spawn_food
function, food is only spawned with probability 0.02 (i.e., 2%) instead of a random number between 0 and 10. This makes food much more rare on the grid.In the updated
food_turtle
object, thecolor
attribute is set to"pink"
and theshape
attribute is set to"square"
instead of"circle"
. This changes the appearance of the food from yellow circles to pink squares.
Step 14: Everything is slow and noisy 🙁
Turtle defaults to showing lines when you move, and also animates everything. This made the simulation both very visually noisy, and far too slow to really work with.
Now, this took a bit of doing. We had to iterate a few times on some stuff. Turn off a few drawing methods, draw food less often. This section has two prompts.
Prompt: “Remove line drawing when moving bug turtles. Update the drawing of the food turtle to not animate or have any delays. It must be fast. Don’t show me the whole file. Just relevant lines of new code.”
Answer:
for bug, t in zip(bugs, bug_turtles): if bug.life > 0: print("I'm feeling hungry!") bug.move() bug.find_food(food_grid) # Update the turtle's position on the screen without drawing a line t.penup() t.goto(bug.position[0] * 10 - 500, bug.position[1] * 10 - 500) t.pendown()# Only spawn food every 200 iterations if counter % 200 == 0: spawn_food(food_grid) # Draw a square at the location of each food item without animation or delay food_turtle.speed(0) for i in range(100): for j in range(100): if food_grid[i][j] > 0: food_turtle.goto(i * 10 - 500, j * 10 - 500) food_turtle.stamp()
Prompt: “Update to only draw food when respawning food or when starting the simulation. Also, don’t show lines when drawing food.”
Answer:
# Only draw food when respawning or when starting the simulation if counter % 200 == 0 or counter == 0: # Only spawn food every 200 iterations spawn_food(food_grid) # Draw a square at the location of each food item without animation or delay food_turtle.speed(0) food_turtle.penup() for i in range(100): for j in range(100): if food_grid[i][j] > 0: food_turtle.goto(i * 10 - 500, j * 10 - 500) food_turtle.stamp() food_turtle.pendown()
Step 15: Shouldn’t food disappear when eaten?
This was starting to look pretty good! But I noticed that food stuck around after being eaten. I pointed this out, and got some code back, but it had some of the same performance problems we just fixed. So I gave it some feedback about optimizations — just like in a code review! — and in the end, we had some workable code.
Prompt: “Hide food once it’s been fully eaten.”
Answer:
# Only draw food when respawning or when starting the simulation if counter % 200 == 0 or counter == 0: # ... else: # Hide food once it's been fully eaten for i in range(100): for j in range(100): if food_grid[i][j] == 0: food_turtle.goto(i * 10 - 500, j * 10 - 500) food_turtle.clearstamp(0)
Prompt: “Apply the same pen and speed optimizations used when drawing turtles to hiding them.”
Answer:
# Only draw food when respawning or when starting the simulation if counter % 200 == 0 or counter 0: # ... else: # Hide food once it's been fully eaten food_turtle.speed(0) food_turtle.penup() for i in range(100): for j in range(100): if food_grid[i][j] == 0: food_turtle.goto(i * 10 - 500, j * 10 - 500) food_turtle.clearstamp(0) food_turtle.pendown()
Prompt: “That’s slow. Only hide food if it’s 0 but wasn’t previously 0.”
Answer:
# Only draw food when respawning or when starting the simulation if counter % 200 == 0 or counter 0: # ... else: # Hide food once it's been fully eaten food_turtle.speed(0) food_turtle.penup() for i in range(100): for j in range(100): if food_grid[i][j] = 0 and prev_food_grid[i][j] > 0: food_turtle.goto(i * 10 - 500, j * 10 - 500) food_turtle.clearstamp(0) food_turtle.pendown() prev_food_grid = food_grid.copy()
Step 16: Seriously, shouldn’t food disappear when eaten?
Hiding of food wasn’t working. The AI made some bad assumptions about that clearstamp()
method. I wasn’t sure what was going wrong at first (I was starting to get a bit cross-eyed doing this), but we tried alternate drawings to the food location, we tried avoiding over-stamping of food.
These didn’t work, but some other issues were found in the process. And, in step 17, we’ll work on an actual fix.
Prompt: “clearstamp isn’t working. Try something else to clear that square.”
Answer:
# ... if food_grid[i][j] == 0 and prev_food_grid[i][j] > 0: food_turtle.goto(i * 10 - 500, j * 10 - 500) food_turtle.shape("blank") food_turtle.stamp() food_turtle.shape("square") # ...
Prompt: “The food stamp is being drawn too many times on the same position. Update food drawing to only stamp if there wasn’t previously food before.”
Answer:
# ... if counter % 200 == 0 or counter == 0: # ... for i in range(100): for j in range(100): if food_grid[i][j] > 0 and prev_food_grid[i][j] == 0: # ... # ... # ...
Prompt: “I’m getting an undefined variable error for prev_food_grid in the food drawing loop. I think this should be initialized before the main loop.”
Answer:
# Initialize prev_food_grid with the initial food grid prev_food_grid = food_grid.copy() # Main simulation loop # ...
Prompt: “I found a problem. prev_food_grid is a shallow copy, so the internal arrays aren’t being copied.”
Answer:
# Initialize prev_food_grid with the initial food grid prev_food_grid = [row.copy() for row in food_grid] # Main simulation loop while any(bug.life > 0 for bug in bugs): # ... # Make a deep copy of food_grid to prev_food_grid prev_food_grid = [row.copy() for row in food_grid] # ...
Step 17: Okay, now the food is gone.
By this point, my AI session started to act up again, so I started a new one, provided the current code and explained where we left off, and then began prompting again to try to fix this properly.
This new session used different syntax highlighting, and described the locations of changes differently. Interesting.
Prompt: “There’s a problem with clearing food. I think we need to store the locations of stamp IDs When we draw new food, and then clear the stamps when hiding food. Can you show me the relevant changes for that? I don’t need to see the whole file.”
Answer:
To fix the problem with clearing food in the simulation, you can store the locations of the food stamps in a list, and then iterate over this list and clear the stamps when hiding food. Here is an example of how this could be implemented:
# Add a list to store the locations of the food stamps food_stamp_locations = [] # Inside the main simulation loop: # Only draw food when respawning or when starting the simulation if counter % 200 == 0 or counter == 0: # ... for i in range(100): for j in range(100): if food_grid[i][j] > 0 and prev_food_grid[i][j] == 0: food_turtle.goto(i * 10 - 500, j * 10 - 500) # Stamp the food at the current location stamp_id = food_turtle.stamp() # Add the stamp location to the list food_stamp_locations.append((i, j, stamp_id)) # Clear the food stamps that are no longer needed food_turtle.speed(0) food_turtle.penup() for i, j, stamp_id in food_stamp_locations: if food_grid[i][j] == 0 and prev_food_grid[i][j] > 0: food_turtle.clearstamp(stamp_id)This code will store the location and stamp ID of each food item when it is drawn on the screen, and then clear the stamps when the food disappears from the grid.
Prompt: “It needs to clear every tick of the main loop, not just when respawning food or in the first tick.”
Answer:
To make the code clear the food stamps every tick of the main simulation loop, you can move the code that clears the stamps to the end of the loop, after all of the bugs have moved and found food. Here is an example of how this could be implemented:
# Main simulation loop while any(bug.life > 0 for bug in bugs): # ... # Clear the food stamps that are no longer needed food_turtle.speed(0) food_turtle.penup() for i, j, stamp_id in food_stamp_locations: if food_grid[i][j] == 0 and prev_food_grid[i][j] > 0: food_turtle.clearstamp(stamp_id) # Only draw food when respawning or when starting the simulation # ...In this code, the food stamps are cleared at the end of each iteration of the main simulation loop, after all of the bugs have moved and found food. The code that spawns and draws food is only executed every 200 iterations, or at the beginning of the simulation. This will ensure that the food stamps are cleared every tick of the main loop, while only spawning and drawing food at regular intervals.
Some other ideas
I was feeling pretty good, and basically done at this point. So I just asked the AI if it had any other ideas. It listed a few, one being competing for food (avoiding eating food that other bugs have eaten).
Prompt: “do you have any ideas for this simulation?”
Answer:
There are many ways that you could extend or modify this simulation. Here are a few ideas:
These are just a few examples of the many ways that you could extend or modify this simulation. I’m sure you can come up with even more creative ideas!
I thought these were good, and we explored the following:
- Competing for food
- Predators
- Reproduction (something it later suggested and took the initiative of coding without my input!)
- Seasons that affect food growth
- Natural disasters, including floods, fires, hurricanes, and blizzards
This post is already too long, so I’m not going to dive into all of those. Instead, you can find all the screenshots in the GitHub repository.
In summary…
Super cool stuff.
I can understand why people may be concerned about their jobs, their livelihood. But I’m not concerned, not at this point anyway.
This tool was a really helpful creative aid, something that let me prototype and debug with nothing but words, the way I might with another human.
But it very clearly wasn’t another human. It didn’t go back and rethink its approach to the code. It didn’t design with an eye toward future maintainability. It didn’t push back on ideas. It couldn’t test what it wrote.
A human still needed to be in the driver’s seat.
I’m excited to use this to talk through ideas, to get insights into code, to rapidly prototype.
But I’ve also worked on million line codebases, and this ain’t gonna cut it. Certainly not yet.
I would recommend that everyone spends some time with this tool. Make it real and not theoretical. Play with it, find the boundaries the experience. Reaffirm what you yourself are capable of, and how much you bring to the table.
Because the human element still matters. The AI is just a tool, but one that you might find to be a useful ally.
Thanks for reading this far.