LLM seems to be a better programmer than me.
Can artificial intelligence (AI) outperform human programmers when writing code? After a series of experiments, it becomes clear that the answer to this question is a resounding yes!
![Evolution of programmers Evolution of programmers](https://habrastorage.org/getpro/habr/upload_files/9ac/ac1/036/9acac1036bf397c19d3aa7d165d64eaf.jpg)
This article will not contain a single line of theoretical discussion about the advantages and disadvantages of using LLM in programming. There will only be practice and at the end some well-founded conclusions with an ironic look into the near future for all programmers. The content of all steps will be presented completely as is, so the article may seem a little long, but it is necessary to understand the essence of the process itself.
First, to lighten the mood, here’s some “bad advice” for programmers from LLM (it turns out she not only writes code, but also has a peculiar sense of humor):
Never learn new programming languages; after all, you already know enough to be able to write your normal code anyway – so stick to what you're used to and don't waste time learning anything new!
What will the experiment be like?
The goal of the experiment is to write a game that is quite complex from a logical point of view, using the model as much as possible with minimal manual modifications.
If this succeeds, it will be possible to compare the new programming paradigm with the old one according to the criteria of resource expenditure (time, intellectual effort), ease of use of the technology, quality of the results obtained, and overall satisfaction with the process of solving the problem.
Why will we create a game, and not some, for example, useful utility for a computer?
The result is immediately visible, starting from the first step, and then all subsequent changes and improvements are visually assessed easily and quickly. Each next step naturally follows from the results of the last step and therefore the design logic is clearly visible. Plus it's fun and creates a nice atmosphere.
How will we conduct the experiment?
First, let's try to immediately create an initial working version with basic functionality.
Next, I will create the code using the method of successive clarifications and additions. Step by step the code will change, the game logic will improve and become more diverse. Graphics features will also be consistently improved, enhancing the gaming experience. I will try to make sure that all the main code is written by the model and will not interfere much with the code that it itself will offer at each step. However, I will still make minor errors and minor corrections from time to time if absolutely necessary, but this is truly minimal intervention.
I divided the experiment itself into two stages.
The first stage is getting fully functional code and user interface.
The second stage is bringing the code up to standard and getting a working game.
What are the initial conditions of the experiment?
I will deliberately complicate the experimental conditions, although much could have been done more correctly from the beginning. But in this case, a healthy dose of masochism would be appropriate. So it's time to define our rules.
I will give instructions in Russian.
The game will be created from scratch, so that the model, if possible, knows nothing about it.
C#, which is not the most suitable for this, will be chosen as the language.
As a model, I will use the quantized Codestral-22B-v0.1-Q4_K_M, specially trained for coding in 80 languages (You can find out about the original model on the developers’ website https://mistral.ai/news/codestral/).
I will work with the code in VS, transferring the code generated by the model into the project simply by copy-paste, following its instructions, which it will give in the comments for each portion of the code it creates.
I will create a fairly well-known among the people game “Balls”, Lenes (Color Lines), which is difficult to implement both in a logical and graphical sense. First, I made sure that the model knew nothing about her.
Let's start the first stage
Before I start, I'll set up the model in a specific way, setting values for several of its tuning parameters that are important for its best performance.
Next, I will detail, step by step, the entire protocol for interacting with the model, excluding only the generated code itself, instead of which there will be the text “Further code and comments.” Otherwise, the article will turn into a sheet with a pile of hard-to-read text. At the end, for those who are interested in the details, I will provide a link to the full protocol with a download code.
So, you can start the experiment itself.
The first prompt, which should explain to the model the meaning of the game that it must create.
Write Windows forms code in C#, taking into account the game logic and specific functionality for playing lines. The essence of the game is as follows.
On a playing field of 10 by 10 cells, a ball of one of 5 random colors appears in a random cell. The player selects any ball in the field with the mouse and indicates a free cell where this ball needs to be moved and the ball smoothly moves into this cell. Then another ball of one of the random 5 colors appears in a random free cell again and thus the game continues. The player's task is to use 5 or more balls of the same color to form a continuous line vertically, horizontally or diagonally. In this case, all these 5 balls disappear. The game ends when all the cells are filled with balls. A new ball can only appear on an empty cell.
Model's answer.
Here is a simple implementation of the game's logic in C# Windows Forms. This version doesn't include any animations; the movement of balls is instant.
Below is the code and comments.
Note: To run this code, you need to have a Windows Forms project in your C# environment and replace the contents of the Form1.cs file with this code. This is just a simple text-based representation of the game and does not include any graphics or animations. For a more complete implementation, you may want to consider using a graphics library like Unity or XNA for the visual representation of the game.
We immediately get working code without errors and we can try to play this game to find the first flaw and fix it.
It consists in the fact that we select the ball with the left mouse button, and indicate the target with the right one, so we write the following prompt.
Change the Grid_MouseClick function so that both actions, selecting a ball and specifying a cell to move it, are performed only by pressing MouseButtons.Left
Model's answer.
Here's how you can modify the `Grid_MouseClick` function to handle both selecting a ball and specifying a destination for it solely through left clicks:
Below is the code and comments.
In this version, clicking on a ball will first select it if no ball is currently selected. Clicking on another ball will change the selection to that ball. If we then click on an empty cell, the previously selected ball will move to the new cell. This only works if there are two distinct clicks – one on a ball and one on an empty cell – in between.
We draw your attention to the fact that the selected ball is no different from the others and we want it to be different in some way, so we write the following prompt.
Change the code so that the selected ball retains its color, but is different from the unselected balls.
Model's answer.
You can modify the `Grid_MouseClick` function to change the color of the selected ball when it's clicked, and revert its color back to normal when it's deselected:
First, you need to introduce a new variable to keep track of the original color of the selected ball:
Below is the code and comments.
Then, adjust your `Grid_MouseClick` method like so:
Below is the code and comments.
In this version, clicking on a ball will change its color to the contrast color (which is calculated by the `GetContrastColor` function), and if you click on another ball, the first one will revert back to its original color. Then, you can move the selected ball to an empty cell.
Note: You should also add a `GetContrastColor` function that takes a `Color` as input and returns either black or white based on the perceived brightness of the input color.
The model forgot to define the GetContrastColor function itself, so we ask you to write it.
Write a GetContrastColor function
Model's answer.
Here's a simple implementation of the `GetContrastColor` function in C#:
Below is the code and comments.
This function calculates the perceived brightness of a color using the RGB values and the formula for luminance (also known as relative luminance). If the brightness is greater than 128 (out of 255), it returns black; otherwise, it returns white. This provides a simple way to choose a contrasting color for any given color.
Now the selected ball looks a bit clumsy when selected, but it actually changes, so we want to improve this function and make the ball selection beautiful.
Change the GetContrastColor function so that the color of the ball does not change when it is selected, and the brightness smoothly changes cyclically in a sinusoid using a timer
Model's answer.
To create this effect, you could use a `Timer` object to change the brightness of the selected ball at regular intervals. Here's an example of how to do this:
First, add a `Timer` field to your form:
Below is the code and comments.
Then, in your constructor, initialize the timer and subscribe to its `Tick` event:
Below is more code and comments.
Next, modify your `Grid_MouseClick` method to start the timer when a ball is selected and stop it when it's deselected:
Below is more code and comments.
Finally, implement your `Timer_Tick` event handler. This should change the color of the selected ball based on a sinusoidal brightness value:
Below is more code and comments.
In this version, the `time` variable accumulates over time, and the brightness is calculated as a function of this variable using a sinusoidal waveform that cycles between 0 and 1. The resulting brightness value is then used to calculate a new grayscale color for the selected ball.
Now, when you select a ball, its brightness changes beautifully, then more, then less, until the target is indicated.
It's time to correct another obvious misunderstanding: our balls are not round balls at all, but colored squares.
Transform the appearance of the balls from square to round.
Model's answer.
To make the balls circular instead of square, you can set their `Region` property to an instance of the `System.Drawing.Drawing2D.GraphicsPath` class with an ellipse shape. Here's how to modify your code to achieve this:
First, add the following `using` directive at the top of your file:
Below is the code and comments.
Then, in your constructor, create a new `GraphicsPath` object with an ellipse shape and set it as the `Region` of each `PictureBox`:
Below is the code and comments.
In this version, a new `GraphicsPath` object is created for each `PictureBox`, and an ellipse is added to its path that fits within the bounds of the `PictureBox`. This ellipse is then used to define the region of the `PictureBox`, which determines which pixels are considered part of the control and which are transparent. This makes the balls circular instead of square.
We transfer the created code according to the instructions into our project and get what we wanted. You can select beautiful round balls and indicate the target where they move, and when a continuous line of 5 or more balls of the same color in a row is formed, this line is deleted. In principle, the game is ready, but we need to bring it up to standard, so we are writing a new prompt.
Add a button that starts a new game by clicking, as well as a Label that counts the number of removed lines of balls. Make the panel, button and Label more beautiful, with clear lines and nice colors.
Model's answer.
To add a new game button, a label to display the number of removed lines, and improve the appearance of the panel, button, and label, you can use the following code:
First, add the following fields to your form:
Below is the code and comments.
Then, in your constructor, create and initialize these controls, and set their properties as desired:
Below is the code and comments.
In this version, a new `Button` and `Label` are created, and their properties are set to display the desired text and appearance. The button's `Click` event is also handled by the `NewGameButton_Click` method, which you can implement to start a new game.
Below is the code and comments.
To update the number of removed lines, you can modify your `RemoveLine` method as follows:
In this version, the `linesRemoved` field is incremented each time a line is removed, and the label's text is updated to reflect the new value.
The model forgot to define the NewGameButton_Click function, we remind her of this.
Write a function NewGameButton_Click.
Model's answer.
Here's an example implementation of the `NewGameButton_Click` function:
Below is the code and comments.
In this version, the `NewGameButton_Click` function clears the grid by setting the background color of each `PictureBox` to white, resets the `linesRemoved` field and the label's text, and then fills the grid with new balls using the `AddNewBall` method .
So, the first stage of creating the game is completed. All the basic functions are there, the logic works, the appearance is quite satisfactory. The first stage took less than one day with breaks.
What can you say about code quality? It is clean, commented, well structured and most importantly error free.
I manually corrected only one minor error that was not related to the logic of operation. The model accurately fulfills the conditions of the prompt and comments in detail on its decisions. The result is beyond any wildest expectations, since I was internally prepared for logical errors and all other errors too. But we managed to avoid them, as well as routine coding, by once again reinventing wheels or searching for them on the Internet, then downloading and adapting them for our project. I was doing truly creative work, inventing and directing the creation of the program, rather than plunging into the jungle of tedious coding and debugging. Speaking of debugging. This is surprising, but I didn’t need to debug the word at all. The code turned out to be so clean that after the next modification it worked flawlessly every time.
Let's move on to the second stage
In principle, everything is already more or less clear. The experiment inspires us and we are clearly on the path to success, but we want to achieve perfection, so we move on to the second stage of the experiment. We are moving from failed masochists to a club of perfectionists.
We start a new communication session with the model with a new prompt.
Below is the Windows forms code in C#, taking into account the game logic and specific functionality for playing lines. The essence of the game is as follows.
On a playing field of 10 by 10 cells, a ball of one of 5 random colors appears in a random cell. The player selects any ball in the field with the mouse and indicates a free cell where this ball needs to be moved and the ball smoothly moves into this cell. Then another ball of one of the random 5 colors appears in a random free cell again and thus the game continues. The player's task is to use 5 or more balls of the same color to form a continuous line vertically, horizontally or diagonally. In this case, all these 5 balls disappear. The game ends when all the cells are filled with balls. A new ball can only appear on an empty cell.
Below is all the working code from our project in VS.
And new instructions.
Change the code so that the selected ball changes not only its color, but also its size.
Model's answer.
Sure, I can help you modify the code to change both the color and size of the selected ball. Here's how you could do it:
First, we need to add a new variable to keep track of the initial size of the ball. We will use this value to calculate the new size during the animation. Let's add it in the `Form1` class:
Below is the code and comments.
Then, when selecting a ball, store its initial size:
Below is the code and comments.
Now let's modify the `Timer_Tick` function to also change the size of the ball:
Below is the code and comments.
This should make the selected ball expand and shrink in size while changing its color. You may need to adjust the calculation of the new size to get the exact effect you want.
It turns out that now the size of the cell of the selected ball itself changes, and not the ball itself, so we clarify the problem.
Replace changing the size of the selected ball Size with changing the size AddEllipse.
Model's answer.
Sure, I can help you with that. Instead of changing the `Size` property of the `PictureBox`, we will change the size of the ellipse used to draw the ball. This requires us to create a new `GraphicsPath` with each tick of the timer. Here's how you can modify the code:
Instead of storing the initial size of the ball, let's store the initial radius of the ellipse:
Below is the code and comments.
Then, when selecting a ball, store its initial radius:
Below is the code and comments.
Now let's modify the `Timer_Tick` function to also change the size of the ellipse:
Below is the code and comments.
This should make the selected ball expand and shrink in size while changing its color. Note that we're assuming that the width and height of the `PictureBox` are always equal to maintain a circular shape. If they can be different, you would need to store and calculate with both initial width and height instead of just the radius.
Now we have achieved the desired effect: the selected ball not only changes its brightness cyclically, but also its size, which looks as it should.
![Balls work Balls work](https://habrastorage.org/getpro/habr/upload_files/647/0ed/948/6470ed948ef7433a235b3da5949dc607.jpg)
The final and most difficult revision
And now, finally, we have reached the final, most difficult milestone, which must show the full power of the model as a good programmer, or it will break at this level of complexity. I honestly expected the model to be a failure with many errors and structural violations, but this is actually why everything was started.
So far, our selected ball simply jumps into the specified cell without any restrictions and this needs to be fixed.
We are writing the most complex prompt.
Change the code so that the selected ball moves smoothly into the specified cell, sequentially moving to one of the adjacent adjacent cells on the left, right, above or below until it reaches the specified cell. The trajectory of movement must be calculated each time so as not to intersect with any other ball in the playing field.
Model's answer.
Sure, I can help you modify the code to move the selected ball to the target cell smoothly and sequentially, moving one step at a time towards the target cell without intersecting any other balls on the field. Here's how you could do it:
Firstly, we need a way to calculate the shortest path from the current position of the selected ball to the target cell, taking into account the positions of all other balls on the field. This is a complex problem known as pathfinding, and there are many algorithms to solve it. For simplicity, let's use A* (A-Star) algorithm for this task.
We need to add a new method `FindShortestPath` to the `Form1` class that takes the starting point and the ending point of the path as parameters and returns an array of points representing the shortest path:
Below is the code and comments.
Then, when clicking on a target cell, if the clicked cell is not empty, we don't select or move any ball. Otherwise, we calculate the shortest path from the current position of the selected ball to the target cell. If the shortest path exists, we start moving the selected ball along this path, one step at a time.
Here's how you may modify the `Grid_MouseClick` method to handle this:
Below is the code and comments.
Now let's add a new method `MoveAlongPath` that takes an array of points representing the path as a parameter and moves the selected ball along this path, one step at a time:
Below is the code and comments.
This should move the selected ball along the shortest path to the target cell smoothly and sequentially, one step at a time without intersecting any other balls on the field. You may need to adjust the speed and number of steps of the movement to get the exact effect you want.
The model defined a basic FindShortestPath function without content but with comments.
// Calculate the shortest path using A* algorithm.
// This function should return a list of points representing the shortest path.
// The implementation of this function is beyond the scope of this response.
// You can find many implementations of A* algorithm online.
Therefore, let's force her to write this function.
Write a FindShortestPath function.
Model's answer.
Sure, I can help you write a function to find the shortest path between two points in the game grid using A* algorithm. Here's a simple implementation of the `FindShortestPath` function:
Below is the code and comments.
This function uses a `Node` class that represents a position in the game grid with its G cost, H cost, and parent node:
Below is the code and comments.
The function also uses a `PriorityQueue` class to store nodes in the open set with their priority based on their F cost:
Below is the code and comments.
The `GetNeighbors` function returns a list of valid neighboring positions of the given position:
Below is the code and comments.
The `Heuristic` function calculates the H cost (estimated distance to the destination) using Manhattan distance:
Below is the code and comments.
Finally, the `ReconstructPath` function reconstructs the path from the destination node to the starting node:
Next is another piece of code.
Having transferred all this mass of code into the project, we notice that the model forgot to define three functions that are called from its code, we remind it of this.
Write the Heuristic function.
Model's answer.
Sure, I can help you write a function for the heuristic calculation in the A* algorithm. The heuristic function estimates the cost to reach the destination from a given position on the game grid. A common choice for this is the Manhattan distance, which calculates the sum of the absolute differences between the x and y coordinates of two points. Here's a simple implementation of the `Heuristic` function:
Below is the code and comments.
This function takes two `Point` objects as input, representing the starting point and the ending point, and returns an integer value that represents the estimated cost to reach the destination from the starting point using Manhattan distance
Write a ReconstructPath function.
Model's answer.
Sure, I can help you write a function to reconstruct the path from the destination node to the starting node in the A* algorithm. This function backtracks from the destination node to the starting node by following the parent nodes of each node in the path. Here's a simple implementation of the `ReconstructPath` function:
Below is the code and comments.
This function takes a `Node` object as input, representing the destination node, and returns a list of `Point` objects that represent the positions of the nodes in the shortest path from the starting node to the destination node. The function starts at the destination node and adds its position to the path. Then it moves to the parent node of the current node and repeats this process until it reaches the starting node. Finally, the function reverses the path so that it goes from the starting node to the destination node.
Write a GetNeighbors function.
Model's answer.
Sure, I can help you write a function to get the valid neighboring positions of a given position on the game grid. This function checks if a neighboring position is within the bounds of the game grid and if it's not occupied by another ball. Here's a simple implementation of the `GetNeighbors` function:
Below is the code and comments.
This function takes a `Point` object as input, representing the current position, and returns a list of `Point` objects that represent the valid neighboring positions of the current position. The function loops through four possible directions (up, down, left, right) and checks if each neighboring position is within the bounds of the game grid and if it's not occupied by another ball. If a neighboring position is valid, it's added to the list of neighbors. Finally, the function returns the list of neighbors.
After all this code created by the model was simply transferred to the project without any changes and launched, the incredible happened: without a single error or any shortcomings, everything worked as it was formulated in the task.
The selected ball finds the shortest path to the goal and beautifully moves through the cells along this path.
The model did an excellent job and at the end of the second stage it turned out to be a pretty solid game.
Conclusions from all this wonderful disgrace
The model wrote a total of 672 lines of code. The total development time spent was two days with numerous breaks. This time also includes simply studying the code written by the model in order to understand what logic and methods the model uses in this project.
The conclusion is quite obvious, the new model-based programming paradigm is clearly more efficient from any point of view.
Routine work is reduced to a minimum, time is reduced, code quality improves, the programming process simply becomes more comfortable and more like intellectual creativity.
I can't help but take a humble look at the near future of programming.
So, as we now appear to be on the cusp of a new era of technology, let's embrace this future consciously and with open arms, rather than skittishly retreating into the familiar, ossified conservatism of cozy old paradigms. Leverage the LLMs available now and all the other AI tools that are sure to follow in their footsteps in the future. Let's master them to improve our creative and design skills, solve tasks and problems faster and better at a new level. After all, isn't that what new technologies are all about?
I'm not saying that AI will completely replace human programmers. The creative process, human touch, and unique set of skills that developers bring to the job are irreplaceable. Instead, I believe that AI will greatly enhance our capabilities, allowing us to focus on tasks that require human intuition and creativity in problem solving.