preface
Chinese people talk about "Qin, chess, calligraphy and painting". It can be seen that playing chess, which requires wisdom, is very important in the daily life of the ancients.
When it comes to chess, we are familiar with go, chess, military flag, checkers and so on. Of course, there is Gobang.
Today's focus is on Gobang π₯οΌ Let's make a Python version of Gobang to satisfy our greed!
Popular science:
In ancient times, although Gobang was similar to go, its playing methods were completely different.
Gobang is a "chess game. The chess equipment is the same as go. Two people play a game, take turns, and connect the five children into one to win". Some people will
Gobang is called "lianwuzi" and "Lianzhu", which may be derived from "the sun and moon are like a combination, and the five stars are like Lianzhu" in the book of Han Dynasty.
It is said that in the Song Dynasty, a man named Zhao Shixiu made an appointment with a man named Sima Guang to play Gobang. Sima Guang failed to keep the appointment because of an urgent matter, which made Zhao Shixiu
be on tenterhooks; As a result, Zhao Shixiu left a famous poem "about":
"It rains at home in the season of yellow plum, and frogs are everywhere in the green grass pond. You can't come in the middle of the night and knock chess pieces and drop lanterns."
It can be seen that Gobang had a wide influence in China's ancient society, and people also liked it very much.
It's a little too much. Let's start——
Show Time
Here's the thing:
Hello everyone, Xiaobian brushed an extremely outrageous video when he was in the water group today π€³
Lying slot, why is the black chess piece fission π²
Can you still play Gobang like this?
If I learn this
There is great hope for a child!
------
The video is a fission of black chess
Don't say five sons, ten even beads
Forget it, Gobang, just Gobang
Xiaobian opens it first, and it's over β!
1) Background environment
This paper is an interface Gobang game written based on Pygame game module.
To install Pygame:
pip install pygame
C:\Users> pip install pygame Collecting pygame Downloading https://files.pythonhosted.org/packages/3e/f5/feabd88a2856ec86166a897b62bfad828bfe7a94a27cbd7ebf07fd 70399/pygame-1.9.4-cp37-cp37m-win_amd64.whl (4.2MB) 100% |ββββββββββββββββββββββββββ| 4.2MB 6.6MB/s Installing collected packages: pygam Successfully installed pygame-1.9.4
Successful means that the installation has been successful.
Common Pygame modules:
Module name function pygame.cdrom Access optical drive pygame.cursors Load cursor pygame.display Access display devices pygame.draw Draw shapes, lines, and points pygame.event Manage events pygame.font Use font pygame.image Loading and storing pictures pygame.joystick Use a joystick or something like that pygame.key Read keyboard keys pygame.mixer voice pygame.mouse mouse pygame.movie Play video pygame.music Play audio pygame.overlay Access advanced video overlay pygame.rect Manage rectangular areas pygame.scrap Local clipboard access pygame.sndarray Operating sound data pygame.sprite Operation moving image pygame.surface Manage images and screens pygame.surfarray Manage lattice image data pygame.time Manage time and frame information pygame.transform Zoom and move images |
Background material: (pictures only)
2) Code demonstration
Main program:
import pygame from drawing import Display from status import State from setup import * def main(): """ main program """ state = State() display = Display(state.screen) display.drawChessBoard() display.drawRightSide() while True: checkEvents(state, display) state.clock.tick(FPS) pygame.display.update() # noinspection PyPep8Naming def checkEvents(state, display): """ Check event procedure """ for event in pygame.event.get(): if event.type == pygame.QUIT: exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_F1: state.reStart() display.drawChessBoard() display.drawRightSide() if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1 and state.startGame(): human_piece = state.humanPiece() if human_piece: display.drawMain(human_piece[0], human_piece[1], human_piece[2], human_piece[3], human_piece[4]) if not human_piece[3]: return pygame.display.flip() ai_piece = state.aiPiece() display.drawMain(ai_piece[0], ai_piece[1], ai_piece[2], ai_piece[3], ai_piece[4]) pygame.display.flip() if __name__ == '__main__': main()
Operation interface: drawing of chessboard, chess sub interface, etc.
import pygame from setup import * # noinspection PyPep8Naming class Display(object): def __init__(self, screen): pygame.init() self.screen = screen self.black = pygame.image.load(BLACK_IMG) self.white = pygame.image.load(WHITE_IMG) self.black_small = pygame.image.load(BLACK_SMALL_IMG) self.white_small = pygame.image.load(WHITE_SMALL_IMG) self.restart_surf = pygame.image.load(RESTART_IMG) def drawMain(self, cur_pos, turn, result_text, starting, step_list): """ Main display function """ piece_surf = self.white if turn == 0 else self.black self.drawPiece(cur_pos, piece_surf) self.drawStep(step_list) self.drawResult(result_text) if not starting: self.drawRestart(self.restart_surf) else: if turn == 0: next_text = 'Next Black' else: next_text = 'Next White' self.drawNext(next_text) def drawStep(self, step_list): """ Display drop records """ pygame.draw.rect(self.screen, BG_COLOR, (WINDOW_W-RIGHT_W+15, RIGHT_SIDE_CENTER_LINE_Y+10, RIGHT_W-15, WINDOW_H-B_BORDER-RIGHT_SIDE_CENTER_LINE_Y-RIGHT_SIDE_BOTTOM_BLOCK_H), 0) for n, value in enumerate(step_list[-10:]): text = '{:03d}: {} X={:02d} Y={:02d}'.format(value[0], value[1], value[2][0], value[2][1]) self.drawText(text, RIGHT_SIDE_STEP_TEXT_FONT, RIGHT_SIDE_STEP_TEXT_SIZE, RIGHT_SIDE_STEP_TEXT_COLOR, WINDOW_W-RIGHT_W+15, RIGHT_SIDE_CENTER_LINE_Y+10+n*18, 'topleft') def drawNext(self, next_text): """ Show next steps """ pygame.draw.rect(self.screen, RIGHT_SIDE_COLOR, (WINDOW_W-RIGHT_W, WINDOW_H-B_BORDER-RIGHT_SIDE_BOTTOM_BLOCK_H, RIGHT_SIDE_BOTTOM_BLOCK_W, RIGHT_SIDE_BOTTOM_BLOCK_H), 0) self.drawText(next_text, RIGHT_SIDE_TEXT_FONT, RIGHT_SIDE_BOTTOM_TEXT_SIZE, RIGHT_SIDE_TEXT_COLOR, WINDOW_W - R_BORDER - RIGHT_SIDE_BOTTOM_BLOCK_W / 2, WINDOW_H - B_BORDER - RIGHT_SIDE_BOTTOM_BLOCK_H / 2, 'center') def drawRestart(self, restart_surf): """ Display press F1 Re play """ restart_rect = restart_surf.get_rect() restart_rect.center = (L_BORDER+COL*SPACE/2, WINDOW_H/2) self.screen.blit(restart_surf, restart_rect) def drawPiece(self, cur_pos, piece_surf): """ Draw chess pieces """ piece_rect = piece_surf.get_rect() piece_rect.center = (cur_pos[0], cur_pos[1]) self.screen.blit(piece_surf, piece_rect) def drawRightSide(self): """ Draw the screen in the right column """ pygame.draw.line(self.screen, RIGHT_SIDE_COLOR, (WINDOW_W-RIGHT_W+5, T_BORDER), (WINDOW_W-RIGHT_W+5, WINDOW_H-B_BORDER)) pygame.draw.line(self.screen, RIGHT_SIDE_COLOR, (WINDOW_W-RIGHT_W, T_BORDER+RIGHT_SIDE_BLOCK_H), (WINDOW_W-R_BORDER, T_BORDER+RIGHT_SIDE_BLOCK_H)) pygame.draw.line(self.screen, RIGHT_SIDE_COLOR, (WINDOW_W-RIGHT_W, RIGHT_SIDE_CENTER_LINE_Y), (WINDOW_W-R_BORDER, RIGHT_SIDE_CENTER_LINE_Y)) pygame.draw.rect(self.screen, RIGHT_SIDE_COLOR, (WINDOW_W-RIGHT_W, T_BORDER, RIGHT_SIDE_BLOCK_W, RIGHT_SIDE_BLOCK_H), 0) pygame.draw.rect(self.screen, RIGHT_SIDE_COLOR, (WINDOW_W-RIGHT_W, RIGHT_SIDE_CENTER_LINE_Y-RIGHT_SIDE_BLOCK_H, RIGHT_SIDE_BLOCK_W, RIGHT_SIDE_BLOCK_H), 0) pygame.draw.rect(self.screen, RIGHT_SIDE_COLOR, (WINDOW_W-RIGHT_W, WINDOW_H-B_BORDER-RIGHT_SIDE_BOTTOM_BLOCK_H, RIGHT_SIDE_BOTTOM_BLOCK_W, RIGHT_SIDE_BOTTOM_BLOCK_H), 0) self.drawText('Players', RIGHT_SIDE_TEXT_FONT, RIGHT_SIDE_TEXT_SIZE, RIGHT_SIDE_TEXT_COLOR, WINDOW_W-RIGHT_W+5, T_BORDER+RIGHT_SIDE_BLOCK_H, 'bottomleft') self.drawText('Human', RIGHT_SIDE_TEXT_FONT, RIGHT_SIDE_TEXT_SIZE, RIGHT_SIDE_STEP_TEXT_COLOR, WINDOW_W-RIGHT_W+35, T_BORDER+RIGHT_SIDE_BLOCK_H+7, 'topleft') self.drawText('AI', RIGHT_SIDE_TEXT_FONT, RIGHT_SIDE_TEXT_SIZE, RIGHT_SIDE_STEP_TEXT_COLOR, WINDOW_W-RIGHT_W+35, T_BORDER+RIGHT_SIDE_BLOCK_H+27, 'topleft') self.drawText('Step List', RIGHT_SIDE_TEXT_FONT, RIGHT_SIDE_TEXT_SIZE, RIGHT_SIDE_TEXT_COLOR, WINDOW_W-RIGHT_W+5, RIGHT_SIDE_CENTER_LINE_Y, 'bottomleft') self.drawText('Click Start', RIGHT_SIDE_TEXT_FONT, RIGHT_SIDE_BOTTOM_TEXT_SIZE, RIGHT_SIDE_TEXT_COLOR, WINDOW_W - R_BORDER - RIGHT_SIDE_BOTTOM_BLOCK_W / 2, WINDOW_H - B_BORDER - RIGHT_SIDE_BOTTOM_BLOCK_H / 2, 'center') self.screen.blit(self.black_small, (WINDOW_W-RIGHT_W+15, T_BORDER+RIGHT_SIDE_BLOCK_H+10)) self.screen.blit(self.white_small, (WINDOW_W-RIGHT_W+15, T_BORDER+RIGHT_SIDE_BLOCK_H+30)) def drawChessBoard(self): """ Draw a chessboard and draw horizontal lines, vertical lines, points, horizontal axis numbers and vertical axis numbers respectively """ self.screen.fill((128, 128, 128)) for i in range(ROW): pygame.draw.line(self.screen, LINE_COLOR, (L_BORDER, T_BORDER+i*SPACE), (L_BORDER+SPACE*(COL-1), T_BORDER+i*SPACE)) for j in range(COL): pygame.draw.line(self.screen, LINE_COLOR, (L_BORDER+j*SPACE, T_BORDER), (L_BORDER+j*SPACE, T_BORDER+SPACE*(ROW-1))) for p in POINT_LIST: pos = (L_BORDER+p[0]*SPACE, T_BORDER+p[1]*SPACE) pygame.draw.circle(self.screen, LINE_COLOR, pos, POINT_R) for m in range(1, ROW): self.drawText(str(m), AXIS_TEXT_FONT, AXIS_TEXT_SIZE, AXIS_TEXT_COLOR, L_BORDER-AXIS_TEXT_SIZE/2, T_BORDER+AXIS_TEXT_SIZE/2+m*SPACE, 'bottomright') for n in range(0, COL): self.drawText(X_AXIS_LIST[n], AXIS_TEXT_FONT, AXIS_TEXT_SIZE, AXIS_TEXT_COLOR, L_BORDER+n*SPACE, T_BORDER-int(AXIS_TEXT_SIZE/1.5), 'center') def drawText(self, text, font, size, color, x, y, site): """ Displays text at the specified location in the window """ text_font = pygame.font.Font(font, size) text_surf = text_font.render(text, True, color) text_rect = text_surf.get_rect() exec('text_rect.{}=({},{})'.format(site, x, y)) self.screen.blit(text_surf, text_rect) def drawResult(self, result_text): """ Display result text """ pygame.draw.rect(self.screen, RIGHT_SIDE_COLOR, (WINDOW_W-RIGHT_W, WINDOW_H-B_BORDER-RIGHT_SIDE_BOTTOM_BLOCK_H, RIGHT_SIDE_BOTTOM_BLOCK_W, RIGHT_SIDE_BOTTOM_BLOCK_H), 0) self.drawText(result_text, RIGHT_SIDE_TEXT_FONT, RIGHT_SIDE_BOTTOM_TEXT_SIZE, RIGHT_SIDE_TEXT_COLOR, WINDOW_W-R_BORDER-RIGHT_SIDE_BOTTOM_BLOCK_W/2, WINDOW_H-B_BORDER-RIGHT_SIDE_BOTTOM_BLOCK_H/2, 'center')
Man machine Combat: let's set the parameters of the robot.
from setup import * # noinspection PyPep8Naming class AI(object): # noinspection PyUnusedLocal def __init__(self, maps): self.maps = maps self.is_end = False @staticmethod def inBoard(x, y): """ Judge whether the current position is inside the chessboard """ return True if ROW > x >= 0 and COL > y >= 0 else False def downOk(self, x, y): """ Judge whether the current position can be dropped """ return True if self.inBoard(x, y) and self.maps[x][y] is None else False def sameColor(self, x, y, i): """ Judge whether the current position matches the given chess piece(i value)identical """ return True if self.inBoard(x, y) and self.maps[x][y] == i else False def numInLine(self, x, y, d): """ In a given direction direct(direct Distinguish positive and negative)On, the number of pieces that are the same as this point """ i = x + DX[d] j = y + DY[d] same_num = 0 piece = self.maps[x][y] if piece is None: return 0 while self.sameColor(i, j, piece): same_num = same_num + 1 i = i + DX[d] j = j + DY[d] return same_num def numOfSameKey(self, x, y, d, i, key, same_key): """ Statistics in d Direction, and key The number of points with the same value, i.e. and key Number of connectors of the same color """ if i == 1: while self.sameColor(x + DX[d] * i, y + DY[d] * i, key): same_key += 1 i += 1 elif i == -1: while self.sameColor(x + DX[d] * i, y + DY[d] * i, key): same_key += 1 i -= 1 return same_key, i def judgeResult(self, x, y): """ Judge whether there are five sub connected from eight directions, First judge whether there are five children connected, and then judge the draw """ piece = self.maps[x][y] for d in range(8): same_key, i = self.numOfSameKey(x, y, d, 1, piece, 1) if same_key == 5: if piece == '1': return 'B' elif piece == '0': return 'W' none_count = 0 for row in self.maps: for i in row: if i is None: none_count += 1 if none_count == 0: return 'T' return 'C' def liveFour(self, x, y): """ The point is in four directions(Namely v No distinction between positive and negative)οΌNumber of live four situations """ key = self.maps[x][y] s = 0 for d in range(4): same_key = 1 same_key, i = self.numOfSameKey(x, y, d, 1, key, same_key) if not self.downOk(x + DX[d] * i, y + DY[d] * i): continue same_key, i = self.numOfSameKey(x, y, d, -1, key, same_key) if not self.downOk(x + DX[d] * i, y + DX[d] * i): continue if same_key == 4: s = s + 1 return s def chongFour(self, x, y): """ The point is in eight directions(Namely v Distinguish positive and negative)οΌNumber of four situations """ key = self.maps[x][y] s = 0 for d in range(8): same_key = 0 flag = True i = 1 while self.sameColor(x+DX[d]*i, y+DY[d]*i, key) or flag: if not self.sameColor(x+DX[d]*i, y+DY[d]*i, key): if flag and self.inBoard(x+DX[d]*i, y+DY[d]*i) and self.maps[x+DX[d]*i][y+DY[d]*i] is not None: same_key -= 10 flag = False same_key += 1 i += 1 i -= 1 if not self.inBoard(x+DX[d]*i, y+DY[d]*i): continue same_key, i = self.numOfSameKey(x, y, d, -1, key, same_key) if same_key == 4: s += 1 return s - self.liveFour(x, y) * 2 def liveThree(self, x, y): """ The number of active three in four directions and broken three in eight directions of the point """ key = self.maps[x][y] s = 0 for d in range(4): same_key = 1 same_key, i = self.numOfSameKey(x, y, d, 1, key, same_key) if not self.downOk(x+DX[d]*i, y+DY[d]*i): continue if not self.downOk(x+DX[d]*(i+1), y+DY[d]*(i+1)): continue same_key, i = self.numOfSameKey(x, y, d, -1, key, same_key) if not self.downOk(x+DX[d]*i, y+DY[d]*i): continue if not self.downOk(x+DX[d]*(i-1), y+DX[d]*(i-1)): continue if same_key == 3: s += 1 for d in range(8): same_key = 0 flag = True i = 1 while self.sameColor(x+DX[d]*i, y+DY[d]*i, key) or flag: if not self.sameColor(x+DX[d]*i, y+DY[d]*i, key): if flag and self.inBoard(x+DX[d]*i, y+DY[d]*i) and self.maps[x+DX[d]*i][y+DY[d]*i] is not None: same_key -= 10 flag = False same_key += 1 i += 1 if not self.downOk(x+DX[d]*i, y+DY[d]*i): continue if self.inBoard(x+DX[d]*(i-1), y+DX[d]*(i-1)) and self.maps[x+DX[d]*(i-1)][y+DX[d]*(i-1)] is None: continue same_key, i = self.numOfSameKey(x, y, d, -1, key, same_key) if not self.downOk(x+DX[d]*i, y+DY[d]*i): continue if same_key == 3: s += 1 return s def gameOver(self, x, y): """ If there are five sub connections, the maximum score is 10000 """ for d in range(4): if (self.numInLine(x, y, d) + self.numInLine(x, y, d + 4)) >= 4: return True return False def getScore(self, x, y): """ The main evaluation function returns the evaluation score """ if self.gameOver(x, y): return 10000 score = self.liveFour(x, y) * 1000 + (self.chongFour(x, y) + self.liveThree(x, y)) * 100 for d in range(8): if self.inBoard(x+DX[d], y+DY[d]) and self.maps[x+DX[d]][y+DY[d]] is not None: score = score + 1 return score def layerOne(self): """ The first layer of game tree, maximum, self layer """ l1_max = -100000 if self.maps[int((COL-1)/2)][int((ROW-1)/2)] is None: return int((COL-1)/2), int((ROW-1)/2) pos_x = -1 pos_y = -1 for y in [8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 0]: for x in [8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 0]: if not self.downOk(x, y): continue self.maps[x][y] = '0' score = self.getScore(x, y) if score == 0: self.maps[x][y] = None continue if score == 10000: return x, y score = self.layerTwo(l1_max) self.maps[x][y] = None if score > l1_max: l1_max = score pos_x = x pos_y = y print('{}, score:{}'.format((pos_x, pos_y), l1_max)) return pos_x, pos_y def layerTwo(self, l1_max): """ Game tree, second layer, minimum, opponent layer """ l2_min = 100000 for y in [8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 0]: for x in [8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 0]: if not self.downOk(x, y): continue self.maps[x][y] = '1' score = self.getScore(x, y) if score == 0: self.maps[x][y] = None continue if score == 10000: self.maps[x][y] = None return -10000 score = self.layerThree(score, l2_min) if score < l1_max: self.maps[x][y] = None return -10000 self.maps[x][y] = None if score < l2_min: l2_min = score return l2_min def layerThree(self, l2_score, l2_min): """ The third layer of game tree """ three_max = -100000 for y in [8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 0]: for x in [8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 0]: if not self.downOk(x, y): continue self.maps[x][y] = '0' score = self.getScore(x, y) if score == 0: self.maps[x][y] = None continue if score == 10000: self.maps[x][y] = None return -10000 if score - l2_score * 2 > l2_min: self.maps[x][y] = None return 10000 self.maps[x][y] = None if score - l2_score * 2 > three_max: three_max = score - l2_score * 2 return three_max @staticmethod def changePos(x, y): """ First, judge whether the coordinates are in the chessboard, and then convert the mouse coordinates to the point coordinates on the chessboard, otherwise it returns False :return: [(Coordinates corresponding to chessboard points), Rotation value, Outcome] """ # Determine whether the coordinates are in the chessboard if x < L_BORDER - PIECE_NEAR or x > L_BORDER + (ROW-1) * SPACE + PIECE_NEAR: return False if y < T_BORDER - PIECE_NEAR or y > T_BORDER + (COL-1) * SPACE + PIECE_NEAR: return False # Convert the coordinates to those that match the points on the chessboard x_int = (x - L_BORDER) // SPACE y_int = (y - T_BORDER) // SPACE if x - L_BORDER - PIECE_NEAR <= x_int * SPACE: x_c = L_BORDER + x_int * SPACE elif x - L_BORDER + PIECE_NEAR >= (x_int + 1) * SPACE: x_c = L_BORDER + (x_int + 1) * SPACE else: return False if y - T_BORDER - PIECE_NEAR <= y_int * SPACE: y_c = T_BORDER + y_int * SPACE elif y - T_BORDER + PIECE_NEAR >= (y_int + 1) * SPACE: y_c = T_BORDER + (y_int + 1) * SPACE else: return False # To convert coordinates to array coordinates, you need to transpose X and y x_n = (y_c - T_BORDER) // SPACE y_n = (x_c - L_BORDER) // SPACE return [(x_c, y_c), (x_n, y_n)]
3) The effect is as follows
3.1 game interface
three point two Game victory
(this robot is not very clever Yazi. There is no pressure to win directly! Hahaha)
Summary
"Chess" thinks wisely and decisively depends on its own wisdom to win ππ. Click here for the complete code