Writing a chess Program in one hour with chatGPT

Coding skills test

Andreas Stöckl
DataDrivenInvestor

--

Image: www.pexels.com

In a previous article, I developed a complete chess program in one day using Python.

Now, I started the experiment to shorten this time significantly by using chatGPT to generate the code. chatGPT is a chatbot based on GPT3 from OpenAI that is currently the talk of the town:

The goal of this experiment is to test the coding capabilities of chatGPT and gain experience.

Let’s look at the dialog I had with chatGPT

Question: Lets write a chess program with python together

Answer: Sure, sounds like a fun project! Before we get started, I should mention that writing a full-featured chess program is a non-trivial task and will likely require a significant amount of time and effort. However, we can certainly start by discussing some of the basic concepts and ideas that would be involved in such a project.

To start with, we would need to represent the state of the chess board in our program. This could be done using a two-dimensional array, where each element of the array represents a single square on the chess board. We would need to store the type of piece that occupies each square, as well as any other relevant information such as whether the piece has moved, whether it is threatened by any other pieces, etc.

Once we have a way to represent the state of the chess board, we would need to implement the rules of chess. This would include things like ensuring that pieces move only in the ways that they are allowed to (e.g. a bishop can only move diagonally), preventing players from making illegal moves (such as moving a piece to a square that is occupied by one of their own pieces), and handling special moves like castling and en passant.

Next, we would need to implement the game logic, which would involve keeping track of whose turn it is, checking for the end of the game (e.g. when a player is in checkmate), and handling other aspects of the game such as pawn promotion and capturing pieces.

Finally, we would need to implement some kind of user interface, such as a command-line interface or a graphical user interface, to allow players to interact with the program and make their moves.

Overall, there are many different aspects to consider when writing a chess program, and it will require a good understanding of the rules of chess and some careful planning to get it right. However, I think it would be a challenging and rewarding project to work on, and I’m looking forward to hearing more about your ideas for how to approach it!

Question: Start by generating the code of the board representation

Answer: Sure, we can start by implementing the board representation. As I mentioned earlier, one way to do this would be to use a two-dimensional array, where each element of the array represents a single square on the chess board. Here’s one possible way to do that:

# Define a constant for the size of the chess board
BOARD_SIZE = 8

# Create an empty array to represent the chess board
board = [[None for i in range(BOARD_SIZE)] for j in range(BOARD_SIZE)]

# Populate the array with the initial positions of the pieces
board[0][0] = "Rook"
board[0][1] = "Knight"
board[0][2] = "Bishop"
board[0][3] = "Queen"
board[0][4] = "King"
board[0][5] = "Bishop"
board[0][6] = "Knight"
board[0][7] = "Rook"

for i in range(BOARD_SIZE):
board[1][i] = "Pawn"
board[6][i] = "Pawn"

board[7][0] = "Rook"
board[7][1] = "Knight"
board[7][2] = "Bishop"
board[7][3] = "Queen"
board[7][4] = "King"
board[7][5] = "Bishop"
board[7][6] = "Knight"
board[7][7] = "Rook"

# Print out the resulting board
for i in range(BOARD_SIZE):
for j in range(BOARD_SIZE):
print(board[i][j], end=" ")
print()

This code creates an 8x8 array called board and populates it with the initial positions of the pieces. It then prints out the resulting board, which should look something like this:

Rook Knight Bishop Queen King Bishop Knight Rook 
Pawn Pawn Pawn Pawn Pawn Pawn Pawn Pawn
None None None None None None None None
None None None None None None None None
None None None None None None None None
None None None None None None None None
Pawn Pawn Pawn Pawn Pawn Pawn Pawn Pawn
Rook Knight Bishop Queen King Bishop Knight Rook

Of course, this is just one possible way to represent the chess board, and there are many other ways that we could do it. For example, instead of using strings to represent the types of pieces, we could use integers or other data types to represent the different types of pieces. Additionally, we could store additional information about each piece, such as its color, whether it has moved, and so on.

Once we have a way to represent the chess board, we can move on to implementing the rules of chess. This will involve writing code to handle things like moving pieces, checking for illegal moves, and handling special moves like castling and en passant.

Question: write a function that generates all possible moves of the position

Answer: Sure, we can write a function that generates all possible moves for a given position on the chess board. To do this, we will need to consider the rules of chess, which dictate how each type of piece can move. Here’s one possible way to implement this function:

def get_possible_moves(board, x, y):
# This function will return a list of all possible moves that can be made
# from the given position (x, y) on the given board.

# First, we need to check what type of piece is located at the given position
piece = board[x][y]
if piece is None:
# If there is no piece at the given position, there are no possible moves
return []

# Next, we need to handle the different types of pieces and generate the
# list of possible moves for each type
if piece == "Pawn":
# Pawns can move forward one square, unless there is another piece
# blocking their path. They can also capture pieces that are located
# on the squares diagonally in front of them.
moves = []
if board[x+1][y] is None:
moves.append((x+1, y))
if y > 0 and board[x+1][y-1] is not None:
moves.append((x+1, y-1))
if y < BOARD_SIZE-1 and board[x+1][y+1] is not None:
moves.append((x+1, y+1))

elif piece == "Rook":
# Rooks can move any number of squares horizontally or vertically,
# but they cannot move through other pieces.
moves = []
for i in range(x+1, BOARD_SIZE):
if board[i][y] is None:
moves.append((i, y))
else:
break
for i in range(x-1, -1, -1):
if board[i][y] is None:
moves.append((i, y))
else:
break
for j in range(y+1, BOARD_SIZE):
if board[x][j] is None:
moves.append((x, j))
else:
break
for j in range(y-1, -1, -1):
if board[x][j] is None:
moves.append((x, j))
else:
break

elif piece == "Knight":
# Knights can move in an "L" shape, either two squares horizontally
# and one square vertically, or two squares vertically and one
# square horizontally. They can move over other pieces.
moves = []
if x < BOARD_SIZE-2 and y > 0:
moves.append((x+2, y-1))
if x < BOARD_SIZE-2 and y < BOARD_SIZE-1:
moves.append((x+2, y+1))
if x > 1 and y > 0:
moves.append((x-2, y-1))
if x > 1 and y < BOARD_SIZE-1:
moves.append((x-2, y+1))
if x < BOARD_SIZE-1

Question: whats with the rest of the pices?

Answer: In the code that I provided earlier, I only included the rules for moving pawns, rooks, and knights. The rules for the other pieces (bishop, queen, and king) are similar, but slightly different. Here’s how the rest of the code might look:

 elif piece == "Bishop":
# Bishops can move any number of squares diagonally, but they cannot
# move through other pieces.
moves = []
for i in range(1, BOARD_SIZE):
if x+i < BOARD_SIZE and y+i < BOARD_SIZE and board[x+i][y+i] is None:
moves.append((x+i, y+i))
else:
break
for i in range(1, BOARD_SIZE):
if x-i >= 0 and y+i < BOARD_SIZE and board[x-i][y+i] is None:
moves.append((x-i, y+i))
else:
break
for i in range(1, BOARD_SIZE):
if x+i < BOARD_SIZE and y-i >= 0 and board[x+i][y-i] is None:
moves.append((x+i, y-i))
else:
break
for i in range(1, BOARD_SIZE):
if x-i >= 0 and y-i >= 0 and board[x-i][y-i] is None:
moves.append((x-i, y-i))
else:
break

elif piece == "Queen":
# Queens can move any number of squares horizontally, vertically,
# or diagonally, but they cannot move through other pieces.
moves = []
for i in range(1, BOARD_SIZE):
if x+i < BOARD_SIZE and board[x+i][y] is None:
moves.append((x+i, y))
else:
break
for i in range(1, BOARD_SIZE):
if x-i >= 0 and board[x-i][y] is None:
moves.append((x-i, y))
else:
break
for j in range(1, BOARD_SIZE):
if y+j < BOARD_SIZE and board[x][y+j] is None:
moves.append((x, y+j))
else:
break
for j in range(1, BOARD_SIZE):
if y-j >= 0 and board[x][y-j] is None:
moves.append((x, y-j))
else:
break
for i in range(1, BOARD_SIZE):
if x+i < BOARD_SIZE and y+i < BOARD_SIZE and board[x+i][y+i] is None:
moves.append((x+i, y+i))
else:
break
for i in range(1, BOARD_SIZE):
if x-i >= 0 and y+i < BOARD_SIZE and board[x-i][y+i] is None:
moves.append((x-i, y+i))
else:
break
for i in

Question: please continue

Answer: Sure! Here’s the rest of the code for the get_possible_moves() function:

range(1, BOARD_SIZE):
if x+i < BOARD_SIZE and y-i >= 0 and board[x+i][y-i] is None:
moves.append((x+i, y-i))
else:
break
for i in range(1, BOARD_SIZE):
if x-i >= 0 and y-i >= 0 and board[x-i][y-i] is None:
moves.append((x-i, y-i))
else:
break

elif piece == "King":
# Kings can move one square in any direction (horizontally, vertically,
# or diagonally), but they cannot move into check (i.e. they cannot
# move into a square that is threatened by an enemy piece).
moves = []
if x > 0:
moves.append((x-1, y))
if x < BOARD_SIZE-1:
moves.append((x+1, y))
if y > 0:
moves.append((x, y-1))
if y < BOARD_SIZE-1:
moves.append((x, y+1))
if x > 0 and y > 0:
moves.append((x-1, y-1))
if x > 0 and y < BOARD_SIZE-1:
moves.append((x-1, y+1))
if x < BOARD_SIZE-1 and y > 0:
moves.append((x+1, y-1))
if x < BOARD_SIZE-1 and y < BOARD_SIZE-1:
moves.append((x+1, y+1))

# Once we have generated the list of possible moves, we can return it
return moves

This code handles the rules for moving each type of piece, and generates a list of possible moves for the given position. For example, if we call get_possible_moves(board, 0, 1), the function will return the list of possible moves for the knight that is initially located at square (0,1) on the chess board. This should include all of the squares that the knight can move to in a single turn, such as (2,0), (2,2), (1,3), and so on.

Of course, this is just one way to implement the get_possible_moves() function, and there are many other ways that we could do it. For example, we could use different data structures to represent the chess board and the possible moves, or we could include additional information in the list of possible moves (such as whether a move is a capture, or whether a pawn can be promoted on that square). However, I hope this gives you a general idea of how we could approach this problem. Let me know if you have any other questions!

Question: can you write a function that generates the next best move?

Answer: It is possible to write a function that generates the next “best” move for a given position on the chess board, but it is important to note that this is a very difficult problem to solve, and there is no one-size-fits-all solution. In fact, even the most advanced chess programs in the world are not able to consistently find the absolute “best” move in every situation.

One possible way to approach this problem would be to use a technique called “minimax” search, which is a common method used in game-playing AI programs. The basic idea behind minimax is to consider all of the possible moves that can be made from the current position, and then for each of those moves, consider all of the possible countermoves that the opponent could make. The minimax algorithm then “minimizes” the value of the opponent’s best move, while “maximizing” the value of the original player’s move, in order to find the move that is most likely to lead to a win (or at least, to not lose).

To implement this, we would need to define a “value” function that assigns a numerical score to each position on the chess board. This function would take into account factors such as the relative strength of each player’s pieces, the mobility of each player’s pieces, and so on. The minimax algorithm would then use this value function to evaluate each possible move and countermove, and select the move that results in the highest overall score.

However, as I mentioned earlier, this is a very difficult problem to solve, and even the most advanced chess programs are not always able to find the absolute “best” move. Additionally, the performance of the minimax algorithm can be very slow, since it has to consider every possible move and countermove in order to find the best move. For these reasons, it is often necessary to use various optimization techniques, such as alpha-beta pruning and transposition tables, in order to make the minimax algorithm more efficient.

Overall, while it is possible to write a function that generates the next “best” move for a given position on the chess board, it is a complex and challenging task that will require a good understanding of game-playing AI techniques and a lot of careful planning and implementation. I hope this gives you a general idea of how it might be possible to approach this problem, but let me know if you have any other questions!

Question: can you generate the python code?

Answer: Sure, here is an example of how the minimax algorithm might be implemented in Python. Keep in mind that this is just one possible way to implement the algorithm, and there are many other ways that we could do it. Additionally, this code does not include all of the optimizations that are typically used in real-world chess programs, so it will not be very efficient for large chess positions.

def minimax(board, depth, maximizingPlayer):
# This function will use the minimax algorithm to find the best move for
# the current player. The "board" parameter is the current state of the
# chess board, the "depth" parameter is the depth of the search tree (i.e.
# how many moves to look ahead), and the "maximizingPlayer" parameter
# indicates whether the current player is the maximizing player (True) or
# the minimizing player (False).

# If the search tree has reached the maximum depth, we can evaluate the
# current position using the value function and return that value.
if depth == 0:
return evaluate(board)

# Generate a list of all possible moves that can be made from the current
# position.
moves = get_possible_moves(board)

# If there are no possible moves, the game is over and we can evaluate
# the final position using the value function.
if len(moves) == 0:
return evaluate(board)

# If the current player is the maximizing player, we want to find the
# move that leads to the highest score, so we initialize the bestValue
# variable to a very low value.
if maximizingPlayer:
bestValue = -float("inf")

# Loop through all of the possible moves and compute the score for
# each one.
for move in moves:
# Make the move on a copy of the board.
newBoard = make_move(board, move)

# Recursively call the minimax function to find the best move
# for the opponent.
value = minimax(newBoard, depth-1, False)

# Update the bestValue variable if the current move leads to a
# higher score than the previous best move.
bestValue = max(bestValue, value)

# Once we have considered all of the possible moves, we can return
# the best score.
return bestValue

# If the current player is the minimizing player, we want to find the
# move that leads to the lowest score, so we initialize the bestValue
# variable to a very high value.
else:
bestValue = float("inf")

# Loop through all of the possible moves and compute the score for
# each one.
for move in moves:
# Make the move on a copy of the board.
newBoard = make_move(board, move)

# Recursively call the minimax function to find the best move
# for the opponent.
value = minimax(newBoard, depth-1, True)

# Update the bestValue variable if the current move leads to a
# lower score than the previous best move.
bestValue = min(bestValue

Question: please continue

Answer: Sure, here is the rest of the minimax() function:

value)

# Once we have considered all of the possible moves, we can return
# the best score.
return bestValue

# If the current player is the minimizing player, we want to find the
# move that leads to the lowest score, so we initialize the bestValue
# variable to a very high value.
else:
bestValue = float("inf")

# Loop through all of the possible moves and compute the score for
# each one.
for move in moves:
# Make the move on a copy of the board.
newBoard = make_move(board, move)

# Recursively call the minimax function to find the best move
# for the opponent.
value = minimax(newBoard, depth-1, True)

# Update the bestValue variable if the current move leads to a
# lower score than the previous best move.
bestValue = min(bestValue, value)

# Once we have considered all of the possible moves, we can return
# the best score.
return bestValue

This code uses the minimax algorithm to search through the space of possible moves and countermoves in order to find the move that is most likely to lead to a win (or at least, to not lose). The evaluate() function is used to assign a numerical score to each position on the board, and the get_possible_moves() and make_move() functions are used to generate and apply the possible moves.

Again, keep in mind that this is just one possible way to implement the minimax algorithm, and there are many other ways that we could do it. Additionally, this code does not include all of the optimizations that are typically used in real-world chess programs, so it will not be very efficient for large chess positions. I hope this gives you a general idea of how the minimax algorithm works, and how it might be implemented in Python, but let me know if you have any other questions!

Question: can you generate an evaluation function for me?

Answer: Sure, here is an example of how we might implement an evaluation function for a chess program in Python:

def evaluate(board):
# This function will evaluate the current position on the chess board and
# return a numerical score. The higher the score, the better the position
# is for the player who is currently moving.

# First, we will compute the material advantage for each player. This
# will give us a basic measure of the relative strength of each player's
# pieces.
whiteMaterial = 0
blackMaterial = 0
for i in range(BOARD_SIZE):
for j in range(BOARD_SIZE):
piece = board[i][j]
if piece is not None:
if piece.isupper():
whiteMaterial += PIECE_VALUES[piece]
else:
blackMaterial += PIECE_VALUES[piece]

# Next, we will compute the mobility for each player. This will give us
# a measure of how many squares each player's pieces can move to.
whiteMobility = 0
blackMobility = 0
for i in range(BOARD_SIZE):
for j in range(BOARD_SIZE):
piece = board[i][j]
if piece is not None:
if piece.isupper():
whiteMobility += len(get_possible_moves(board, i, j))
else:
blackMobility += len(get_possible_moves(board, i, j))

# Finally, we will combine the material advantage and mobility scores
# to compute the overall score for the position.
score = whiteMaterial + whiteMobility - blackMaterial - blackMobility

# Return the score for the position.
return score

This code uses two factors to evaluate the current position on the chess board: the material advantage of each player (i.e. the relative strength of their pieces), and the mobility of each player’s pieces (i.e. how many squares they can move to). These two factors are combined to compute an overall score for the position, which is returned by the evaluate() function.

Of course, this is just one possible way to implement an evaluation function for a chess program, and there are many other factors that we could include in the evaluation (such as pawn structure, king safety, and so on). Additionally, the exact values that we assign to each factor (such as the values for each type of chess piece) can have a big impact on the performance of the chess program, so it is important to carefully consider these values and adjust them as needed. I hope this gives you a general idea of how an evaluation function might work, but let me know if you have any other questions!

Question: finally i need a make move function

Answer: Sure, here is an example of how we might implement a make_move() function for a chess program in Python:

def make_move(board, move):
# This function will take a chess board and a move, and return a new
# chess board that reflects the move that has been made.

# First, we will make a copy of the original board, so that we can
# modify the copy without affecting the original.
newBoard = copy.deepcopy(board)

# Next, we will extract the source and destination coordinates for the
# move that is being made.
(x1, y1) = move[0]
(x2, y2) = move[1]

# We will then move the piece from the source square to the destination
# square on the new board.
newBoard[x2][y2] = newBoard[x1][y1]
newBoard[x1][y1] = None

# Finally, we will return the new board.
return newBoard

This code uses the copy.deepcopy() function to make a deep copy of the original chess board, so that we can modify the copy without affecting the original. Then, it uses the source and destination coordinates of the move that is being made to update the board, moving the piece from the source square to the destination square.

Summary and Evaluation:

I find the results impressive. The not simple task was not only solved with code outputs but also explained with appropriate and correct texts. Limitations and possible extensions were also pointed out.

What did not work:
- PIECE_VALUES Dict had to be added
- import copy had to be added.
- The generated function to create all moves did not fit the minimax function because the minimax function expected all moves of a position, but the created function only generates all moves of a figure of the position.

However, all these shortcomings could also be because I did not ask precise enough questions in the dialog. I think to use this tool effectively, we all still need to practice using it to its full potential.

Subscribe to DDIntel Here.

Visit our website here: https://www.datadriveninvestor.com

Join our network here: https://datadriveninvestor.com/collaborate

--

--

University of Applied Sciences Upper Austria / School of Informatics, Communications and Media http://www.stoeckl.ai/profil/