婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 教你如何用python開發一款數字推盤小游戲

教你如何用python開發一款數字推盤小游戲

熱門標簽:蘇州人工外呼系統軟件 廣東旅游地圖標注 淮安呼叫中心外呼系統如何 京華圖書館地圖標注 看懂地圖標注方法 電話外呼系統招商代理 佛山通用400電話申請 電話機器人貸款詐騙 打印谷歌地圖標注

今年年初,新一季的《最強大腦》開播了,第一集選拔的時候大家做了一個數字游戲,名叫《數字華容道》,當時何猷君以二十幾秒的成績奪得該項目的冠軍,看了這個游戲之后我決定要寫一個《數字華容道》的程序,過去了半年,我終于記起了這件事,今天就來實現。

數字推盤游戲(n-puzzle)是一種智力游戲,常見的類型有十五數字推盤游戲和八數字推盤游戲等。十五數字推盤游戲的板上會有十五個方塊和一個大小相當于一個方塊的空位(供方塊移動之用),當15個數字依次排序并且最后一個格子為空位即代表挑戰成功。

本文使用 PyQt5 進行設計與實現,PyQt5 是該程序的一個呈現方式,最重要的是算法,學會了算法,完全可以使用 PyGame 或者 Tkinter 實現。

PyQt5安裝:pip install PyQt5

本文使用環境:

系統:Windows 10 64位Python版本:3.6

1、布局設計

做一個簡版的數字華容道,布局設計如圖所示:

圖中灰色的部分使用 QWidget 作為整個游戲的載體;黃色部分使用 QGridLayout 作為數字方塊的布局;紅色部分使用 QLabel 作為數字方塊。

2、算法設計

如上圖所示,本游戲共需要15個方塊,每個方塊代表一個數字。我們可以使用 一個二維 list 來存儲方塊上的數字。其實我們要創建一個 4x4 的 list 存儲 0~15 各個數字,0 代表空的位置。

2.1 創建并初始化數組

  • 創建數組的方法:
  • 創建一個長度為16的數組,并且在對應位置上保存著 0~15 ;打亂順序
import random

# 用來存放位置信息的二維數組
blocks = []

# 產生隨機數組,0 代表空的位置
arr = range(16)
numbers = random.sample(arr, 16)

for row in range(4):
	blocks.append([])
	for column in range(4):
		blocks[row].append(numbers[row*4 + column])

# 打印結果
for i in range(4):
	print(blocks[i])

[out]
[2, 5, 7, 9]
[11, 8, 4, 12]
[6, 13, 10, 15]
[1, 14, 0, 3]
[Finished in 0.1s]

2.2 移動算法

假如移動之前個數字位置如左圖所示,那么當按下左箭頭時,會變成如右圖所示:

可以看到 (1, 2) 和 (1, 3) 兩個位置上的數字互換了,即 0 和 8 互換;如果右圖所示再次按下左箭頭,那么所有數字都不會改變,因為 數字 0 右邊沒有數了。

總結一下:如果 數字 0 所在位置為 (row, column),并且 column≠3 那么按下左箭頭之后,(row, column) 和 (row, column+1) 位置上的數組互換,同理可得:

  • 如果 數字 0 所在位置為 (row, column),并且 column≠0 那么按下右箭頭之后,(row, column) 和 (row, column-1) 位置上的數組互換;
  • 如果 數字 0 所在位置為 (row, column),并且 row≠3 那么按下上箭頭之后,(row, column) 和 (row+1, column) 位置上的數組互換;
  • 如果 數字 0 所在位置為 (row, column),并且 row≠0 那么按下下箭頭之后,(row, column) 和 (row-1, column) 位置上的數組互換;

將移動算法封裝成一個函數如下:

# 移動
# zero_row 代表數字0 所在二維數組的行下標,zero_column代表數字0 所在二維數組的列下標
def move(direction):
    if(direction == 'UP'): # 上
        if zero_row != 3:
            blocks[zero_row][zero_column] = blocks[zero_row + 1][zero_column]
            blocks[zero_row + 1][zero_column] = 0
            zero_row += 1
    if(direction == 'DOWN'): # 下
        if zero_row != 0:
            blocks[zero_row][zero_column] = blocks[zero_row - 1][zero_column]
            blocks[zero_row - 1][zero_column] = 0
            zero_row -= 1
    if(direction == 'LEFT'): # 左
        if zero_column != 3:
            blocks[zero_row][zero_column] = blocks[zero_row][zero_column + 1]
            blocks[zero_row][zero_column + 1] = 0
            zero_column += 1
    if(direction == 'RIGHT'): # 右
        if zero_column != 0:
            blocks[zero_row][zero_column] = blocks[zero_row][zero_column - 1]
            blocks[zero_row][zero_column - 1] = 0
            zero_column -= 1

2.3 是否勝利檢測算法

檢測是否勝利其實很簡單:前15個位置分別對應,最后一個為0即為勝利 ,不過為了避免不必要的計算,我們先檢測最后一個是否為 0 ,如果不為0 前面的就不用比較了。具體代碼實現如下:

# 檢測是否完成
def checkResult():
        # 先檢測最右下角是否為0
        if blocks[3][3] != 0:
            return False

        for row in range(4):
            for column in range(4):
            	# 運行到此處說名最右下角已經為0,pass即可
                if row == 3 and column == 3:
                    pass
                # 值是否對應
                elif blocks[row][column] != row * 4 + column + 1:
                    return False

        return True

3、實現

下面講解所有功能模塊的實現。

3.1 框架搭建

創建 QWidget 作為整個游戲的載體:

import sys
from PyQt5.QtWidgets import QWidget, QApplication

class NumberHuaRong(QWidget):
    """ 華容道主體 """
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # 設置寬和高
        self.setFixedSize(400, 400)
        # 設置標題
        self.setWindowTitle('數字華容道')
        # 設置背景顏色
        self.setStyleSheet("background-color:gray;")
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = NumberHuaRong()
    sys.exit(app.exec_())

運行結果如下圖所示:

3.2 數字方塊實現

前面已經提到,用一個二維數組來存放 0~16 個數字,最終我們要轉換成一個數字方塊,單獨創建一個類:

class Block(QLabel):
    """ 數字方塊 """
    def __init__(self, number):
        super().__init__()

        self.number = number
        self.setFixedSize(80, 80)

        # 設置字體
        font = QFont()
        font.setPointSize(30)
        font.setBold(True)
        self.setFont(font)

        # 設置字體顏色
        pa = QPalette()
        pa.setColor(QPalette.WindowText, Qt.white)
        self.setPalette(pa)

        # 設置文字位置
        self.setAlignment(Qt.AlignCenter)

        # 設置背景顏色\圓角和文本內容
        if self.number == 0:
            self.setStyleSheet("background-color:white;border-radius:10px;")
        else:
            self.setStyleSheet("background-color:red;border-radius:10px;")
            self.setText(str(self.number))

該類繼承自 QLablel ,初始化需要傳入一個參數 number ,number就是數字方塊上顯示的數字。

3.3 將數字轉換成方塊添加到布局

布局采用 QGridLayout 創建一個 4X4 的 self.gltMain,將16個 Block 添加到 self.gltMain:

def updatePanel(self):
    for row in range(4):
        for column in range(4):
            self.gltMain.addWidget(Block(self.blocks[row][column]), row, column)

    self.setLayout(self.gltMain)

3.4 初始化布局

初始化布局包括隨機數據的產生與將數字轉換成方塊添加到布局:

# 初始化布局
    def onInit(self):
        # 產生隨機數組,0 代表空的位置
        arr = range(16)
        self.numbers = random.sample(arr, 16)

        # 將數字方塊添加到布局
        for row in range(4):
            self.blocks.append([])
            for column in range(4):
                temp = self.numbers[row * 4 + column]

                if temp == 0:
                    self.zero_row = row
                    self.zero_column = column
                self.blocks[row].append(temp)
                self.gltMain.addWidget(Block(temp), row, column)

3.5 按鍵檢測

QWidget 有一個 keyPressEvent 事件句柄,我們只需要重新實現該方法即可:

# 檢測按鍵
def keyPressEvent(self, event):
    key = event.key()
    if(key == Qt.Key_Up or key == Qt.Key_W):
        self.move(Direction.UP)
    if(key == Qt.Key_Down or key == Qt.Key_S):
        self.move(Direction.DOWN)
    if(key == Qt.Key_Left or key == Qt.Key_A):
        self.move(Direction.LEFT)
    if(key == Qt.Key_Right or key == Qt.Key_D):
        self.move(Direction.RIGHT)
    self.updatePanel()
    if self.checkResult():
        if QMessageBox.Ok == QMessageBox.information(self, '挑戰結果', '恭喜您完成挑戰!'):
            self.onInit()

按鍵檢測到按鍵按下之后判斷該鍵值是否為 “↑↓←→”或“WSAD”,并作出相應的移動(move),移動之后刷新布局(updatePannel),最后檢測是否完成挑戰(checkResult),如果完成挑戰,彈出提示框。如果點擊了 OK 按鈕,游戲重新開始(onInit)。

3.6 試玩測試

至此,所有功能模塊介紹完畢,不要著急看完整代碼,我們先運行一下程序看是否還有 Bugs。

玩了幾局之后發現,并不是所有的局都能都還原,如下面這種情況:

如圖所示,14 和 15 方塊位置反了,無論如何也還原不聊了,這種情況是隨機出現的。到底是怎么回事呢?經過一番上網搜索,確實如果只有兩個數字的位置反了,無論如何也還原不了的。那這是由什么造成的呢?還記得我們的二維數組是怎么產生的吧,隨機的,也就是說可能會隨機到無法還原的情況。

如何避免這種情況呢?初始化數組時,所有的位置都是正確的數字,然后使用 move 進行移動打亂。

3.7 改進完善

由于前面已經將各個功能模塊單獨寫成了方法,因此我們只需修改 onInit 方法即可。

# 初始化布局
def onInit(self):
    # 產生順序數組
    self.numbers = list(range(1, 16))
    self.numbers.append(0)

    # 將數字添加到二維數組
    for row in range(4):
        self.blocks.append([])
        for column in range(4):
            temp = self.numbers[row * 4 + column]

            if temp == 0:
                self.zero_row = row
                self.zero_column = column
            self.blocks[row].append(temp)

    # 打亂數組
    for i in range(500):
        random_num = random.randint(0, 3)
        self.move(Direction(random_num))

    self.updatePanel()

先生成一個順序數組,里面保存著[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0],然后轉為二維數組 blocks,再后隨即移動500次,最后添加到布局。

4、完整代碼

import sys
import random
from enum import IntEnum
from PyQt5.QtWidgets import QLabel, QWidget, QApplication, QGridLayout, QMessageBox
from PyQt5.QtGui import QFont, QPalette
from PyQt5.QtCore import Qt

# 用枚舉類表示方向
class Direction(IntEnum):
    UP = 0
    DOWN = 1
    LEFT = 2
    RIGHT = 3


class NumberHuaRong(QWidget):
    """ 華容道主體 """
    def __init__(self):
        super().__init__()
        self.blocks = []
        self.zero_row = 0
        self.zero_column = 0
        self.gltMain = QGridLayout()

        self.initUI()

    def initUI(self):      
        # 設置方塊間隔
        self.gltMain.setSpacing(10)

        self.onInit()

        # 設置布局
        self.setLayout(self.gltMain)
        # 設置寬和高
        self.setFixedSize(400, 400)
        # 設置標題
        self.setWindowTitle('數字華容道')
        # 設置背景顏色
        self.setStyleSheet("background-color:gray;")
        self.show()

    # 初始化布局
    def onInit(self):
        # 產生順序數組
        self.numbers = list(range(1, 16))
        self.numbers.append(0)

        # 將數字添加到二維數組
        for row in range(4):
            self.blocks.append([])
            for column in range(4):
                temp = self.numbers[row * 4 + column]

                if temp == 0:
                    self.zero_row = row
                    self.zero_column = column
                self.blocks[row].append(temp)

        # 打亂數組
        for i in range(500):
            random_num = random.randint(0, 3)
            self.move(Direction(random_num))

        self.updatePanel()

    # 檢測按鍵
    def keyPressEvent(self, event):
        key = event.key()
        if(key == Qt.Key_Up or key == Qt.Key_W):
            self.move(Direction.UP)
        if(key == Qt.Key_Down or key == Qt.Key_S):
            self.move(Direction.DOWN)
        if(key == Qt.Key_Left or key == Qt.Key_A):
            self.move(Direction.LEFT)
        if(key == Qt.Key_Right or key == Qt.Key_D):
            self.move(Direction.RIGHT)
        self.updatePanel()
        if self.checkResult():
            if QMessageBox.Ok == QMessageBox.information(self, '挑戰結果', '恭喜您完成挑戰!'):
                self.onInit()

    # 方塊移動算法
    def move(self, direction):
        if(direction == Direction.UP): # 上
            if self.zero_row != 3:
                self.blocks[self.zero_row][self.zero_column] = self.blocks[self.zero_row + 1][self.zero_column]
                self.blocks[self.zero_row + 1][self.zero_column] = 0
                self.zero_row += 1
        if(direction == Direction.DOWN): # 下
            if self.zero_row != 0:
                self.blocks[self.zero_row][self.zero_column] = self.blocks[self.zero_row - 1][self.zero_column]
                self.blocks[self.zero_row - 1][self.zero_column] = 0
                self.zero_row -= 1
        if(direction == Direction.LEFT): # 左
            if self.zero_column != 3:
                self.blocks[self.zero_row][self.zero_column] = self.blocks[self.zero_row][self.zero_column + 1]
                self.blocks[self.zero_row][self.zero_column + 1] = 0
                self.zero_column += 1
        if(direction == Direction.RIGHT): # 右
            if self.zero_column != 0:
                self.blocks[self.zero_row][self.zero_column] = self.blocks[self.zero_row][self.zero_column - 1]
                self.blocks[self.zero_row][self.zero_column - 1] = 0
                self.zero_column -= 1

    def updatePanel(self):
        for row in range(4):
            for column in range(4):
                self.gltMain.addWidget(Block(self.blocks[row][column]), row, column)

        self.setLayout(self.gltMain)

    # 檢測是否完成
    def checkResult(self):
        # 先檢測最右下角是否為0
        if self.blocks[3][3] != 0:
            return False

        for row in range(4):
            for column in range(4):
                # 運行到此處說名最右下角已經為0,pass即可
                if row == 3 and column == 3:
                    pass
                #值是否對應
                elif self.blocks[row][column] != row * 4 + column + 1:
                    return False

        return True

class Block(QLabel):
    """ 數字方塊 """

    def __init__(self, number):
        super().__init__()

        self.number = number
        self.setFixedSize(80, 80)

        # 設置字體
        font = QFont()
        font.setPointSize(30)
        font.setBold(True)
        self.setFont(font)

        # 設置字體顏色
        pa = QPalette()
        pa.setColor(QPalette.WindowText, Qt.white)
        self.setPalette(pa)

        # 設置文字位置
        self.setAlignment(Qt.AlignCenter)

        # 設置背景顏色\圓角和文本內容
        if self.number == 0:
            self.setStyleSheet("background-color:white;border-radius:10px;")
        else:
            self.setStyleSheet("background-color:red;border-radius:10px;")
            self.setText(str(self.number))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = NumberHuaRong()
    sys.exit(app.exec_())

5、總結

在做的過程中遇到最大的坑就是隨機數組導致無法還原。另外在做這個游戲的時候我已經找到還原規律了,這樣在測試的時候可以做完完整測試,否則根本無法測試都挑戰成功那一步。

另外要對《最強大腦》做一下吐槽:這個項目根本就是有偏袒的,玩過的人會很快,沒有玩過的找規律的時間就很長。我在手機上玩4X4的最快還原用了 33 秒,對于該節目的冠軍(即便是玩過)很是敬仰。

到此這篇關于教你如何用python開發一款數字推盤小游戲的文章就介紹到這了,更多相關python開發數字推盤小游戲內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • python實現滑雪者小游戲
  • 教你用Python實現一個輪盤抽獎小游戲
  • python實現21點小游戲
  • 教你用Python寫一個植物大戰僵尸小游戲
  • python反編譯教程之2048小游戲實例
  • Python實現我的世界小游戲源代碼
  • Python實現簡單的2048小游戲
  • 基于Python-Pycharm實現的猴子摘桃小游戲(源代碼)
  • Python約瑟夫生者死者小游戲實例講解
  • 用Python實現童年貪吃蛇小游戲功能的實例代碼
  • 利用python制作拼圖小游戲的全過程
  • 利用python如何實現貓捉老鼠小游戲
  • 學會用Python實現滑雪小游戲,再也不用去北海道啦

標簽:股票 衡水 中山 江蘇 畢節 駐馬店 呼和浩特 湖州

巨人網絡通訊聲明:本文標題《教你如何用python開發一款數字推盤小游戲》,本文關鍵詞  教你,如,何用,python,開發,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《教你如何用python開發一款數字推盤小游戲》相關的同類信息!
  • 本頁收集關于教你如何用python開發一款數字推盤小游戲的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    色久优优欧美色久优优| 精品久久久影院| 久久精品国产亚洲5555| 国产蜜臀97一区二区三区| 91亚洲精品久久久蜜桃| 九九精品视频在线看| 一区二区欧美视频| 国产精品久久久久久久久免费丝袜 | 日本欧美一区二区在线观看| 欧美经典一区二区| 亚洲精品一区二区三区香蕉 | 日韩女优毛片在线| 欧美视频中文字幕| 欧美系列一区二区| 欧美最新大片在线看| 91在线视频播放地址| 成人午夜精品在线| 成人免费高清在线观看| 亚洲综合免费观看高清在线观看| 最好看的中文字幕久久| 中文字幕在线不卡一区| 亚洲成人av电影| 日本精品一级二级| 日韩一区二区中文字幕| 精品国产91亚洲一区二区三区婷婷| 亚洲国产一区二区三区| 一区二区三区日韩欧美精品| 亚洲视频在线一区二区| 伊人婷婷欧美激情| 亚洲午夜久久久久久久久久久| 一区二区理论电影在线观看| 亚洲成人tv网| 日韩精品免费专区| 久久爱www久久做| 国内精品在线播放| 国产成人免费在线观看| 91网站视频在线观看| 欧美日韩中文精品| 日韩三级精品电影久久久| 久久久久国产一区二区三区四区| 国产精品美女一区二区三区| 一区2区3区在线看| 狠狠色丁香久久婷婷综合_中 | 亚洲视频网在线直播| 亚洲最大成人综合| 精品亚洲欧美一区| 色综合久久中文综合久久牛| 中文字幕成人av| 五月天国产精品| 日产精品久久久久久久性色| 亚洲精品视频在线| 狠狠v欧美v日韩v亚洲ⅴ| 欧美精品aⅴ在线视频| a级精品国产片在线观看| 亚洲男人的天堂av| 亚洲日本成人在线观看| 99re8在线精品视频免费播放| 国产精品视频第一区| 欧美一区二区不卡视频| 欧美日韩一卡二卡三卡| 亚洲成av人片在www色猫咪| 国产麻豆成人精品| 中文字幕一区av| 欧美伊人久久久久久久久影院| 日韩综合一区二区| 精品久久久久99| 欧美精品一区二| 不卡一二三区首页| 亚洲三级在线观看| 成人av免费在线播放| 91精品91久久久中77777| 国产亚洲综合在线| 欧美日韩一区在线观看| 国产精品888| 国产精品久久久久久久久晋中| 欧美优质美女网站| 日本精品一区二区三区高清 | 国产精品亚洲视频| 国产成人综合网| 视频一区二区三区在线| 亚洲精品视频免费观看| 成人福利电影精品一区二区在线观看| 日本一二三四高清不卡| 粉嫩高潮美女一区二区三区 | 亚洲一区二区三区精品在线| 日本伦理一区二区| 国产精品乱码一区二区三区软件| 日韩一区有码在线| 国产午夜精品一区二区三区四区| 经典三级在线一区| 精品久久久久久综合日本欧美| 久久精品日产第一区二区三区高清版 | 老司机午夜精品| 欧美在线观看禁18| 亚洲欧美激情插| 成人免费黄色在线| 久久影院午夜论| 久久福利资源站| 欧美一区二区精品久久911| 亚洲午夜电影在线| 色拍拍在线精品视频8848| 最新不卡av在线| 972aa.com艺术欧美| 亚洲精品成人a在线观看| 国产专区欧美精品| 午夜欧美一区二区三区在线播放| wwwwxxxxx欧美| 狠狠色综合日日| 国产亚洲欧美一级| 不卡av在线网| 亚洲男同1069视频| 色噜噜夜夜夜综合网| 亚洲午夜免费福利视频| 欧美久久久影院| 亚洲影院免费观看| 日韩一区二区免费在线电影| 日韩不卡一区二区| 日本一区二区三区国色天香 | 日本高清不卡一区| 亚洲无人区一区| 欧美中文字幕不卡| 美女视频一区二区三区| 国产视频911| 欧美天天综合网| 日韩影院精彩在线| 91精品视频网| 国产一二精品视频| 亚洲精品久久7777| 欧美日韩国产欧美日美国产精品| 精品亚洲成a人在线观看| 日韩理论电影院| 678五月天丁香亚洲综合网| 五月天激情综合| 久久久久9999亚洲精品| 色国产综合视频| 国内久久精品视频| 色欧美乱欧美15图片| 国产毛片精品一区| 国产亚洲精品aa| 在线免费观看成人短视频| 国产在线观看免费一区| 欧美大片国产精品| 91精品中文字幕一区二区三区| 蜜桃传媒麻豆第一区在线观看| 亚洲日本va午夜在线影院| 日韩一级免费一区| 麻豆成人在线观看| 国产精品不卡视频| 久久综合九色综合久久久精品综合 | 亚洲视频小说图片| 日韩一区二区在线观看视频| 日韩影院在线观看| 日本午夜精品视频在线观看| 国产亚洲一区二区三区四区| 欧美在线999| 成人免费视频网站在线观看| 午夜电影久久久| 中文在线免费一区三区高中清不卡| 69堂精品视频| 99精品视频中文字幕| 久久成人麻豆午夜电影| 香蕉乱码成人久久天堂爱免费| 中文字幕一区二区在线观看| 欧美大胆人体bbbb| 欧美精品第1页| 欧美精品久久久久久久多人混战| 东方aⅴ免费观看久久av| 美女脱光内衣内裤视频久久网站 | 国产网站一区二区| 日韩一区二区三区视频在线观看| 国产精品一区二区三区网站| 久久99国产精品久久| 日本sm残虐另类| 依依成人综合视频| 亚洲欧美区自拍先锋| 国产丝袜在线精品| 久久综合狠狠综合久久激情| 欧美一区二区日韩一区二区| 91国偷自产一区二区开放时间| 99精品国产91久久久久久| www.99精品| 国产精品99久久久久| 裸体健美xxxx欧美裸体表演| 老鸭窝一区二区久久精品| 国内久久婷婷综合| 精品夜夜嗨av一区二区三区| 国产在线精品一区二区夜色 | 精品视频999| 欧美日韩国产综合草草| 在线综合视频播放| 欧美日韩亚州综合| 777xxx欧美| 久久伊人蜜桃av一区二区| 国产欧美一区二区精品性色超碰| 日韩天堂在线观看| 久久影院午夜片一区| 国产精品视频免费看| 欧美激情在线看| 一区二区高清免费观看影视大全| 日韩精品视频网站|