python+pygame实现扫雷游戏之二

python+pygame实现扫雷游戏之一,继续写游戏局的类:

五、

mineblock.py

# -*- coding: utf-8 -*-
import random

from  blockstatus import *
from  mine import *

# 9*9-10  16*16-40 30*16-99   30*24-**
# BLOCK_WIDTH = 30
# BLOCK_HEIGHT = 16
# MINE_COUNT = 99     # 地雷数
BLOCK_WIDTH = 9
BLOCK_HEIGHT = 9 
MINE_COUNT = 10     # 地雷数

SIZE = 20           # 块大小

#Mine构成游戏类MineBlock
class MineBlock:    
    def __init__(self):
        self._block = [[Mine(i, j) for i in range(BLOCK_WIDTH)] for j in range(BLOCK_HEIGHT)]

        # 埋雷
        # 使用random.sample函数,它的作用是从指定序列中随机获取指定长度的片断并随机排列,结果以列表的形式返回,
        # 返回结果是无序的,省去了写循环读取随机数的工作。
        # sample函数不会修改原有序列。
        for i in random.sample(range(BLOCK_WIDTH * BLOCK_HEIGHT), MINE_COUNT):
            self._block[i // BLOCK_WIDTH][i % BLOCK_WIDTH].value = 1       #一维转二维

    def get_block(self):
        return self._block
    #定义属性block
    block = property(fget=get_block)

    def getmine(self, x, y):
        return self._block[y][x]

    def open_mine(self, x, y):
        # 踩到雷了
        if self._block[y][x].value:
            self._block[y][x].status = BlockStatus.bomb
            return False

        # 先把状态改为 opened
        self._block[y][x].status = BlockStatus.opened

        around = _get_around(x, y)

        _sum = 0
        for i, j in around:
            if self._block[j][i].value:
                _sum += 1
        self._block[y][x].around_mine_count = _sum

        # 如果周围没有雷,那么将周围8个未中未点开的递归算一遍
        # 这就能实现一点出现一大片打开的效果了
        if _sum == 0:
            for i, j in around:
                if self._block[j][i].around_mine_count == -1:
                    self.open_mine(i, j)

        return True

    def double_mouse_button_down(self, x, y):
        if self._block[y][x].around_mine_count == 0:
            return True

        self._block[y][x].status = BlockStatus.double

        around = _get_around(x, y)

        sumflag = 0     # 周围被标记的雷数量
        for i, j in _get_around(x, y):
            if self._block[j][i].status == BlockStatus.flag:
                sumflag += 1
        # 周边的雷已经全部被标记
        result = True
        if sumflag == self._block[y][x].around_mine_count:
            for i, j in around:
                if self._block[j][i].status == BlockStatus.normal:
                    if not self.open_mine(i, j):
                        result = False
        else:
            for i, j in around:
                if self._block[j][i].status == BlockStatus.normal:
                    self._block[j][i].status = BlockStatus.hint
        return result

    def double_mouse_button_up(self, x, y):
        self._block[y][x].status = BlockStatus.opened
        for i, j in _get_around(x, y):
            if self._block[j][i].status == BlockStatus.hint:
                self._block[j][i].status = BlockStatus.normal


def _get_around(x, y):
    """返回(x, y)周围的点的坐标"""
    # 这里注意,range 末尾是开区间,所以要加 1
    return [(i, j) for i in range(max(0, x - 1), min(BLOCK_WIDTH - 1, x + 1) + 1)
            for j in range(max(0, y - 1), min(BLOCK_HEIGHT - 1, y + 1) + 1) if i != x or j != y]

由于这里有一定的逻辑,所以要看一下:

5.1  首先是一些常量的定义:

BLOCK_WIDTH = 9

BLOCK_HEIGHT = 9

MINE_COUNT = 10     # 地雷数

这里就是扫雷的初级模式

SIZE = 20 指的是每个格子的大小

5.2  在MineBlock类的__init__中,开始是初始化出一个二维的数组_block,数组大小是:BLOCK_WIDTH *BLOCK_HEIGHT,里面每一个元素就是一个Mine。同时利用random.sample函数产生MINE_COUNT 个地雷,将数组的相应元素的value赋值为1,表示地雷,其他的就不是地雷,其value值为默认值0.

5.3  接着定义了一个属性block,指向上面定义的二维数组

5.4 定义方法getmine,获取指定位置的Mine对象

5.5 这里先介绍在最后面的辅助的方法:_get_around(x, y):  返回(x, y)周围的点的坐标,因为当鼠标左右按键同时按下时;以及点击某点时,假如它恰好位于不是雷的地方,同时周围还没有雷,会开出一大片这两种时候,会去遍历(x,y)周围的8个方向,所以用_get_around函数获取周围点的坐标的集合。

5.6 主要逻辑函数是open_mine,由于这里不是界面元素,所以本质就是计算每个Mine对象的状态,并赋值给_block中相应下标的那个元素的status。(到这里,应该能够体会到前面Mine类中那样写属性的用处了。)就是这个逻辑:

   5.6.1 先判断坐标处是不是雷,

      5.6.1.1若是雷,就将状态设置为bomb,并返回False,结束该函数;

      5.6.1.2否则,就先将该坐标处状态设置为opened,同时调用5.5的辅助方法_get_around获取                     周围的坐标集合,计算这些集合对应的value之和,将这个和赋值给该点的属性                            around_mine_count(注意,这个属性默认值是-1),表示该点坐标周围的雷的总和。

   5.6.2 如果上述的雷的总和是0,表示周边没有雷,就遍历这个around集合,分别递归调用一下本         方法open_mine,执行完后返回True

5.7  有了5.5和5.6的基础,下面的鼠标左右双击逻辑就好理解了,它对应的是double_mouse_button_down函数和double_mouse_button_up函数,结合扫雷的实际操作很容易理解,将周边可能出现雷的地方显示一下就可以了(就是说如果已经标记了所有雷,则打开周围一圈, 如果还未标记完所有雷,则有一个周围一圈被同时按下的效果,状态如果是normal,就设置成hint),鼠标弹起up时恢复原状(状态如果是hint,就设置成normal)。

待续。。。

python+pygame实现扫雷游戏之三

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值