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 [Ici] et rejoignez-nous aujourd’hui !

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.

../_images/4.1.17_game_guess_number_list.png

Il est certainement pratique d’acheter un kit complet, voici le lien :

Nom

ARTICLES DANS CE KIT

LIEN

Kit Raphael

337

Raphael Kit

Vous pouvez également les acheter séparément via les liens ci-dessous.

INTRODUCTION DU COMPOSANT

LIEN D’ACHAT

Carte d’extension GPIO

ACHETER

Plaque d’expérimentation (Breadboard)

ACHETER

Fils de Liaison

ACHETER

Résistance

ACHETER

Clavier

-

LCD1602 I2C

ACHETER

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)

../_images/4.1.17_game_guess_number_schematic.png

Procédures expérimentales

Étape 1 : Construire le circuit.

../_images/4.1.17_game_guess_number_circuit.png

Étape 2 : Configurer I2C (voir Configuration I²C.)

Étape 3 : Changer de répertoire.

cd ~/raphael-kit/python-pi5

Étape 4 : Exécuter.

sudo python3 4.1.17_GAME_GuessNumber_zero.py

Après l’exécution du programme, la page initiale s’affiche sur le LCD :

Bienvenue !
Appuyez sur A pour commencer !

Appuyez sur ‘A’, et le jeu commencera et la page du jeu apparaîtra sur le LCD.

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 Configuration I²C 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.

Avertissement

Si vous recevez le message d’erreur RuntimeError: Cannot determine SOC peripheral base address, veuillez consulter Si « gpiozero » ne fonctionne pas.

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.

#!/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

  1. 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.

    #!/usr/bin/env python3
    
    from gpiozero import DigitalOutputDevice, Button
    from time import sleep
    import LCD1602
    import random
    
  2. 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.

    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
    
  3. 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.

    # Game-related variables
    count = 0
    pointValue = 0
    upper = 99
    lower = 0
    
  4. Configure le clavier et l’affichage LCD, affichant un message de bienvenue et des instructions.

    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!')
    
  5. Initialise une nouvelle valeur cible pour le jeu et réinitialise les paramètres du jeu.

    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)
    
  6. Vérifie si le numéro deviné correspond à la cible et met à jour la plage de devinettes en conséquence.

    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
    
  7. Affiche l’état du jeu sur l’écran LCD, montrant la devinette actuelle, la plage et le résultat.

    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))
    
  8. 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.

    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)
    
  9. Lance la configuration et entre dans la boucle principale du jeu, permettant une sortie propre à l’aide d’une interruption du clavier.

    try:
       setup()
       loop()
    except KeyboardInterrupt:
       LCD1602.clear()  # Clear LCD on interrupt