python實現五子棋遊戲(pygame版)

目錄

  • 簡介
  • 實現過程
  • 結語

簡介

使用python實現pygame版的五子棋遊戲;

  環境:Windows系統+python3.8.0

  遊戲規則:

    1.分兩位棋手對戰,默認黑棋先下;當在棋盤點擊左鍵,即在該位置繪製黑棋;

    2.自動切換到白棋,當在棋盤點擊左鍵,即在該位置繪製白棋;

    3.輪流切換棋手下棋,當那方先形成5子連線者獲勝(橫、豎、斜、反斜四個方向都可以)。

  遊戲運行效果如下:

實現過程

  1. 新建文件settings.py,用來定義一些必須的基本屬性和初始值;
    class Settings():
    	def __init__(self):
    		"""初始化的遊戲配置"""
    		# 屏幕寬高
    		self.width = 700
    		self.height = 554
    		# 文字顏色和大小
    		self.fontsize = 14
    		self.fonttype = 'simsunnsimsun'
    		# 棋盤格數
    		self.number = 15
    		# 棋盤左邊距、上邊距和間隔
    		self.bd_left = 30
    		self.bd_top = 30
    		self.bd_space = 36
    		# 判斷遊戲是否結束(默認開始)
    		self.game_active = True
    		# 判斷哪方下棋(默認黑子先寫)
    		self.chess_player = 1
    		self.prompt_info = '當前棋手:黑棋'
    		# 開始校驗輸贏(兩邊合計9,因爲已經有一邊5步)
    		self.win_number = 0
    		# 設置背景圖、黑棋圖片、白棋圖片路徑
    		self.checkerboard_bg = 'images/checkerboard_bg.png'
    		self.black_chess = 'images/black_chess.png'
    		self.white_chess = 'images/white_chess.png'
    		# 存儲落子數據
    		self.move_chess = []

     

  2. 新建文件checkerboard.py,主要用來繪製背景圖和棋格線;
    import sys
    import pygame
    
    class Checkerboard():
    	def __init__(self, ck_settings, screen, position):
    		self.ck_settings = ck_settings
    		self.screen = screen
    		self.position = position
    		
    		# 顏色和座標大小
    		self.text_color = (0, 0, 0)
    		self.font = pygame.font.SysFont(ck_settings.fonttype, ck_settings.fontsize)
    		# 存儲棋子座標
    		self.checkerboard = []
    		# 加載背景圖、黑棋和白棋(當有圖片不存在時,打印錯誤並退出遊戲)
    		try:
    			self.bg_image = pygame.image.load(ck_settings.checkerboard_bg)		
    			self.black_image = pygame.image.load(ck_settings.black_chess).convert_alpha() # convert_alpha背景透明
    			self.white_image = pygame.image.load(ck_settings.white_chess).convert_alpha()
    			self.chess_rect = self.black_image.get_rect()
    		except Exception as e:
    			print('error:', e)
    			sys.exit()
    
    	def draw_board(self):		
    		# 存儲棋子座標		
    		for i in range(self.ck_settings.number):
    			self.checkerboard.append([])
    			for j in range(self.ck_settings.number):
    				self.checkerboard[i].append(self.position(self.ck_settings.bd_left + i * self.ck_settings.bd_space, self.ck_settings.bd_top + j * self.ck_settings.bd_space))
    		# 繪製棋盤座標
    		for i in range(0, self.ck_settings.number):
    			# ord返回字符的ASCII數值,chr再返回字符
    			x_text = self.font.render(chr(ord('A') + i), True, self.text_color) # A-O
    			y_text = self.font.render(str(i + 1), True, self.text_color) # 1-15
    
    			# 繪製xy軸座標(在棋盤背景圖繪製)
    			self.bg_image.blit(x_text, (self.checkerboard[i][0].x - x_text.get_width() / 2, self.checkerboard[i][0].y - 20))
    			self.bg_image.blit(y_text, (self.checkerboard[0][i].x - 20, self.checkerboard[0][i].y - y_text.get_height() / 2))
    						
    			# 繪製橫豎線(在棋盤背景圖繪製)
    			pygame.draw.line(self.bg_image, self.text_color, self.checkerboard[0][i], self.checkerboard[self.ck_settings.number-1][i])
    			pygame.draw.line(self.bg_image, self.text_color, self.checkerboard[i][0], self.checkerboard[i][self.ck_settings.number-1])
    		# 繪製棋盤背景圖
    		self.screen.blit(self.bg_image, (0, 0))

     

  3. 新建文件infopanel.py,主要用來繪製棋盤右邊提示信息(暫時只有顯示下棋方和獲勝信息);
    import pygame.font
    class Infopanel():
    	def __init__(self, ck_settings, screen):
    		"""初始化屬性"""
    		self.settings = ck_settings
    		self.screen = screen
    		self.screen_rect = screen.get_rect()
    		# 設置文字顏色和字體大小
    		self.info_color = (217, 8, 10)
    		self.font = pygame.font.SysFont(ck_settings.fonttype, 16)
    		
    	def draw_info(self, info):
    		"""將文字渲染爲圖像,並定位到右邊水平居中"""
    		self.info_image = self.font.render(info, True, self.info_color)
    		self.info_image_rect = self.info_image.get_rect()
    		self.info_image_rect.right = self.screen_rect.right - (self.screen_rect.width - 536 - self.info_image_rect.width) / 2
    		self.info_image_rect.top = 50
    		# 繪製到屏幕
    		self.screen.blit(self.info_image, self.info_image_rect)

     

  4. 新建文件“game_functions.py”,存放跟遊戲有關的所有業務邏輯函數;
    import sys
    import pygame
     
    # 棋
    def update_board(ck_settings, cb, index_coordinates, position):
    	"""更新棋盤信息"""
    	# 判斷棋手(黑棋或白棋)
    	if ck_settings.chess_player == 1:
    		ck_settings.prompt_info = '當前棋手:白棋'
    		img = cb.black_image
    		chess_type = 'black'
    	else:
    		ck_settings.prompt_info = '當前棋手:黑棋'
    		img = cb.white_image
    		chess_type = 'white'
     
    	"""落棋"""
    	dropState = check_at(ck_settings, index_coordinates)
    	if dropState:
    		i, j = index_coordinates
    		chess_x = cb.checkerboard[j][i].x - cb.chess_rect.width / 2
    		chess_y = cb.checkerboard[j][i].y - cb.chess_rect.height / 2
    		# 累計步數(兩邊合計)
    		ck_settings.win_number += 1
    		# 落子並轉換棋手
    		ck_settings.move_chess.append({'type': chess_type, 'coord': position(i, j)})
    		cb.bg_image.blit(img, (chess_x, chess_y))
    		ck_settings.chess_player *= -1
    		# 合計9步開始校驗輸贏
    		if ck_settings.win_number >= 9:
    			check_stats(ck_settings, (i, j))			
    	else:
    		ck_settings.prompt_info = '已經有其他棋子'
    		
    
    # 檢查(i,j)位置是否已佔用	
    def check_at(ck_settings, index_coordinates):
    	for item in ck_settings.move_chess:
    		if index_coordinates == item['coord']:
    			return False
    	return True
     
    def check_stats(ck_settings, pos):
    	"""校驗四個方向,是否有了輸贏"""
    	pos_i, pos_j = pos
    	directs = [(1, 0), (0, 1), (1, 1), (1, -1)]	# 橫、豎、斜、反斜 四個方向檢查	
    	for direct in directs:
    		line_checkerboard = []
    		d_x, d_y = direct
     
    		last = ck_settings.move_chess[-1]
    		line_ball = []	# 存放在一條線上的棋子
    		for ball in ck_settings.move_chess:
    			# 跟最後落子判斷
    			if ball['type'] == last['type']:
    				x = ball['coord'].x - last['coord'].x 
    				y = ball['coord'].y - last['coord'].y
    				if d_x == 0:
    					if x == 0:
    						line_ball.append(ball['coord'])
    				if d_y == 0:
    					if y == 0:
    						line_ball.append(ball['coord'])
    				if x * d_y == y * d_x:
    					line_ball.append(ball['coord'])
     
    		if len(line_ball) >= 5:	# 只有5子及以上才繼續判斷
    			sorted_line = sorted(line_ball)
    			for i, item in enumerate(sorted_line): 
    				index = i + 4
    				if index < len(sorted_line):
    					if d_x == 0:
    						y1 = item.y
    						y2 = sorted_line[index].y
    						# 此點和第5個點比較y值,如相差爲4則連成5子
    						if abs(y1 - y2) == 4:
    							ck_settings.prompt_info = '黑棋獲勝' if last['type'] == 'black' else '白棋獲勝'
    					else:
    						x1 = item.x
    						x2 = sorted_line[index].x
    						# 此點和第5個點比較x值,如相差爲4則連成5子
    						if abs(x1 - x2) == 4:
    							ck_settings.prompt_info = '黑棋獲勝' if last['type'] == 'black' else '白棋獲勝'
    				else:
    					break
    		
    # 事件
    def check_events(ck_settings, cb, position):
    	"""監聽事件"""
    	for event in pygame.event.get():
    		if event.type == pygame.QUIT:
    			sys.exit()
    		elif event.type == pygame.MOUSEBUTTONDOWN:
    			# 點擊左鍵
    			if event.button == 1:
    				pos = pygame.mouse.get_pos() # 獲取點擊實際座標
    				# 判斷是否溢出
    				x_first = cb.checkerboard[0][0].x
    				x_last = cb.checkerboard[ck_settings.number - 1][ck_settings.number - 1].x
    				y_first = cb.checkerboard[0][0].y
    				y_last = cb.checkerboard[ck_settings.number - 1][ck_settings.number - 1].y
    				if pos[0] < x_first or pos[0] > x_last or pos[1] < y_first or pos[1] > y_last:
    					ck_settings.prompt_info = '落子位置不正確!'
    				else:
    					index_coordinates = to_index(ck_settings, pos)
    					update_board(ck_settings, cb, index_coordinates, position)
     
    def to_index(ck_settings, pos):
    	"""實際座標轉換爲棋盤下標"""
    	i = round((pos[1] - ck_settings.bd_top) / ck_settings.bd_space)
    	j = round((pos[0] - ck_settings.bd_left) / ck_settings.bd_space)
    	return (i, j)
    

     

  5. 新建文件gobang.py,主函數用來初始化程序,並同步更新程序的信息;
    import pygame
    from settings import Settings
    from checkerboard import Checkerboard
    from collections import namedtuple
    import game_functions as gf
    from infopanel import Infopanel
    
    def run_game():
    	"""運行遊戲"""
    	# 初始化遊戲屏幕
    	pygame.init()
    	# 創建時鐘對象 (可以控制遊戲循環頻率)
    	clock = pygame.time.Clock()
    	# 配置實例化
    	ck_settings = Settings()	
    	screen = pygame.display.set_mode((ck_settings.width, ck_settings.height))
    	pygame.display.set_caption('五子棋遊戲')
    	# namedtuple創建類似於元組的數據類型,除了可以用索引訪問,能夠迭代,還能用屬性名訪問數據
    	position = namedtuple('Position', ['x', 'y'])
    	# 創建實例
    	cb = Checkerboard(ck_settings, screen, position)
    	
    	# 實例化面板信息
    	infopanel = Infopanel(ck_settings, screen)
    
    	while ck_settings.game_active:
    		# 繪製棋盤
    		cb.draw_board()
    		# 繪製面板信息
    		infopanel.draw_info(ck_settings.prompt_info)
    		# 檢查玩家事件並更新棋盤
    		gf.check_events(ck_settings, cb, position)
    		# 讓最近繪製的屏幕可見
    		pygame.display.flip()
    
    		# 通過時鐘對象指定循環頻率
    		clock.tick(60) # 每秒循環60次
    
    run_game()

     

  6. 在文件gobang.py目錄路徑下,執行命令“python gobang.py”彈出窗口,即可對其操作遊玩。

結語

該遊戲只是實現了基礎功能,還有很多可優化的功能:

1.根據實際情況加上更詳細的面板信息(比如倒計時等);

2.加上開始遊戲按鈕,可參考前面python實例;

3.勝負榜單等,可參考前面python實例。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章