python实现文字版扫雷

本文针对会基本python语法的读者。

转载请注明,有问题可以留言一起探讨。

文章中代码运行的环境为Windows下  Python 2.7.14

1、实现的简单效果

pycharm上运行效果

        注: [-]:未翻转; [1] 周边的地雷数量; [*]地雷,[ ]周边没有地雷

2、需求的简单分析

(1)先在windows的附件里面把扫雷游戏打开,来多玩几盘

(2)整理整个游戏需求的流程图:

需求简要分析流程图

注:初级9行*9列~10个雷,中级16*16~40,高级16*30~99,自定义行列尚未实现

3、关键代码分析

  前置:

     将每一格封装成一个类:CGameCell

     用m_CellList记录整个画面中每个类的对象

     用mineList记录布雷的位置(所在的行,列)

(1)布雷:

布雷的函数主体

思路:如在9*9~10的级别里,需要随机布置10个雷,这10个随机数需要在 [0 ~ 81)之间产生,之后在对每个随机数进行 r, c =divmod(index, self.m_ColBoard) 取模、取余的操作,模代表该雷所在的行,余代表该雷所在的列,再用mineList对所有的雷的位置进行记录。这样做的好处是,每次的布雷都是精准的,时间复杂度低。

(2)统计每格周边雷的数量:

统计每格周边雷的数量

思路:在mineList记录了雷的位置,以每个雷为中心,向其周边的八个方向(左上,正上,右上,正左,正右,左下,正下,右下)进行扩展(注意判断越界),判断该格是否为雷,非雷的话对该格记录的数据值+1。该做法比按照每格进行遍历,效率高出数量级.....

(3)非递归实现用户翻转指定格的效果,截图代码不完整,详细代码见后一章节:

非递归实现用户翻转格

思路:

新开两个数组一个是待检测列表(waitChecklist),一个是已检测数组(m_CellList);检查某个位置,如x,y时,先把它Point(x,y) append进待检查列表。然后循环while(待检测列表的长度>0){

count = round(point.x,point.y)

把point从待检测列表放到已经侧列表

如果count等于0,把point周围的八个point放进待检测列表

注意:如果已检测数组里面已经有那个point了,就不要把它加到待检测列表里面,不然会死循环,可参考广搜的原理和二叉树的非递归遍历。也可以用递归实现,但是公司一般不让用递归...

4、整体代码(首次用简书,代码粘贴进来有点奇怪)

# -*- coding: gbk -*-

# Created by zhoullin on 2018-03-27

import random

LEVEL_ONE = 1

LEVEL_TWO = 2

LEVEL_THREE = 3

MINE_VALUE = -1

EMPTY_VALUE = 0

UNCOVER_STATUS = 1

COVER_STATUS = 0

INPUT_GAME_LEVEL_ERROR = '输入游戏编号错误'

USER_SELECT_TIPS = ("1、初级:10个雷,9*9平铺网格\n"

                    "2、中级:40个雷,16*16平铺网格\n"

                    "3、高级:99个雷,16*30平铺网格")

LEVEL_DIC = {

    1: (9, 9, 10),

    2: (16, 16, 40),

    3: (16, 30, 99)

}

def CheckInputIsCorrect(levelStr):

    if len(levelStr) == 1 and levelStr[0].isdigit():

        levelInt = int(levelStr[0])

        if levelInt in (LEVEL_ONE, LEVEL_TWO, LEVEL_THREE):

            return True

    print INPUT_GAME_LEVEL_ERROR

    return False

def GetUserSelectedLevel():

    '''

    获取用户选择的游戏级别

    '''

    print USER_SELECT_TIPS

    while True:

        levelStr = raw_input("请输入你要选择的游戏级别编号:").split()

        if CheckInputIsCorrect(levelStr):

            return int(levelStr[0])

    return -1

class CGameCore(object):

    def __init__(self, levelInt):

        self.m_RowBoard, self.m_ColBoard, self.m_MineNum = LEVEL_DIC[levelInt]

        self.m_TotalCell = self.m_RowBoard * self.m_ColBoard

        self.m_CellList = [[CGameCell(r, c) for c in range(self.m_ColBoard)] for r in range(self.m_RowBoard)]

        self.m_UncoverCount = 0

        # for test

        # print "self.m_CellList:",self.m_CellList

        mineList = self.SetMinePosition()

        self.UpdateMineBoardData(mineList)

    def SetMinePosition(self):

        if self.m_MineNum >= self.m_TotalCell:  # 对mineNumber的参数是否合理进行判断

            print "布雷数量过多,不符合游戏规则"

            return

        randomList = random.sample(range(self.m_TotalCell), self.m_MineNum)  # 在[0,row*col]之间产生一个长度为mineNum的列表

        mineList = []

        if self.m_ColBoard == 0:

            return mineList

        for index in randomList:

            r, c = divmod(index, self.m_ColBoard)

            self.m_CellList[r][c].SetValue(MINE_VALUE)

            mineList.append([r, c])

        return mineList

    def UpdateMineBoardData(self, mineList):

        for mine in mineList:

            row, col = mine

            for i in range(row - 1, row + 2):

                for j in range(col - 1, col + 2):

                    if self.CheckRowAndColIsCorrect(i, j):

                        self.m_CellList[i][j].UpdateValue()

        #for test

        #print mineList

    def ShowBoard(self):

        for r in range(0, self.m_RowBoard + 1):

            for c in range(0, self.m_ColBoard + 1):

                if r == 0 or c == 0:

                    self.showBoardHeader(r, c)

                else:

                    self.m_CellList[r-1][c-1].PrintSelf()

            print " "

        print '当前游戏雷数量:', self.m_MineNum

    def showBoardHeader(self, row, col):

        if row == 0:

            if col == 0:

                print "  ",

            else:

                if (col - 1) < 10:  # 为了显示对齐

                    print ' %d ' % (col - 1),

                else:

                    print ' %d' % (col - 1),

        elif col == 0:

            if (row - 1) < 10:  # 为了显示对齐

                print '%d ' % (row - 1),

            else:

                print (row - 1),

    def UncoverPosition(self, row, col):

        # 对用户指定的翻转格进行判断

        if self.m_CellList[row][col].GetStatus() == UNCOVER_STATUS:

            return 0

        if self.m_CellList[row][col].GetValue() == MINE_VALUE:

            return MINE_VALUE

        self.m_CellList[row][col].SetStatus(UNCOVER_STATUS)

        self.m_UncoverCount += 1

        waitChecklist = []

        waitChecklist.append((row, col))

        while len(waitChecklist) > 0:

            # for test

            print "waitChecklist:",waitChecklist

            tempRow, tempCol = waitChecklist[0]

            if self.m_CellList[tempRow][tempCol].GetValue() == EMPTY_VALUE:

                # for test

                aroundList = self.GetAroundPosition(tempRow, tempCol)

                for around in aroundList:

                    i, j = around

                    if (self.m_CellList[i][j].GetValue() == EMPTY_VALUE and (i, j) not in waitChecklist and self.m_CellList[i][j].GetStatus() == COVER_STATUS):

                        waitChecklist.append((i, j))

                    elif self.m_CellList[i][j].GetStatus() == COVER_STATUS:

                        self.m_CellList[i][j].SetStatus(UNCOVER_STATUS)

                        self.m_UncoverCount += 1

            del waitChecklist[0]

        print "m_UncoverCount:", self.m_UncoverCount

        return 0

    def GetAroundPosition(self, row, col):

        aroundList = []

        for i in range(max(0, row - 1), min(row + 2, self.m_RowBoard)):

            for j in range(max(0, col - 1), min(col + 2, self.m_ColBoard)):

                aroundList.append((i, j))

        return aroundList

    def ShowAllMineInBoard(self):

        '''

        显示所有的雷区

        '''

        print "显示所有的雷区"

        for r in range(0, self.m_RowBoard + 1):

            for c in range(0, self.m_ColBoard + 1):

                if r == 0 or c == 0:

                    self.showBoardHeader(r, c)

                else:

                    if self.m_CellList[r - 1][c - 1].GetValue() == MINE_VALUE:

                        self.m_CellList[r-1][c-1].SetStatus(UNCOVER_STATUS)

                    self.m_CellList[r-1][c-1].PrintSelf()

            print " "

    def CheckUncoverParameter(self,rowAndColStr):

        if len(rowAndColStr) == 2 and rowAndColStr[0].isdigit() and rowAndColStr[1].isdigit():

            if self.CheckRowAndColIsCorrect(int(rowAndColStr[0]), int(rowAndColStr[1])):

                return True

        return False

    def CheckRowAndColIsCorrect(self, row, col):

        if (0 <= row < self.m_RowBoard) and (0 <= col < self.m_ColBoard):

            return True

        return False

    def MainLoop(self):

        '''

        正式进入游戏阶段

        '''

        while True:

            rowAndColStr = raw_input("请输入你要翻转格子所在的行与列(中间用空格分离):").split()

            if self.CheckUncoverParameter(rowAndColStr) is False:

                print "输入的行或列错误!!!"

                continue

            result = self.UncoverPosition(int(rowAndColStr[0]), int(rowAndColStr[1]))

            if result == MINE_VALUE:

                self.ShowAllMineInBoard()

                print '踩雷啦!!!游戏结束····'

                break

            else:

                self.ShowBoard()

                if (self.m_TotalCell - self.m_UncoverCount) == self.m_MineNum:

                    print "恭喜!恭喜!游戏通过啦!"

                    break

    def Run(self):

        self.ShowBoard()

        self.MainLoop()

class CGameCell(object):

    s_UncoverCount = 0

    def __init__(self, row, column, value=0, uncover=COVER_STATUS):

        self.m_Row = row

        self.m_Column = column

        self.m_Value = value

        self.m_Uncover = uncover

    def SetValue(self, value):

        self.m_Value = value

    def UpdateValue(self):

        if self.m_Value != MINE_VALUE:

            self.m_Value += 1

    def GetValue(self):

        return self.m_Value

    def SetStatus(self, uncover):

        self.m_Uncover = uncover

    def GetStatus(self):

        return self.m_Uncover

    def PrintSelf(self):

        if self.m_Uncover == COVER_STATUS:

            print '[-]',

        else:

            if self.m_Value == 0:

                print '[ ]',

            elif self.m_Value == MINE_VALUE:

                print '[*]',

            else:

                print '[%d]' % (self.m_Value),

if __name__ == "__main__":

    levelInt = GetUserSelectedLevel()

    gameExample = CGameCore(levelInt)

    gameExample.Run()

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容