python扫雷游戏_Python扫雷游戏

#coding: utf-8

__note__ = """

* 扫雷小游戏

* 需要python3.x以上

* 需要安装PyQt5

* pip install PyQt5

"""

import sys

try:

import PyQt5

except ImportError:

import tkinter

from tkinter import messagebox

err_str = "请安装PyQt5后再打开: pip install PyQt5"

messagebox.showerror("模块错误!", err_str)

raise ImportError(err_str)

sys.exit()

from random import randint

from PyQt5.QtWidgets import \

QApplication, \

QWidget, \

QPushButton, \

QLCDNumber, \

QDesktopWidget, \

QMessageBox

from PyQt5.QtCore import Qt

class Mine(object):

mine = 9

no_mine = 0

n_mine = 10

width = 10

height = 10

def __init__(self, width=10, height=10, nMines=10):

self.map = []

for _ in range(height):

t_line = []

for _ in range(width):

t_line.append(self.no_mine)

self.map.append(t_line)

self.width = width

self.height = height

self.n_mine = nMines

self.remix()

# 打乱布局重新随机编排

def remix(self):

for y in range(self.height):

for x in range(self.width):

self.map[y][x] = self.no_mine

def add_mark(x, y):

# 如果不是雷的标记就+1

if self.map[y][x]+1 < self.mine:

self.map[y][x] += 1

mine_count = 0

while mine_count < self.n_mine:

x = randint(0, self.width-1)

y = randint(0, self.height-1)

if self.map[y][x] != self.mine:

self.map[y][x] = self.mine

mine_count += 1

# 雷所在的位置的8个方位的数值+1

## 上下左右

if y-1 >= 0: add_mark(x, y-1)

if y+1 < self.height: add_mark(x, y+1)

if x-1 >= 0: add_mark(x-1, y)

if x+1 < self.width: add_mark(x+1, y)

## 四个角: 左上角、左下角、右上角、右下角

if x-1 >= 0 and y-1 >=1: add_mark(x-1, y-1)

if x-1 >= 0 and y+1 < self.height: add_mark(x-1, y+1)

if x+1 < self.width and y-1 >= 1: add_mark(x+1, y-1)

if x+1 < self.width and y+1 < self.height: add_mark(x+1, y+1)

def __getitem__(self, key):

return self.map[key]

def __str__(self):

format_str = ""

for y in range(self.height):

format_str += str(self[y]) + "\n"

return format_str

__repr__ = __str__

class LCDCounter(QLCDNumber):

__counter = 0

def __init__(self, start=0, parent=None):

super().__init__(4, parent)

self.setSegmentStyle(QLCDNumber.Flat)

self.setStyleSheet("background: black; color: red")

self.counter = start

@property

def counter(self):

return self.__counter

@counter.setter

def counter(self, value):

self.__counter = value

self.display(str(self.__counter))

def inc(self):

self.counter += 1

def dec(self):

self.counter -= 1

class MineButton(QPushButton):

# 按钮类型

MINE = Mine.mine # 雷

NOTMINE = Mine.no_mine # 不是雷

m_type = None

# 按钮状态

mark = False # 是否是标记状态(默认: 未被标记)

s_flag = '⚑' # 标记

s_mine = '☠' # 雷

s_success = '👌'

# 按钮是否按下(默认False: 未按下)

__pushed = False

# 按钮对应map的位置

m_x = 0

m_y = 0

def __init__(self, map_pos, m_type, parent):

super().__init__(parent)

self.m_type = m_type

self.pushed = False

self.m_x = map_pos[0]

self.m_y = map_pos[1]

@property

def pushed(self):

return not self.__pushed

@pushed.setter

def pushed(self, value):

self.__pushed = not value

self.setEnabled(self.__pushed)

## 按钮上的鼠标按下事件

def mousePressEvent(self, e):

#print("m_x:%d"%self.m_x, "m_y:%d"%self.m_y, "m_type:%d"%self.m_type)

p = self.parent()

# 记录鼠标单击次数

p.nwap_lcd_clicked.counter += 1

# 左键扫雷

if e.buttons() == Qt.LeftButton:

# 踩中雷, 全部雷都翻起来

if self.m_type == self.MINE:

for t_line_btn in p.btn_map:

for btn in t_line_btn:

if btn.m_type == btn.MINE:

btn.setText(btn.s_mine)

else:

if btn.mark != True:

if btn.m_type != btn.NOTMINE:

btn.setText(str(btn.m_type))

btn.pushed = True

# 苦逼脸

p.RestartBtn.setText('😣')

QMessageBox.critical(self, "失败!", "您不小心踩到了雷! " + self.s_mine)

return None

elif self.m_type == self.NOTMINE:

self.AutoSwap(self.m_x, self.m_y)

else:

self.setText(str(self.m_type))

p.mine_counter -= 1

self.pushed = True

# 右键添加标记

elif e.buttons() == Qt.RightButton:

if self.mark == False:

self.setText(self.s_flag)

self.mark = True

else:

self.setText("")

self.mark = False

self.setFocus(False)

## 当按下的位置是NOTMINE时自动扫雷

def AutoSwap(self, x, y):

p = self.parent()

map_btn = p.btn_map

def lookup(t_line, index):

# 向左扫描

i = index

while i >= 0 and not t_line[i].pushed and t_line[i].m_type != MineButton.MINE:

if t_line[i].m_type != MineButton.NOTMINE:

t_line[i].setText(str(t_line[i].m_type))

t_line[i].pushed = True

p.mine_counter -= 1

p.nwap_lcd_counter.counter = p.mine_counter

i -= 1

if t_line[i].m_type != MineButton.NOTMINE:

break

# 向右扫描

i = index + 1

while i < p.mine_map.width and not t_line[i].pushed and t_line[i].m_type != MineButton.MINE:

if t_line[i].m_type != MineButton.NOTMINE:

t_line[i].setText(str(t_line[i].m_type))

t_line[i].pushed = True

p.mine_counter -= 1

p.nwap_lcd_counter.counter = p.mine_counter

i += 1

if t_line[i].m_type != MineButton.NOTMINE:

break

# 向上扫描

j = y

while j >= 0:

lookup(map_btn[j], x)

j -= 1

# 向下扫描

j = y + 1

while j < p.mine_map.height:

lookup(map_btn[j], x)

j += 1

class MineWindow(QWidget):

def __init__(self):

super().__init__()

self.mine_map = Mine(nMines=16)

self.InitGUI()

#print(self.mine_map)

def InitGUI(self):

w_width = 304

w_height = 344

self.resize(w_width, w_height)

self.setFixedSize(self.width(), self.height())

self.setWindowTitle("扫雷")

## 窗口居中于屏幕

qr = self.frameGeometry()

cp = QDesktopWidget().availableGeometry().center()

qr.moveCenter(cp)

self.move(qr.x(), qr.y())

l_start_x = 2

l_start_y = 40

l_x = l_start_x

l_y = l_start_y

l_width = 30

l_height = 30

# 雷区按钮

self.btn_map = []

for h in range(self.mine_map.height):

l_x = l_start_x

self.btn_map.append(list())

for w in range(self.mine_map.width):

self.btn_map[h].append(MineButton([w, h], self.mine_map[h][w], self))

self.btn_map[h][w].resize(l_width, l_height)

self.btn_map[h][w].move(l_x, l_y)

self.btn_map[h][w].show()

l_x += l_width

l_y += l_height

r_width = 30

r_height = 30

# 恢复按钮

self.RestartBtn = QPushButton('😊', self)

self.RestartBtn.clicked.connect(self.restart_btn_event)

self.RestartBtn.resize(r_width, r_height)

self.RestartBtn.move((w_width-r_width)//2, 6)

## 计数器

self.__mine_counter = self.mine_map.width * self.mine_map.height - self.mine_map.n_mine

## 两个LCD显示控件

# 操作次数

self.nwap_lcd_clicked = LCDCounter(0, self)

self.nwap_lcd_clicked.move(44, 8)

# 无雷块个数

self.nwap_lcd_counter = LCDCounter(self.mine_counter, self)

self.nwap_lcd_counter.move(204, 8)

def restart_btn_event(self):

self.mine_map.remix()

#QMessageBox.information(self, "look up", str(self.mine_map))

for y in range(len(self.btn_map)):

for x in range(len(self.btn_map[y])):

self.btn_map[y][x].pushed = False

self.btn_map[y][x].setText("")

self.btn_map[y][x].m_type = self.mine_map[y][x]

self.mine_counter = self.mine_map.width * self.mine_map.height - self.mine_map.n_mine

self.RestartBtn.setText('😊')

self.nwap_lcd_clicked.counter = 0

self.nwap_lcd_counter.counter = self.mine_counter

### 计数器

@property

def mine_counter(self):

return self.__mine_counter

@mine_counter.setter

def mine_counter(self, value):

self.__mine_counter = value

self.nwap_lcd_counter.dec()

if self.mine_counter == 0:

for t_line_btn in self.btn_map:

for btn in t_line_btn:

if btn.m_type == btn.MINE:

btn.setText(btn.s_success)

btn.pushed = True

QMessageBox.information(self, "恭喜!", "您成功扫雷! " + MineButton.s_success)

if __name__ == '__main__':

app = QApplication(sys.argv)

w = MineWindow()

w.show()

sys.exit(app.exec_())

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值