.. note::
こんにちは、SunFounderのRaspberry Pi & Arduino & ESP32愛好家コミュニティへようこそ!Facebook上でRaspberry Pi、Arduino、ESP32についてもっと深く掘り下げ、他の愛好家と交流しましょう。
**参加する理由は?**
- **エキスパートサポート**:コミュニティやチームの助けを借りて、販売後の問題や技術的な課題を解決します。
- **学び&共有**:ヒントやチュートリアルを交換してスキルを向上させましょう。
- **独占的なプレビュー**:新製品の発表や先行プレビューに早期アクセスしましょう。
- **特別割引**:最新製品の独占割引をお楽しみください。
- **祭りのプロモーションとギフト**:ギフトや祝日のプロモーションに参加しましょう。
👉 私たちと一緒に探索し、創造する準備はできていますか?[|link_sf_facebook|]をクリックして今すぐ参加しましょう!
.. _4.1.17_py_pi5:
4.1.14 ゲーム – 数当て
==============================
はじめに
------------------
数当ては、あなたと友達が交互に数字(0〜99)を入力する楽しいパーティーゲームです。数字の入力に従って、範囲は狭まっていき、プレイヤーが謎を正しく解答するまで続きます。その後、プレイヤーは負けて罰せられます。たとえば、幸運の数字が51で、プレイヤー1が50を入力した場合、数字の範囲は50〜99に変わります。プレイヤー2が70を入力すると、数字の範囲は50〜70になります。プレイヤー3が51を入力した場合、そのプレイヤーは不運です。ここでは、キーパッドを使用して数字を入力し、LCDを使用して結果を表示します。
必要な部品
------------------------------
このプロジェクトには、次のコンポーネントが必要です。
.. image:: ../python_pi5/img/4.1.17_game_guess_number_list.png
:width: 800
:align: center
一式を購入するのが便利です、こちらがリンクです:
.. list-table::
:widths: 20 20 20
:header-rows: 1
* - 名前
- このキットのアイテム
- リンク
* - Raphael Kit
- 337
- |link_Raphael_kit|
以下のリンクから別々に購入することもできます。
.. list-table::
:widths: 30 20
:header-rows: 1
* - コンポーネントの紹介
- 購入リンク
* - :ref:`cpn_gpio_board`
- |link_gpio_board_buy|
* - :ref:`cpn_breadboard`
- |link_breadboard_buy|
* - :ref:`cpn_wires`
- |link_wires_buy|
* - :ref:`cpn_resistor`
- |link_resistor_buy|
* - :ref:`cpn_keypad`
- \-
* - :ref:`cpn_i2c_lcd`
- |link_i2clcd1602_buy|
回路図
-----------------------
============ ======== ======== =======
T-Board Name physical wiringPi BCM
GPIO18 Pin 12 1 18
GPIO23 Pin 16 4 23
GPIO24 Pin 18 5 24
GPIO25 Pin 22 6 25
SPIMOSI Pin 19 12 10
GPIO22 Pin 15 3 22
GPIO27 Pin 13 2 27
GPIO17 Pin 11 0 17
SDA1 Pin 3 SDA1(8) SDA1(2)
SCL1 Pin 5 SCL1(9) SDA1(3)
============ ======== ======== =======
.. image:: ../python_pi5/img/4.1.17_game_guess_number_schematic.png
:align: center
実験手順
-----------------------------
**ステップ 1:** 回路を組み立てます。
.. image:: ../python_pi5/img/4.1.17_game_guess_number_circuit.png
**ステップ 2**: I2Cをセットアップします(詳細は :ref:`i2c_config` を参照)。
**ステップ 3**: ディレクトリを変更します。
.. raw:: html
.. code-block::
cd ~/raphael-kit/python-pi5
**ステップ 4**: 実行します。
.. raw:: html
.. code-block::
sudo python3 3.1.12_GAME_GuessNumber_zero.py
プログラムが実行されると、LCDに初期ページが表示されます:
.. code-block::
Welcome!
Press A to go!
'A'ボタンを押すと、ゲームが開始し、LCDにゲームページが表示されます。
.. code-block::
Enter number:
0 < point < 99
ランダムな数字 '‹point‹' がゲーム開始時に生成されますが、LCDには表示されません。必要なことは、それを推測することです。入力した数値は、最終的な計算が終了するまで、最初の行の末尾に表示されます(比較を開始するには 'D' を押し、入力された数値が **10** より大きい場合、自動的な比較が開始されます)。
'‹point‹' の数値範囲が2行目に表示されます。指定された範囲内で数値を入力する必要があります。数値を入力すると、範囲が狭まり、幸運か不運かにかかわらず、 ``当たりました!`` と表示されます。
.. note::
* エラー ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'`` が表示される場合、I2Cを有効にするには :ref:`i2c_config` を参照してください。
* エラー ``ModuleNotFoundError: No module named 'smbus2'`` が表示される場合、 ``sudo apt install python3-smbus2`` を実行してください。
* エラー ``OSError: [Errno 121] Remote I/O error`` が表示される場合、モジュールの接続が誤っているか、モジュールが壊れている可能性があります。
* コードと配線が正常であるにもかかわらず、LCDにコンテンツが表示されない場合は、背面のポテンショメーターを回してコントラストを上げることができます。
.. warning::
エラー メッセージ ``RuntimeError: Cannot determine SOC peripheral base address`` が表示された場合は、 :ref:`faq_soc` を参照してください。
**コード**
.. note::
以下のコードを **修正/リセット/コピー/実行/停止** することができます。ただし、その前に ``raphael-kit/python-pi5`` のソースコードパスに移動する必要があります。
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
from gpiozero import DigitalOutputDevice, Button
from time import sleep
import LCD1602
import random
class Keypad:
def __init__(self, rows_pins, cols_pins, keys):
"""
Initialize the keypad with specified row and column pins and key layout.
:param rows_pins: List of GPIO pins for the rows.
:param cols_pins: List of GPIO pins for the columns.
:param keys: Layout of keys on the keypad.
"""
self.rows = [DigitalOutputDevice(pin) for pin in rows_pins] # Setup row pins
self.cols = [Button(pin, pull_up=False) for pin in cols_pins] # Setup column pins
self.keys = keys # Define keypad layout
def read(self):
"""
Read and return the currently pressed keys.
:return: List of pressed keys.
"""
pressed_keys = []
for i, row in enumerate(self.rows):
row.on() # Activate current row
for j, col in enumerate(self.cols):
if col.is_pressed:
index = i * len(self.cols) + j
pressed_keys.append(self.keys[index]) # Append pressed key
row.off() # Deactivate row
return pressed_keys
# Game-related variables
count = 0
pointValue = 0
upper = 99
lower = 0
def setup():
"""
Setup function for initializing the keypad and LCD display.
"""
global keypad, last_key_pressed, keys
rowsPins = [18, 23, 24, 25]
colsPins = [10, 22, 27, 17]
keys = ["1", "2", "3", "A",
"4", "5", "6", "B",
"7", "8", "9", "C",
"*", "0", "#", "D"]
keypad = Keypad(rowsPins, colsPins, keys)
last_key_pressed = []
LCD1602.init(0x27, 1) # Initialize LCD
LCD1602.clear()
LCD1602.write(0, 0, 'Welcome!')
LCD1602.write(0, 1, 'Press A to Start!')
def init_new_value():
"""
Initialize a new target value and reset game parameters.
"""
global pointValue, upper, lower, count
pointValue = random.randint(0, 99)
upper = 99
lower = 0
count = 0
print('point is %d' % pointValue)
def detect_point():
"""
Check if the guessed number is the target, too high, or too low.
:return: 1 if correct guess, 0 otherwise.
"""
global count, upper, lower
if count > pointValue and count < upper:
upper = count
elif count < pointValue and count > lower:
lower = count
elif count == pointValue:
count = 0
return 1
count = 0
return 0
def lcd_show_input(result):
"""
Display the current game state and results on the LCD.
:param result: Result of the last guess (0 or 1).
"""
LCD1602.clear()
if result == 1:
LCD1602.write(0, 1, 'You have got it!')
sleep(5)
init_new_value()
lcd_show_input(0)
else:
LCD1602.write(0, 0, 'Enter number:')
LCD1602.write(13, 0, str(count))
LCD1602.write(0, 1, str(lower))
LCD1602.write(3, 1, ' < Point < ')
LCD1602.write(13, 1, str(upper))
def loop():
"""
Main game loop for handling keypad input and updating game state.
"""
global keypad, last_key_pressed, count
while True:
result = 0
pressed_keys = keypad.read()
if pressed_keys and pressed_keys != last_key_pressed:
if pressed_keys == ["A"]:
init_new_value()
lcd_show_input(0)
elif pressed_keys == ["D"]:
result = detect_point()
lcd_show_input(result)
elif pressed_keys[0] in keys:
if pressed_keys[0] in ["A", "B", "C", "D", "#", "*"]:
continue
count = count * 10 + int(pressed_keys[0])
if count >= 10:
result = detect_point()
lcd_show_input(result)
print(pressed_keys)
last_key_pressed = pressed_keys
sleep(0.1)
try:
setup()
loop()
except KeyboardInterrupt:
LCD1602.clear() # Clear LCD on interrupt
**コード説明**
#. GPIO Zeroライブラリからデジタル出力デバイスとボタンのための重要なクラスをインポートするセクションです。スクリプト内で遅延を導入するために、timeモジュールのsleep関数も含まれています。LCD1602ライブラリは、テキストやデータ出力を表示するために役立つLCDディスプレイの操作に利用されます。さらに、ランダムな数字を生成するための関数を提供するrandomライブラリも組み込まれています。これはプロジェクトのさまざまな面で有利になる可能性があります。
.. code-block:: python
#!/usr/bin/env python3
from gpiozero import DigitalOutputDevice, Button
from time import sleep
import LCD1602
import random
#. キーパッドのクラスを定義し、行と列のピンで初期化し、押されたキーを読み取るメソッドを定義します。
.. code-block:: python
class Keypad:
def __init__(self, rows_pins, cols_pins, keys):
"""
Initialize the keypad with specified row and column pins and key layout.
:param rows_pins: List of GPIO pins for the rows.
:param cols_pins: List of GPIO pins for the columns.
:param keys: Layout of keys on the keypad.
"""
self.rows = [DigitalOutputDevice(pin) for pin in rows_pins] # Setup row pins
self.cols = [Button(pin, pull_up=False) for pin in cols_pins] # Setup column pins
self.keys = keys # Define keypad layout
def read(self):
"""
Read and return the currently pressed keys.
:return: List of pressed keys.
"""
pressed_keys = []
for i, row in enumerate(self.rows):
row.on() # Activate current row
for j, col in enumerate(self.cols):
if col.is_pressed:
index = i * len(self.cols) + j
pressed_keys.append(self.keys[index]) # Append pressed key
row.off() # Deactivate row
return pressed_keys
#. ゲームに関連する変数 ``count`` をゼロとして初期化し、キーパッドとLCDディスプレイを設定し、ウェルカムメッセージと指示を表示します。ゲームでの特定のスコアや値を表す可能性がある ``pointValue`` 変数をゼロに初期化します。当初は99に設定された ``upper`` は、数字当てゲームの最大値として使用される可能性があります。ゲームの最小境界として使用される可能性のあるゼロからの ``lower`` 限界を設定します。
.. code-block:: python
# Game-related variables
count = 0
pointValue = 0
upper = 99
lower = 0
#. キーパッドとLCDディスプレイを設定し、ウェルカムメッセージと指示を表示します。
.. code-block:: python
def setup():
"""
Setup function for initializing the keypad and LCD display.
"""
global keypad, last_key_pressed, keys
rowsPins = [18, 23, 24, 25]
colsPins = [10, 22, 27, 17]
keys = ["1", "2", "3", "A",
"4", "5", "6", "B",
"7", "8", "9", "C",
"*", "0", "#", "D"]
keypad = Keypad(rowsPins, colsPins, keys)
last_key_pressed = []
LCD1602.init(0x27, 1) # Initialize LCD
LCD1602.clear()
LCD1602.write(0, 0, 'Welcome!')
LCD1602.write(0, 1, 'Press A to Start!')
#. 新しいターゲット値を初期化し、ゲームのパラメータをリセットします。
.. code-block:: python
def init_new_value():
"""
Initialize a new target value and reset game parameters.
"""
global pointValue, upper, lower, count
pointValue = random.randint(0, 99)
upper = 99
lower = 0
count = 0
print('point is %d' % pointValue)
#. 推測された数字がターゲットと一致するかどうかをチェックし、それに応じて推測範囲を更新します。
.. code-block:: python
def detect_point():
"""
Check if the guessed number is the target, too high, or too low.
:return: 1 if correct guess, 0 otherwise.
"""
global count, upper, lower
if count > pointValue and count < upper:
upper = count
elif count < pointValue and count > lower:
lower = count
elif count == pointValue:
count = 0
return 1
count = 0
return 0
#. LCDにゲームの状態を表示し、現在の推測、範囲、結果を示します。
.. code-block:: python
def lcd_show_input(result):
"""
Display the current game state and results on the LCD.
:param result: Result of the last guess (0 or 1).
"""
LCD1602.clear()
if result == 1:
LCD1602.write(0, 1, 'You have got it!')
sleep(5)
init_new_value()
lcd_show_input(0)
else:
LCD1602.write(0, 0, 'Enter number:')
LCD1602.write(13, 0, str(count))
LCD1602.write(0, 1, str(lower))
LCD1602.write(3, 1, ' < Point < ')
LCD1602.write(13, 1, str(upper))
#. キーパッド入力の処理、ゲームの状態の更新、LCDへの結果の表示を行うメインループです。
.. code-block:: python
def loop():
"""
Main game loop for handling keypad input and updating game state.
"""
global keypad, last_key_pressed, count
while True:
result = 0
pressed_keys = keypad.read()
if pressed_keys and pressed_keys != last_key_pressed:
if pressed_keys == ["A"]:
init_new_value()
lcd_show_input(0)
elif pressed_keys == ["D"]:
result = detect_point()
lcd_show_input(result)
elif pressed_keys[0] in keys:
if pressed_keys[0] in ["A", "B", "C", "D", "#", "*"]:
continue
count = count * 10 + int(pressed_keys[0])
if count >= 10:
result = detect_point()
lcd_show_input(result)
print(pressed_keys)
last_key_pressed = pressed_keys
sleep(0.1)
#. セットアップを実行し、メインゲームループに入ります。キーボード割り込みを使用してクリーンな終了が可能です。
.. code-block:: python
try:
setup()
loop()
except KeyboardInterrupt:
LCD1602.clear() # Clear LCD on interrupt