This article is contributed. See the original author and article here.
We’ve heard a lot about GitHub Copilot, but maybe more specifically about LLMs, large language models and how they can be used to generate code. You might even have used ChatGPT.
GitHub Copilot chat, is a product built by GitHub, it relies on a specific type of LLm a so called codex model and integrates with your IDE. It’s a bit like a pair programmer, but one that has seen a lot of code and can help you write it.
So what will we do today? We’ll use GitHub Copilot chat to solve a problem. The problem we have is Rock Paper Scissors. It’s a small game that most people knows the rules to. It’s also an interesting problem as it’s small and contained, but still has some complexity to it.
Where do we start? The interesting part here is that there are many ways to start which I discovered speaking to my colleague Cynthia. What we’re doing today is based on the excellent challenge module by Cynthia.
> https://learn.microsoft.com/en-us/training/modules/challenge-project-create-mini-game-with-copilot/
References
Approaches
So what approach do we choose?
– Domain description. In this version, we write a domain descriptions with all rules and concepts in it and feed that to our AI pair programmer.
– One comment at a time. Here, we write a comment and gradually work our towards a solution. In this approach we tackle one concept and rule at a time.
For the sake of this article, we’ll use the domain description approach.
Solving the problem: use domain description
Luckily for us, the training module already have a domain description, here it is:
Game rules:
Rock beats scissors (breaking it).
Scissors beat paper (cutting it).
Paper beat rock (wrapping it).
The minigame is multiplayer and the computer plays the role of your opponent and chooses a random element from the list of elements
Interaction with the player:
The console is used to interact with the player.
The player can choose one of the three options: rock, paper, or scissors.
The player can choose whether to play again.
The player should be warned if they enter an invalid option.
The player is shown their score at the end of the game.
Validation of user input:
At each round, the player must enter one of the options in the list and be informed if they won, lost, or tied with the opponent.
The minigame must handle user inputs, putting them in lowercase and informing the user if the option is invalid.
By the end of each round, the player must answer whether they want to play again or not.
> You can find this description in the
> training module, https://learn.microsoft.com/en-us/training/modules/challenge-project-create-mini-game-with-copilot/4-exercise-create-the-game-logic
Ok, now what? Now we do the following:
1. Create a new file called rockpaperscissor.py and paste the domain description at the top like so:
# rockpaperscissor.py
# Game rules:
# Rock beats scissors (breaking it).
# Scissors beat paper (cutting it).
# Paper beat rock (wrapping it).
# The minigame is multiplayer and the computer plays the role of your opponent and chooses a random element from the list of elements
# Interaction with the player:
# The console is used to interact with the player.
# The player can choose one of the three options: rock, paper, or scissors.
# The player can choose whether to play again.
# The player should be warned if they enter an invalid option.
# The player is shown their score at the end of the game.
# Validation of user input:
# At each round, the player must enter one of the options in the list and be informed if they won, lost, or tied with the opponent.
# The minigame must handle user inputs, putting them in lowercase and informing the user if the option is invalid.
# By the end of each round, the player must answer whether they want to play again or not.
# game loop where the player and computer selects rock, paper, or scissors, round is repeated until player quits by typing "quit"
Now we’ve provided context to Copilot in two ways, both by providing a domain description and by providing a file name *rockpaperscissor.py*. In the next step, let’s see what Copilot can do for us.
1. Type the following code:
quit = False
while
Here’s where I stopped typing code because Copilot suggested the following:
not quit:
and for every Enter I pressed, Copilot suggested code. So after having typed Enter a number of times and accepting all completions I arrived at this code:
quit = False
while not quit:
# player input
player = input("rock, paper, or scissors? ")
# computer input
import random
computer = random.choice(["rock", "paper", "scissors"])
# game logic
if player == computer:
print("tie")
elif player == "rock":
if computer == "paper":
print("computer wins")
else:
print("player wins")
elif player == "paper":
if computer == "scissors":
print("computer wins")
else:
print("player wins")
elif player == "scissors":
if computer == "rock":
print("computer wins")
else:
print("player wins")
else:
print("invalid input")
# ask player if they want to play again
play_again = input("play again? (y/n) ")
if play_again == "n":
quit = True
elif play_again == "y":
quit = False
else:
print("invalid input")
quit = True
Improve the code, step 1
This code works, but it’s not the greatest code to look at. It doesn’t keep track of scores and it’s not very readable. So let’s see if we can improve it.
Open the the Chat component by selecting it at the bottom left of your left side menu (looks like a chat window). In it, type the prompt “improve code”. It should generate a response like so:
One improvement you could make is to add a score counter for the player and computer, so that the player can see their score at the end of the game. Here's an updated version of the code with a score counter:
followed by the code:
# Game rules:
# Rock beats scissors (breaking it).
# Scissors beat paper (cutting it).
# Paper beat rock (wrapping it).
# The minigame is multiplayer and the computer plays the role of your opponent and chooses a random element from the list of elements
# Interaction with the player:
# The console is used to interact with the player.
# The player can choose one of the three options: rock, paper, or scissors.
# The player can choose whether to play again.
# The player should be warned if they enter an invalid option.
# The player is shown their score at the end of the game.
# Validation of user input:
# At each round, the player must enter one of the options in the list and be informed if they won, lost, or tied with the opponent.
# The minigame must handle user inputs, putting them in lowercase and informing the user if the option is invalid.
# By the end of each round, the player must answer whether they want to play again or not.
# initialize score counters
player_score = 0
computer_score = 0
# game loop where the player and computer selects rock, paper, or scissors, round is repeated until player quits by typing "quit"
quit = False
while not quit:
# player input
player = input("rock, paper, or scissors? ")
# computer input
import random
computer = random.choice(["rock", "paper", "scissors"])
# game logic
if player == computer:
print("tie")
elif player == "rock":
if computer == "paper":
print("computer wins")
computer_score += 1
else:
print("player wins")
player_score += 1
elif player == "paper":
if computer == "scissors":
print("computer wins")
computer_score += 1
else:
print("player wins")
player_score += 1
elif player == "scissors":
if computer == "rock":
print("computer wins")
computer_score += 1
else:
print("player wins")
player_score += 1
else:
print("invalid input")
# ask player if they want to play again
play_again = input("play again? (y/n) ")
if play_again == "n":
quit = True
elif play_again == "y":
quit = False
else:
print("invalid input")
quit = True
# print final scores
print("player score:", player_score)
print("computer score:", computer_score)
In the above code, we’ve added a score counter for the player and computer, so that the player can see their score at the end of the game. We’ve also added a print statement to print the final scores.
Improve the code, step 2, use your know-how as a developer
What else can we do? At this point, we can start to refactor the code. An improvement we can do is to add a so called rule matrix. A rule matrix is a matrix that contains all the rules of the game. It’s a bit like a lookup table. Let’s provide that as a prompt to Copilot.
Here’s what we’re typing in Copilot chat:
improve code by adding a rule matrix to compare player and computer choices
which results in the following output from Copilot:
# Game rules:
# Rock beats scissors (breaking it).
# Scissors beat paper (cutting it).
# Paper beat rock (wrapping it).
# The minigame is multiplayer and the computer plays the role of your opponent and chooses a random element from the list of elements
# Interaction with the player:
# The console is used to interact with the player.
# The player can choose one of the three options: rock, paper, or scissors.
# The player can choose whether to play again.
# The player should be warned if they enter an invalid option.
# The player is shown their score at the end of the game.
# Validation of user input:
# At each round, the player must enter one of the options in the list and be informed if they won, lost, or tied with the opponent.
# The minigame must handle user inputs, putting them in lowercase and informing the user if the option is invalid.
# By the end of each round, the player must answer whether they want to play again or not.
# initialize score counters
player_score = 0
computer_score = 0
# rule matrix
rules = {
"rock": {"rock": "tie", "paper": "lose", "scissors": "win"},
"paper": {"rock": "win", "paper": "tie", "scissors": "lose"},
"scissors": {"rock": "lose", "paper": "win", "scissors": "tie"}
}
# game loop where the player and computer selects rock, paper, or scissors, round is repeated until player quits by typing "quit"
quit = False
while not quit:
# player input
player = input("rock, paper, or scissors? ")
# computer input
import random
computer = random.choice(["rock", "paper", "scissors"])
# game logic
if player not in rules:
print("invalid input")
else:
result = rules[player][computer]
if result == "win":
print("player wins")
player_score += 1
elif result == "lose":
print("computer wins")
computer_score += 1
else:
print("tie")
# ask player if they want to play again
play_again = input("play again? (y/n) ")
if play_again == "n":
quit = True
elif play_again == "y":
quit = False
else:
print("invalid input")
quit = True
# print final scores
print("player score:", player_score)
print("computer score:", computer_score)
Now, you see how the code looks a lot better, no more nested if statements. We’ve also added a rule matrix (technically it added a dictionary not a matrix, but it’s still a big improvement over the code that was there before) to compare player and computer choices. Of course, we can still improve the code. For example, we can add a function to print the final scores. We should also add tests and documentation before we call it a day.
Conclusion
Sometimes using an AI assistant may look like magic, we could give it a full domain description. That could be a valid approach if the problem is small enough. Even then you need to improve the code in stages.
Another learning is that the more knowledge you have of code in general and the problem domain, the better you can guide the AI assistant to arrive at the solution you want.
Compare the difference between the first and last attempt, the last attempt is much better, don’t you think?
AI assistants aren’t here to replace us YET, but to help us solve problems, we still need to guide, we still need to know what we’re doing. But they can help us solve problems faster and better.
Brought to you by Dr. Ware, Microsoft Office 365 Silver Partner, Charleston SC.
Recent Comments