.. note::

    Ciao, benvenuto nella Community di appassionati di Raspberry Pi, Arduino e ESP32 di SunFounder su Facebook! Approfondisci il mondo di Raspberry Pi, Arduino e ESP32 insieme ad altri appassionati.

    **Perché unirsi?**

    - **Supporto esperto**: Risolvi problemi post-vendita e sfide tecniche con l'aiuto della nostra community e del nostro team.
    - **Impara & Condividi**: Scambia consigli e tutorial per migliorare le tue competenze.
    - **Anteprime esclusive**: Ottieni accesso anticipato agli annunci di nuovi prodotti e anteprime.
    - **Sconti speciali**: Approfitta di sconti esclusivi sui nostri prodotti più recenti.
    - **Promozioni festive e giveaway**: Partecipa a giveaway e promozioni festive.

    👉 Pronto per esplorare e creare con noi? Clicca [|link_sf_facebook|] e unisciti oggi stesso!

.. _4.1.17_py:

4.1.17 GIOCO – Indovina il Numero
==============================================

Introduzione
------------------

"Indovina il Numero" è un gioco divertente da fare in gruppo, in cui tu e i 
tuoi amici vi alterniate nell'inserire un numero (0~99). L'intervallo numerico 
si riduce con l'inserimento del numero finché un giocatore non indovina correttamente 
l'enigma. Allora il giocatore viene sconfitto e punito. Ad esempio, se il numero 
fortunato è 51, che i giocatori non possono vedere, e il giocatore ① inserisce 50, 
l'intervallo numerico cambia a 50~99; se il giocatore ② inserisce 70, l'intervallo 
numerico diventa 50~70; se il giocatore ③ inserisce 51, questo giocatore è il 
"sfortunato". Qui utilizziamo il tastierino per inserire i numeri e l'LCD per 
mostrare i risultati.

Componenti Necessari
------------------------------

In questo progetto, ci servono i seguenti componenti.

.. image:: ../img/list_GAME_Guess_Number.png
    :align: center

È sicuramente conveniente acquistare un intero kit, ecco il link: 

.. list-table::
    :widths: 20 20 20
    :header-rows: 1

    *   - Nome	
        - ELEMENTI IN QUESTO KIT
        - LINK
    *   - Raphael Kit
        - 337
        - |link_Raphael_kit|

Puoi anche acquistarli separatamente dai link qui sotto.

.. list-table::
    :widths: 30 20
    :header-rows: 1

    *   - INTRODUZIONE COMPONENTE
        - LINK DI ACQUISTO

    *   - :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|

Schema Elettrico
-----------------------

============ ======== ======== =======
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:: ../img/Schematic_three_one12.png
   :align: center

Procedure Sperimentali
-----------------------------

**Passo 1:** Costruisci il circuito.

.. image:: ../img/image273.png

**Passo 2**: Configura I2C (vedi :ref:`i2c_config`.)

**Passo 3**: Cambia directory.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/raphael-kit/python/

**Passo 4**: Esegui.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo python3 4.1.17_GAME_GuessNumber.py

Dopo l'avvio del programma, sulla LCD appare la pagina iniziale:

.. code-block:: 

   Welcome!
   Press A to go!

Press ‘A’, and the game will start and the game page will appear on the
LCD.

.. code-block:: 

   Inserisci numero:
   0 ‹punto‹ 99


Un numero casuale ' \ **punto**\ ' viene generato ma non visualizzato sull'LCD 
quando il gioco inizia, e il tuo compito è indovinarlo. Il numero che hai digitato 
appare alla fine della prima riga fino a quando non viene effettuato il calcolo finale.
(Premi 'D' per avviare il confronto e se il numero inserito è maggiore di **10** , il confronto automatico inizia.)


L'intervallo numerico di 'punto' viene visualizzato sulla seconda riga. Devi 
inserire il numero all'interno dell'intervallo. Quando inserisci un numero, 
l'intervallo si restringe; se indovini correttamente o meno, apparirà "L'hai preso!"


.. note::

    * Se visualizzi l'errore ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'``, devi fare riferimento a :ref:`i2c_config` per abilitare l'I2C.
    * Se ricevi l'errore ``ModuleNotFoundError: No module named 'smbus2'``, esegui ``sudo pip3 install smbus2``.
    * Se compare l'errore ``OSError: [Errno 121] Remote I/O error``, significa che il modulo è cablato in modo errato o è guasto.
    * Se il codice e il cablaggio sono corretti, ma l'LCD non mostra ancora contenuti, puoi regolare il potenziometro sul retro per aumentare il contrasto.


**Codice**

.. note::
    Puoi **Modificare/Reimpostare/Copiare/Eseguire/Interrompere** il codice qui sotto. Tuttavia, prima di fare ciò, devi accedere al percorso del codice sorgente come ``raphael-kit/python``.

.. raw:: html

    <run></run>

.. code-block:: python

   #!/usr/bin/env python3

   import RPi.GPIO as GPIO
   import time
   import LCD1602
   import random

   ##################### ECCO LA LIBRERIA KEYPAD TRASFERITA DA Arduino ############
   #class Key:Definisci alcune delle proprietà di Key
   class Keypad():

      def __init__(self, rowsPins, colsPins, keys):
         self.rowsPins = rowsPins
         self.colsPins = colsPins
         self.keys = keys
         GPIO.setwarnings(False)
         GPIO.setmode(GPIO.BCM)
         GPIO.setup(self.rowsPins, GPIO.OUT, initial=GPIO.LOW)
         GPIO.setup(self.colsPins, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

      def read(self):
         pressed_keys = []
         for i, row in enumerate(self.rowsPins):
               GPIO.output(row, GPIO.HIGH)
               for j, col in enumerate(self.colsPins):
                  index = i * len(self.colsPins) + j
                  if (GPIO.input(col) == 1):
                     pressed_keys.append(self.keys[index])
               GPIO.output(row, GPIO.LOW)
         return pressed_keys

   ################ ESEMPIO DI CODICE INIZIA QUI ################  

   count = 0
   pointValue = 0
   upper=99
   lower=0

   def setup():
      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)    # init(slave address, luce di sfondo)
      LCD1602.clear()
      LCD1602.write(0, 0, 'Welcome!')
      LCD1602.write(0, 1, 'Press A to Start!')

   def init_new_value():
      global pointValue,upper,count,lower
      pointValue = random.randint(0,99)
      upper = 99
      lower = 0
      count = 0
      print('point is %d' %(pointValue))
      
   def detect_point():
      global count,upper,lower
      if count > pointValue:
         if count < upper:
               upper = count 
      elif count < pointValue:
         if count > lower:
               lower = count
      elif count == pointValue:
         count = 0
         return 1
      count = 0
      return 0

   def lcd_show_input(result):
      LCD1602.clear()
      if result == 1:
         LCD1602.write(0,1,'You have got it!')
         time.sleep(5)
         init_new_value()
         lcd_show_input(0)
         return
      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():
      global keypad, last_key_pressed,count
      while(True):
         result = 0
         pressed_keys = keypad.read()
         if len(pressed_keys) != 0 and last_key_pressed != pressed_keys:
               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 list(["A","B","C","D","#","*"]):
                     continue
                  count = count * 10
                  count += int(pressed_keys[0])
                  if count >= 10:
                     result = detect_point()
                  lcd_show_input(result)
               print(pressed_keys)
         last_key_pressed = pressed_keys
         time.sleep(0.1)

   # Definisci una funzione destroy per ripulire tutto dopo la fine dello script
   def destroy():
      # Rilascia le risorse
      GPIO.cleanup()
      LCD1602.clear() 

   if __name__ == '__main__':     # Il programma inizia qui
      try:
         setup()
         while True:
               loop()
      except KeyboardInterrupt:   # Quando viene premuto 'Ctrl+C', il programma destroy() verrà eseguito.
         destroy()

**Spiegazione del Codice**

Nella parte iniziale del codice troviamo le funzioni operative di
**keypad** e **I2C LCD1602**. Puoi approfondire maggiori dettagli 
su di esse nelle sezioni :ref:`1.1.7_py` e :ref:`2.1.8_py`.

Qui, quello che ci serve sapere è il seguente:

.. code-block:: python

    def init_new_value():
        global pointValue,upper,count,lower
        pointValue = random.randint(0,99)
        upper = 99
        lower = 0
        count = 0
        print('point is %d' %(pointValue))

La funzione genera il numero casuale ‘\ **point**\ ’ e reimposta l'intervallo 
indicativo del numero.

.. code-block:: python

    def detect_point():
        global count,upper,lower
        if count > pointValue:
            if count < upper:
                upper = count 
        elif count < pointValue:
            if count > lower:
                lower = count
        elif count == pointValue:
            count = 0
            return 1
        count = 0
        return 0

``detect_point()`` confronta il numero inserito (**count**) con il numero generato
“\ **point**\ ”. Se il confronto indica che non sono uguali,
**count** assegnerà valori a **upper** e **lower** e restituirà
‘\ **0**\ ’; altrimenti, se sono uguali, verrà restituito ‘\ **1**\ ’.

.. code-block:: python

    def lcd_show_input(result):
        LCD1602.clear()
        if result == 1:
            LCD1602.write(0,1,'You have got it!')
            time.sleep(5)
            init_new_value()
            lcd_show_input(0)
            return
        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))

Questa funzione serve a visualizzare la pagina del gioco.

``str(count)``: Poiché ``write()`` supporta solo il tipo di dati —
**string**, è necessario utilizzare ``str()`` per convertire il **numero** in **string**.

.. code-block:: python

    def loop():
        global keypad, last_key_pressed,count
        while(True):
            result = 0
            pressed_keys = keypad.read()
            if len(pressed_keys) != 0 and last_key_pressed != pressed_keys:
                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 list(["A","B","C","D","#","*"]):
                        continue
                    count = count * 10
                    count += int(pressed_keys[0])
                    if count >= 10:
                        result = detect_point()
                    lcd_show_input(result)
                print(pressed_keys)
            last_key_pressed = pressed_keys
            time.sleep(0.1)
   

``main()`` contiene l'intero processo del programma, come mostrato di seguito:

1) Inizializza **I2C LCD1602** e **Keypad**.

2) Verifica se il pulsante è stato premuto e ottieni la lettura del pulsante.

3) Se viene premuto il pulsante ‘\ **A**\ ’, comparirà un numero casuale **0-99** 
   e il gioco inizierà.

4) Se viene rilevato che il pulsante ‘\ **D**\ ’ è stato premuto, il programma 
   entrerà nella fase di giudizio del risultato.

5) Se viene premuto un pulsante da **0-9**, il valore di **count** cambierà; se 
   **count** è maggiore di **10**, allora inizierà il giudizio.

6) Le variazioni del gioco e dei suoi valori vengono visualizzate su **LCD1602**.

Immagine del Fenomeno
---------------------------

.. image:: ../img/image274.jpeg
   :align: center