.. note::
Ciao, benvenuto nella SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community su Facebook! Unisciti a noi per approfondire l'uso di Raspberry Pi, Arduino ed ESP32 insieme ad altri appassionati.
**Perché Unirsi?**
- **Supporto Esperto**: Risolvi i problemi post-vendita e le sfide tecniche con l'aiuto della nostra comunità e del nostro team.
- **Impara e Condividi**: Scambia suggerimenti e tutorial per migliorare le tue competenze.
- **Anteprime Esclusive**: Ottieni accesso anticipato alle novità sui prodotti e anteprime esclusive.
- **Sconti Speciali**: Goditi sconti esclusivi sui nostri prodotti più recenti.
- **Promozioni Festive e Omaggi**: Partecipa a promozioni speciali e omaggi durante le festività.
👉 Pronto a esplorare e creare con noi? Clicca [|link_sf_facebook|] e unisciti oggi stesso!
.. _py_pi5_guess_num:
3.1.12 GIOCO – Indovina il Numero
=====================================
Introduzione
------------------
"Indovina il Numero" è un gioco divertente da fare in gruppo: i giocatori
inseriscono a turno un numero (da 0 a 99). Ad ogni tentativo, l’intervallo
di ricerca si riduce fino a quando qualcuno indovina il numero giusto. Il
giocatore che indovina perde e viene "punito". Per esempio, se il numero
misterioso è 51, ma i giocatori non lo sanno, e il giocatore ① inserisce 50,
il messaggio mostrerà l’intervallo aggiornato a 50~99; se il giocatore ②
inserisce 70, l’intervallo diventa 50~70; se il giocatore ③ inserisce 51,
è lui a perdere. In questo progetto, useremo un tastierino per inserire i
numeri e un LCD per mostrare i risultati.
Componenti Necessari
------------------------------
In questo progetto, ci servono i seguenti componenti.
.. image:: ../python_pi5/img/4.1.17_game_guess_number_list.png
:width: 800
:align: center
.. È sicuramente conveniente acquistare un kit completo, ecco il link:
.. .. list-table::
.. :widths: 20 20 20
.. :header-rows: 1
.. * - Nome
.. - ARTICOLI NEL KIT
.. - LINK
.. * - Raphael Kit
.. - 337
.. - |link_Raphael_kit|
.. Puoi anche acquistarli singolarmente dai link sottostanti.
.. .. list-table::
.. :widths: 30 20
.. :header-rows: 1
.. * - INTRODUZIONE AI COMPONENTI
.. - LINK ACQUISTO
.. * - :ref:`gpio_extension_board`
.. - |link_gpio_board_buy|
.. * - :ref:`breadboard`
.. - |link_breadboard_buy|
.. * - :ref:`wires`
.. - |link_wires_buy|
.. * - :ref:`resistor`
.. - |link_resistor_buy|
.. * - :ref:`keypad`
.. - \-
.. * - :ref:`i2c_lcd1602`
.. - |link_i2clcd1602_buy|
Schema del Circuito
------------------------
============ ======== ======== =======
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
Procedure Sperimentali
-----------------------------
**Passo 1:** Monta il circuito.
.. image:: ../python_pi5/img/4.1.17_game_guess_number_circuit.png
**Passo 2**: Configura l’I2C (vedi :ref:`i2c_config`).
**Passo 3**: Cambia directory.
.. raw:: html
.. code-block::
cd ~/davinci-kit-for-raspberry-pi/python-pi5
**Passo 4**: Avvia il programma.
.. raw:: html
.. code-block::
sudo python3 3.1.12_GAME_GuessNumber.py
Dopo l'avvio del programma, sull'LCD comparirà la schermata iniziale:
.. code-block::
Welcome!
Press A to go!
Premi 'A' per iniziare il gioco e apparirà la schermata di gioco sul LCD.
.. code-block::
Enter number:
0 ‹point‹ 99
Quando il gioco inizia, viene generato un numero casuale “\ **point**\ ”, ma
non viene mostrato sull'LCD. Il tuo compito è indovinare questo numero. Il
numero che inserisci appare alla fine della prima riga fino a quando il
confronto non viene effettuato. (Premi 'D' per avviare il confronto; se il
numero inserito è maggiore di **10**, il confronto avverrà automaticamente.)
L'intervallo del numero “point” è mostrato sulla seconda riga. Devi inserire il
numero entro questo intervallo. Ogni tentativo riduce l'intervallo; se indovini
il numero, comparirà “You've got it!”
.. note::
* Se ricevi l'errore ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'``, consulta la sezione :ref:`i2c_config` per abilitare l’I2C.
* Se ricevi l'errore ``ModuleNotFoundError: No module named 'smbus2'``, esegui il comando ``sudo apt install python3-smbus2``.
* Se appare l'errore ``OSError: [Errno 121] Remote I/O error``, significa che il modulo è cablato male o difettoso.
* Se il codice e i collegamenti sono corretti ma l'LCD non visualizza contenuti, regola il contrasto con il potenziometro sul retro.
.. warning::
Se appare il messaggio di errore ``RuntimeError: Cannot determine SOC peripheral base address``, consulta :ref:`faq_soc`
**Codice**
.. note::
Puoi **Modificare/Resettare/Copiare/Eseguire/Fermare** il codice qui sotto. Prima di fare ciò, però, è necessario accedere al percorso del codice sorgente come ``davinci-kit-for-raspberry-pi/python-pi5``. Dopo aver modificato il codice, puoi eseguirlo direttamente per vedere l'effetto.
.. 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] # Configura i pin delle righe
self.cols = [Button(pin, pull_up=False) for pin in cols_pins] # Configura i pin delle colonne
self.keys = keys # Definisci il layout del tastierino
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() # Attiva la riga corrente
for j, col in enumerate(self.cols):
if col.is_pressed:
index = i * len(self.cols) + j
pressed_keys.append(self.keys[index]) # Aggiungi il tasto premuto
row.off() # Disattiva la riga
return pressed_keys
# Variabili relative al gioco
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) # Inizializza 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() # Pulisci l'LCD in caso di interruzione
**Spiegazione del Codice**
#. Questa sezione importa le classi essenziali dalla libreria GPIO Zero per gestire dispositivi di output digitale e pulsanti. Include anche la funzione sleep dal modulo time per introdurre ritardi nello script. La libreria LCD1602 è importata per gestire il display LCD, utile per mostrare testi o dati di output. Inoltre, viene importata la libreria random, utile per generare numeri casuali, vantaggiosa per vari aspetti del progetto.
.. code-block:: python
#!/usr/bin/env python3
from gpiozero import DigitalOutputDevice, Button
from time import sleep
import LCD1602
import random
#. Definisce una classe per il tastierino, inizializzandolo con i pin di riga e colonna e definendo un metodo per leggere i tasti premuti.
.. 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] # Configura i pin delle righe
self.cols = [Button(pin, pull_up=False) for pin in cols_pins] # Configura i pin delle colonne
self.keys = keys # Definisce il layout del tastierino
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() # Attiva la riga corrente
for j, col in enumerate(self.cols):
if col.is_pressed:
index = i * len(self.cols) + j
pressed_keys.append(self.keys[index]) # Aggiungi il tasto premuto
row.off() # Disattiva la riga
return pressed_keys
#. Inizializza una variabile ``count`` a zero, usata potenzialmente per tracciare i tentativi o valori specifici nel gioco. Configura il tastierino e il display LCD con un messaggio di benvenuto e le istruzioni. Inizializza la variabile ``pointValue`` a zero, probabilmente rappresentante un valore o un punteggio obiettivo. Definisce un limite ``upper`` per il gioco, inizialmente impostato a 99, che potrebbe essere il massimo in un gioco di indovinare i numeri. Imposta il limite ``lower`` a zero, probabilmente utilizzato come limite minimo nel gioco.
.. code-block:: python
# Variabili di gioco
count = 0
pointValue = 0
upper = 99
lower = 0
#. Configura il tastierino e il display LCD, mostrando un messaggio di benvenuto e le istruzioni.
.. 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) # Inizializza LCD
LCD1602.clear()
LCD1602.write(0, 0, 'Welcome!')
LCD1602.write(0, 1, 'Press A to Start!')
#. Inizializza un nuovo valore target per il gioco e reimposta i parametri di gioco.
.. 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)
#. Controlla se il numero indovinato corrisponde al target e aggiorna di conseguenza l'intervallo di tentativi.
.. 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
#. Mostra lo stato del gioco sul display LCD, visualizzando il tentativo corrente, l'intervallo e il risultato.
.. 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))
#. Ciclo principale per gestire l'input del tastierino, aggiornare lo stato del gioco e visualizzare i risultati sul display 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)
#. Esegue il setup ed entra nel ciclo principale del gioco, permettendo un'uscita pulita utilizzando un'interruzione della tastiera.
.. code-block:: python
try:
setup()
loop()
except KeyboardInterrupt:
LCD1602.clear() # Pulisci LCD in caso di interruzione