AI扫雷有多牛?他国纷纷来求师学艺(附完整教程)
前文
大家好!我是梨子同學(xué)!
希望大家多多支持我!哈哈
為了感謝每一個關(guān)注我的小可愛:💓每篇文章的項目源碼都是無償分享滴💓見文末!
很多csdn的功能還在研究中,還有小編的文筆不好勿怪,會慢慢進(jìn)步跟大家一起學(xué)習(xí)的
小編也一直在學(xué)習(xí)編程,如果代碼小程序出現(xiàn)錯誤歡迎大家評論區(qū)留言哈!
最后——如果文章有幫助到你,記得“關(guān)注”、“點(diǎn)贊”、“評論”三連哦~
?前言
《掃雷》是一款大眾類的益智小游戲,于1992年發(fā)行。
游戲目標(biāo)是在最短的時間內(nèi)根據(jù)點(diǎn)擊格子出現(xiàn)的數(shù)字找出所有非雷格子,同時避免踩雷,踩到一個
雷即全盤皆輸。
它是許多人接觸到的第一款游戲,大概也是廣大辦公族和無網(wǎng)學(xué)生無聊時消遣的最佳游戲,是不是
每次見到戴上墨鏡的小人很有成就感?在那些還沒有網(wǎng)(被切斷網(wǎng))的歲月,掃雷曾陪伴無數(shù)人度
過了他們的童年。你的最佳紀(jì)錄是多少?小編在工作間隙隨手刷了一局30秒(囧😳)。
那么?怎么才能通關(guān)呢?這,有生之年靠自己猜可能做不到了,BUT我們可以靠一靠我們的Python
自動掃雷的嘛!不要慌呢~我們正式開始吧!
《自動掃雷》
環(huán)境配置:
Python3、 Pycharm 、Pygame以及部分自帶的模塊。
第三方庫的安裝:pip ?install pygame
效果展示:
游戲開始:
?
?自動掃雷:
?
?
游戲結(jié)束:
?
代碼演示:
1)主程序
代碼比較多哈,每行都有注釋大家自己看,不懂的可以找我交流、一起學(xué)習(xí)嘛!
# -*- coding: utf-8 -*- import pygame from pygame.locals import * import numpy as np import random import sys import time import copy# 屏幕大小 Screen_Size = (1200, 600) # 行數(shù) Rows = 20 # 列數(shù) Colums = 40 # 雷的數(shù)量 numOfMines = 80 # 勝率 VictoryRate=0class Sweep(object):"""docstring for Sweep"""def __init__(self):# 初始化一個頁面self.Screen = pygame.display.set_mode(Screen_Size)# 字體self.myfont = pygame.font.SysFont('幼圓', 25)# 格子大小self.gwide = int(Screen_Size[0] / Colums)self.gheight = int(Screen_Size[1] / Rows)self.board = np.zeros((Rows, Colums))# 存儲下一步可選的位置self.NBS = []# NBS輔助容器,用于判斷NBS有沒變化self.NBSTool = []# 判斷是否進(jìn)行概率選擇掃雷self.GO = False# 遍歷存儲容器self.container = []# 標(biāo)注地雷存儲容器self.mineContainer = []# 實(shí)際地雷位置存儲容器self.Mines = []# 數(shù)字存儲容器self.numbers = []# 加載圖片self.LoadImg()# 畫格子self.DrawGrid()# 埋雷self.HideMines()def LoadImg(self):# 加載地雷圖片self.mine = pygame.image.load('image/mine.jpg').convert_alpha()self.mine = pygame.transform.scale(self.mine, (self.gwide, self.gheight))# 加載旗子圖片self.flag = pygame.image.load('image/flag.jpg').convert_alpha()self.flag = pygame.transform.scale(self.flag, (self.gwide, self.gheight))# 加載地雷爆炸圖片self.boom = pygame.image.load('image/boom.png').convert_alpha()self.boom = pygame.transform.scale(self.boom, (self.gwide, self.gheight))# 加載數(shù)字圖片self.num1 = pygame.image.load('image/1.png')self.num1 = pygame.transform.scale(self.num1, (self.gwide, self.gheight))self.num2 = pygame.image.load('image/2.png')self.num2 = pygame.transform.scale(self.num2, (self.gwide, self.gheight))self.num3 = pygame.image.load('image/3.png')self.num3 = pygame.transform.scale(self.num3, (self.gwide, self.gheight))self.num4 = pygame.image.load('image/4.png')self.num4 = pygame.transform.scale(self.num4, (self.gwide, self.gheight))self.num5 = pygame.image.load('image/5.png')self.num5 = pygame.transform.scale(self.num5, (self.gwide, self.gheight))self.num6 = pygame.image.load('image/6.png')self.num6 = pygame.transform.scale(self.num6, (self.gwide, self.gheight))self.num7 = pygame.image.load('image/7.png')self.num7 = pygame.transform.scale(self.num7, (self.gwide, self.gheight))self.num8 = pygame.image.load('image/8.png')self.num8 = pygame.transform.scale(self.num8, (self.gwide, self.gheight))# 加載訪問過后設(shè)置背景圖self.back = pygame.image.load('image/back.jpg')self.back = pygame.transform.scale(self.back, (self.gwide, self.gheight))# 加載游戲失敗背景self.gameOver=pygame.image.load('image/gameover.jpg')self.gameOver=pygame.transform.scale(self.gameOver,Screen_Size)# 加載游戲勝利背景self.victoryOver=pygame.image.load('image/victory.jpg')self.victoryOver=pygame.transform.scale(self.victoryOver,Screen_Size)def HideMines(self):"""埋雷"""for i in range(numOfMines):while True:y = random.randint(0, Colums - 1)x = random.randint(0, Rows - 1)if self.board[x][y] == 0:self.board[x][y] = -1self.Mines.append((x, y))breakdef ShowAllMines(self):"""顯示所有地雷的位置"""for i in range(Rows):for j in range(Colums):if self.board[i][j] == -1:self.Screen.blit(self.mine, (self.gwide * j, self.gheight * i))def DrawGrid(self):"""繪制背景界面"""self.Screen.fill((191, 251, 255))# 畫橫線for i in range(1, Rows):pygame.draw.line(self.Screen, (0, 0, 0), (0, self.gheight * i), (Screen_Size[0], self.gheight * i))# 畫豎線for i in range(1, Colums):pygame.draw.line(self.Screen, (0, 0, 0),(self.gwide * i, 0), (self.gwide * i, Screen_Size[1]))def NumOfPos(self, pos):"""返回一個點(diǎn)周圍的地雷數(shù)pos為地圖坐標(biāo)同時在二維數(shù)組對應(yīng)位置設(shè)置地雷數(shù)"""n = 0y, x = pos[0], pos[1]if x - 1 >= 0:if self.board[x - 1][y] == -1:n += 1if y - 1 >= 0 and self.board[x - 1][y - 1] == -1:n += 1if y + 1 <= Colums - 1 and self.board[x - 1][y + 1] == -1:n += 1if x + 1 <= Rows - 1:if self.board[x + 1][y] == -1:n += 1if y - 1 >= 0 and self.board[x + 1][y - 1] == -1:n += 1if y + 1 <= Colums - 1 and self.board[x + 1][y + 1] == -1:n += 1if y - 1 >= 0 and self.board[x][y - 1] == -1:n += 1if y + 1 <= Colums - 1 and self.board[x][y + 1] == -1:n += 1# self.board[x][y] = nreturn ndef SetNumOfPos(self, pos):"""設(shè)置一個安全點(diǎn)周圍地雷的數(shù)量pos是地圖坐標(biāo)"""n = self.NumOfPos(pos)if n == 0:self.Screen.blit(self.back, (self.gwide * pos[0], self.gheight * pos[1]))if n == 1:self.Screen.blit(self.num1, (self.gwide * pos[0], self.gheight * pos[1]))if n == 2:self.Screen.blit(self.num2, (self.gwide * pos[0], self.gheight * pos[1]))if n == 3:self.Screen.blit(self.num3, (self.gwide * pos[0], self.gheight * pos[1]))if n == 4:self.Screen.blit(self.num4, (self.gwide * pos[0], self.gheight * pos[1]))if n == 5:self.Screen.blit(self.num5, (self.gwide * pos[0], self.gheight * pos[1]))if n == 6:self.Screen.blit(self.num6, (self.gwide * pos[0], self.gheight * pos[1]))if n == 7:self.Screen.blit(self.num7, (self.gwide * pos[0], self.gheight * pos[1]))if n == 8:self.Screen.blit(self.num8, (self.gwide * pos[0], self.gheight * pos[1]))return ndef NeighborsOf(self, pos):"""獲取一個點(diǎn)的鄰居坐標(biāo)pos為二維數(shù)組的坐標(biāo)"""x, y = pos[0], pos[1]neibors = []if x - 1 >= 0:if y - 1 >= 0:neibors.append((x - 1, y - 1))if y + 1 <= Colums - 1:neibors.append((x - 1, y + 1))neibors.append((x - 1, y))if x + 1 <= Rows - 1:if y - 1 >= 0:neibors.append((x + 1, y - 1))if y + 1 <= Colums - 1:neibors.append((x + 1, y + 1))neibors.append((x + 1, y))if y - 1 >= 0:neibors.append((x, y - 1))if y + 1 <= Colums - 1:neibors.append((x, y + 1))return neiborsdef Boom(self, pos):"""pos為二維數(shù)組位置"""self.Screen.blit(self.boom, (self.gwide * pos[1], self.gheight * pos[0]))# pygame.display.update()def Ergodic(self, pos):"""從一個位置向四周發(fā)散直到遇到有雷的位置結(jié)束,是一個遞歸函數(shù)pos是二維數(shù)組的坐標(biāo)將二維數(shù)組pos坐標(biāo)和周圍的地雷數(shù)存入容器self.container中"""x, y = pos[0], pos[1]# 如果該位置周圍地雷數(shù)不為0,停止if self.NumOfPos((y, x)) > 0 and self.board[x][y] != -1:self.numbers.append(pos)return# 將二維數(shù)組pos坐標(biāo)和周圍的地雷數(shù)存入容器self.container中if self.board[x][y] != -1:self.container.append(pos)# 向上遍歷if x - 1 >= 0 and (x - 1, y) not in self.container:self.Ergodic((x - 1, y))# 向下遍歷if x + 1 <= Rows - 1 and (x + 1, y) not in self.container:self.Ergodic((x + 1, y))# 想左遍歷if y - 1 >= 0 and (x, y - 1) not in self.container:self.Ergodic((x, y - 1))# 箱右遍歷if y + 1 <= Colums - 1 and (x, y + 1) not in self.container:self.Ergodic((x, y + 1))def DrawContainer(self):# self.ShowAllMines()for pos in self.container:x, y = pos[0], pos[1]self.SetNumOfPos((y, x))def DrawNumbers(self):for pos in self.numbers:self.SetNumOfPos((pos[1], pos[0]))def DrawFlags(self):for pos in self.mineContainer:self.Screen.blit(self.flag, (pos[1] * self.gwide, pos[0] * self.gheight))def Removed(self):n = 0for pos in self.mineContainer:if pos in self.Mines:n += 1return ndef AutoPlay(self):# 二維數(shù)組隨機(jī)位置x = random.randint(0, Rows - 1)y = random.randint(0, Colums - 1)print("第一步:",self.board[x][y])if self.board[x][y]==-1:self.Boom((x,y))pygame.display.update()self.GameOver()print(x, y)while True:for ev in pygame.event.get():if ev.type == pygame.QUIT:sys.exit(0)if self.board[x][y] == -1:self.Boom((x, y))time.sleep(3)sys.exit(0)# 畫格子self.DrawGrid()# 向四周發(fā)散遍歷self.Ergodic((x, y))# 畫已經(jīng)遍歷過且周圍沒雷的位置(用白色背景)self.DrawContainer()# 畫已經(jīng)遍歷過但周圍有雷的位置(用數(shù)字)self.DrawNumbers()# 找出下一步可能走的所有位置self.NextSteps()# 畫已經(jīng)標(biāo)注過的地雷的位置(用旗子)self.DrawFlags()# 找出一定是地雷的位置并標(biāo)注(用旗子)self.SetFlags()# 找出一定沒雷的位置標(biāo)注(數(shù)字或空白)self.NoMines()# NBS為0時,概率選擇self.ChooseWithBigProbability()# 刷新pygame.display.update()# 打印被標(biāo)注的地雷數(shù)print("被標(biāo)注的地雷數(shù):", len(self.mineContainer))print("被排除的地雷數(shù):", self.Removed())if self.Removed()==numOfMines:time.sleep(3)self.Victory()def NextSteps(self):"""找出下一步掃雷的可選擇位置算法思想:找出每個已被標(biāo)明周圍地雷數(shù)的位置的八鄰域誒被訪問過的位置,這些位置就是下一步可能走的位置"""self.NBS.clear()for pos in self.numbers:for n in self.NeighborsOf(pos):if n not in self.NBS + self.container + self.numbers:self.NBS.append(n)if self.NBSTool == self.NBS:print(self.GO)self.GO = Trueself.NBSTool = copy.deepcopy(self.NBS)# print(self.NBS)def SetFlags(self):"""找出一定有雷的位置并用旗子標(biāo)注算法思想:對每個已經(jīng)標(biāo)明過地雷數(shù)的位置,找出該位置八鄰域還沒有訪問過的位置,找出還沒發(fā)現(xiàn)的地雷數(shù)目,如果該位置周圍還沒發(fā)現(xiàn)的地雷數(shù)大于等于可走的位置數(shù)目,那么該位置剩余八鄰域可走位置必定全為地雷,標(biāo)注該位置為地雷,并放入self.mineContainer容器"""for pos in self.numbers:s = list(set(self.NeighborsOf(pos)) -set(self.container) - set(self.numbers) - set(self.mineContainer))s1 = list(set(self.NeighborsOf(pos)) -set(self.container) - set(self.numbers))# if self.NumOfPos((pos[1], pos[0])) == 1 and len(s) == 1:if self.NumOfPos((pos[1], pos[0])) - len(set(s1) & set(self.mineContainer)) >= len(s):if self.board[pos[0]][pos[1]] == -1:self.Boom(pos)time.sleep(3)sys.exit(0)for pos1 in s:self.mineContainer.append(pos1)self.Screen.blit(self.flag, ((self.gwide * pos1[1], self.gheight * pos1[0])))# time.sleep(1)# pygame.display.update()def NoMines(self):"""找出能確定沒有地雷的位置算法思想:對于每個已被標(biāo)明周圍地雷數(shù)的位置,找出該位置八鄰域內(nèi)剩下未訪問過的位置,查看當(dāng)前位置周圍的地雷是否被全部標(biāo)記了,如果已經(jīng)全部被標(biāo)記,那么該位置八鄰域內(nèi)剩下未訪問過的位置,如果位置周圍的地雷數(shù)為0,那么用Ergodic()函數(shù)遍歷,如果位置周圍地雷數(shù)不為0,那么標(biāo)明該位置的地雷數(shù)"""for pos in self.numbers:s = list(set(self.NeighborsOf(pos)) -set(self.container) - set(self.numbers) - set(self.mineContainer))if self.NumOfPos((pos[1], pos[0])) == len(set(self.NeighborsOf(pos)) & set(self.mineContainer)):for pos1 in s:if self.board[pos1[0]][pos1[1]] == -1:self.mineContainer.append(pos)continueif self.NumOfPos((pos1[1], pos1[0])) == 0:self.container.append(pos1)self.Ergodic(pos1)self.Screen.blit(self.back, (pos1[1] * self.gwide, pos1[0] * self.gheight))continueif self.NumOfPos((pos1[1], pos1[0])) > 0:self.SetNumOfPos((pos1[1], pos1[0]))self.numbers.append(pos1)# self.DrawContainer()# pygame.display.update()def ChooseWithBigProbability(self):"""概率選擇函數(shù)算法思想:當(dāng)遇到無法肯定有雷或無雷的情況時,找出還沒有被訪問過的位置找出這些位置八鄰域內(nèi)已被標(biāo)明地雷數(shù)的位置的地雷數(shù)的和,并用和除以8,將這些位置和其對應(yīng)的概率存入容器并按概率從大到小的順序排序,如果概率最大的位置的概率大于等于0.75,那么將該位置標(biāo)注為地雷,如果概率小于0.75,那么找出還未訪問過且不在下一步計劃的位置容器的位置,隨機(jī)選擇一個位置,如果踩到雷游戲結(jié)束,如果該位置周圍沒有地雷,則調(diào)用Ergodic()遍歷,如果周圍有地雷那么標(biāo)注該位置的地雷數(shù)"""if self.GO == True:print("進(jìn)入概率選擇環(huán)境")noSeen = []# 待排雷數(shù)量leftmines=numOfMines-self.Removed()# 找出還未遍歷過的位置for i in range(Rows):for j in range(Colums):if (i, j) not in self.container + self.mineContainer + self.numbers:s = list(set(self.NeighborsOf((i, j)))& set(self.numbers))numerator = 0for s1 in s:numerator += self.NumOfPos((s1[1], s1[0]))# 計算概率noSeen.append([(i, j), numerator / 8])sorted(noSeen, key=lambda proba: proba[1], reverse=True)if noSeen != []:if noSeen[0][1] >= 0.75:pos = noSeen[0][0]self.mineContainer.append(pos)else:nos = [p[0] for p in noSeen]s = list(set(nos) - set(self.NBS))index = 0pos = (-1, -1)if len(s) > 1:index = random.randint(0, len(s) - 1)pos = s[index]elif len(s) == 1:pos = s[0]elif s == []:pos = noSeen[0][0]if self.board[pos[0]][pos[1]] == -1:self.Boom(pos)time.sleep(2)self.GameOver()elif self.NumOfPos((pos[1], pos[0])) > 0:self.numbers.append(pos)elif self.NumOfPos((pos[1], pos[0])) == 0:self.Ergodic(pos)noSeen.clear()self.GO = Falsedef GameOver(self):for pos in self.Mines:self.Boom(pos)pygame.display.update()time.sleep(0.1)self.Screen.blit(self.gameOver,(0,0))VictoryRate=content="排雷率:%d"%((self.Removed()/numOfMines)*100)text=self.myfont.render(content+'%',True,(0,0,0),(255,255,255))self.Screen.blit(text,(500,150))pygame.display.update()time.sleep(5)sys.exit(0)def Victory(self):# if self.Removed()==numOfMines:VictoryRate=100self.Screen.blit(self.victoryOver,(0,0))pygame.display.update()time.sleep(5)sys.exit(0)def Show(self):self.DrawGrid()self.ShowAllMines()pygame.display.update()time.sleep(5)self.DrawGrid()pygame.display.update()time.sleep(3)while True:for ev in pygame.event.get():if ev.type == pygame.QUIT:sys.exit(0)self.AutoPlay()pygame.display.update()if __name__ == '__main__':pygame.display.init()pygame.font.init()app = Sweep()app.Show()結(jié)尾
話說——不靠AI掃雷,大家自己手動玩兒通關(guān)的有嘛?
自動掃雷的、還有一款掃雷,這2款源碼都可以找我拿去自己玩下的哈!
關(guān)注小編獲取更多精彩內(nèi)容!
?制作不易,記得一鍵三連哦!!?如需打包好的源碼+素材免費(fèi)分享滴!!傳送門
?
總結(jié)
以上是生活随笔為你收集整理的AI扫雷有多牛?他国纷纷来求师学艺(附完整教程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Python小游戏】当当当当 万众瞩目
- 下一篇: 【Opencv实战】图像修复神技?看我一