.. note::

    Hallo und willkommen in der SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasten-Gemeinschaft auf Facebook! Tauchen Sie tiefer ein in die Welt von Raspberry Pi, Arduino und ESP32 mit anderen Enthusiasten.

    **Warum beitreten?**

    - **Expertenunterstützung**: Lösen Sie Nachverkaufsprobleme und technische Herausforderungen mit Hilfe unserer Gemeinschaft und unseres Teams.
    - **Lernen & Teilen**: Tauschen Sie Tipps und Anleitungen aus, um Ihre Fähigkeiten zu verbessern.
    - **Exklusive Vorschauen**: Erhalten Sie frühzeitigen Zugang zu neuen Produktankündigungen und exklusiven Einblicken.
    - **Spezialrabatte**: Genießen Sie exklusive Rabatte auf unsere neuesten Produkte.
    - **Festliche Aktionen und Gewinnspiele**: Nehmen Sie an Gewinnspielen und Feiertagsaktionen teil.

    👉 Sind Sie bereit, mit uns zu erkunden und zu erschaffen? Klicken Sie auf [|link_sf_facebook|] und treten Sie heute bei!

.. _4.1.17_py:

4.1.17 SPIEL – Zahlenraten
=================================

Einführung
------------------

Zahlenraten ist ein unterhaltsames Partyspiel, bei dem Sie und Ihre Freunde abwechselnd eine Zahl (0~99) eingeben. Der Bereich wird mit der Eingabe der Zahl kleiner, bis ein Spieler das Rätsel richtig beantwortet. Dann wird dieser Spieler besiegt und bestraft. Zum Beispiel, wenn die Glückszahl 51 ist, die die Spieler nicht sehen können, und der Spieler ① 50 eingibt, ändert sich der Zahlenbereich zu 50~99; wenn der Spieler ② 70 eingibt, kann der Zahlenbereich 50~70 sein; wenn der Spieler ③ 51 eingibt, ist dieser Spieler der Pechvogel. Hier verwenden wir ein Tastenfeld zur Eingabe von Zahlen und ein LCD zur Ausgabe von Ergebnissen.

Benötigte Komponenten
------------------------------

Für dieses Projekt benötigen wir folgende Komponenten.

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

Es ist definitiv praktisch, ein komplettes Kit zu kaufen, hier ist der Link:

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

    *   - Name	
        - ARTIKEL IN DIESEM KIT
        - LINK
    *   - Raphael Kit
        - 337
        - |link_Raphael_kit|

Sie können sie auch einzeln über die untenstehenden Links kaufen.

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

    *   - KOMPONENTENBESCHREIBUNG
        - KAUF-LINK

    *   - :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_lcd1602`
        - |link_i2clcd1602_buy|

Schaltplan
-----------------------

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

Experimentelle Verfahren
-----------------------------

**Schritt 1:** Bauen Sie den Schaltkreis.

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

**Schritt 2**: I2C einrichten (siehe :ref:`i2c_config`.)

**Schritt 3**: Verzeichnis wechseln.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/raphael-kit/python/

**Schritt 4**: Ausführen.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo python3 4.1.17_GAME_GuessNumber.py

Nach dem Start des Programms wird die Startseite auf dem LCD angezeigt:

.. code-block:: 

   Willkommen!
   Drücke A zum Starten!

Drücken Sie „A“, und das Spiel beginnt und die Spielseite wird auf dem LCD angezeigt.

.. code-block:: 

   Zahl eingeben:
   0 ‹Punkt‹ 99

Eine zufällige Zahl „\ **Punkt**\ “ wird erzeugt, aber beim Spielstart nicht auf dem LCD angezeigt. Ihre Aufgabe ist es, diese zu erraten. Die von Ihnen eingegebene Zahl erscheint am Ende der ersten Zeile, bis die endgültige Berechnung abgeschlossen ist. (Drücken Sie „D“, um den Vergleich zu starten. Wenn die eingegebene Zahl größer als **10** ist, beginnt der automatische Vergleich.)

Der Zahlenbereich von „Punkt“ wird in der zweiten Zeile angezeigt. Sie müssen eine Zahl innerhalb dieses Bereichs eingeben. Wenn Sie eine Zahl eingeben, verkleinert sich der Bereich. Wenn Sie zufällig oder unglücklicherweise die Glückszahl erreichen, erscheint die Meldung „Du hast es geschafft!“

.. note::

    * Wenn der Fehler ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'`` auftritt, müssen Sie :ref:`i2c_config` konsultieren, um I2C zu aktivieren.
    * Wenn der Fehler ``ModuleNotFoundError: No module named 'smbus2'`` auftritt, führen Sie bitte ``sudo pip3 install smbus2`` aus.
    * Wenn der Fehler ``OSError: [Errno 121] Remote I/O error`` erscheint, bedeutet dies, dass das Modul falsch verdrahtet ist oder das Modul defekt ist.
    * Wenn der Code und die Verdrahtung in Ordnung sind, das LCD aber immer noch keinen Inhalt anzeigt, können Sie das Potentiometer auf der Rückseite drehen, um den Kontrast zu erhöhen.

**Code**

.. note::
    Sie können den untenstehenden Code **Ändern/Zurücksetzen/Kopieren/Ausführen/Stoppen**. Bevor Sie das tun, müssen Sie zum Quellcode-Pfad wie ``raphael-kit/python`` navigieren. Nachdem Sie den Code geändert haben, können Sie ihn direkt ausführen, um das Ergebnis zu sehen.

.. raw:: html

    <run></run>

.. code-block:: python

   #!/usr/bin/env python3

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

   ##################### HERE IS THE KEYPAD LIBRARY TRANSPLANTED FROM Arduino ############
   #class Key:Define some of the properties of 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

   ################ EXAMPLE CODE START HERE ################  

   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 a destroy function for clean up everything after the script finished
   def destroy():
      # Release resource
      GPIO.cleanup()
      LCD1602.clear() 

   if __name__ == '__main__':     # Program start from here
      try:
         setup()
         while True:
               loop()
      except KeyboardInterrupt:   # When 'Ctrl+C' is pressed, the program destroy() will be executed.
         destroy()

**Code-Erklärung**

Zu Beginn des Codes finden sich die Funktionsmethoden von 
**keypad** und **I2C LCD1602**. Detailliertere Informationen über diese können 
in :ref:`1.1.7_py` und :ref:`2.1.8_py` nachgelesen werden.

Wichtige Stellen im Code sind wie folgt:

.. 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))

Die Funktion generiert die zufällige Zahl „\ **Punkt**\ “ und setzt den Bereichs-Hinweis zurück.

.. 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()`` vergleicht die eingegebene Zahl (**count**) mit dem generierten „\ **Punkt**\ “. Wenn das Ergebnis des Vergleichs zeigt, dass sie nicht gleich sind, weist **count** Werte an **upper** und **lower** zu und gibt „\ **0**\ “ zurück. Andernfalls, wenn sie gleich sind, gibt es „\ **1**\ “ zurück.

.. 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))

Die Funktion dient dazu, die Spielseite anzuzeigen.

``str(count)``: Da ``write()`` nur den Datentyp **string** unterstützt, ist ``str()`` notwendig, um die **Zahl** in einen **String** zu konvertieren.

.. 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()`` beinhaltet den gesamten Prozess des Programms, wie unten gezeigt:

1) Initialisierung von **I2C LCD1602** und **Keypad**.

2) Überprüfung, ob eine Taste gedrückt wurde und das Auslesen der Taste.

3) Wenn die Taste „\ **A**\ “ gedrückt wird, erscheint eine Zufallszahl zwischen **0-99** und das Spiel beginnt.

4) Wird die Taste „\ **D**\ “ erkannt, tritt das Programm in das Ergebnisurteil ein.

5) Wenn die Taste **0-9** gedrückt wird, ändert sich der Wert von **count**; ist **count** größer als **10**, beginnt das Urteil.

6) Die Änderungen des Spiels und seiner Werte werden auf dem **LCD1602** angezeigt.

Phänomen-Bild
------------------------

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