.. note::
¡Hola! Bienvenido a la Comunidad de Entusiastas de SunFounder Raspberry Pi & Arduino & ESP32 en Facebook. Sumérgete más en Raspberry Pi, Arduino y ESP32 con otros entusiastas.
**¿Por qué unirse?**
- **Soporte experto**: Resuelve problemas postventa y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
- **Aprende y comparte**: Intercambia consejos y tutoriales para mejorar tus habilidades.
- **Previsualizaciones exclusivas**: Obtén acceso anticipado a nuevos anuncios de productos y adelantos.
- **Descuentos especiales**: Disfruta de descuentos exclusivos en nuestros productos más nuevos.
- **Promociones y sorteos festivos**: Participa en sorteos y promociones navideñas.
👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy mismo.
.. _4.1.17_py:
4.1.17 JUEGO – Adivina el Número
==============================================
Introducción
------------------
Adivinar Números es un divertido juego de fiesta donde tú y tus amigos toman
turnos para ingresar un número (0~99). El rango será más pequeño con la entrada
del número hasta que un jugador responda el acertijo correctamente. Entonces el
jugador es derrotado y castigado. Por ejemplo, si el número de la suerte es 51,
que los jugadores no pueden ver, y el jugador ① ingresa 50, el rango de números
cambia a 50~99; si el jugador ② ingresa 70, el rango de números puede ser 50~70;
si el jugador ③ ingresa 51, este jugador es el desafortunado. Aquí, usamos un
teclado para ingresar números y una pantalla LCD para mostrar los resultados.
Componentes necesarios
------------------------------
En este proyecto, necesitamos los siguientes componentes.
.. image:: ../img/list_GAME_Guess_Number.png
:align: center
Es definitivamente conveniente comprar un kit completo, aquí está el enlace:
.. list-table::
:widths: 20 20 20
:header-rows: 1
* - Nombre
- ARTÍCULOS EN ESTE KIT
- ENLACE
* - Kit Raphael
- 337
- |link_Raphael_kit|
También puedes comprarlos por separado en los enlaces a continuación.
.. list-table::
:widths: 30 20
:header-rows: 1
* - INTRODUCCIÓN DEL COMPONENTE
- ENLACE DE COMPRA
* - :ref:`cpn_gpio_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|
Diagrama esquemático
-------------------------
============== ========== ======== =======
Nombre T-Board Pin físico 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
**Paso 2**: Configura I2C (ver :ref:`i2c_config`).
**Paso 3**: Cambia de directorio.
.. raw:: html
.. code-block::
cd ~/raphael-kit/python/
**Paso 4**: Ejecuta.
.. raw:: html
.. code-block::
sudo python3 4.1.17_GAME_GuessNumber.py
Después de que el programa se ejecute, se muestra la página inicial en la LCD:
.. code-block::
Welcome!
Press A to go!
Presiona 'A' y el juego comenzará y la página del juego aparecerá en la LCD.
.. code-block::
Enter number:
0 ‹punto‹ 99
Se produce un número aleatorio 'punto' pero no se muestra en la LCD cuando el
juego comienza, y lo que necesitas hacer es adivinarlo. El número que has escrito
aparece al final de la primera línea hasta que se finaliza el cálculo. (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 de números de 'punto' se muestra en la segunda línea. Y debes escribir el
número dentro del rango. Cuando escribes un número, el rango se reduce; si adivinaste
el número de la suerte afortunada o desafortunadamente, aparecerá "¡Lo conseguiste!".
.. note::
* Si obtienes el error ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'``, necesitas consultar :ref:`i2c_config` para habilitar el I2C.
* Si obtienes el error ``ModuleNotFoundError: No module named 'smbus2'``, por favor ejecuta ``sudo apt install python3-smbus2``.
* Si aparece el error ``OSError: [Errno 121] Remote I/O error``, significa que el módulo está mal conectado o está dañado.
* Si el código y las conexiones están bien, pero la LCD aún no muestra contenido, puedes girar el potenciómetro en la parte posterior para aumentar el contraste.
**Código**
.. note::
Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a continuación. Pero antes de eso, necesitas ir a la ruta del código fuente como ``raphael-kit/python``. Después de modificar el código, puedes ejecutarlo directamente para ver el efecto.
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import time
import LCD1602
import random
##################### AQUÍ ESTÁ LA LIBRERÍA DE TECLADO TRANSPLANTADA DESDE Arduino ############
#class Key: Define algunas 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 EMPIEZA 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) # init(slave address, background light)
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 termine
def destroy():
# Liberar recursos
GPIO.cleanup()
LCD1602.clear()
if __name__ == '__main__': # Program start from here
try:
setup()
while True:
loop()
except KeyboardInterrupt: # Cuando se presiona 'Ctrl+C', se ejecutará la función destroy().
destroy()
**Explicación del Código**
En la parte inicial del código se encuentran las funciones funcionales
del **teclado** y del **I2C LCD1602**. Puedes aprender más detalles sobre
ellas en :ref:`1.1.7_py` y :ref:`2.1.8_py`.
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 produce el número aleatorio ‘\ **point**\ ’ y restablece el rango de pistas 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 número
producido “\ **point**\ ”. Si el resultado de la comparación indica que no
son iguales, **count** asignará valores a **upper** y **lower** y devolverá
‘\ **0**\ ’; de lo contrario, si el resultado indica que son iguales, se devolverá ‘\ **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 puede soportar el tipo de
dato — **cadena** , se necesita ``str()`` para convertir el **número** en **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 **Keypad**.
2) Juzga si se ha presionado el 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
luego comenzará el juego.
4) Si se detecta que el botón ‘\ **D**\ ’ ha sido presionado, el programa entrará
en el juicio del resultado.
5) Si se presiona el botón **0-9**, el valor de **count** cambiará; si **count** es
mayor que **10**, entonces comenzará el juicio.
6) Los cambios del juego y sus valores se muestran en **LCD1602**.
Imagen del Fenómeno
------------------------
.. image:: ../img/image274.jpeg
:align: center