.. note::

    ¡Hola! Bienvenido a la comunidad de entusiastas de SunFounder para Raspberry Pi, Arduino y ESP32 en Facebook. Únete para profundizar en Raspberry Pi, Arduino y ESP32 junto a otros apasionados.

    **¿Por qué unirte?**

    - **Soporte de Expertos**: Resuelve problemas post-venta y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
    - **Aprende y Comparte**: Intercambia consejos y tutoriales para mejorar tus habilidades.
    - **Avances Exclusivos**: Obtén acceso anticipado a anuncios de nuevos productos y vistas previas.
    - **Descuentos Especiales**: Disfruta de descuentos exclusivos en nuestros productos más recientes.
    - **Promociones Festivas y Sorteos**: Participa en sorteos y promociones de temporada.

    👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy.

3.1.12 JUEGO– Adivina el Número
=================================

Introducción
------------------

Adivina el Número es un juego de fiesta en el que tú y tus amigos toman 
turnos para ingresar un número (0~99). El rango se reduce con cada intento 
hasta que un jugador adivina correctamente, momento en el cual el jugador 
pierde y recibe un castigo. Por ejemplo, si el número secreto es 51 (invisible 
para los jugadores) y el jugador ① ingresa 50, el rango se ajusta a 50~99; 
si el jugador ② ingresa 70, el rango será de 50~70; si el jugador ③ ingresa 
51, este jugador será el desafortunado. Aquí, usamos un teclado para ingresar 
números y una LCD para mostrar los resultados.

Componentes
-----------------

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

Diagrama Esquemático
-----------------------

============ ======== ======== =======
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

Procedimientos Experimentales
---------------------------------

**Paso 1:** Construye el circuito.

.. image:: img/image273.png
   :alt: Guess Number_bb
   :width: 800

**Paso 2**: Configura I2C (consulta el Apéndice. Si ya lo has configurado, 
omite este paso.)

**Para Usuarios de Lenguaje C**
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Paso 3**: Cambia de directorio.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/davinci-kit-for-raspberry-pi/c/3.1.12/

**Paso 4**: Compila.

.. raw:: html

   <run></run>

.. code-block:: 

    gcc 3.1.12_GAME_GuessNumber.c -lwiringPi

**Paso 5**: Ejecuta.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo ./a.out


Después de ejecutar el programa, la pantalla LCD muestra la página inicial:

.. code-block:: 

   Welcome!
   Press A to go!

Presiona \'A\', y el juego comenzará mostrando la página de juego en la
LCD.

.. code-block:: 

   Enter number:
   0 ‹point‹ 99

.. note::

   Si no funciona después de ejecutarlo, o aparece un mensaje de error: \"wiringPi.h: No such file or directory", consulta :ref:`C code is not working?`.

Un número aleatorio \'**punto**\' es generado pero no se muestra en la pantalla 
LCD cuando el juego comienza, y lo que necesitas hacer es adivinarlo. El número 
ingresado aparecerá al final de la primera línea hasta que se complete el cálculo 
final. (Presiona \'D\' para iniciar la comparación, y si el número ingresado es 
mayor que **10**, la comparación automática comenzará.)

El rango del número \'punto\' se muestra en la segunda línea, y debes ingresar 
un número dentro de ese rango. A medida que ingresas un número, el rango se 
reduce; si adivinas el número afortunado o desafortunado, aparecerá el mensaje 
\"¡Lo conseguiste!\"

**Explicación del Código**

Al comienzo del código se encuentran las funciones para manejar el **teclado** y 
la **LCD I2C 1602**. Puedes obtener más detalles sobre estas funciones en 
**1.1.7 I2C LCD1602** y **2.1.5 Teclado.**

Aquí, lo que necesitamos saber es lo siguiente:

.. code-block:: c

    /****************************************/
    //Comienza desde aquí
    /****************************************/
    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!");
    }

    
Esta función se utiliza para definir inicialmente **I2C LCD1602** y **Teclado**
y para mostrar \"¡Bienvenido!\" y \"Presiona A para empezar\".

.. 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 función genera el número aleatorio \'**punto**\' y restablece el rango del punto.

.. 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() compara el número ingresado con el \"punto\" generado. Si
el resultado de la comparación es que no coinciden, **count** asignará
valores a **upper** y **lower** y devolverá \'**0**\'; de lo contrario, si
el resultado indica coincidencia, devuelve \'**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);
    }

Esta función muestra la página del juego. Presta atención a la función 
**Int2Str(str, count)**, que convierte las variables **count**, **lower**, 
y **upper** de **entero** a **cadena de caracteres** para la visualización 
correcta en la **LCD**.

.. code-block:: c

    int main(){
        unsigned char pressed_keys[BUTTON_NUM];
        unsigned char last_key_pressed[BUTTON_NUM];
        if(wiringPiSetup() == -1){ //when initialize wiring failed,print messageto screen
            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 todo el proceso del programa, como se muestra a continuación:

1) Inicializa **I2C LCD1602** y **Teclado**.

2) Usa **init_new_value()** para crear un número aleatorio entre **0-99**.

3) Determina si se ha presionado un botón y obtiene la lectura del botón.

4) Si se presiona el botón \'**A**\', aparecerá un número aleatorio **0-99** y 
   el juego comienza.

5) Si se detecta que se ha presionado el botón \'**D**\', el programa entra en 
   el juicio de resultado y muestra el resultado en la LCD. Este paso permite 
   que puedas juzgar el resultado presionando solo un número y luego el botón \'**D**\'.

6) Si se presiona un botón **0-9**, el valor de **count** cambiará; si **count** 
   es mayor que **10**, entonces comienza el juicio.

7) Los cambios en el juego y sus valores se muestran en la **LCD1602**.

**Para Usuarios de Lenguaje Python**
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Paso 3**: Cambia de directorio.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/davinci-kit-for-raspberry-pi/python/

**Paso 4**: Ejecuta.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo python3 3.1.12_GAME_GuessNumber.py

Después de ejecutar el programa, la pantalla LCD muestra la página inicial:

.. code-block:: 

   Welcome!
   Press A to go!

Presiona \'A\', y el juego comenzará mostrando la página de juego en la
LCD.

.. code-block:: 

   Enter number:
   0 ‹point‹ 99

Un número aleatorio \'**punto**\' es generado pero no se muestra en la 
pantalla LCD cuando el juego comienza, y lo que necesitas hacer es adivinarlo. 
El número ingresado aparecerá al final de la primera línea hasta que se complete 
el cálculo final. (Presiona \'D\' para iniciar la comparación, y si el número 
ingresado es mayor que **10**, la comparación automática comenzará.)

El rango del número \'punto\' se muestra en la segunda línea, y debes ingresar 
un número dentro de ese rango. A medida que ingresas un número, el rango se 
reduce; si adivinas el número afortunado o desafortunado, aparecerá el mensaje 
\"¡Lo conseguiste!\"

**Código**

.. note::

   Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a 
   continuación. Pero antes, necesitas dirigirte a la ruta del código fuente, 
   como ``davinci-kit-for-raspberry-pi/python``. 
   
.. raw:: html

    <run></run>

.. code-block:: python

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

   ##################### AQUÍ ESTÁ LA LIBRERÍA DEL TECLADO TRANSFERIDA DESDE Arduino ############
   #class Key: Define algunas de las propiedades de 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

   ################ EL CÓDIGO DE EJEMPLO INICIA AQUÍ ################  

   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)    # inicializar (dirección esclava, luz de fondo)
      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)

   # Define una función destroy para limpiar todo después de que el script haya terminado
   def destroy():
      # Liberar recursos
      GPIO.cleanup()
      LCD1602.clear() 

   if __name__ == '__main__':     # El programa comienza desde aquí
      try:
         setup()
         while True:
               loop()
      except KeyboardInterrupt:   # Cuando se presiona 'Ctrl+C', se ejecuta destroy().
         destroy()

**Explicación del Código**

Al comienzo del código se encuentran las funciones funcionales de
**teclado** y **I2C LCD1602**. Puedes obtener más detalles sobre ellas en
**1.1.7 I2C LCD1602** y **2.1.5 Teclado.**

Aquí, lo que necesitamos saber es lo siguiente:

.. 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 función genera el número aleatorio \'**punto**\' y restablece el
rango del punto.

.. 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() compara el número ingresado (**count**) con el \"**punto**\" 
generado. Si el resultado de la comparación es que no coinciden, **count** 
asignará valores a **upper** y **lower** y devolverá \'**0**\'; 
de lo contrario, si el resultado indica coincidencia, devuelve \'**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))


Esta función se utiliza para mostrar la página del juego.

str(count): Debido a que **write()** solo admite el tipo de dato —
**cadena de caracteres**, es necesario **str()** para convertir el 
**número** en una **cadena**.

.. 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 todo el proceso del programa, como se muestra a continuación:

1) Inicializa **I2C LCD1602** y **Teclado**.

2) Verifica si se ha presionado un botón y obtiene la lectura del botón.

3) Si se presiona el botón \'**A**\', aparecerá un número aleatorio **0-99** 
   y el juego comenzará.

4) Si se detecta que se ha presionado el botón \'**D**\', el programa entrará 
   en el juicio de resultado.

5) Si se presiona un botón **0-9**, el valor de **count** cambiará; si **count** 
   es mayor que **10**, entonces comenzará el juicio.

6) Los cambios en el juego y sus valores se muestran en **LCD1602**.

Imagen del Fenómeno
------------------------

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