.. note::
Bonjour et bienvenue dans la Communauté Facebook des passionnés de Raspberry Pi, Arduino et ESP32 de SunFounder ! Plongez plus profondément dans l'univers des Raspberry Pi, Arduino et ESP32 avec d'autres passionnés.
**Pourquoi rejoindre ?**
- **Support d'experts** : Résolvez les problèmes après-vente et les défis techniques avec l'aide de notre communauté et de notre équipe.
- **Apprendre et partager** : Échangez des astuces et des tutoriels pour améliorer vos compétences.
- **Aperçus exclusifs** : Accédez en avant-première aux annonces de nouveaux produits et aux aperçus.
- **Réductions spéciales** : Profitez de réductions exclusives sur nos produits les plus récents.
- **Promotions festives et cadeaux** : Participez à des cadeaux et des promotions de vacances.
👉 Prêt à explorer et à créer avec nous ? Cliquez [|link_sf_facebook|] et rejoignez-nous aujourd'hui !
.. _4.1.17_py_pi5:
4.1.14 JEU - Devinez le Nombre
==============================
Introduction
------------------
« Devinez le Nombre » est un jeu de fête amusant où vous et vos amis vous
relayez pour saisir un nombre (0 à 99). La plage de nombres se réduit à
chaque saisie jusqu'à ce qu'un joueur résolve l'énigme correctement. Alors,
ce joueur est déclaré perdant et subit une pénalité. Par exemple, si le
nombre chanceux est 51, que les joueurs ne peuvent pas voir, et que le joueur ①
saisit 50, l'indication de la plage de nombres change pour 50~99 ; si le joueur ②
saisit 70, la plage de nombres devient 50~70 ; si le joueur ③ saisit 51, ce joueur
est le malchanceux. Ici, nous utilisons un clavier pour entrer les nombres et un LCD pour
afficher les résultats.
Composants nécessaires
------------------------------
Pour ce projet, nous avons besoin des composants suivants.
.. image:: ../python_pi5/img/4.1.17_game_guess_number_list.png
:width: 800
:align: center
Il est certainement pratique d'acheter un kit complet, voici le lien :
.. list-table::
:widths: 20 20 20
:header-rows: 1
* - Nom
- ARTICLES DANS CE KIT
- LIEN
* - Kit Raphael
- 337
- |link_Raphael_kit|
Vous pouvez également les acheter séparément via les liens ci-dessous.
.. list-table::
:widths: 30 20
:header-rows: 1
* - INTRODUCTION DU COMPOSANT
- LIEN D'ACHAT
* - :ref:`cpn_gpio_extension_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|
Schéma
-----------------------
============ ======== ======== =======
Nom T-Board physique 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
Procédures expérimentales
-----------------------------
**Étape 1 :** Construire le circuit.
.. image:: ../python_pi5/img/4.1.17_game_guess_number_circuit.png
**Étape 2 :** Configurer I2C (voir :ref:`i2c_config`.)
**Étape 3 :** Changer de répertoire.
.. raw:: html
.. code-block::
cd ~/raphael-kit/python-pi5
**Étape 4 :** Exécuter.
.. raw:: html
.. code-block::
sudo python3 4.1.17_GAME_GuessNumber_zero.py
Après l'exécution du programme, la page initiale s'affiche sur le LCD :
.. code-block::
Bienvenue !
Appuyez sur A pour commencer !
Appuyez sur ‘A’, et le jeu commencera et la page du jeu apparaîtra sur le
LCD.
.. code-block::
Entrez le nombre :
0 < point < 99
Un nombre aléatoire ‘\ **point**\ ’ est produit mais non affiché sur le LCD
au début du jeu, et ce que vous devez faire est de le deviner. Le nombre
que vous avez tapé apparaît à la fin de la première ligne jusqu'à ce que le
calcul final soit terminé. (Appuyez sur ‘D’ pour démarrer la comparaison, et si le
nombre entré est supérieur à **10**, la comparaison automatique
commencera.)
La plage de nombres de ‘point’ est affichée sur la deuxième ligne. Et vous
devez taper le nombre dans cette plage. Lorsque vous tapez un nombre, la plage
se rétrécit ; si vous obtenez le nombre chanceux par chance ou malchance, il
apparaîtra « Vous l'avez trouvé ! »
.. note::
* Si vous rencontrez l'erreur ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'``, vous devez consulter :ref:`i2c_config` pour activer l'I2C.
* Si l'erreur ``ModuleNotFoundError: No module named 'smbus2'`` apparaît, veuillez exécuter ``sudo apt install python3-smbus2``.
* Si l'erreur ``OSError: [Errno 121] Remote I/O error`` survient, cela signifie que le module est mal câblé ou que le module est défectueux.
* Si le câblage et le code sont corrects, mais que l'écran LCD n'affiche toujours pas de contenu, vous pouvez tourner le potentiomètre à l'arrière pour augmenter le contraste.
.. warning::
Si vous recevez le message d'erreur ``RuntimeError: Cannot determine SOC peripheral base address``, veuillez consulter :ref:`faq_soc`
**Code**
.. note::
Vous pouvez **modifier/réinitialiser/copier/exécuter/arrêter** le code ci-dessous. Mais avant cela, vous devez vous rendre au chemin du code source comme ``raphael-kit/python-pi5``. Après modification du code, vous pouvez l'exécuter directement pour voir l'effet.
.. 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
**Explication du code**
#. Cette section importe les classes essentielles de la bibliothèque GPIO Zero pour gérer les dispositifs de sortie numérique et les boutons. Elle inclut également la fonction sleep du module time pour introduire des délais dans le script. La bibliothèque LCD1602 est importée pour l'opération de l'affichage LCD, utile pour afficher des textes ou des sorties de données. De plus, la bibliothèque random est incorporée, offrant des fonctions pour générer des nombres aléatoires, ce qui peut être avantageux pour divers aspects du projet.
.. code-block:: python
#!/usr/bin/env python3
from gpiozero import DigitalOutputDevice, Button
from time import sleep
import LCD1602
import random
#. Définit une classe pour le clavier, l'initialisant avec des broches de rangées et de colonnes et définissant une méthode pour lire les touches pressées.
.. 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
#. Initialise une variable ``count`` à zéro, potentiellement utilisée pour suivre les tentatives ou des valeurs spécifiques dans le jeu. Configure le clavier et l'affichage LCD avec un message de bienvenue et des instructions. Initialise la variable ``pointValue`` à zéro, représentant potentiellement un score ou une valeur cible dans le jeu. Définit une limite ``upper`` pour le jeu, initialement fixée à 99, ce qui pourrait être le maximum dans un jeu de devinettes numériques. Définit la limite ``lower`` à partir de zéro, probablement utilisée comme borne minimale dans le jeu.
.. code-block:: python
# Game-related variables
count = 0
pointValue = 0
upper = 99
lower = 0
#. Configure le clavier et l'affichage LCD, affichant un message de bienvenue et des instructions.
.. 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!')
#. Initialise une nouvelle valeur cible pour le jeu et réinitialise les paramètres du jeu.
.. 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)
#. Vérifie si le numéro deviné correspond à la cible et met à jour la plage de devinettes en conséquence.
.. 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
#. Affiche l'état du jeu sur l'écran LCD, montrant la devinette actuelle, la plage et le résultat.
.. 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))
#. La boucle principale pour gérer l'entrée du clavier, mettre à jour l'état du jeu et afficher les résultats sur l'écran 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)
#. Lance la configuration et entre dans la boucle principale du jeu, permettant une sortie propre à l'aide d'une interruption du clavier.
.. code-block:: python
try:
setup()
loop()
except KeyboardInterrupt:
LCD1602.clear() # Clear LCD on interrupt