sql >> Database teknologi >  >> RDS >> Database

Hvad har poker, blackjack, Belot og Préférence med databaser at gøre?

Hvordan man designer en database, der er fleksibel nok til at rumme flere meget forskellige kortspil.

For nylig viste vi, hvordan en database kunne bruges til at gemme brætspilsresultater. Brætspil er sjove, men de er ikke den eneste onlineversion af klassiske spil, der kører. Kortspil er også meget populære. De introducerer et element af held i gameplayet, og der er meget mere end held involveret i et godt kortspil!

I denne artikel vil vi fokusere på at opbygge en datamodel til at gemme spilkampe, resultater, spillere og scoringer. Den største udfordring her er at gemme data relateret til mange forskellige kortspil. Vi kunne også overveje at analysere disse data for at bestemme vinderstrategier, forbedre vores egne spillefærdigheder eller opbygge en bedre AI-modstander.

De fire kortspil, vi vil bruge i vores database

Fordi spillere ikke kan kontrollere den hånd, de får uddelt, kombinerer kortspil strategi, færdigheder og held. Den held-faktor giver en nybegynder chancen for at slå en erfaren spiller, og det gør kortspil vanedannende. (Dette adskiller sig fra spil som skak, der er stærkt afhængige af logik og strategi. Jeg har hørt fra mange spillere, at de ikke er interesserede i at spille skak, fordi de ikke kan finde modstandere på deres færdighedsniveau.)

Vi vil fokusere på fire velkendte kortspil:poker, blackjack, belot (eller belote) og préférence. Hver af dem har relativt komplekse regler og kræver lidt tid at mestre. Forholdet mellem held og viden er også forskelligt for hvert spil.

Vi tager et hurtigt kig på de forenklede regler og detaljer for alle fire spil nedenfor. Spilbeskrivelser er temmelig sparsomme, men vi har inkluderet nok til at vise de forskellige spiltilstande og de forskellige regler, vi vil støde på under databasedesignprocessen.

Blackjack:

  • Dæk: Et til otte spil med hver 52 kort; ingen joker-kort
  • Spillere: Dealer og 1 eller flere modstandere
  • Anvendt enhed: Normalt penge
  • Grundlæggende regler: Spillere får 2 kort, som kun de kan se; dealeren får to kort, det ene med billedsiden opad og det andet med billedsiden nedad; hver spiller beslutter sig for at trække flere kort (eller ej); forhandleren trækker sidst. Kort har tildelt pointværdier fra 1 til 11.
  • Mulige spillerhandlinger: Hit, Stand, Split, Surrender
  • Mål og sejrstilstand: Summen af ​​en spillers kort er større end dealerens; hvis en spiller går over 21, taber den spiller.

Poker (Texas Hold'Em):

  • Dæk: Standard (også kendt som fransk farve) 52-korts kortspil; ingen joker-kort. Kort er oftest røde og sorte i farven.
  • Spillere: To til ni; spillere skiftes til at dele
  • Anvendt enhed:Normalt chips
  • Grundlæggende regler: Hver spiller starter med at få tildelt to kort; spillere placerer deres indsatser; tre kort uddeles med billedsiden opad i midten af ​​bordet; spillere placerer igen deres indsatser; et fjerde kort placeres i midten, og spillerne satser igen; derefter placeres det femte og sidste kort, og den sidste indsatsrunde er afsluttet.
  • Mulige spillerhandlinger: Fold, Call, Raise, Small Blind, Big Blind, Genraise
  • Mål: Kombiner den bedst mulige hånd af fem kort (fra de to kort i spillerens hånd og de fem kort i midten af ​​bordet)
  • Sejrsbetingelse:Normalt for at vinde alle jetonerne på bordet

Belot (kroatisk variant af Belote):

  • Dæk: Normalt det traditionelle tyske eller ungarske 32-korts kortspil; ingen joker-kort
  • Spillere: To til fire; normalt fire spillere i par af to
  • Anvendt enhed: Point
  • Grundlæggende regler: For et spil med fire spillere får hver spiller seks kort på hånden og to kort med billedsiden nedad; spillere byder først på trumffarve; efter at trumf er bestemt, tager de de to kort med billedsiden nedad og lægger dem i deres hånd; en erklæringsrunde følger, hvorunder visse kortkombinationer annonceres for yderligere point; spillet fortsætter, indtil alle kort er brugt.
  • Mulige spillerhandlinger: Beståelse, budfarve, erklæring, kastekort
  • Mål for hånden: At vinde mere end halvdelen af ​​pointene
  • Sejrstilstand: Vær det første hold, der scorer 1001 point eller mere

Préférence:

  • Dæk: Oftest et traditionelt tysk eller ungarsk spil med 32 kort; ingen joker-kort
  • Spillere: Tre
  • Enheder: Point
  • Grundlæggende regler: Alle spillere får 10 kort; to "kitty" eller "talon" kort placeres midt på bordet; spillere bestemmer, om de vil byde på en kulør; spillere beslutter sig for at spille eller ej.
  • Mulige spillerhandlinger: Pass, Byd Farbe, Spil, Spil ikke, Kast kort
  • Mål: Afhænger af den variant af Préférence, der spilles; i standardversionen skal budgiveren vinde i alt seks stik.
  • Sejrstilstand: Når summen af ​​alle tre spilleres score er 0, vinder spilleren med det laveste antal point.

Hvorfor kombinere databaser og kortspil?

Vores mål her er at designe en databasemodel, der kan gemme alle relevante data for disse fire kortspil. Databasen kunne bruges af en webapplikation som et sted til at gemme alle relevante data. Vi ønsker at gemme indledende spilindstillinger, spildeltagere, handlinger udført under spillet og resultatet af en enkelt handel, hånd eller trick. Vi skal også huske på, at en kamp kan have en eller flere aftaler forbundet med sig.

Ud fra det, vi gemmer i vores database, burde vi være i stand til at genskabe alle de handlinger, der fandt sted under spillet. Vi bruger tekstfelter til at beskrive sejrsbetingelser, spilhandlinger og deres resultater. Disse er specifikke for hvert spil, og webapplikationslogikken vil fortolke teksten og transformere dem efter behov.

En hurtig introduktion til modellen




Denne model gør det muligt for os at gemme alle relevante spildata, herunder:

  • Spilegenskaber
  • Liste over spil og kampe
  • Deltagere
  • Handlinger i spillet

Da spil adskiller sig på mange måder, vil vi ofte bruge varchar(256) datatype til at beskrive egenskaber, bevægelser og resultater.

Spillere, kampe og deltagere

Denne del af modellen består af tre borde og bruges til at gemme data om registrerede spillere, de spillede kampe og de spillere, der deltog.

player tabellen gemmer data om registrerede spillere. username og email attributter er unikke værdier. nick_name attribut gemmer spillernes skærmnavne.

match tabel indeholder alle relevante matchdata. Generelt er en kamp sammensat af en eller flere kortuddelinger (også kendt som runder, hænder eller tricks). Alle kampe har fastlagte regler før spillet begynder. Attributterne er som følger:

  • game_id – henviser til tabellen, der indeholder listen over spil (poker, blackjack, belot og préférence, i dette tilfælde).
  • start_time og end_time er de faktiske tidspunkter, hvor en kamp starter og slutter. Bemærk, at end_time kan være NULL; vi vil ikke have dens værdi, før spillet slutter. Hvis en kamp afbrydes, før den er afsluttet, er end_time værdien kan forblive NULL.
  • number_of_players – er antallet af deltagere, der kræves for at starte spillet
  • deck_id – refererer til det spil, der bruges i spillet.
  • decks_used – er antallet af dæk, der bruges til at spille spillet. Normalt vil denne værdi være 1, men nogle spil bruger flere dæk.
  • unit_id – er den enhed (point, jetoner, penge osv.), der bruges til at score spillet.
  • entrance_fee – er antallet af nødvendige enheder for at deltage i spillet; dette kan være NULL, hvis spillet ikke kræver, at hver spiller starter med et bestemt antal enheder.
  • victory_conditions – bestemmer, hvilken spiller der vandt kampen. Vi bruger varchar datatype for at beskrive hvert spils sejrstilstand (dvs. det første hold, der når 100 point), og lad applikationen fortolke den. Denne fleksibilitet giver plads til, at masser af spil kan tilføjes.
  • match_result – gemmer resultatet af kampen i tekstformat. Som med victory_conditions , lader vi applikationen fortolke værdien. Denne attribut kan være NULL, fordi vi udfylder denne værdi samtidig med, at vi indsætter end_time værdi.

participant tabel gemmer data om alle deltagerne i en kamp. match_id og player_id attributter er referencer til match og player tabeller. Tilsammen danner disse værdier tabellens alternative nøgle.

De fleste af spillene roterer, hvilken spiller der byder eller spiller først. Normalt i første runde bestemmes den spiller, der spiller først (åbningsspilleren), af spillereglerne. I næste runde vil spilleren til venstre (eller nogle gange til højre) for den oprindelige åbningsspiller gå først. Vi bruger initial_player_order attribut for at gemme ordensnummeret for første rundes åbningsspiller. match_id og initial_player_order attributter danner en anden alternativ nøgle, fordi to spillere ikke kan spille på samme tid.

score egenskaben opdateres, når en spiller afslutter en kamp. Nogle gange vil dette være på samme tidspunkt for alle spillere (f.eks. i belot eller préférence) og nogle gange mens kampen stadig er i gang (f.eks. poker eller blackjack).

Handlinger og handlingstyper

Når vi tænker på handlinger, som spillere kan foretage i et kortspil, indser vi, at vi skal gemme:

  • Hvad handlingen var
  • Hvem udførte den handling
  • Hvornår (i hvilken aftale) handlingen fandt sted
  • Hvilke kort(er) blev brugt i den handling

action_type table er en simpel ordbog, der indeholder navnene på spillerens handlinger. Nogle mulige værdier inkluderer trække kort, spille kort, give kort til en anden spiller, check og raise.

I action tabel, gemmer vi alle de begivenheder, der skete under en aftale. deal_id , card_id , participant_id og action_type_id er referencer til tabellerne, der indeholder værdier for deal, kortdeltager og action_type. Bemærk, at participant_id og card_id kan være NULL-værdier. Dette skyldes det faktum, at nogle handlinger ikke udføres af spillere (f.eks. trækker dealeren et kort og lægger det med billedsiden opad), mens nogle ikke inkluderer kort (f.eks. et raise i poker). Vi skal gemme alle disse handlinger for at kunne genskabe hele kampen.

action_order attribut gemmer ordenstallet for en handling i spillet. For eksempel vil et åbningsbud modtage en 1-værdi; det næste bud ville have en 2-værdi osv. Der kan ikke ske mere end én handling på samme tid. Derfor er deal_id og action_order attributter danner sammen den alternative nøgle.

action_notation attribut indeholder en detaljeret beskrivelse af en handling. I poker kan vi for eksempel gemme en forhøjelse handling og et vilkårligt beløb. Nogle handlinger kan være mere komplicerede, så det er klogt at gemme disse værdier som tekst og lade programmet fortolke det.

Tilbud og aftaleordre

En kamp er sammensat af en eller flere kortuddelinger. Vi har allerede diskuteret participant og match tabeller, men vi har inkluderet dem i billedet for at vise deres relation til deal og deal_order tabeller.

deal tabel gemmer alle de data, vi har brug for om en enkelt match-instans.

match_id attribut relaterer den instans til det relevante match, mens start_time og end_time angiv det nøjagtige tidspunkt, hvor den instans startede, og hvornår den var færdig.

move_time_limit og deal_result attributter er både tekstfelter, der bruges til at gemme tidsgrænser (hvis relevant) og en beskrivelse af resultatet af den pågældende aftale.

I participant tabellen, initial_player_order attribut gemmer spillerrækkefølgen for åbningskampen. Lagring af ordrer til efterfølgende ture kræver et helt nyt bord – deal_order tabel.

Det er klart, deal_id og participant_id er referencer til en kampinstans og en deltager. Sammen danner de den første alternative nøgle i deal_order bord. player_order attribut indeholder værdier, der angiver de ordrer, spillere deltog i den pågældende kampinstans. Sammen med deal_id , den danner den anden alternative nøgle i denne tabel. deal_result attribut er et tekstfelt, der beskriver resultatet af kampen for en individuel spiller. score attribut gemmer en numerisk værdi relateret til aftaleresultatet.

Suits, Rangs and Cards

Denne sektion af modellen beskriver de kort, vi vil bruge i alle de understøttede spil. Hvert kort har en kulør og rang.

suit_type table er en ordbog, der indeholder alle de kulørtyper, vi vil bruge. For suit_type_name , vil vi bruge værdier som "franske jakkesæt", "tyske jakkesæt", "schweizisk-tyske jakkesæt" og "latinske jakkesæt".

suit tabellen indeholder navnene på alle de dragter, der er indeholdt af specifikke dæktyper. For eksempel har det franske dæk dragter kaldet "Spades", "Hearts", "Diamonds" og "Clubs".

I rank ordbog, finder vi velkendte kortværdier som "Es", "Konge", "Dronning" og "Knægt".

card tabellen indeholder en liste over alle mulige kort. Hvert kort vises kun én gang i denne tabel. Det er grunden til, at suit_id og rank_id attributter danner denne tabels alternative nøgle. Begge attributters værdier kan være NULL, fordi nogle kort ikke har en kulør eller en rang (f.eks. joker-kort). is_joker_card er en selvforklarende boolsk værdi. card_name attribut beskriver et kort med tekst:"Spades es".

Kort og kortspil

Kortene hører til dæk. Fordi et kort kan optræde i flere bunker, skal vi bruge et n:n forholdet mellem card og deck tabeller.

I deck bordet, gemmer vi navnene på alle de kortspil, vi vil bruge. Et eksempel på værdier gemt i deck_name egenskaber er:"Standard 52-korts kort (fransk)" eller "32-korts kortspil (tysk)".

card_in_deck relation bruges til at tildele kort til passende bunker. card_iddeck_id par er den alternative nøgle til deck bord.

Match-egenskaber, dæk og brugte enheder

Denne sektion af modellen indeholder nogle grundlæggende parametre for at starte et nyt spil.

Hoveddelen af ​​denne sektion er game bord. Denne tabel gemmer data om applikationsunderstøttede spil. game_name attribut indeholder værdier som "poker", "blackjack", "belot" og "préférence".

min_number_of_players og max_number_of_players er det minimale og maksimale antal deltagere i en kamp. Disse egenskaber tjener som grænser for spillet, og de vises på skærmen i starten af ​​en kamp. Den person, der starter kampen, skal vælge en værdi fra dette interval.

min_entrance_fee og max_entrance_fee attributter angiver adgangsgebyrintervallet. Igen er dette baseret på det spil, der spilles.

I possible_victory_condition , vi gemmer alle de sejrsbetingelser, der kunne tildeles en kamp. Værdier er adskilt af en afgrænsning.

unit ordbogen bruges til at gemme hver enhed, der bruges i alle vores spil. unit_name attribut vil indeholde værdier som "point", "dollar", "euro" og "chip".

game_deck og game_unit tabeller bruger den samme logik. De indeholder lister over alle dæk og enheder, der kan bruges i en kamp. Derfor er game_iddeck_id parret og game_idunit_id par danner alternative nøgler i deres respektive tabeller.

Score

I vores applikation vil vi gerne gemme scoringerne for alle spillere, der deltog i vores kortspil. For hvert spil beregnes og gemmes en enkelt numerisk værdi. (Beregningen er baseret på spillerens resultater i alle spil af en enkelt type.) Denne spillerscore svarer til en rang; det lader brugerne vide, hvor god en spiller er.

Tilbage til beregningsprocessen. Vi opretter en n:n forholdet mellem player og game tabeller. Det er player_score bord i vores model. player_id og score_id ” danner sammen tabellens alternative nøgle. "score attribut bruges til at gemme den tidligere nævnte numeriske værdi.

Der er mange forskellige kortspil, der bruger meget forskellige regler, kort og dæk. For at skabe en database, der gemmer data for mere end ét kortspil, skal vi lave nogle generaliseringer. En måde vi gør dette på er ved at bruge beskrivende tekstfelter og lade applikationen interpetere dem. Vi kunne finde på måder at dække de mest almindelige situationer på, men det ville eksponentielt komplicere databasedesignet.

Som denne artikel har vist, kan du bruge én database til mange spil. Hvorfor ville du gøre dette? Tre grunde:1) du kan genbruge den samme database; 2) det ville forenkle analyser; og dette ville føre til 3) opbygningen af ​​bedre AI-modstandere.


  1. Top almindelige problemer med MHA og hvordan man løser dem

  2. hvordan man bruger Blob datatype i Postgres

  3. Opret et databasediagram i MySQL Workbench

  4. Sådan får du aktuelle ugedata i MySQL