建檔日期: 2019/12/07
更新日期: None
相關軟體資訊:
Win 10 | Python 3.7.2 | PySimpleGUI 4.6.0 |
說明:所有內容歡迎引用,只需註明來源及作者,本文內容如有錯誤或用詞不當,敬請指正.
主題: 002.07 MineSweeper - PsSimleGUI 的應用
還是用PySimpleGU來寫一個常見的遊戲MineSweeper, 其中PySimpleGUI Button沒有提供滑鼠右鍵功能下, 自己加了個event handler來處理, 其他沒啥好說, 請見下文.
滑鼠右鍵Event Handler
def right_click(self, event): # Right_click handler
if self.state == 1:
self.update(3)
elif self.state == 3:
self.update(1)
window[b[x][y].key].Widget.bind('<Button-3>', b[x][y].right_click)
遊戲方法:
滑鼠左鍵點選, 顯示數字或炸彈, 數字的意義為’周圍有多少顆炸彈’.
滑鼠右鍵點選, 以旗子標記自己認為是炸彈的格子, 滑鼠左鍵不可點選顯示, 再點選則去除標記.
上方記錄炸彈總數, 已點到炸彈總數, 以及旗子總數, 後兩者數目等於前者時, 遊戲結束
遊戲目標:
遊戲畫面:
程式碼:
import PySimpleGUI as sg
import random
import sys
'''
Source code of MineSweeper Game
'''
font = 'Courier 16 bold'
width = 25
height = 14
all = 80
new_start = True
size = (30,30)
# 0: 0, 1: hidden card, 2: bomb card, 3: flag card, 4: shown card
im = ['', 'blank.png', 'bomb.png', 'flag.png', '']
color = [('grey', 'grey'), ('black', 'green'),
('black', 'green'), ('black', 'green'), ('black', 'grey')]
def binding_all(): # Bind right button of mouse to cell object
for x in range(width):
for y in range(height):
window[b[x][y].key].Widget.bind(
'<Button-3>', b[x][y].right_click)
# Setting for top buttons
def button1(text, key=None, disabled=False, button_color=('white', 'green')):
return sg.Button(text, pad=(10, 10), font=font, focus=False, key=key,
disabled=disabled, button_color=button_color)
def button2(x, y): # define cell as instance of button and
b[x][y] = button(x,y) # bulid Button
return b[x][y].button
def check_blank(x, y): # Check if cell near 0-bomb cel
if b[x][y].num==0: return False
for i in [-1, 0, 1]:
for j in [-1, 0, 1]:
if i==0 and j==0: continue
if ((0<=x+i<width) and (0<=y+j<height) and
(b[x+i][y+j].num==0)): return True
return False
def check_num(): # check number of bombs, flags and hides
bomb_count = flag_count = hide_count = 0
for x in range(width):
for y in range(height):
if b[x][y].state == 1:
hide_count += 1
elif b[x][y].state == 2:
bomb_count += 1
elif b[x][y].state == 3:
flag_count += 1
return bomb_count, flag_count, hide_count
# Count number of bombs about cell
def count_bomb(x, y):
global bomb
if bomb[x][y]==10: return 10
count = 0
for i in [-1, 0, 1]:
for j in [-1, 0, 1]:
if i==0 and j==0: continue
if ((0<=x+i<width) and (0<=y+j<height) and
(bomb[x+i][y+j]==10)):
count += 1
return count
# set position for all boms
def deal():
global bomb
bomb_list = random.sample(range(width*height), all)
bomb = [[0 for y in range(height)] for x in range(width)]
for x in range(width):
for y in range(height):
if x*height+y in bomb_list: bomb[x][y]=10
for x in range(width):
for y in range(height):
bomb[x][y] = count_bomb(x, y)
return
def new_card(): # refresh all cells to hidden card
for x in range(width):
for y in range(height):
b[x][y].state = 1
b[x][y].num = bomb[x][y]
b[x][y].color = color[1]
b[x][y].update(1)
def show_blank(): # Show all cell not around by any bomb
for x in range(width):
for y in range(height):
if b[x][y].num == 0:
b[x][y].update(0)
elif check_blank(x, y):
b[x][y].update(4)
# Class for each button object
class button():
def __init__(self, x, y):
self.x = x
self.y = y
self.state = 1
self.color = color[self.state]
self.disabled = False
self.key = 'Button{:0>2d}{:0>2d}'.format(x, y)
self.num = bomb[x][y]
self.button = sg.Button(' ',
auto_size_button=False,
border_width=2,
button_color=self.color,
disabled=self.disabled,
focus=False,
font=font,
image_size=size,
image_filename=im[self.state],
key=self.key,
pad=(1,1))
def right_click(self, event): # Right_click handler
if self.state == 1:
self.update(3)
elif self.state == 3:
self.update(1)
def update(self, state): # update state of cell
self.state = state
if state == 0:
self.disabled = True
text = ' '
elif state in [1,2,3]:
self.disabled = False
text = ' '
elif state == 4:
self.disabled = True
text = str(self.num)
self.color = color[self.state]
window[self.key].TKButton['disabledforeground'] = 'white'
self.button.Update(text=text, disabled=self.disabled,
image_filename=im[self.state], image_size=size,
button_color=self.color)
# Check platform, only for Windows. Maybe wrok on other platform
if not sys.platform.startswith('win'):
sg.popup_error('Sorry, you gotta be on Windows')
sys.exit(0)
# set theme for window
sg.change_look_and_feel('DarkGreen')
deal() # Initial position of bombs
b = [[0 for j in range(height)] for i in range(width)]
layout = [[button1('New Game', key='-New Game-'), # Layout of window
button1('Game Over', key='-Game Over-'),
button1('Target:'+str(all), key='-Target-'),
button1('Bomb:0', key='-Count-Bomb-'),
button1('Flag:0', key='-Count-Flag-')]]+[
[button2(x, y) for x in range(width)] for y in range(height)]
window = sg.Window('MineSweeper', layout=layout).Finalize() # Create window
binding_all() # Binding right button event handler of all cells
show_blank() # Show all cells near no-bomb cell
new_start = True # Flag for new game
message = False # Flag for game over message sent
while True:
if new_start: # Actions for new game
deal()
new_card()
show_blank()
message = False
new_start = False
pass
event, values = window.read(timeout=100) # read window event
if event==None or event=='-Game Over-': # Window close / Game over
break
elif event == '-New Game-': # New Game, set the flag
new_start = True
elif event[:6] == 'Button': # Left button clicked
x, y = int(event[6:8]), int(event[8:10])
if b[x][y].state == 1:
if b[x][y].num == 10:
b[x][y].update(2)
else:
b[x][y].update(4)
# Update number onf bombs, flags
bomb_num, flag_num, hide_num = check_num()
window['-Count-Bomb-'].Update(text='Bomb:'+str(bomb_num))
window['-Count-Flag-'].Update(text='Flag:'+str(flag_num))
# Check if game over
if hide_num==0 and (bomb_num+flag_num==all) and (not message):
message = True
sg.popup('Game Over', title='Note')
window.close()
鏈結
drive.google.com/open?id=1J9i_tUK3...
本作品採用《CC 協議》,轉載必須註明作者和本文連結