sql >> Database >  >> RDS >> Database

Wat hebben poker, blackjack, Belot en Préférence met databases te maken?

Hoe een database te ontwerpen die flexibel genoeg is voor verschillende zeer verschillende kaartspellen.

Onlangs hebben we laten zien hoe een database kan worden gebruikt om bordspelresultaten op te slaan. Bordspellen zijn leuk, maar ze zijn niet de enige online versie van klassieke spellen. Kaartspellen zijn ook erg populair. Ze introduceren een element van geluk in het spel, en er komt veel meer bij kijken dan geluk bij een goed kaartspel!

In dit artikel zullen we ons concentreren op het bouwen van een datamodel om wedstrijdwedstrijden, resultaten, spelers en scores op te slaan. De grootste uitdaging hier is het opslaan van gegevens met betrekking tot veel verschillende kaartspellen. We kunnen ook overwegen om deze gegevens te analyseren om winnende strategieën te bepalen, onze eigen speelvaardigheden te verbeteren of een betere AI-tegenstander op te bouwen.

De vier kaartspellen die we in onze database zullen gebruiken

Omdat spelers geen controle hebben over de hand die ze krijgen, combineren kaartspellen strategie, vaardigheid en geluk. Die geluksfactor geeft een beginner de kans om een ​​ervaren speler te verslaan, en het maakt kaartspellen verslavend. (Dit verschilt van spellen als schaken, die sterk afhankelijk zijn van logica en strategie. Ik heb van veel spelers gehoord dat ze niet geïnteresseerd zijn in schaken omdat ze geen tegenstanders op hun vaardigheidsniveau kunnen vinden.)

We concentreren ons op vier bekende kaartspellen:poker, blackjack, belot (of belote) en préférence. Elk van hen heeft relatief complexe regels en vereist enige tijd om onder de knie te krijgen. De verhouding tussen geluk en kennis is ook voor elk spel anders.

We zullen de vereenvoudigde regels en details voor alle vier de spellen hieronder kort bekijken. Spelbeschrijvingen zijn vrij schaars, maar we hebben genoeg toegevoegd om de verschillende spelmodi en de diverse regels te laten zien die we tegenkomen tijdens het ontwerpproces van de database.

Blackjack:

  • Deck: Een tot acht decks van elk 52 kaarten; geen jokerkaarten
  • Spelers: Dealer en 1 of meer tegenstanders
  • Eenheid gebruikt: Meestal geld
  • Basisregels: Spelers krijgen 2 kaarten die alleen zij kunnen zien; de dealer krijgt twee kaarten, een met de afbeelding naar boven en de andere met de afbeelding naar beneden; elke speler besluit om meer kaarten te trekken (of niet); de dealer trekt als laatste. Kaarten hebben een puntwaarde van 1 tot 11 toegewezen.
  • Mogelijke acties van spelers: Slaan, staan, splitsen, overgeven
  • Doelpunt en overwinningsvoorwaarde: De som van de kaarten van een speler is groter dan die van de dealer; als een speler over de 21 gaat, verliest die speler.

Poker (Texas Hold'Em):

  • Deck: Standaard (ook bekend als Frans pak) 52-kaartendek; geen jokerkaarten. Kaarten zijn meestal rood en zwart van kleur.
  • Spelers: Twee tot negen; spelers delen om de beurt
  • Gebruikte eenheid:meestal chips
  • Basisregels: Elke speler begint met het krijgen van twee kaarten; spelers plaatsen hun weddenschappen; drie kaarten worden open in het midden van de tafel gedeeld; spelers plaatsen opnieuw hun weddenschappen; een vierde kaart wordt in het midden geplaatst en spelers zetten opnieuw in; dan wordt de vijfde en laatste kaart geplaatst en is de laatste inzetronde voltooid.
  • Mogelijke acties van spelers: Fold, Call, Raise, Small Blind, Big Blind, Reraise
  • Doel: Combineer de best mogelijke hand van vijf kaarten (van de twee kaarten in de hand van de speler en de vijf kaarten in het midden van de tafel)
  • Overwinningsvoorwaarde:meestal om alle fiches op tafel te winnen

Belot (Kroatische variant van Belote):

  • Deck: Meestal het traditionele Duitse of Hongaarse kaartspel met 32 ​​kaarten; geen jokerkaarten
  • Spelers: Twee tot vier; meestal vier spelers in paren van twee
  • Eenheid gebruikt: Punten
  • Basisregels: Bij een spel met vier spelers krijgt elke speler zes kaarten in de hand en twee gesloten kaarten; spelers bieden eerst op troefkleur; nadat de troef is bepaald, nemen ze de twee gesloten kaarten en leggen ze in hun hand; er volgt een declaratieronde, waarin bepaalde kaartcombinaties worden aangekondigd voor extra punten; het spel gaat door totdat alle kaarten zijn gebruikt.
  • Mogelijke acties van spelers: Pass, Biedkleur, Verklaring, Gooikaart
  • Doelpunt voor de hand: Om meer dan de helft van de punten te winnen
  • Overwinningsvoorwaarde: Wees het eerste team dat 1001 punten of meer scoort

Voorkeur:

  • Deck: Meestal een traditioneel Duits of Hongaars kaartspel met 32 ​​kaarten; geen jokerkaarten
  • Spelers: Drie
  • Eenheden: Punten
  • Basisregels: Alle spelers krijgen 10 kaarten; twee "kitty"- of "talon" -kaarten worden in het midden van de tafel gelegd; spelers bepalen of ze op een kleur willen bieden; spelers beslissen om te spelen of niet.
  • Mogelijke acties van spelers: Passen, Bieden, Spelen, Niet Spelen, Kaart gooien
  • Doel: Hangt af van de variant van Préférence die wordt gespeeld; in de standaardversie moet de bieder in totaal zes slagen winnen.
  • Overwinningsvoorwaarde: Wanneer de som van de scores van alle drie de spelers 0 is, wint de speler met het laagste aantal punten.

Waarom databases en kaartspellen combineren?

Ons doel hier is om een ​​databasemodel te ontwerpen waarin alle relevante gegevens voor deze vier kaartspellen kunnen worden opgeslagen. De database zou door een webapplicatie kunnen worden gebruikt als een plek om alle relevante gegevens op te slaan. We willen de initiële spelinstellingen, speldeelnemers, acties die tijdens het spel worden ondernomen en de uitkomst van een enkele deal, hand of trick opslaan. We moeten ook rekening houden met het feit dat een match een of meer deals kan hebben.

Van wat we in onze database opslaan, zouden we in staat moeten zijn om alle acties die tijdens het spel hebben plaatsgevonden, opnieuw te creëren. We gebruiken tekstvelden om overwinningsvoorwaarden, spelacties en hun resultaten te beschrijven. Deze zijn specifiek voor elk spel en de logica van de webtoepassing interpreteert de tekst en transformeert ze indien nodig.

Een korte introductie tot het model




Dit model stelt ons in staat om alle relevante spelgegevens op te slaan, waaronder:

  • Spel-eigenschappen
  • Lijst met games en wedstrijden
  • Deelnemers
  • In-game acties

Omdat games op veel manieren verschillen, gebruiken we vaak de varchar(256) gegevenstype om eigenschappen, zetten en resultaten te beschrijven.

Spelers, wedstrijden en deelnemers

Dit gedeelte van het model bestaat uit drie tabellen en wordt gebruikt om gegevens op te slaan over geregistreerde spelers, de gespeelde wedstrijden en de spelers die hebben deelgenomen.

De player tabel slaat gegevens op over geregistreerde spelers. De username en email attributen zijn unieke waarden. De nick_name attribute slaat de schermnamen van spelers op.

De match tabel bevat alle relevante wedstrijdgegevens. Over het algemeen bestaat een wedstrijd uit een of meer kaartdeals (ook bekend als rondes, handen of trucs). Alle wedstrijden hebben vaste regels voordat het spel begint. De attributen zijn als volgt:

  • game_id – verwijst naar de tabel met de lijst met spellen (in dit geval poker, blackjack, belot en préférence).
  • start_time en end_time zijn de werkelijke tijden waarop een wedstrijd begint en eindigt. Merk op dat de end_time kan NULL zijn; we zullen zijn waarde pas hebben als het spel eindigt. Als een wedstrijd wordt afgebroken voordat deze is afgelopen, wordt de end_time waarde kan NULL blijven.
  • number_of_players – is het aantal deelnemers dat nodig is om het spel te starten
  • deck_id - verwijst naar het kaartspel dat in het spel wordt gebruikt.
  • decks_used – is het aantal kaartspellen dat wordt gebruikt om het spel te spelen. Meestal is deze waarde 1, maar sommige spellen gebruiken meerdere kaartspellen.
  • unit_id – is de eenheid (punten, chips, geld, enz.) die wordt gebruikt om het spel te scoren.
  • entrance_fee – is het aantal eenheden dat nodig is om deel te nemen aan het spel; dit kan NULL zijn als het spel niet vereist dat elke speler met een bepaald aantal eenheden begint.
  • victory_conditions – bepaalt welke speler de wedstrijd heeft gewonnen. We gebruiken de varchar gegevenstype om de overwinningsvoorwaarde van elk spel te beschrijven (d.w.z. eerste team dat 100 punten bereikt) en verlaat de applicatie om het te interpreteren. Deze flexibiliteit laat ruimte voor veel games die kunnen worden toegevoegd.
  • match_result – slaat het resultaat van de wedstrijd op in tekstformaat. Net als bij victory_conditions , laten we de toepassing de waarde interpreteren. Dit attribuut kan NULL zijn omdat we die waarde invullen op hetzelfde moment dat we de end_time invoegen waarde.

De participant tabel slaat gegevens op over alle deelnemers aan een wedstrijd. De match_id en player_id attributen zijn verwijzingen naar de match en player tafels. Samen vormen deze waarden de alternatieve sleutel van de tabel.

De meeste spellen roteren welke speler als eerste biedt of speelt. Meestal wordt in de eerste ronde de speler die als eerste speelt (de openingsspeler) bepaald door de spelregels. In de volgende ronde gaat de speler links (of soms rechts) van de oorspronkelijke openingsspeler als eerste. We gebruiken de initial_player_order attribuut om het volgnummer van de openingsspeler van de eerste ronde op te slaan. De match_id en de initial_player_order attributen vormen een andere alternatieve sleutel omdat twee spelers niet tegelijkertijd kunnen spelen.

De score kenmerk wordt bijgewerkt wanneer een speler een wedstrijd beëindigt. Soms is dit op hetzelfde moment voor alle spelers (bijvoorbeeld in belot of préférence) en soms terwijl de wedstrijd nog aan de gang is (bijvoorbeeld poker of blackjack).

Acties en actietypes

Als we denken aan acties die spelers kunnen uitvoeren in een kaartspel, realiseren we ons dat we het volgende moeten opslaan:

  • Wat de actie was
  • Wie heeft die actie uitgevoerd
  • Wanneer (in welke deal) de actie plaatsvond
  • Welke kaart(en) werden bij die actie gebruikt

Het action_type table is een eenvoudig woordenboek dat de namen van speleracties bevat. Enkele mogelijke waarden zijn:kaart trekken, kaart spelen, kaart doorgeven aan een andere speler, controleren en verhogen.

In de action tabel, slaan we alle gebeurtenissen op die tijdens een deal hebben plaatsgevonden. De deal_id , card_id , participant_id en action_type_id zijn verwijzingen naar de tabellen die waarden voor deal, kaartdeelnemer en action_type bevatten. Merk op dat de participant_id en card_id kunnen NULL-waarden zijn. Dit komt door het feit dat sommige acties niet door spelers worden gedaan (bijv. de dealer trekt een kaart en legt deze open), terwijl andere geen kaarten bevatten (bijv. een verhoging bij poker). We moeten al deze acties opslaan om de hele wedstrijd opnieuw te kunnen maken.

De action_order attribuut slaat het volgnummer van een in-game actie op. Een openingsbod zou bijvoorbeeld een 1-waarde krijgen; het volgende bod zou een waarde 2 hebben, enz. Er kan niet meer dan één actie tegelijkertijd plaatsvinden. Daarom is de deal_id en action_order attributen vormen samen de alternatieve sleutel.

De action_notation attribuut bevat een gedetailleerde beschrijving van een actie. In poker kunnen we bijvoorbeeld een raise . opslaan actie en een willekeurig bedrag. Sommige acties kunnen ingewikkelder zijn, dus het is verstandig om deze waarden als tekst op te slaan en de toepassing de interpretatie ervan over te laten.

Deals en dealvolgorde

Een wedstrijd bestaat uit een of meer kaartdeals. We hebben het al gehad over de participant en de match tabellen, maar we hebben ze in de afbeelding opgenomen om hun relatie tot de deal en deal_order tabellen.

De deal tabel slaat alle gegevens op die we nodig hebben over een enkele overeenkomstinstantie.

De match_id kenmerk relateert die instantie aan de juiste overeenkomst, terwijl start_time en end_time geven de exacte tijd aan waarop die instantie begon en wanneer deze was voltooid.

De move_time_limit en de deal_result attributen zijn zowel tekstvelden die worden gebruikt om tijdslimieten op te slaan (indien van toepassing) als een beschrijving van het resultaat van die deal.

In de participant tabel, de initial_player_order attribuut slaat de spelersvolgorde op voor de instantie van de openingswedstrijd. Het opslaan van de orders voor volgende beurten vereist een geheel nieuwe tafel - de deal_order tafel.

Uiteraard, deal_id en participant_id zijn verwijzingen naar een match-instantie en een deelnemer. Samen vormen ze de eerste alternatieve sleutel in de deal_order tafel. De player_order attribuut bevat waarden die de bestellingen aangeven die spelers hebben deelgenomen aan die wedstrijdinstantie. Samen met deal_id , vormt het de tweede alternatieve sleutel in deze tabel. De deal_result attribuut is een tekstveld dat het resultaat van de wedstrijd voor een individuele speler beschrijft. De score attribuut slaat een numerieke waarde op die gerelateerd is aan het dealresultaat.

Saturen, rangen en kaarten

Dit gedeelte van het model beschrijft de kaarten die we in alle ondersteunde spellen zullen gebruiken. Elke kaart heeft een kleur en rang.

De suit_type table is een woordenboek dat alle soorten kostuums bevat die we zullen gebruiken. Voor suit_type_name , gebruiken we waarden als "Franse pakken", "Duitse pakken", "Zwitsers-Duitse pakken" en "Latijnse pakken".

Het suit tabel bevat de namen van alle kleuren die zijn opgenomen in specifieke kaartsoorten. Het Franse kaartspel heeft bijvoorbeeld kleuren genaamd "Spades", "Hearts", "Diamonds" en "Clubs".

In de rank woordenboek, vinden we bekende kaartwaarden zoals "Aas", "Koning", "Koningin" en "Jack".

De card tabel bevat een lijst van alle mogelijke kaarten. Elke kaart komt maar één keer in deze tabel voor. Dat is de reden dat de suit_id en rank_id attributen vormen de alternatieve sleutel van deze tabel. De waarden van beide attributen kunnen NULL zijn omdat sommige kaarten geen reeks of rang hebben (bijv. jokerkaarten). De is_joker_card is een zelfverklarende Booleaanse waarde. De card_name attribuut beschrijft een kaart met de tekst:"Schoppenaas".

Kaarten en kaartspellen

Kaarten horen bij kaartspellen. Omdat één kaart in meerdere kaartspellen kan voorkomen, hebben we een n:n . nodig relatie tussen de card en deck tabellen.

In het deck tabel, slaan we de namen op van alle kaartspellen die we willen gebruiken. Een voorbeeld van waarden die zijn opgeslagen in de deck_name attributen zijn:"Standaard kaartspel met 52 kaarten (Frans)" of "spel met 32 ​​kaarten (Duits)".

Het card_in_deck relatie wordt gebruikt om kaarten toe te wijzen aan de juiste kaartspellen. De card_iddeck_id pair is de alternatieve sleutel van het deck tafel.

Overeenkomsteigenschappen, gebruikte decks en eenheden

Dit gedeelte van het model bevat enkele basisparameters voor het starten van een nieuw spel.

Het belangrijkste onderdeel van deze sectie is het game tafel. In deze tabel worden gegevens opgeslagen over door applicaties ondersteunde spellen. De game_name attribuut bevat waarden zoals “poker”, “blackjack”, “belot” en “préférence”.

De min_number_of_players en max_number_of_players zijn het minimale en maximale aantal deelnemers aan een wedstrijd. Deze attributen dienen als grenzen voor het spel en worden aan het begin van een wedstrijd op het scherm getoond. De persoon die de wedstrijd start, moet een waarde uit dit bereik selecteren.

De min_entrance_fee en de max_entrance_fee attributen geeft het bereik van de toegangsprijs aan. Nogmaals, dit is gebaseerd op het spel dat wordt gespeeld.

In possible_victory_condition , slaan we alle overwinningsvoorwaarden op die aan een wedstrijd kunnen worden toegewezen. Waarden worden gescheiden door een scheidingsteken.

De unit woordenboek wordt gebruikt om elke eenheid op te slaan die in al onze spellen wordt gebruikt. De unit_name attribuut zal waarden bevatten zoals “point”, “dollar”, “euro” en “chip”.

Het game_deck en game_unit tabellen gebruiken dezelfde logica. Ze bevatten lijsten met alle kaartspellen en eenheden die in een wedstrijd kunnen worden gebruikt. Daarom is de game_iddeck_id paar en de game_idunit_id koppel alternatieve sleutels in hun respectievelijke tabellen.

Scores

In onze applicatie willen we de scores opslaan van alle spelers die hebben deelgenomen aan onze kaartspellen. Voor elk spel wordt een enkele numerieke waarde berekend en opgeslagen. (De berekening is gebaseerd op de resultaten van de speler in alle spellen van een enkel type.) Deze spelersscore is vergelijkbaar met een rangorde; het laat gebruikers ongeveer weten hoe goed een speler is.

Terug naar het rekenproces. We maken een n:n relatie tussen de player en game tafels. Dat is de player_score tafel in ons model. De player_id en de score_id ” vormen samen de alternatieve sleutel van de tafel. De “score attribuut wordt gebruikt om de eerder genoemde numerieke waarde op te slaan.

Er zijn verschillende kaartspellen die zeer verschillende regels, kaarten en kaartspellen gebruiken. Om een ​​database te maken die gegevens voor meer dan één kaartspel opslaat, moeten we enkele generalisaties maken. Een manier waarop we dit doen is door beschrijvende tekstvelden te gebruiken en de toepassing deze te laten interpreteren. We zouden manieren kunnen bedenken om de meest voorkomende situaties te dekken, maar dat zou het databaseontwerp exponentieel compliceren.

Zoals dit artikel heeft laten zien, kun je voor veel spellen één database gebruiken. Waarom zou je dit doen? Drie redenen:1) u kunt dezelfde database hergebruiken; 2) het zou de analyse vereenvoudigen; en dit zou leiden tot 3) het bouwen van betere AI-tegenstanders.


  1. ADD_MONTHS() Functie in Oracle

  2. Maak een draaiweergave in SQL vanuit een SQL-tabel

  3. Oracle sql:volgorde op en afzonderlijke clausule

  4. SQL selecteer waar niet in subquery geeft geen resultaten