Homepage von Papa

Projekt Schiffeversenken

Die Datenbank

Kurzer Exkurs zu Datenbanken, bevor wir das programmieren.

Der Begriff "Datenbank" wird oft synonym mit "Datenbanktabelle" oder kurz nur "Tabelle" genutzt. Zur Abgrenzung werde ich versuchen hier so genau wie möglich zu sein.

Die Daten selbst liegen in der Datenbanktabelle. Die Organisation der Datenbanktabelle obliegt dabei dem Datenbanksystem, in unserem Fall also SQLite. In einer Datenbank können viele verschiedene Datenbankabellen gespeichert sein, diese sollten allerdings immer einen fachlichen Bezug untereinander haben.

Zur Veranschaulichung mal ein Beispiel einer Autovermietung gemacht, da hatten wir eine Datenbanktabelle mit den Informationen zum "Kunden", eine weitere mit den Informationen zu unserem "Fuhrpark" und eine dritte Datenbanktabelle zur "Vermietung" selbst. Also 3 Datenbanktabellen in einer Datenbank namens "Autovermietung".

Machen wir es für unser Projekt konkret, die Datenbank wird bei uns "battle.db" heißen, die Datenbanktabelle in der die Informationen abgelegt sind, heißt "game".

Nun stellt sich die Frage, welche Informationen müssen wir überhaupt speichern? Dazu überlegen wir uns, welche Subjekte es in unserem Spiel gibt und welche Informationen wir zu diesen Subjekten benötigen.

Subjekt Erklärung
Kennung des Spiels Ein Spiel besteht aus genau 2 Spielern, und diese müssen sich über eine eindeutige Kennung des Spiels zusammenfinden
Name Spieler 1 Name des ersten Spielers
Spielfeld Spieler 1 Informationen zum Spielfeld, also Position der Schiffe, Treffer- oder Wasserschüsse, des Gegners
Status Spieler 1 z.B. "Spiel eröffnet", "wartet auf Zug", "hat gewonnen"
Name Spieler 2 Name des zweiten Spielers
Spielfeld Spieler 2 Wie oben, allerdings die Abbildung der gegnerischen Schiffe
Status Spieler 2 z.B. "Spiel beigetreten", "am Zug", "hat verloren"

Wenn wir diese Tabelle jetzt kippen, also Spalten werden zu Zeilen, dann haben wir schon die Struktur für eine Datenbanktabelle. Geben wir noch eine eindeutige ID dazu und füllen das gleich noch mit ein paar hypothetischen Inhalten, sehen wir auch, ob das Konzept passt:

ID Kennung des Spiels Name Spieler 1 Spielfeld Spieler 1 Status Spieler 1 Name Spieler 2 Spielfeld Spieler 2 Status Spieler 2
1 ABCDEF Adam 1100TW... am Zug Adele 1111WW... wartet
2 GHIJKL Berta 1111100... wartet Ben WW0000... am Zug
3 MNOPQ Casper Spiel gestartet

Legen wir uns zuerst eine neue version_02 an und schauen kurz auf die Änderungen in der Struktur (neue Komponenten = rot umrandet):

Cool

Wir erstellen den Ordner instance, die Datenbank wird dann durch die Anwendung selbst erzeugt.

Zusätzlich brauchen wir noch 2 Module, models.py und script.py.

Das Modul models.py enthält die Klassendefinition, das script.py ist eine Hilfe zur Erzeugung und Pflege der Datenbank.

Erweitert werden die Module routes.py und app_init.py.

Hinweis

Bevor Ihr alles per Hand kopiert, könnt Ihr Euch auch die Sourcen hier oder über den Button unten herunterladen.

Nachdem wir die leeren Hüllen angelegt haben, geht es weiter mit app_init.py. Der neue Code ist folgender:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# Erstelle die db Instanz
db = SQLAlchemy()

def create_app():
    app = Flask(__name__)

    # Konfiguration laden
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///battle.db'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['SECRET_KEY'] = 'IrgendeinWortOderEineZahlWie42'

    # Datenbank initialisieren 
    db.init_app(app)

    # Blueprints registrieren
    from routes import main
    app.register_blueprint(main)

    return app
    

Neu ist jetzt models.py. Hier tragen wir die Datenbanktabellenfelder als Klasse ein:

from app_init import db

class Game(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    game_code = db.Column(db.String(6), nullable=False)
    p_1_name = db.Column(db.String(100), nullable=True)
    p_1_board  = db.Column(db.String(100), nullable=True)
    p_1_status = db.Column(db.String(100), nullable=True)
    p_2_name = db.Column(db.String(100), nullable=True)
    p_2_board = db.Column(db.String(100), nullable=True)
    p_2_status = db.Column(db.String(100), nullable=True)

    def __repr__(self):
        return f"{self.game_code}"
    

Damit kommen wir zum Modul script.py. Nachfolgenden Code könnt Ihr einfach übernehmen:

from app_init import create_app, db
from models import Game
from sqlalchemy import create_engine, inspect

# Initialwerte
game_code_init = 'ABCDEF'
p_1_name_init = 'Adam' 
p_1_board_init  = '1000T0…'
p_1_status_init = 'am Zug'
p_2_name_init = 'Adele'
p_2_board_init = '1110T0…'
p_2_status_init = 'wartet'

app = create_app()
engine = create_engine('sqlite:///instance/battle.db', echo=True)

def drop_table():
    inspector = inspect(engine)
    if 'game' in inspector.get_table_names():
        Game.__table__.drop(engine)
        print("Tabelle 'Game' wurde gelöscht.")
    else:
        print("Tabelle 'Game' existiert nicht, Step wird übersprungen.")

def create_table():
    with app.app_context():
        try:
            db.create_all()  # Erstellt alle Tabellen
            print("Tabellen wurden erstellt.")
        except Exception as e:
            print(f"Fehler beim Erstellen der Tabellen: {e}")
            return  # Funktion abbrechen, wenn Tabellen nicht erstellt werden konnten

        try:
            new_game = Game(game_code   = game_code_init, 
                            p_1_name    = p_1_name_init,
                            p_1_board   = p_1_board_init, 
                            p_1_status  = p_1_status_init,
                            p_2_name    = p_2_name_init,
                            p_2_board   = p_2_board_init,
                            p_2_status  = p_2_status_init
                            )  
            db.session.add(new_game)
            db.session.commit()
            print("Initiales Spiel erfolgreich angelegt.")
        except Exception as e:
            db.session.rollback()  # wichtig: Rollback bei Fehlern
            print(f"Fehler beim Einfügen des initialen Spiels: {e}")

if __name__ == '__main__':
    print('Start')
    drop_table()
    create_table()
    print('Ende')
    

Okay, cool, showtime!

Da wir mit if __name__ == '__main__': in Zeile 50 den autonomen Programmstart des Skripts festgelegt haben, können wir das Skript in VSCode einfach mit dem Run-Button oben rechts starten. Bei mir kommt dann ein Terminal-Fenster mit der Info:

Wie können wir den Erfolg nun kontrollieren? Wie greifen wir auf die Datenbank zu?

Zum Betrachten der Inhalte reicht das Plugin "SQLIte Viewer" in VSCode:

Wenn wir das installieren, können wir die Datei per Doppelklick öffnen, das sieht dann so aus:

Als kostenlose Alternative habe ich wie oben beschrieben SQLiteStudio installiert. Die Installation von oben hat ja funktioniert, der erste Aufruf sollte bei Euch dann etwa so aussehen:

Mit "Database/Add a database"...

Cool

... und Navigation zu unserer battle.db in der version_02,...

Cool

...dann oben links auf "Connect to database"...

Cool

...und Rechtsklick auf game ein Select-Fenster aufmachen:

Cool

Im Fenster rechts dann erscheint die Abfrage mit allen Feldern. Oben auf den blauen Pfeil klicken und die Abfrage wird ausgeführt. In der Mitte sieht man dann das Ergebnis der Abfrage, unsere Daten sind angekommen, also alles okay!

0,000 Sekunden – das ist mal schnell...

Wunderbar, damit haben wir die Datenbank battle.db mit der Datenbanktabelle game erfolgreich eingebunden!

Eine genauere Beschreibung gibt es in der Projektdoku (Download hier). Den Sourcecode könnt Ihr hier oder über den Button unten herunterladen.


  • Zurück
  • Weiter

Inhaltsverzeichnis:

1. Vorwort
2. Das Projekt
3. Vorarbeiten
4. Das Projekt „Schiffeversenken“
4.1. Der Funktionsumfang
4.2. Die Planung der Umsetzung
4.3. Das Coden
4.3.1 Arbeiten mit Flask
4.3.2 Die Datenbank
4.3.3 Der Spielstart
4.3.4 Der Spielcode
4.3.5 Die Spielfelder
4.3.6 Setzen der Schiffe
4.3.7 Das Spielen
4.4. Die Veröffentlichung
5. Abschluss

© by Papa. Die Seite ist online seit 2020.

Menu

  • Startseite
  • Projekte
    • Übersicht aller Projekte
    • Schiffeversenken
    • Taschenrechner
    • Nachbau Snake
  • Helferlein
    • Übersicht Hilfprogramme
    • Fonts in pygame
    • Quellcode nach HTML
    • Text nach HTML
  • Impressum
  • Disclaimer

Modal content goes here