Как написать шахматы на python

от admin

Как написать шахматы на python

The chess module is a pure Python chess library with move generation, move validation and support for common formats. We can play chess with it. It will help us to move the king queen, pawn, bishops and knights. We need to know the basics of chess to play chess with it. This module does every task in python that is possible in the real game.

Installation:

We just have to import the chess library and with it, we can play chess. When we will import the chess library we have to call the function named board so that we can see the status of the chess board.

Как написать шахматы на python

Коркунова Наталья Ивановна

  1. Реализовать классы фигур, механики передвижения.
  2. Создать поле для игры, механику атаки
  3. Реализовать таймер, обработку событий мыши.
  4. С помощью PyQt создаем графический интерфейс

if not self .is_path_clear(board , row , col , row1 , col1):
return False

def can_attack ( self , board , row , col , row1 , col1):
direction = 1 if ( self .color == WHITE) else — 1
return (row + direction == row1
and (col + 1 == col1 or col — 1 == col1))

class Knight(Piece):
ch = ‘N’

class Bishop(Piece):
ch = ‘B’

def can_move ( self , board , row , col , row1 , col1):

if not self .is_path_clear(board , row , col , row1 , col1):
return False

class Queen(Piece):
ch = ‘Q’

def can_move ( self , board , row , col , row1 , col1):

if not self .is_path_clear(board , row , col , row1 , col1):
return False

def can_move ( self , board , row , col , row1 , col1):

if not self .is_path_clear(board , row , col , row1 , col1):
return False

self .field = [[ None ] * 8 for _ in range ( 8 )]
self .field[ 0 ] = [
Rook(WHITE) , Knight(WHITE) , Bishop(WHITE) , Queen(WHITE) ,
King(WHITE) , Bishop(WHITE) , Knight(WHITE) , Rook(WHITE)
]
self .field[ 1 ] = [
Pawn(WHITE) , Pawn(WHITE) , Pawn(WHITE) , Pawn(WHITE) ,
Pawn(WHITE) , Pawn(WHITE) , Pawn(WHITE) , Pawn(WHITE)
]
self .field[ 6 ] = [
Pawn(BLACK) , Pawn(BLACK) , Pawn(BLACK) , Pawn(BLACK) ,
Pawn(BLACK) , Pawn(BLACK) , Pawn(BLACK) , Pawn(BLACK)
]
self .field[ 7 ] = [
Rook(BLACK) , Knight(BLACK) , Bishop(BLACK) , Queen(BLACK) ,
King(BLACK) , Bishop(BLACK) , Knight(BLACK) , Rook(BLACK)
]

if isinstance (piece , King) and self .is_under_attack(row1 , col1 , opponent( self .current_player_color())):
return False

if not (piece.can_move( self .field , row , col , row1 , col1) and target is None ) and \
not (piece.can_attack( self .field , row , col , row1 , col1) and
(target is not None and not isinstance (target , King)
and target.get_color() == opponent( self .current_player_color()))):
return False

def is_under_attack ( self , row , col , color):
for row1 in range ( 8 ):
for col1 in range ( 8 ):
if self .field[row1][col1] is not None :
if self .field[row1][col1].get_color() == color and \
self .field[row1][col1].can_attack( self .field , row1 , col1 , row , col):
return True
return False

Machine Learning and Chess

In late 2020, Netflix released the Queen’s Gambit, a TV show taking place in the 1950’s where we follow the journey of a young women thriving to become the best chess player.

However, unlike the protagonist Beth Harmon, chess isn’t really my strongest suit. So I did the next best thing by building my own python chess engine to compensate my poor chess skills.

Episode I: Strategies

When it comes to building any board game engine, there are multiple strategies:

  • Reinforcement Learning
  • Minimax
  • ML model trained on human knowledge

I opted for an hybrid of the second and third strategies: As a Data scientist, I am fond of working with large datasets and machine learning models. Also, despite being a little slower, Minimax is a quite reliable algorithm and does a good job at capturing enemy pieces. Reinforcement learning is simply too complex.

My strategy is simple:

  • First of all, using the machine learning model, the engine will dismiss 50% of the possible moves given a board. It does so by finding the probability of a move being a ‘good move’. All the moves are sorted according to this probability and only the 50th percentile remains.
  • Secondly, the engine will perform the Minimax algorithm on the remaining moves. Depending on the complexity of the board, the search tree will go to a certain depth.

Episode II: Data

In order to make accurate predictions, we need a lot of data. For this project, I will be using a dataset that I found on Kaggle. This dataset is a collection of thousands of games played by chess grand masters in the .pgn format (portable game notation).

The next step is to extract all the moves from all the games and label them as good or bad.

In my opinion, a ‘good move’ is a move that the winner played at some point during the game. A ‘bad move’ is a legal move that the winner chose not to play.

This python script got the job done leaving me with a brand new .csv dataset.

  1. 1. Перемещение;
  2. 2. Оценка доски; ; . На каждом этапе работы с алгоритмом будет использоваться одна из них, это позволит постепенно совершенствовать игровые способности ИИ.

I’m having trouble beating a chess program I wrote.

Not sure if I’m a bad player or the algorithm is decent.

— Lauri Hartikka (@lhartikk) March 28, 2017


При клике на картинке она откроется в полном разрешении.


Здесь лучшим ходом для белых является b2-c3, поскольку он гарантирует, что игрок доберется до позиции с оценкой -50.


Изображение демонстрирует ходы, которые становятся ненужными в процессе использования альфа-бета-отсечения.


Количество позиций, которые требуется оценить в случае поиска с глубиной 4 и начальной позицией, которая изображена выше. (исходники и игра доступны здесь)

Making Chess in Python

I will first describe what’s happening and then show the code afterward.

This is a large project that me and a friend in school conducted. This is pretty funny because we had plans on doing this over several months and 7 days later we have the entire thing completed. I must say, this would not have been possible if it weren’t for the help of my friend Edwin. Firstly we abstracted the entire game since this is a very complex game to code and we decided that I would be responsible for the interface(what the user can see) while Edwin was responsible for the actual behaviour of each piece. They both have their own forms of difficulties to make and we did have to co-ordinate a lot so it wasn’t like we didn’t help each other make each other’s parts eg. i did teach him a bit of list comprehension to speed up his code while he exposed my pretty stupid mistake of doing column row instead of row column.

This code is everything that I wrote alongside some of the dictionary and methods above it. First we create the window object which is the window that comes up when we run the chess game on. We set the dimensions to 800×800 which is the tuple argument which we passed into it. We specifically chose 800 x 800 because the images for the chess pieces that we hard were all 100×100 which meant it would fit perfectly if the board was 800×800.

The main thing that makes my program work are these node objects and they are just the containers which hold the chess pieces(they are simulated as the tiles of the chess board in this case. They have their attributes which are their row, column,x,y co-ordinates. We need these separately because all these nodes are going to be stored in a 8×8 2d list so if we call it we would need to call it using its row and col numbers while if we were drawing it onto the screen we need its x,y pixel values(we could just do row*100 but that would risk us forgetting to add that 1 time in the entire code and watching the entire thing break).

The draw function is used to used to draw the tile onto the screen(so the black and white pattern) while the setup method is used to draw any images onto the screen if we had a piece on the screen at that position. You draw onto the screen using blit.

Draw grid draws the boundaries to the grid(so the black horizontal and vertical lines that separate the tiles) and draw grid and make grid is creating the 2d list which are going to use to access all the nodes later. Update display is used to update the screen every-time the tick. I think to avoid the CPU being overloaded, we chose to run the program at 20fps which is ofc completely unreasonable for chess but we didn’t want too much delay.

When the user clicks on the screen, we need to figure out what tile they have clicked on which is what find_node does. Display_potential_moves is a function edwin made but it just takes a list of potential moves and for those moves, changes the colour of the tile so that it stands out.

Do_move is used to acc make the swap on the screen but swapping the values on my dictionary, when the screen updates, this change will be visible on the screen.

remove_highlight is used because it is hard to remove the highlights for specific tiles so we decided to just to redraw the black colours for all the tiles instead.

The main function then contains a lot fo standard logic which I would hope you would have a grasp on if you know pygame. I will attach a video here too just incase you don’t

If I were to explain the entirety of the code, this would take hours on hours to write so I am going to explain the functions and any complex concepts which may be in them and leave you to solve out the rest.

Code Explanation:

We used pygame to write this program since it can easily give us the interface and I have experience from my A* algorithm on how to make a grid so most of the grid is just recycled code from that.

Except from the starting order dict, all of this was edwins code and all of it used for the move calculations. Theoretically you could have done this with only one of either a dictionary or a 2d list like he has done but since we both needed access to an array for our parts while we were coding and we couldn’t share a python script, we made our own versions. Edwin makes a class for the pieces since it is easier to manage and at the bottom he is setting up his 2d list so all the pieces are in their starting positions. In my dictionary, I hard wrote all the positions automatically since I needed to put the name of each of the individual image files into the load. pygame.image.load() is going to load an image onto the python file and then we only need to draw the image onto the screen. It is better this way than loading the image and then drawing because it means we only need to load the image once for the entire program and then just translate this image onto new positions on the screen.

Читать:
Как написать программу на c

The rest of edwins code is pretty self-explanatory and is just choosing the correct positions that each piece can move to and then putting those ‘legal’ tiles on the chessboard for us to use on the interface as a way of highlighting the board.

Level Up Coding

Thanks for being a part of our community! Level Up is transforming tech recruiting. Find your perfect job at the best companies.

Creating a Chessboard with Pygame Part 1

I mentioned recently that I was learning Python. I’m working with a few friends on learning the basics. My background is mostly Objective-C and in recent years, Swift. I also programmed in PHP last year for several months working with Laravel, Lumen, Lighthouse, and GraphQL.

To learn Python we decided to begin looking at making a chess game using Pygame. This post shows my attempt to get the chessboard on the screen. I opted to store the coordinates of each square in a class along with their size and if they are black or white. I don’t yet know if this is an efficient way, but for now, it’s helping me learn the Python syntax and work with a few nested loops and a multidimensional list.

One thing to note before I move on to showing my work, I spent just a day on this and my aim wasn’t to separate classes into their own files or work too much on the structure of the program. I just wanted to get it done quickly to see if I could draw the chessboard and if all went well, then begin looking at the structure of the program.

To get more familiar with Pygame I searched and found this tutorial by Jon Fincher at realpython.com. This is a great tutorial and I recommend it if you want a good introduction to Pygame.

Getting going with Pygame

In main.py I used the following code. It first imports pygame. If you haven’t installed this module, then you need to do that first. Please post a comment below if you are stuck on this part.

Next, I import MOUSEBUTTONUP, K_ESCAPE, KEYDOWN, and QUIT from pygame.locals. These four inputs allow me to detect when a mouse button has been clicked when escape has been tapped when any key has been tapped, or if the program has been called. We’ll use these later on in the program.

Next, we initialise pygame. We then set some constants for the screen width and height. For now, I set these at 700 pixels each.

pygame.display.set_mode returns a surface that we can work with. We pass in the width and height as a tuple and this determines the size of our display.

The Board Squares

For this initial version, I thought I would create a custom object that represents each square. For that, I decided it needed x and y coordinates which are for the top left of each square. It would then have a width and height, although I combined this into a single property called width_height because all squares on the board are square; no surprise there, and then another property to show if the square is white or not. I was going to feed in black or white but decided a boolean would suffice.

The BoardSquare class at the moment just has a default initialiser that accepts x_start, y_start, width_height, and is_white.

The next step was to create a 2D list and fill it with each chessboard square. I created the following to handle this:

I first create an empty list called chess_board. At this point it is not multi-dimensional.

I then set is_white to false.

I then created a for loop with a range of 8. I called this y because it will be working through one row at a time starting at row 0, working through to row 7.

In this first, or outer, loop, I initialise an empty list and call it chess_row. This list is the second dimension and will hold a row of eight squares.

Because a chessboard starts with a white square at the top left, I set is_white to not is_white, effectively toggling that boolean back to white.

I then create a nested loop with x as the number. This is the x coordinate and also counts to 8, working left to right.

I create a BoardSquare object and append it. I’ll explain this in more details in a few moments. I then toggle white to black so that on the next iteration of the nested loop, it creates a black square, and then it toggles back to white.

When the nested loop has run eight times, I then append the chess_row to the chess_board array so that item 1 in chess_board, meaning the top row, contains 8 squares.

When this is appended it loops back around the outer loop and white is toggled back to black for the first square of row 2. On the first run of this, I just saw black and white bands across the screen. The reason for this was that I didn’t notice that when the last square on a row is black, the first square on the next row is also black. I added in this extra toggle so that it switches back to the same colour when the row finishes and the new one starts.

calculate_coordinates

This function is used to calculate the x and y coordinates of each square.

This function is used to calculate the x and y coordinates of each square. Because the constants for SCREEN_WIDTH and SCREEN_HEIGHT can be changed in code before it runs, I decided to make the board flexible as well. If you decide you want a smaller board, the squares will be sized correctly on launching the game.

This function accepts the x and y values from the loops (ie, on the first iteration it would be 0, 0). It also accepts the boolean of the square being white or black.

The first if/else statement checks if the board is taller or wider or square. If taller, we use the shorter edge. If it’s wider, we use the shorter edge. This means that the board will always fit into the game. I store this in width_height which is the width/height of each square.

The next challenge is to calculate the top left corner of each square. To do this I get the x_array value and multiply it by width_height. If we are 4 squares along, the x passed in will be a 3 which will multiple by perhaps 80 making it 240 pixels. The same principle is used for y.

I then return an instantiated BoardSquare with the correct parameters passed into it.

Putting the Chessboard on Screen

Now that I have a multidimensional list of all of the chess squares I next put them on screen.

I loop around chess_board and call the value “row”. This means I am beginning on the top row.

I then create a nested loop that works across the row. I call the value “square” as it represents a square on the board.

I create a surface with the squares width_height variable. Because we know that chess squares are square, I just access the same square.width_height for both the width and length.

if square.is_white is true, I set the fill for the box to be white. If not, it gets set to black.

The last three lines of code are Pygame’s way of drawing the surface.

When running the program now, a chessboard will appear.

Main Loop

Now that the board is displayed I have added the main loop, although at the moment it just checks for escape, quit, and mouse clicks.

The code above is partly from what I found at realpython.com, but also with MOUSEBUTTONUP added which I call a function and pass in the position of the mouse click. I haven’t finished this yet, but right now the position is passed into get_square_for_position and this function passes back the square object from the multidimensional list.

The other function, highlight_selected_square will be used to test if the correct square has been selected. My plan with that is to put a border around each square as it is clicked on.

get_square_for_position has the following code:

The position is passed in which is an x, y coordinate of the mouse click. I learned tonight that this can be accessed with x, y = get_pos(), but in this example, I access pos[0] for x and pos[1] for y.

This looks through the first row of the chess_board list and checks if the y coordinates are within the first row. If true we know that the selected square is on a certain row.

When that is true, I loop through each square in the row and check if the x coordinates are within a certain square, and if true, I return the square.

This doesn’t feel too efficient looping through until the correct square is found. In big-o notation, this wouldn’t be the quickest way when iterating through every item until found, but for now, it will do.

Closing Comments

I am mostly happy with how this turned out. I need to break out the logic a bit more and create a separate file for the BoardSquare class. I don’t know for sure if I will continue down this path of programmatically drawing a chessboard. I may end up just using an image and then calculating which square is clicked a different way, but for now, it works.

The initial purpose of doing this was to become familiar with Python, which I haven’t used much at all. Now that I have some familiarity with it I will be drawing out the structure of the program first to decide what logic should be handled where. Right now, there is no MVC pattern with my example code. I assume people work with MVC when using Python, but that is something I need to read up on to see if it’s best practice for the language.

Related Posts