Making classic games with pygame: Gobang

Get ready

Basic python preparation:

  1. Fundamentals of pygame, refer to Eye Blog's "Write games with Python and Pygame - from getting started to mastering"
  2. Install python 3.8.0 to download on python's official website, not to mention more.
  3. Install pygame, command: pip install pygame
  4. If the installation is slow, you can change the pip source to a domestic mirror site by referring to the following commands:
  5. pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
  6. The discussion group 887934385 is available within the group for problem solving and related materials needed

plan

Prepare to complete the Gobang Single Machine Human-Machine game, has completed the interface and determine the win or lose functions, has not joined the computer AI, in the future there is time to add (I do not know if it will pit). At present, the main functions are as follows:

  1. Drawing the interface of Gobang, left mouse button click on the drop (black first, black and white alternating order).
  2. Decide whether a black or white Schisandra is lianju.
  3. When one side wins, a prompt pops up to end the game.

The game interface looks like this:

start

Design Ideas

The core of the game is to divide the board into two levels. The first level is the physical level, which represents the position of the physical pixels, mainly used for drawing and other operations. The other level is to abstract the board into a matrix of 15*15, where the black and white children fall. The specific position is represented by coordinates (i, j) (0<=i, j<15).Mainly used to judge wins, losses, etc.

  1. Checkerboard drawing, the network has chessboard and black and white picture resources can be downloaded and used, I downloaded the chessboard picture grid line pixel location is not accurate, so I made a 544544 wooden background map with ps, and then use the program to draw the chessboard line (if PS is more familiar with points, it is recommended to draw the chessboard grid lines on the chessboard background map), around the chessboard grid lineEmpty 20 pixels, checkerboard grid size 36 pixels, downloaded online checkerboard size 3232 pixels.
  2. The judgment of win or lose, since no five children are connected when no one wins or loses, it is only necessary to judge if there are five children connected in the four directions of horizontal, vertical, diagonal and backslant of the last drop position.

Main Code

  1. Main function, pygame's main control flow, abbreviated code as follows:
I don't know what to add to my learning
python Learn to buckle qun,784758214
//There are good learning video tutorials, development tools and e-books in the group.
//Share with you the current talent needs of the python enterprise and how to learn Python from a zero-based perspective, and what to learn

def main():
    pygame.init()   #pygame initialization
    size = width,height = 544,544
    screen = pygame.display.set_mode(size, 0, 32)
    pygame.display.set_caption('Gobang')
    font = pygame.font.Font('simhei.ttf', 48)
    clock = pygame.time.Clock()    #set clock
    game_over = False
    renju = Renju()    # Renju is the core class, realizing lost and won judgment, etc.
    renju.init()   # Initialization

    while True:
        clock.tick(20)    # Set frame rate
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN and (not game_over):
                if event.button == 1:    # Left mouse button is pressed
                    i,j = renju.get_coord(event.pos)    # Converting physical coordinates to logical coordinates of a matrix
                    if renju.check_at(i, j):    # Check if (i,j) location is occupied, return True if not occupied
                        renju.drop_at(i, j)        # In (i,j) position, the function draws black or white on the board
                        if renju.check_over():    # Check if there are five sublines and return True if there are
                            text = ''
                            if renju.black_turn:    #check_at will switch the order of the fallers, so it is black's turn, which means that the last faller is white, so white's smooth
                                text = 'White wins, the game is over!'
                            else:
                                text = 'Black wins, the game is over!'
                            gameover_text = font.render(text, True, (255,0,0))
                            renju.chessboard().blit(gameover_text, (round(width/2-gameover_text.get_width()/2), round(height/2-gameover_text.get_height()/2)))
                            game_over = True
                    else:
                        print('This position is occupied and cannot fall here')
        
        screen.blit(renju.chessboard(),(0,0))
        pygame.display.update()
    pygame.quit()

  1. renju class, core class, fallen child and judge win or lose operation, code as follows:
I don't know what to add to my learning
python Learn to buckle qun,784758214
//There are good learning video tutorials, development tools and e-books in the group.
//Share with you the current talent needs of the python enterprise and how to learn Python from a zero-based perspective, and what to learn
Position = namedtuple('Position', ['x', 'y'])

class Renju(object):
    
    background_filename = 'chessboard.png'
    white_chessball_filename = 'white_chessball.png'
    black_chessball_filename = 'black_chessball.png'
    top, left, space, lines = (20, 20, 36, 15)    # Checkerboard grid position related???
    color  = (0, 0, 0)    # Checkerboard grid line color
    
    black_turn = True    # Black First Hand
    ball_coord  = []    # Record Black and White Logical Locations
    
    def init(self):
        try:
            self._chessboard = pygame.image.load(self.background_filename)
            self._white_chessball = pygame.image.load(self.white_chessball_filename).convert_alpha()
            self._black_chessball = pygame.image.load(self.black_chessball_filename).convert_alpha()
            self.font = pygame.font.SysFont('arial', 16)
            self.ball_rect = self._white_chessball.get_rect()
            self.points = [[] for i in range(self.lines)]
            for i in range(self.lines):
                for j in range(self.lines):
                    self.points[i].append(Position(self.left + i*self.space, self.top + j*self.space))
            self._draw_board()
        except pygame.error as e:
            print(e)
            sys.exit()
    
    def chessboard(self):
        return self._chessboard
    
    # Fall at position (i,j)    
    def drop_at(self, i, j):
        pos_x = self.points[i][j].x - int(self.ball_rect.width/2)
        pos_y = self.points[i][j].y - int(self.ball_rect.height/2)

        ball_pos = {'type':0 if self.black_turn else 1, 'coord':Position(i,j)}
        if self.black_turn:    # It's Black's turn
            self._chessboard.blit(self._black_chessball, (pos_x, pos_y))
        else:
            self._chessboard.blit(self._white_chessball, (pos_x, pos_y))    
            
        self.ball_coord.append(ball_pos)    # Record lost child information
        self.black_turn = not self.black_turn    # Switch Black and White Order
    
    # Draw the grid lines on the board and omit this step if the background of the board is accurate enough
    def _draw_board(self):    
        # Draw coordinate numbers
        for i in range(1, self.lines):
            coord_text = self.font.render(str(i), True, self.color)
            self._chessboard.blit(coord_text, (self.points[i][0].x-round(coord_text.get_width()/2), self.points[i][0].y-coord_text.get_height()))
            self._chessboard.blit(coord_text, (self.points[0][i].x-coord_text.get_width(), self.points[0][i].y-round(coord_text.get_height()/2)))
            
        for x in range(self.lines):
            # Draw horizontal lines
            pygame.draw.line(self._chessboard, self.color, self.points[0][x], self.points[self.lines-1][x])
            # Draw vertical lines
            pygame.draw.line(self._chessboard, self.color, self.points[x][0], self.points[x][self.lines-1])
    
    # Determine if a winner has been created
    def check_over(self):
        if len(self.ball_coord)>8:    # Only black and white children can be judged if they have more than four
            direct = [(1,0),(0,1),(1,1),(1,-1)]    #Check in four directions: horizontal, vertical, oblique and backslant
            for d in direct:
                if self._check_direct(d):
                    return True
        return False
    
    # Determine if the last piece is connected in a direction of five pieces, direct:(1,0),(0,1),(1,1),(1,-1)
    def _check_direct(self, direct):
        dt_x, dt_y = direct    
        last = self.ball_coord[-1]
        line_ball = []    # Checkers stored on a line
        for ball in self.ball_coord:
            if ball['type'] == last['type']:
                x = ball['coord'].x - last['coord'].x 
                y = ball['coord'].y - last['coord'].y
                if dt_x == 0:
                    if x == 0:
                        line_ball.append(ball['coord'])
                        continue
                if dt_y == 0:
                    if y == 0:
                        line_ball.append(ball['coord'])
                        continue
                if x*dt_y == y*dt_x:
                    line_ball.append(ball['coord'])

        if len(line_ball) >= 5:    # Only five or more children can continue to judge
            sorted_line = sorted(line_ball)
            for i,item in enumerate(sorted_line): 
                index = i+4
                if index < len(sorted_line):
                    if dt_x == 0:
                        y1 = item.y
                        y2 = sorted_line[index].y
                        if abs(y1-y2) == 4:    # Compare y values between this point and the fifth point, if the difference is 4 then join 5
                            return True
                    else:
                        x1 = item.x
                        x2 = sorted_line[index].x
                        if abs(x1-x2) == 4: # Compare the x value between this point and the fifth point, if the difference is 4 then connect to 5
                            return True
                else:
                    break
        return False
        
    # Check if (i,j) location is occupied    
    def check_at(self, i, j):
        for item in self.ball_coord:
            if (i,j) == item['coord']:
                return False
        return True
    
    # Obtaining logical coordinates from physical coordinates        
    def get_coord(self, pos):
        x, y = pos
        i, j = (0, 0)
        oppo_x = x - self.left
        if oppo_x > 0:
            i = round(oppo_x / self.space)    # round
        oppo_y = y - self.top
        if oppo_y > 0:
            j = round(oppo_y / self.space)
        return (i, j)

The Renju class has several function descriptions:

  1. The init() method does a few main things:
  • Load resources and set up a _chessboard surface object for this board
  • Calculates the physical coordinates of all the falling points on the board and stores them in attributes such as points, which are a two-dimensional array so that points[i][j] can represent the physical coordinates corresponding to the logical position (i,j).
  • Call the _draw_board() method to draw gridlines and labels on _chessboard, and so on.
  1. The drop_at(i,j) method falls at the logical position (i,j), where the white and black spots are determined by the control switch black_turn of the Renju class.Draw and save the dropped information in the ball_coord list.
  2. The check_at(i,j) method, which looks through the ball_coord list to see if (i,j) positions fall.
  3. The check_over() method is used to determine whether there are five sublines, and the four directions are determined by calling the _check_direct method.
  4. The _check_direct(direct) method is the main logic for determining the five sublines, which is achieved by determining a direction of the last faller.

Keywords: Python pip network

Added by rohithmr on Tue, 05 May 2020 20:13:13 +0300