.. note::

    Ciao, benvenuto nella SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community su Facebook! Approfondisci Raspberry Pi, Arduino ed ESP32 insieme ad altri appassionati.

    **Perché unirti?**

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

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

.. _3.1.11_c_pi5:

3.1.11 GIOCO– Indovina il Numero
======================================

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

"Indovina il Numero" è un divertente gioco di società in cui tu e i tuoi 
amici vi alternate a inserire un numero (0~99). L'intervallo si ridurrà man 
mano che si inseriscono numeri fino a quando un giocatore non indovinerà 
correttamente l'enigma. A quel punto, 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 cambia a 50~99; se il giocatore 
② inserisce 70, l'intervallo diventa 50~70; se il giocatore ③ inserisce 51, 
questo giocatore è il sfortunato. Qui, utilizziamo una tastiera per inserire 
i numeri e un LCD per visualizzare i risultati.

Componenti necessari
------------------------------

In questo progetto, abbiamo bisogno dei seguenti componenti.

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

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

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

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

Puoi anche acquistarli separatamente dai link sottostanti.

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

    *   - INTRODUZIONE COMPONENTE
        - LINK PER L'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 Appendice :ref:`i2c_config`. Se hai già configurato I2C, salta questo passo.)

**Passo 3**: Cambia directory.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/raphael-kit/c/3.1.11/

**Passo 4**: Compila.

.. raw:: html

   <run></run>

.. code-block:: 

    gcc 3.1.11_GAME_GuessNumber.c -lwiringPi

**Passo 5**: Esegui.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo ./a.out

Dopo l'esecuzione del programma, apparirà la pagina iniziale sull'LCD:

.. note::

    * Se appare il messaggio di errore ``wiringPi.h: No such file or directory``, consulta :ref:`install_wiringpi`.
    * Se ottieni l'errore ``Unable to open I2C device: No such file or directory``, devi consultare :ref:`i2c_config` per abilitare I2C e controllare che il cablaggio sia corretto.
    * Se il codice e il cablaggio sono corretti ma l'LCD non visualizza ancora il contenuto, puoi regolare il contrasto con il potenziometro sul retro.

.. code-block:: 

   Benvenuto!
   Premi A per iniziare!

Premi 'A', e il gioco inizierà e la schermata di gioco apparirà sull'LCD.

.. code-block:: 

   Inserisci numero:
   0 ‹point‹ 99

Viene generato un numero casuale '\ **point**\ ' che non viene visualizzato 
sull'LCD all'inizio del gioco, e quello che devi fare è indovinarlo. Il numero 
digitato apparirà alla fine della prima riga fino a quando il calcolo finale 
non sarà completato. (Premi 'D' per avviare la comparazione, e se il numero 
inserito è maggiore di **10**, la comparazione automatica inizierà.)

L'intervallo del numero 'point' viene visualizzato sulla seconda riga. Devi 
digitare il numero entro l'intervallo. Quando digiti un numero, l'intervallo 
si restringe; se ottieni il numero fortunato, comparirà "Hai indovinato!"


**Spiegazione del codice**

All'inizio del codice ci sono le funzioni di base della **keypad** e dell'**I2C LCD1602**. Puoi approfondire maggiori dettagli su di loro in :ref:`1.1.7_c_pi5` e :ref:`2.1.8_c_pi5`.

Ecco cosa dobbiamo sapere:

.. code-block:: c

    /****************************************/
    //Inizia da qui
    /****************************************/
    void init(void){
        fd = wiringPiI2CSetup(LCDAddr);
        lcd_init();
        lcd_clear();
        for(int i=0 ; i<4 ; i++) {
            pinMode(rowPins[i], OUTPUT);
            pinMode(colPins[i], INPUT);
        }
        lcd_clear();
        write(0, 0, "Welcome!");
        write(0, 1, "Press A to go!");
    }
    
Questa funzione viene utilizzata per definire inizialmente l'**I2C LCD1602** e la **keypad** e per visualizzare "Benvenuto!" e "Premi A per iniziare!".

.. code-block:: c

    void init_new_value(void){
        srand(time(0));
        pointValue = rand()%100;
        upper = 99;
        lower = 0;
        count = 0;
        printf("point is %d\n",pointValue);
    }

La funzione genera il numero casuale '\ **point**\ ' e reimposta l'intervallo di suggerimento del numero.

.. code-block:: c

    bool detect_point(void){
        if(count > pointValue){
            if(count < upper){
                upper = count;
            }
        }
        else if(count < pointValue){
            if(count > lower){
                lower = count;
            }
        }
        else if(count = pointValue){
            count = 0;
            return 1;
        }
        count = 0;
        return 0;
    }

``detect_point()`` confronta il numero inserito con il numero generato “point”. 
Se l'esito del confronto non è uguale, **count** assegnerà valori a **upper** e 
**lower** e restituirà '0'; altrimenti, se il risultato indica che sono uguali, 
restituirà '1'.

.. code-block:: c

    void lcd_show_input(bool result){
        char *str=NULL;
        str =(char*)malloc(sizeof(char)*3);
        lcd_clear();
        if (result == 1){
            write(0,1,"You've got it!");
            delay(5000);
            init_new_value();
            lcd_show_input(0);
            return;
        }
        write(0,0,"Enter number:");
        Int2Str(str,count);
        write(13,0,str);
        Int2Str(str,lower);
        write(0,1,str);
        write(3,1,"<Point<");
        Int2Str(str,upper);
        write(12,1,str);
    }

Questa funzione serve per visualizzare la pagina di gioco. 
Presta attenzione alla funzione **Int2Str(str,count)**, 
che converte queste variabili **count**, **lower**, e **upper** 
da **intero** a **stringa di caratteri** per la corretta visualizzazione sull'**lcd**.

.. code-block:: c

    int main(){
        unsigned char pressed_keys[BUTTON_NUM];
        unsigned char last_key_pressed[BUTTON_NUM];
        if(wiringPiSetup() == -1){ //quando l'inizializzazione di wiringPi fallisce, stampa messaggio sullo schermo
            printf("setup wiringPi failed !");
            return 1; 
        }
        init();
        init_new_value();
        while(1){
            keyRead(pressed_keys);
            bool comp = keyCompare(pressed_keys, last_key_pressed);
            if (!comp){
                if(pressed_keys[0] != 0){
                    bool result = 0;
                    if(pressed_keys[0] == 'A'){
                        init_new_value();
                        lcd_show_input(0);
                    }
                    else if(pressed_keys[0] == 'D'){
                        result = detect_point();
                        lcd_show_input(result);
                    }
                    else if(pressed_keys[0] >='0' && pressed_keys[0] <= '9'){
                        count = count * 10;
                        count = count + (pressed_keys[0] - 48);
                        if (count>=10){
                            result = detect_point();
                        }
                        lcd_show_input(result);
                    }
                }
                keyCopy(last_key_pressed, pressed_keys);
            }
            delay(100);
        }
        return 0;   
    }

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

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

2) Usa **init_new_value()** per creare un numero casuale **0-99**.

3) Verifica se un pulsante è stato premuto e leggi il valore del pulsante.

4) Se viene premuto il pulsante ‘A’, verrà generato un numero casuale **0-99** 
e il gioco inizierà.

5) Se viene rilevata la pressione del pulsante ‘D’, il programma entrerà nel giudizio 
   del risultato e lo visualizzerà sull'LCD. Questo passaggio consente di giudicare il 
   risultato anche quando viene premuto un solo numero e poi il pulsante ‘D’.

6) Se viene premuto il pulsante **0-9**, il valore di **count** cambierà; se il **count**
    è maggiore di **10**, inizia il giudizio.

7) Le modifiche del gioco e i suoi valori vengono visualizzati su **LCD1602**.

Immagine del fenomeno
--------------------------

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