Time and Memory: Design Kartenspiel

Hallo zusammen,

mein Wissensstand bezüglich Datenbanken beschränkt sich leider auf den Unterricht der Berufsschule, was nun schon ein paar Jahre her ist.

Gerade das Designen einer Datenbank ist kein Gebiet in dem ich viel Erfahrung habe.

Ich versuche mal mein Problem vernünftig zu erklären und hoffe, dass mir jemand einen Denkanstoß geben kann:

Ich erstelle momentan ein Kartenspiel und würde das erste SET (100 Karten) nun gerne in einer Datenbank (mySQL) abspeichern. Das Spiel ähnelt dem Kartenspiel "Magic the gathering", falls das zum Verständnis beiträgt.

Ich habe mir folgende Überlegungen bezüglich der Tabellenstruktur gemacht:

Table Karte

  • ID
  • Name
  • Seltenheit
  • Kartenart

Table Seltenheit

  • ID
  • Name (Gold, Silber Bronze)

Table Kosten

  • ID
  • Gold
  • Holz
  • Wasser

Das Attribut Seltenheit ist mit der Seltenheit Tabelle verbunden und hat den Zweck die Sicherheits des Werts sicherzustellen. So das wirklich nur die verfügbaren Werte (gold, silber etc.) ausgewählt werden können. Sonst könnte man ja in einem Textfeld eintragen was man möchte.

Über die ID der Tabelle Karte wird eine Beziehung zur Kosten Tabelle aufgebaut. Da sich die Kosten in mehrere Werte teilen (Gold, Holz...) fand ich die Auslagerung in eine weitere Tabelle hier sinnvoll. Man könnte meines Wissens nach zwar auch alle einzelnen Kosten in die "Karte" Tabelle packen, allerdings fühlt sich das nichts sehr "sauber" an, da dadurch auch die "Karte" Tabelle sehr groß werden könnte.

Mein Problem ist nun das Attribut "Kartenart".
Das Kartenspiel unterstützt diverse Kartenarten, wie "Taktischer Zug", "Gebäude" und "Kreaturen".
Kreaturen gibt es auch noch in unterschiedlichen Ausprägungen, z.B. Trolle, Oger, Menschen etc.
Taktischer Zug wird einmalig ausgespielt und landet anschließend im Friedhof. Diese Karte hat keine Lebenspunkte und keinen Angriffswert. Ein Gebäude zum Beispiel hat nur Lebenspunkte, aber ebenfalls keinen Angriffswert. Eine Kreatur hat beides.

Jetzt stelle ich mir die Frage wie ich sowas vernüftig in ein Datenbankmodell übertragen soll. Ich könnte Werte wie Lebenspunkt oder Angriffpunkte beispielsweise in die "Karte" Tabelle packen, allerdings gibt es eine Vielzahl von karten, die diese Attribute gar nicht besitzt. Das bedeutet, meine Tabelle würden so von null Werten wimmeln. Klingt zwar machbar aber nicht nach der besten Lösung.
Eine andere Möglichkeit wäre der Karte Tabelle Attribute zu geben wie "Einheitentyp", "Gebäudetyp" usw. und dann nur dann zu füllen, wenn die Karte eine Kreatur ist z.B. Das ist allerdings auch nicht sauber, da ja dadurch eine Karte zumindest technisch gesehen ein Gebäude und eine Kreatur gleichzeitig sein könnte.

Ich suche nun nach einem Modell, was mir die Sicherheit der Daten gewährleistet, aber dennoch "smart" und korrekt ist.

Ich hoffe ich konnte mein Problem gut beschreiben.
(Bitte nur Antworten, die sich mit dem Thema befassen und keine Belehrungen wie z.B. warum (mySQL, Magic etc)

Danke und viele Grüße,
Time

  1. Hello,

    Table Karte

    • ID
    • Name
    • Seltenheit
    • Kartenart

    Table Seltenheit

    • ID
    • Name (Gold, Silber Bronze)

    Table Kosten

    • ID
    • Gold
    • Holz
    • Wasser

    Es empfiehlt sich, sich das Ganze grafisch zu verdeutlichen:

    https://de.wikipedia.org/wiki/Entity-Relationship-Modell

    https://de.wikipedia.org/wiki/Unified_Modeling_Language

    Anderenfalls steigt man irgendwann nicht mehr durch oder baut sich _unerwünschte_ Redundanzen ein.

    Es gibt durchaus auch erwünschte "Redundanzen", die aber unter einem zeitlichen Aspekt dann meistens keine mehr sind (Historie).

    Ein wesentlicher Startpunkt beim Design ist es daher, zwischen "Stammdaten" und "Bewegungsdaten" zu trennen.

    https://de.wikipedia.org/wiki/Stammdaten

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bikers-lodge.com
    1. Es empfiehlt sich, sich das Ganze grafisch zu verdeutlichen:

      https://de.wikipedia.org/wiki/Entity-Relationship-Modell

      https://de.wikipedia.org/wiki/Unified_Modeling_Language

      Anderenfalls steigt man irgendwann nicht mehr durch oder baut sich _unerwünschte_ Redundanzen ein.

      Es gibt durchaus auch erwünschte "Redundanzen", die aber unter einem zeitlichen Aspekt dann meistens keine mehr sind (Historie).

      Ein wesentlicher Startpunkt beim Design ist es daher, zwischen "Stammdaten" und "Bewegungsdaten" zu trennen.

      https://de.wikipedia.org/wiki/Stammdaten

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      Hallo Tom,

      danke für deine Antwort. Ich habe mir eine Übersicht ganz traditionell auf einem Blatt Papier gemacht, nur konnte ich die hier leider nicht aufzeichnen.

      Nur ist meine Datenbank noch so klein, dass ich hoffe das mein Problem gelöst werden und nicht mehr als meine Beschreibung nötig ist.

      Es fällt mir leider relativ schwer das Problem abstrakt zu formulieren. Ich würde es folgermaßen versuchen:

      Manche Objekte besitzen Eigenschaften, die andere Objekte nicht besitzen. Z.B Hat ein Gebäude keinen Angriffswert, eine Kreatur aber schon.

      Das müsste man nun irgendwie in einem Modell abbilden.

      Gruß,
      Time

      1. Es fällt mir leider relativ schwer das Problem abstrakt zu formulieren. Ich würde es folgermaßen versuchen:

        Manche Objekte besitzen Eigenschaften, die andere Objekte nicht besitzen. Z.B Hat ein Gebäude keinen Angriffswert, eine Kreatur aber schon.

        Das müsste man nun irgendwie in einem Modell abbilden.

        wenn du es sauber machen willst, bedeutet das, dass jedes dieser von dir genannten objekte eine eigene tabelle kriegen muss. aber möglicherweise solltest du dir mal noSQL Datenbanken angucken - die könnten hierbei deutlich besser für dein Anliegen geeignet sein.

        Gruß,
        Time

  2. Tach!

    Table Seltenheit

    • ID
    • Name (Gold, Silber Bronze)

    Das sieht mir eher so aus, als ob da ein Enum reicht. Die drei Werte stehen vermutlich fest und es ich gehe davon aus, dass es keine Erweiterungen geben wird. Anderenfalls fügt man im einfachsten Fall den neuen Wert zum Enum hinzu, in schwierigeren Fällen muss man sowieso neu schauen und dann anhand der konkreten Änderungen die weitere Vorgehensweise entscheiden.

    Table Karte

    • ID
    • Name
    • Seltenheit
    • Kartenart

    Table Kosten

    • ID
    • Gold
    • Holz
    • Wasser

    Wenn es immer diese drei Baustoffe sind und keine weiteren Beziehungen nach anderswo existieren (zum Beispiel zu weiteren Materialen, die man im Spiel braucht. Beispiel Anno, da gibt es neben den Baumaterialen auch Verbrauchsgüter, die aber ansonsten genau gleiche Eigenschaften haben und auch grundlegend so behandelt werden), dann würde ich hier einfach drei Felder in die Tabelle Karte einfügen. Damit spart man sich im weiteren Verlauf ein oder drei Joins (je nachdem, wie man die Abfrage gesteltet).

    allerdings fühlt sich das nichts sehr "sauber" an, da dadurch auch die "Karte" Tabelle sehr groß werden könnte.

    Definiere "sehr groß"! Gibts es noch deutlich mehr Materialien? Um "groß" musst du dir nicht wirklich Gedanken machen. Die üblicherweise in Kartenspielen enthaltene Datenmenge, langweilt ein DBMS nur.

    Das Kartenspiel unterstützt diverse Kartenarten, wie "Taktischer Zug", "Gebäude" und "Kreaturen".

    Das könnte ein Enum werden.

    Kreaturen gibt es auch noch in unterschiedlichen Ausprägungen, z.B. Trolle, Oger, Menschen etc.

    Sieht nach einem weiteren Enum aus.

    Taktischer Zug wird einmalig ausgespielt und landet anschließend im Friedhof. Diese Karte hat keine Lebenspunkte und keinen Angriffswert. Ein Gebäude zum Beispiel hat nur Lebenspunkte, aber ebenfalls keinen Angriffswert. Eine Kreatur hat beides.

    Das wären dann zwei Spalten, die teilweise null bleiben müssten. Du kannst das in eine weitere Tabelle auslagern, aber auch hier sehe ich wie bei den Baumaterialen ähnliche Notwendigkeiten. Je mehr du auslagerst, desto mehr musst du joinen oder Folgeabfragen stellen. Das was du aufzählst sind mehr oder weniger einfache Eigenschaften, die beim Auslagern nur eine 1:1-Beziehung ergeben. Da sollte man sich schon überlegen, ob der Aufwand die Auslagerung rechtfertigt.

    Jetzt stelle ich mir die Frage wie ich sowas vernüftig in ein Datenbankmodell übertragen soll. Ich könnte Werte wie Lebenspunkt oder Angriffpunkte beispielsweise in die "Karte" Tabelle packen, allerdings gibt es eine Vielzahl von karten, die diese Attribute gar nicht besitzt. Das bedeutet, meine Tabelle würden so von null Werten wimmeln.

    Das ist nicht wirklich ein Problem. Man muss auch nicht versuchen, krampfhaft eine Trennung einzubauen, die dann anderswo Nachteile mit sich bringt.

    Eine andere Möglichkeit wäre der Karte Tabelle Attribute zu geben wie "Einheitentyp", "Gebäudetyp" usw. und dann nur dann zu füllen, wenn die Karte eine Kreatur ist z.B. Das ist allerdings auch nicht sauber, da ja dadurch eine Karte zumindest technisch gesehen ein Gebäude und eine Kreatur gleichzeitig sein könnte.

    Das muss dann die Programmlogik anhand der Kartenart unterscheiden. Und das muss sie bei einer Trennung ebenfalls, außerdem auch noch Folgeabfragen stellen. Oder du musst gleich spezialisierte Abfragen mit spezifischen Joins auf bestimmte Kartentypen ausführen, wenn du nach Kartenart getrennt abfragen möchtest.

    Ich suche nun nach einem Modell, was mir die Sicherheit der Daten gewährleistet, aber dennoch "smart" und korrekt ist.

    Das wird dir die Datenbank auch bei Beziehungen nicht vollständig garantieren können. Wenn zum Beispiel bei den Kosten kein Wasser benötigt wird, ergibt es keinen Unterschied ob das Feld nicht mit null gefüllt oder ein überflüssiger Datensatz in der Tabelle Kosten existiert. Beides wäre ein Fehler. Beides kann das DBMS nicht von sich aus verhindern, ohne dass es um komplexe Prüflogik erweitert wird, deren Umgehung auch noch verhindert werden muss.

    (Bitte nur Antworten, die sich mit dem Thema befassen und keine Belehrungen wie z.B. warum (mySQL, Magic etc)

    Wenn du sowas schreibst, reizt es doch gerade manche, sich ausgerechnet diesen Aspekt vorzunehmen. Außerdem liegt es dann (auch) an dir, diese Aussagen zu ignorieren und solche Abschweifungen einfach mit Missachtung zu strafen.

    dedlfix.

    1. Hallo dedlfix,

      zunächstmal danke für deine ausführliche und präzise Antwort.
      Das ist genau der "Denkanstoß" nach dem ich gesucht habe.

      Das sieht mir eher so aus, als ob da ein Enum reicht. Die drei Werte stehen vermutlich fest und es ich gehe davon aus, dass es keine Erweiterungen geben wird. Anderenfalls fügt man im einfachsten Fall den neuen Wert zum Enum hinzu, in schwierigeren Fällen muss man sowieso neu schauen und dann anhand der konkreten Änderungen die weitere Vorgehensweise entscheiden.

      Bei dem Wort "Enum" hat es klick gemacht. Wie gesagt ich bin in dieser Thematik ohne wirkliche Praxis und habe eine Menge wieder vergessen. Du hast natürlich völlig Recht. Enum ist hier die richtige Lösung um das Sicherstellen der richtigen Werte zu gewährleisten.

      Wenn es immer diese drei Baustoffe sind und keine weiteren Beziehungen nach anderswo existieren (zum Beispiel zu weiteren Materialen, die man im Spiel braucht. Beispiel Anno, da gibt es neben den Baumaterialen auch Verbrauchsgüter, die aber ansonsten genau gleiche Eigenschaften haben und auch grundlegend so behandelt werden), dann würde ich hier einfach drei Felder in die Tabelle Karte einfügen. Damit spart man sich im weiteren Verlauf ein oder drei Joins (je nachdem, wie man die Abfrage gesteltet).

      Hier sprach ich davon, dass die Tabelle "sehr groß" werden könnte. Das ist natürlich relativ. Das das DBMS diese Größen ohne Mühe behandeln kann ist mir klar. Ich hatte diesen Lösungsansatz auch schon bedacht, nur wollte ich zunächst nach Alternativen suchen.
      Mein Gedankengang war hier der folgende:
      Die Kosten gehören natürlich direkt zu einer Karte, was dafür sprechen würde, diese direkt in die Tabelle "Karte" zu integrieren. Die wirklichen Ausspielkosten sind allerdings eine Kombination aus den drei genannten Rohstoffen, daher einzeln nur bedingt von der KartenID abhängig.
      Aber auch hier erkenne ich deinen Einwand, dass man ggf. mehr Joins braucht um sich die Datensätze so zusammen zu stellen, wie man sie benötigt. Hier werde ich wohl nochmal in mich gehen und mir auch darüber Gedanken machen, wie ich Backendseitig die Logik aufbauen werden. (Es wird noch weitere Ausspielkosten geben, aber diese werden ganz anders behandelt)

      Ich muss gestehen, dass ich bei deiner Hilfe bezüglich meiner Frage der "Kartenarten" noch nicht sicher bin, ob ich da alles richtig verstanden habe.
      Ist es richtig, das du mir zusammengefasst rätst, sämtliche Kartentypen wie z.B. Gebäude, Spontaner Angriff, Menschen etc. in einem ENUM zusammen zu fassen und zusätzlich die vielen Attribute wie z.B. Angriffskraft, Lebenspunkte etc. in die Tabelle "Karte" zu integrieren?

      Das wäre sicherlich so umzusetzen und meiner Meinung nach auch die einfachste Form, nur bekomme ich dann ggf. bei der Bearbeitung der Daten Probleme. Wenn ich z.B. eine Karte ausspielen möchte, die alle "Kreaturen" betrifft, dann muss ja irgendwo eine Information vermerkt sein, die mir sagt, dass ein Mensch, ein Troll und ein Gnom Kreaturen sind, allerdings ein Gebäude nicht. In einem Enum in der Datenbank wäre ja der Kartentyp Mensch gleichwertig wie ein Gebäude, obwohl es ja eigentlich nur eine Unterkategorie von "Kreaturen" sind.

      Vielleicht liefert mir das Datenbanksystem diese Unterscheidung auch nicht und ich muss das alles mit Interfaces im Sourcecode bearbeiten, aber ich bin ja noch in der Planungsphase und versuche mir möglist viele Scherereien bei der Umsetzung zu sparen! ;)

      Sollte ich irgendetwas nicht richtig zitiert oder verstanden haben, bitte ich um Nachsicht. Ich bin nunmal ein DB Anfänger! ;)

      Gruß,
      Time

      1. Tach!

        Ich muss gestehen, dass ich bei deiner Hilfe bezüglich meiner Frage der "Kartenarten" noch nicht sicher bin, ob ich da alles richtig verstanden habe.
        Ist es richtig, das du mir zusammengefasst rätst, sämtliche Kartentypen wie z.B. Gebäude, Spontaner Angriff, Menschen etc. in einem ENUM zusammen zu fassen und zusätzlich die vielen Attribute wie z.B. Angriffskraft, Lebenspunkte etc. in die Tabelle "Karte" zu integrieren?

        Wenn ich dich richtig verstanden habe, hast du drei Kartenarten und zu jeder Art Unterarten. Das kann man natürlcih in Tabellen auslagern, aber du wirst dich da mehr verzetteln als dass es nützen wird, befürchte ich. Mein Vorschlag wäre, entweder die Kartenart in ein Feld und die Unterart in ein weiteres Feld stellen, dann kannst du unabhängig voneinander filtern. Dabei kann aber die Datenbank keine Integrität der Daten sicherstellen, denn ihr ist es egal, ob die Unterart zur Art passt oder nicht. Oder du nimmst nur ein Feld, in dem alle gültigen Kombinationen als je ein Enum-Wert drinstehen. Das ist dann beim Abfragen etwas ungünstiger, weil du da mit OR oder mit LIKE "bla - %" rangehen müsstest.

        dedlfix.

  3. Hi.
    Bist du jetzt schon sicher, das es niemals eine Karte geben wird, die Kreatur und Gebäude ist? Baba Yagas Hütte...

    Du solltest bei sowas immer möglichst flexibel sein.