002.07 MineSweeper - PySimleGUI 的應用

Jason990420發表於2019-12-07

建檔日期: 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)

遊戲方法:

  • 滑鼠左鍵點選, 顯示數字或炸彈, 數字的意義為’周圍有多少顆炸彈’.

  • 滑鼠右鍵點選, 以旗子標記自己認為是炸彈的格子, 滑鼠左鍵不可點選顯示, 再點選則去除標記.

  • 上方記錄炸彈總數, 已點到炸彈總數, 以及旗子總數, 後兩者數目等於前者時, 遊戲結束

遊戲目標:

  • 以最少數點到的炸彈總數, 完成遊戲.

遊戲畫面:

002.07  MineSweeper - PsSimleGUI 的應用

程式碼:

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 協議》,轉載必須註明作者和本文連結
Jason Yang

相關文章