どのようにpythonを使ってデジタルプッシュボードを開発するかを教えます。
今年の初めに、新シーズンの『最強脳』がスタートしました。第1話の選抜時にみんなでデジタルゲームを作って、『デジタル華容道』と言いました。当時、何計画君は二十数秒の成績でこのプロジェクトの優勝を獲得しました。このゲームを見てから、『デジタル華容道』のプログラムを書くことにしました。今日は実現します。
デジタルディスクゲーム(n-puzle)は知的ゲームで、よくあるタイプは十五数字のプッシュボードゲームと八数字のプッシュボードゲームなどがあります。十五の数字のプッシュ・ボードには十五の正方形と一つの大きさが正方形に相当する空席があります。15の数字が順番に並べられ、最後の格子が空席であるときは挑戦成功を表します。
本論文ではPyQt 5を用いて設計と実現を行い、PyQt 5はこのプログラムの提示方式であり、最も重要なのはアルゴリズムであり、アルゴリズムを習得し、PyGameまたはTkinterを用いて実現できる。
PyQt 5インストール:
システム:Windows 10 64ビットPythonバージョン:3.6
1、レイアウト設計
簡単版の数字華容道を作って、レイアウトの設計は図の通りです。
図中の灰色の部分はゲーム全体のキャリアとしてQWidgetを使用している。黄色の部分はQGridLayoutを数字の四角形のレイアウトとして使用します。赤い部分はQLabelを数字のブロックとして使用します。
2、アルゴリズムの設計
上の図に示すように、このゲームは全部で15個のブロックが必要です。各ブロックは一つの数字を表しています。ブロック上の数字を記憶するために二次元リストを使用することができる。4 x 4のリストを作成します。0は空の位置を表します。
2.1配列を作成して初期化する配列を作成する方法: は、長さ16の配列を作成し、対応する位置に0〜15を保存している。シャッフル
前の数字位置を左図のように移動すると、左矢印を押すと、右図のようになります。
(1,2)と(1,3)の2つの位置の数字が入れ替わります。すなわち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)位置の配列が入れ替わります。 移動アルゴリズムを一つの関数としてカプセル化します。
勝利するかどうかを測定するのは簡単です。前の15の位置はそれぞれ対応しています。最後の1つは0で勝利します。しかし、不必要な計算を避けるために、最後の1つは0ですか?具体的なコードは以下の通り実現されます。
以下、すべての機能モジュールの実装について説明します。
3.1フレーム構築
QWidgetをゲーム全体のキャリヤーとして作成します。
3.2デジタルブロックの実装
前に述べたように、2次元の配列で0〜16個の数字を保存します。最終的には数字のブロックに変換して、単独でクラスを作成します。
3.3数字を四角に変換してレイアウトに追加する
レイアウトはQGridLayoutを採用して4 X 4のself.gltMainを作成し、16のBlockをself.gltMainに追加します。
初期化レイアウトは、ランダムデータの生成と、数値をブロックに変換してレイアウトに追加することを含む。
QWidgetにはkeyPresEventイベントのハンドルがあります。この方法を再実現するだけでいいです。
3.6試遊テスト
ここで、すべての機能モジュールの紹介が終わりました。コードを早く見ないでください。まずプログラムを実行して、Bugsがあるかどうかを確認します。
何ゲームか遊んだら、すべてのゲームが元に戻るというわけではないです。
図に示すように、14と15の正方形の位置が逆になり、どうしても話が元に戻りました。この場合はランダムに発生します。いったいどういうことですか?インターネットで検索したら、確かに2つの数字だけの位置が逆になったら、どうしても元に戻りません。これは何によるものですか?私たちの二次元配列はどうやって作られたのか覚えています。ランダムで、つまり元に戻らない場合にランダムになるかもしれません。
このような状況を避けるにはどうすればいいですか?配列を初期化する時、すべての位置は正しい数字です。そしてmoveを使って移動シャッフルします。
3.7改善と改善
前に各機能モジュールを単独で作成しましたので、onInitメソッドを修正すればいいです。
4、完全コード
作っている間に最大のピットがランダム配列で復元できなくなります。また、このゲームをする時、私はもう復元の法則を見つけました。このようにテストの時には完全なテストができます。そうしないとテストができないです。
また、「最強脳」に対して、このプロジェクトはもともとひいきがあります。遊んだことがある人はすぐにできます。遊んだことがない人は法則を探す時間が長くなります。私は携帯で4 X 4を一番早く再現して33秒使っていますが、この番組の優勝(遊んだことがあります)にはとても尊敬しています。
ここでは、pythonを使ってデジタルのプッシュボードゲームを開発する方法についての記事を紹介します。pythonの開発に関するデジタルのプッシュボードゲームの内容については、以前の文章を検索したり、次の関連記事を見たりしてください。これからもよろしくお願いします。
デジタルディスクゲーム(n-puzle)は知的ゲームで、よくあるタイプは十五数字のプッシュボードゲームと八数字のプッシュボードゲームなどがあります。十五の数字のプッシュ・ボードには十五の正方形と一つの大きさが正方形に相当する空席があります。15の数字が順番に並べられ、最後の格子が空席であるときは挑戦成功を表します。
本論文ではPyQt 5を用いて設計と実現を行い、PyQt 5はこのプログラムの提示方式であり、最も重要なのはアルゴリズムであり、アルゴリズムを習得し、PyGameまたはTkinterを用いて実現できる。
PyQt 5インストール:
pip install PyQt5
本論文の使用環境:システム:Windows 10 64ビットPythonバージョン:3.6
1、レイアウト設計
簡単版の数字華容道を作って、レイアウトの設計は図の通りです。
図中の灰色の部分はゲーム全体のキャリアとしてQWidgetを使用している。黄色の部分はQGridLayoutを数字の四角形のレイアウトとして使用します。赤い部分はQLabelを数字のブロックとして使用します。
2、アルゴリズムの設計
上の図に示すように、このゲームは全部で15個のブロックが必要です。各ブロックは一つの数字を表しています。ブロック上の数字を記憶するために二次元リストを使用することができる。4 x 4のリストを作成します。0は空の位置を表します。
2.1配列を作成して初期化する
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)の2つの位置の数字が入れ替わります。すなわち0と8が入れ替わります。右の図に示すようにもう一度左の矢印を押すと、すべての数字は変わりません。数字0は右の数がないからです。
まとめてみます。数字0の位置が(row、column)で、そしてcolumn≠3であれば左矢印を押した後、(row、column)と(row、column+1)の位置の配列が入れ替わります。
#
# 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の位置はそれぞれ対応しています。最後の1つは0で勝利します。しかし、不必要な計算を避けるために、最後の1つは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デジタルブロックの実装
前に述べたように、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))
このクラスはQLableから継承され、初期化には一つのパラメータnumberに入る必要があります。numberは数字のブロックに表示される数字です。3.3数字を四角に変換してレイアウトに追加する
レイアウトはQGridLayoutを採用して4 X 4の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にはkeyPresEventイベントのハンドルがあります。この方法を再実現するだけでいいです。
#
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」かどうかを判断し、それに応じて移動し、移動してレイアウトを更新し、最後に挑戦が完了したかを検出し、挑戦が完了したら、ティーチングボックスをポップアップします。OKボタンをクリックしたら、ゲームを再開します。3.6試遊テスト
ここで、すべての機能モジュールの紹介が終わりました。コードを早く見ないでください。まずプログラムを実行して、Bugsがあるかどうかを確認します。
何ゲームか遊んだら、すべてのゲームが元に戻るというわけではないです。
図に示すように、14と15の正方形の位置が逆になり、どうしても話が元に戻りました。この場合はランダムに発生します。いったいどういうことですか?インターネットで検索したら、確かに2つの数字だけの位置が逆になったら、どうしても元に戻りません。これは何によるものですか?私たちの二次元配列はどうやって作られたのか覚えています。ランダムで、つまり元に戻らない場合にランダムになるかもしれません。
このような状況を避けるにはどうすればいいですか?配列を初期化する時、すべての位置は正しい数字です。そして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、まとめ作っている間に最大のピットがランダム配列で復元できなくなります。また、このゲームをする時、私はもう復元の法則を見つけました。このようにテストの時には完全なテストができます。そうしないとテストができないです。
また、「最強脳」に対して、このプロジェクトはもともとひいきがあります。遊んだことがある人はすぐにできます。遊んだことがない人は法則を探す時間が長くなります。私は携帯で4 X 4を一番早く再現して33秒使っていますが、この番組の優勝(遊んだことがあります)にはとても尊敬しています。
ここでは、pythonを使ってデジタルのプッシュボードゲームを開発する方法についての記事を紹介します。pythonの開発に関するデジタルのプッシュボードゲームの内容については、以前の文章を検索したり、次の関連記事を見たりしてください。これからもよろしくお願いします。