Das Periodensystem

Grundsätzlich ist das Periodensystem der chemischen Elemente eine strukturierte und tabellarische Darstellung aller bekannten chemischen Elemente.
Bereits in der Antike hatten die Menschen schon Kenntnisse über chemische Elemente wie Gold, Silber, Eisen und Kupfer. Im Laufe der Jahrhunderte sammelten Gelehrte Daten über verschiedene Stoffe – sie alle konnten jedoch kein Muster finden.
Erst im späten 18. Jahrhundert legte der französische Chemiker Antoine Lavoisier den Grundstein für die moderne Chemie, indem er das Gesetz der Erhaltung der Masse formulierte und die chemischen Elemente neu klassifizierte. Er identifizierte und benannte einige der elementaren Bestandteile der Materie.
Im Jahr 1864 stellte der englische Chemiker John Newlands eine Liste der Elemente vor und ordnete sie nach ihrem Atomgewicht. Er bemerkte, dass die Elemente in Achtelgruppen (Oktaven) mit ähnlichen Eigenschaften angeordnet zu sein schienen. Seine Ideen wurden jedoch nicht weit verbreitet akzeptiert.
Fünf Jahre später verfasste der russische Chemiker Dimitri Mendelejew das erste umfassende Periodensystems. Er ordnete die bekannten Elemente in einer Tabelle nach aufsteigendem Atomgewicht und identifizierte Muster und Periodizitäten in ihren Eigenschaften. Mendelejew erkannte, dass es noch unbekannte Elemente geben musste, die in die leeren Stellen in seiner Tabelle passten. Er sagte die Eigenschaften dieser Elemente vorher und nannte sie „Ekasilicium“ und „Ekaaluminium“. Diese Vorhersagen erwiesen sich später als richtig und führten zur Entdeckung von Germanium und Gallium.
Der britische Physiker Henry Moseley trug im frühen 20. Jahrhundert wesentlich zur Verbesserung des Periodensystems bei, indem er das Konzept der Atomnummer einführte. Er ordnete die Elemente nach ihrer Ordnungszahl (Anzahl der Protonen im Kern) an, anstatt nach dem Atomgewicht. Dies führte zu einer genaueren und logischeren Anordnung der Elemente im Periodensystem.
Das Periodensystem ist zu einem grundlegenden Werkzeug für die Chemie geworden und ermöglicht das Verständnis der Beziehungen zwischen den Elementen und die Vorhersage ihres Verhaltens. Es ist eines der wichtigsten Konzepte in der Chemie und wird kontinuierlich erforscht und erweitert, um unser Verständnis der chemischen Welt zu vertiefen.
Da wir aus Interesse oder der Schule wegen uns das Perioden System auswendig erlernen können und dies auch noch Spaß machen sollte, bauen wir uns ein Periodensystem Quiz.
In den bisherigen Beispielen haben wir uns nur auf der Text Ebene bewegt und uns um das GUI (das User Interface) eigentlich nicht gekümmert. Jedoch haben wir viel dabei gelernt. Als ersten Schritt zu unserem Quiz schauen wir uns einmal eine UI – Bibliothek an.
Die Bibliothek die wir verwenden werden ist PySimpleGUI.
PySimpleGUI ist eine Python-Bibliothek, die entwickelt wurde, um die Erstellung von grafischen Benutzeroberflächen (GUIs) einfach und intuitiv zu gestalten.
Der Name „Simple“ in PySimpleGUI spiegelt das Hauptziel der Bibliothek wider: Sie soll einfach zu erlernen und zu verwenden sein. Die API ist so gestaltet, dass sie leicht verständlich ist und weniger Boilerplate-Code erfordert als einige andere GUI-Bibliotheken.

Zuerst müssen wir das Paket installieren. Im Visual Studio öffnen wir unser Projekt und öffnen unter Python-Umgebung Pyhton 3.9.

Dort machen wir einen Rechts-Click und wählen Python Pakete verwalten aus. Nun geben wir im Eingabefeld PySimpleGUI ein.

Unten erscheint nun eine Liste und wir wählen PySimpleGUI aus. Wie von Geisterhand wird es vom Visual Studio installiert.
Den schwierigsten Teil haben wir nun erfolgreich hinter uns gebracht. Nun können wir mit dem lustigen Part, dem Programmieren, beginnen.
Als erstes machen wir zum Einstieg einfach ein Fenster mit einem Button.

import PySimpleGUI as sg

layout = [
          [sg.Button('Close', button_color=('white', 'black'), key='close')]
          ]

window = sg.Window("Periodensystem", layout, auto_size_buttons=False, default_button_element_size=(12,1), use_default_focus=False, finalize=True)

while True:
    event, values = window.read(timeout=100)
    if event == "close":
        break
    if event == sg.WINDOW_CLOSED:
        break
window.close()

So schauen wir uns den Code näher an:

import PySimpleGUI as sg: Dieser Befehl importiert die PySimpleGUI-Bibliothek und stellt sie als sg zur Verfügung, was die Verwendung von PySimpleGUI-Elementen im Code erleichtert.
Unser Augenmerk richtet sich auf die Variabel layout. In dieser Liste ist die die Struktur des GUI-Layouts definiert. In unserem Fall enthält sie eine Liste mit einer Schaltfläche (Button) namens „Close“. Die Schaltfläche wird in einem separaten Unterlayout definiert, um das Layout flexibler zu gestalten.
Mit window wird ein Fensterobjekt erstellt und initialisiert. Der Name des Fensters lautet „Periodensystem“.
Das layout wird dem Fenster übergeben, und verschiedene Parameter werden gesetzt, um das Layout und das Verhalten des Fensters zu konfigurieren, z.B., die Größe der Schaltfläche, den Fokus und die Verwendung der Standardtasten. Das finalize=True stellt sicher, dass das Layout endgültig erstellt wird.
Die while-Schleife sorgt dafür, dass das GUI-Fenster geöffnet bleibt und Benutzereingaben überwacht wird.
Die Zeile event, values = window.read(timeout=100) liest Ereignisse (Events) und Werte (Values) aus dem GUI-Fenster. Das timeout=100 sorgt dafür, dass die window.read-Funktion alle 100 Millisekunden aufgerufen wird, um auf Benutzeraktionen zu reagieren. Das Ergebnis von window.read() wird in den Variablen event und values gespeichert.
Die nächsten beiden if-Anweisungen prüfen auf verschiedene Ereignisse:

  • if event == "close": überprüft, ob der Benutzer auf den „Close“-Button geklickt hat. Wenn dies der Fall ist, wird die Schleife mit break beendet, und das GUI-Fenster wird geschlossen.
  • if event == sg.WINDOW_CLOSED: prüft, ob das GUI-Fenster auf eine andere Weise geschlossen wurde (z.B., durch Klicken auf das Schließen-Symbol oben rechts im Fenster). In diesem Fall wird die Schleife ebenfalls mit break beendet, und das GUI-Fenster wird geschlossen.

Schließlich wird window.close() aufgerufen, um das GUI-Fenster ordnungsgemäß zu schließen, bevor das Programm beendet wird.

Unser Beispiel macht schon mal ein Fenster auf. Nun müssen wir uns überlegen wie wir unser Quiz anlegen wollen.
Das einfachste ist wir fragen den User nach dem Namen, des Elements also zum Beispiel Eisen und der User muss auf das Element klicken – also Fe.
Das Periodensystem ist ja in Spalten und Zeilen aufgebaut. Wir brauchen jedoch die Daten, diese können wir jedoch zusammenstellen. Dem Visual Studio Projekt ist eine beigefügt.
Sie schaut so aus:

Ordnungszahl,Element,Symbol,Atomgewicht,Periode,Gruppe,Phase,Stabilster Kristall,Typ,Ionenradius,Atomradius,Elektronegativität,Erstes Ionisierungspotential,Dichte,Schmelzpunkt (K),Siedepunkt (K),Isotope,Entdecker,Entdeckungsjahr,Spezifische Wärmekapazität,Elektronenkonfiguration,Anzeigezeile,Anzeigespalte
1,Hydrogen,H,1.00794,1,1,gas,,Nonmetal,0.012,0.79,2.2,13.5984,0.00008988,14.175,20.28,3,Cavendish,1766,14.304,1s1,1,1
2,Helium,He,4.002602,1,18,gas,,Noble Gas,,0.49,,24.5874,0.0001785,,4.22,5,Janssen,1868,5.193,1s2,1,18
3,Lithium,Li,6.941,2,1,solid,bcc,Alkali Metal,0.76,2.1,0.98,5.3917,0.534,453.85,1615,5,Arfvedson,1817,3.582,[He] 2s1,2,1
4,Beryllium,Be,9.012182,2,2,solid,hex,Alkaline Earth Metal,0.35,1.4,1.57,9.3227,1.85,1560.15,2742,6,Vaulquelin,1798,1.825,[He] 2s2,2,2
5,Boron,B,10.811,2,13,solid,rho,Metalloid,0.23,1.2,2.04,8.298,2.34,2573.15,4200,6,Gay-Lussac,1808,1.026,[He] 2s2 2p1,2,13

Das ganze ist eine CSV Datei. Wir richten unser Augenmerk auf die letzten zwei Spalten Anzeigespalte und Anzeigespalte. Mit diesen zwei Variablen können wir das Periodensystem leicht aufbauen.
Als erstes schreiben wir eine Funktion, mit der wir die Daten einlesen können. Dazu verwenden wir eine neue Bibliothek namens CSV.
Das CSV (Comma-Separated Values) Paket ist eine Python-Bibliothek, die es ermöglicht, CSV-Dateien in Python zu lesen und zu schreiben. CSV-Dateien sind eine gängige Möglichkeit, Daten in tabellarischer Form zu speichern und auszutauschen, wobei die Werte in den Spalten durch Kommas oder andere Trennzeichen getrennt sind.

Mit dem CSV Paket können wir CSV Dateien lesen und in Datenstrukturen wie Listen oder Dictionaries speichern. Dies erleichtert die Verarbeitung und Analyse von Daten aus externen Quellen.

Beispiel zum Lesen einer CSV-Datei:

import csv

with open('datei.csv', 'r', newline='') as datei:
csv_reader = csv.reader(datei)
for zeile in csv_reader:
print(zeile)

Mit dem csv Paket können wir auch Daten aus Python in eine CSV-Datei schreiben. Dies ist nützlich, um Ergebnisse oder Analysen in einem einfach zu lesenden Format zu speichern.

Beispiel zum Schreiben in eine CSV-Datei:

Import csv

daten = [
['Name', 'Alter', 'Stadt'],
['Alice', 30, 'Graz'],
['Bob', 25, 'München']
]

with open('ergebnisse.csv', 'w', newline='') as datei:
csv_writer = csv.writer(datei)
csv_writer.writerows(daten)

Für unsere Periodensystem.csv schaut der Code zum Einlesen wie folgt aus:

def PeriodensystemEinlesen():

# Dateiname der CSV-Datei
csv_datei = 'PeriodicTableofElements.csv'  

# Liste zum Speichern der Daten
daten = []

# Öffne die CSV-Datei und lies sie ein
with open(csv_datei, 'r', newline='',encoding='latin-1') as datei:
    csv_reader = csv.DictReader(datei)

    for zeile in csv_reader:
        daten.append(zeile)

return daten

Diese Funktion gibt uns alle Felder des Periodensystems zurück.
Nun müssen wir noch das Layout aufbauen. Das Periodensystem ist Gott-Sei-Dank recht stabil (außer im CERN finden sie ein neues Element) und, wie schon erwähnt, in Spalten und Zeilen aufgeteilt. Das macht uns das Leben einfacher

ps_elemente = PeriodensystemEinlesen();

layout = [[NULL for _ in range(18)] for _ in range(9)]

for row in range(9):
for col in range(18):
element = findeElementAnPos(ps_elemente,row+1,col+1)
if element != NULL:

       layout[row][col] = sg.Button(element['Symbol'], size=(4, 2))
    else:
        layout[row][col] = sg.Push(background_color='gray')

Wir definieren uns eine Variable “layout”, die wir mit NULL (also Nichts) initialisieren. Das Array “layout” ist zweidimensional also Zeilen und Spalten. Nun iterieren wir mit den Variablen row und col durch unser layout.
Die Funktion findeElementAnPos sucht uns das richtige Element an der Position. Da nicht an jeder Position ein Element ist, verwenden wir sg.Push um eine “Lücke” zu machen.
Wenn wir an der Position ein Element gefunden haben, dann erstellen wir einen Button.

Abschließend fügen wir noch ein paar Zeilen ein um dem User, also uns, die Möglichkeit zu geben, entweder zu Spielen oder Infos über das Element zu bekommen.

layout.insert(0, [sg.Radio('Info', "Modus", default=True,enable_events=True, size=(10,1), k='-Info-'), sg.Radio('Spiel', "Modus", default=False,enable_events=True, size=(10,1), k='-Spiel-')])
layout.insert(0,[sg.Button(SPIELBUTTON_TEXT_STARTEN,key=SPIELBUTTON,visible=False), sg.Text('', key=FRAGE,visible=False, font='_ 16')])
layout.insert(0,[sg.Text('Periodensystem', font='_ 20')])

Schauen wir uns das Ganze genauer an.
In der Zeile layout.insert(0, [sg.Radio(‚Info‘, „Modus“, default=True, enable_events=True, size=(10,1), k=‘-Info-‚), sg.Radio(‚Spiel‘, „Modus“, default=False, enable_events=True, size=(10,1), k=‘-Spiel-‚)])
Fügen wir eine horizontale Zeile (Reihe) zum GUI-Layout hinzugefügt, diese enthält zwei Radiobuttons (‚Info‘ und ‚Spiel‘), die wir in einer gemeinsamen Gruppe mit dem Namen „Modus“ platzieren.
Wir wollen damit folgendes erreichen. Wenn wir unser Programm auf Info stellen und wir einen Button mit einem Element drücken, dann wird ein PopUp aufgemacht und die Infos über das Element ausgegeben. Wenn wir in den Spiele Modus wechseln, müssen wir das Element finden, nachdem wir gefragt werden.
Der ‚Info‘-Radiobutton ist standardmäßig ausgewählt (default=True).
Damit wir im Code auch mitbekommen, müssen wir beide Radiobuttons so konfigurieren, dass sie Ereignisse auslösen (enable_events=True), wenn sie ausgewählt werden.
In der nächsten Zeile fügen wir ein paar (noch) unsichtbare Elemente für den Spiele Modus hinzu:

layout.insert(0, [sg.Button(SPIELBUTTON_TEXT_STARTEN, key=SPIELBUTTON, visible=False), sg.Text(“, key=FRAGE, visible=False, font=’_ 16′)]):

Das unsichtbare Button-Element (sg.Button, visible=False) mit dem angegebenen Text (SPIELBUTTON_TEXT_STARTEN = eine Konstante, die wir definiert haben) und einem Schlüssel (Key) SPIELBUTTON.

layout.insert(0, [sg.Text(‚Periodensystem‘, font=’_ 20′)])

Zu guter Letzt fügen wir noch die Überschrift ein. Da wir unser Layout mit den ganzen Elementen schon gebaut haben, müssen wir um etwas vor den Buttons einzufügen eben Insert und die Position 0 verwenden.

Das ganze schaut dann so aus:

Nun wollen wir unserem Programm die Info Funktion beibringen.
Da wir im “Info” Modus starten deklarieren wir eine Variable Spielen und setzen sie auf False.
Wenn nun ein Element Button gedrückt wird haben wir zwei Möglichkeiten – entweder es ist die Antwort auf eine Frage oder eben wir wollen Informationen zu dem Element.

element = findeElement(ps_elemente,event)

if element != NULL:
   if Spielen == True:
       Gesamt = Gesamt +1;
       if (element['Symbol'] == AktuelleFrage['Symbol']):
          sg.popup("Richtig!!")
          Richtig = Richtig+1
        else:
              sg.popup("Falsch",f"Leider falsch!!\nDie richtige Antwort ist {AktuelleFrage['Symbol']} - {AktuelleFrage['Element']}\nDu hast {element['Symbol']} mit der Ordnungszahl {element['Atomic Number']} ausgewähl! ")
              AktuelleFrage = random.choice(ps_elemente)
              window[FRAGE].update(f"Welches Atom hat die Ordnungszahl {AktuelleFrage['Atomic Number']} ?")
   else:
        InfosAnzeigen(element)

In unserer Variable Event ist das Element enthalten, auf das wir geklickt haben. Wir suchen also mit der Funktion findeElement aus alles unseren geladenen Elementen das Element heraus. Wenn unsere Variable Spielen False ist, dann rufen wir die Funktion Infos Anziegen auf.

def infosAnzeigen(element):

elementlayout = []
for item in element:
    elementlayout.append([sg.Text(item, size=(30, 1)),sg.Text(element[item])])

layout=[[sg.Column(elementlayout,scrollable=True,expand_x=True,expand_y=True)], [sg.Button('Ok')]]

window = sg.Window('Element Info', layout,resizable=True, grab_anywhere=False, size=(800, 480), return_keyboard_events=True, finalize=True)
window.BringToFront()
while True:
    event, values = window.read()
    if event in (None, 'Ok'):
        break

Zuerst erstellen wir einen leeren Layout C0ntainer namens elementlayout, um die Layout-Elemente für die PySimpleGUI-Oberfläche zu speichern.
Nun durchlaufen wir eine Schleife für jedes Element im element-Dictionary. Für jedes Element wird ein Textfeld (sg.Text) mit einer festen Größe von 30×1 und ein weiteres Textfeld erstellt, das den Wert des aktuellen Elements enthält. Dieses Textpaar fügen wir elementlayout-Liste hinzu.
Das eigentliche GUI-Layout erstellen wir aus einer Spalte (sg.Column), die die gesammelten Elementlayouts enthält. Diese Spalte ist scrollbar, und die Größe kann sowohl horizontal als auch vertikal expandieren. Einen OK-Button fügen wir ebenfalls hinzu.
Als nächstes definieren wir ein PySimpleGUI-Fenster (sg.Window) mit unserem Layout, mit einer festen Größe von 800×480 Pixeln, der Option zur Größenänderung, der Option „grab_anywhere=False“ (um das Verschieben des Fensters zu deaktivieren) und der Möglichkeit, Tastatureingaben zu verarbeiten. Nun sagen wir PySimpleGUI das wir das Fenster im Vordergrund platziert (window.BringToFront()) haben wollen.
Zum Schluss warten wir bis das Fenster geschlossen wird oder wir den OK Button drücken.

So nun zu unserem Spiel.
Wenn wir unseren Radio Button auf Spielen stellen wird die Variable auf Spielen = True umgestellt und wir machen ein paar Felder sichtbar bzw. unsichtbar.

window[SPIELBUTTON].update(visible=True)
window[SPIELBUTTON].update(SPIELBUTTON_TEXT_STARTEN)
window[FRAGE].update(visible=True)

Die update Methode verhilft uns das GUI zu verändern. Wir können entweder, wie in der ersten Zeile ein unsichtbares Element sichtbar machen (visible = True) oder aber auch einen Text ändern, wie in Zeile zwei.
Wir haben nun den Text des SPIELBUTTONs auf “Spiel starten” gestellt. Wenn dieser nun gedrückt wird, so soll das Spiel mit der ersten Frage gestartet werden.
Bei nochmaligen Drücken wird das Spiel gestoppt.

if event == SPIELBUTTON:
   Spielen = not Spielen
   if (Spielen == True):
      window[FRAGE].update(visible=True)
      AktuelleFrage = random.choice(ps_elemente)
      window[SPIELBUTTON].update(SPIELBUTTON_TEXT_STOPPEN)
      window[FRAGE].update(f"Welches Atom hat die Ordnungszahl {AktuelleFrage['Atomic Number']} ?")
   else:
      prozent = Richtig / Gesamt * 100
      SpielerText = "Weiter so Du wirst immer besser!"
      if prozent > 30:
         SpielerText = "Sehr gut!"
      if prozent > 50:
         SpielerText = "Wunderbar! Du bist am bestem Weg zum Experten!"
      if prozent > 70:
         SpielerText = "Viel fehlt nicht mehr und Du bist Experte!"
      if prozent > 80:
         SpielerText = "Du bist Experte!"

      sg.popup("Ergebnis",f"{SpielerText}\nDu hast {Gesamt} Fragen beantwortet davon {Richtig} Richtig!")
      window[SPIELBUTTON].update(SPIELBUTTON_TEXT_STARTEN)
      window[FRAGE].update(visible=False)
      Gesamt =0
      Richtig = 0

Wenn der Spieler mit dem Spiel aufhören will, so drückt er “Spiel beenden”. Wir geben ihm dann eine kleine Statistik und motivierende Worte aus.
Dazu verwenden wir die Funktion popup. Mit der ist es ein leichtes Nachrichten, Fehlermeldungen oder ähnliches dem User anzeigen zu lassen.

Den gesamten Code kannst Du unter gpiwonka/Periodensystem: Ein Programm zum Erlernen des Periodensystems (github.com)