sql >> Databasteknik >  >> RDS >> Database

Vad har poker, blackjack, Belot och Préférence med databaser att göra?

Hur man designar en databas som är tillräckligt flexibel för att rymma flera väldigt olika kortspel.

Nyligen visade vi hur en databas kan användas för att lagra brädspelsresultat. Brädspel är roliga, men de är inte den enda onlineversionen av klassiska spel som finns. Kortspel är också mycket populära. De introducerar ett element av tur i spelet, och det är mycket mer än tur involverat i ett bra kortspel!

I den här artikeln kommer vi att fokusera på att bygga en datamodell för att lagra matcher, resultat, spelare och poäng. Den största utmaningen här är att lagra data relaterad till många olika kortspel. Vi kan också överväga att analysera dessa data för att bestämma vinnande strategier, förbättra våra egna spelfärdigheter eller bygga en bättre AI-motståndare.

De fyra kortspelen vi kommer att använda i vår databas

Eftersom spelare inte kan kontrollera handen de får, kombinerar kortspel strategi, skicklighet och tur. Den turfaktorn ger en nybörjare chansen att slå en erfaren spelare, och det gör kortspel beroendeframkallande. (Detta skiljer sig från spel som schack, som är mycket beroende av logik och strategi. Jag har hört från många spelare att de inte är intresserade av att spela schack eftersom de inte kan hitta motståndare på sin skicklighetsnivå.)

Vi kommer att fokusera på fyra välkända kortspel:poker, blackjack, belot (eller belote) och préférence. Var och en av dem har relativt komplexa regler och kräver lite tid att bemästra. Förhållandet mellan tur och kunskap är också olika för varje spel.

Vi tar en snabb titt på de förenklade reglerna och detaljerna för alla fyra spelen nedan. Spelbeskrivningarna är ganska sparsamma, men vi har inkluderat tillräckligt för att visa de olika spelsätten och de olika reglerna vi kommer att stöta på under designprocessen för databasen.

Blackjack:

  • Däck: En till åtta kortlekar med vardera 52 kort; inga jokerkort
  • Spelare: Dealer och 1 eller flera motståndare
  • Använd enhet: Vanligtvis pengar
  • Grundläggande regler: Spelare får 2 kort som bara de kan se; dealern får två kort, ett med framsidan upp och det andra med framsidan nedåt; varje spelare bestämmer sig för att dra fler kort (eller inte); återförsäljaren drar sist. Kort har tilldelat poängvärden från 1 till 11.
  • Möjliga spelaråtgärder: Hit, Stand, Split, Surrender
  • Mål- och segervillkor: Summan av en spelares kort är större än dealerns; om någon spelare går över 21, förlorar den spelaren.

Poker (Texas Hold’Em):

  • Däck: Standard (även känd som fransk färg) 52-korts kortlek; inga jokerkort. Korten är oftast röda och svarta.
  • Spelare: Två till nio; spelare turas om att dela ut
  • Använd enhet:Vanligtvis chips
  • Grundläggande regler: Varje spelare börjar med att få två kort; spelare lägger sina insatser; tre kort delas ut med framsidan upp i mitten av bordet; spelare lägger igen sina insatser; ett fjärde kort placeras i mitten och spelarna satsar igen; sedan placeras det femte och sista kortet och den sista satsningsrundan är klar.
  • Möjliga spelaråtgärder: Vik, ring, höj, liten mörk, stor mörk, återhöjning
  • Mål: Kombinera den bästa möjliga handen av fem kort (från de två korten i spelarens hand och de fem korten i mitten av bordet)
  • Segervillkor:Vanligtvis för att vinna alla marker på bordet

Belot (kroatisk variant av Belote):

  • Däck: Vanligtvis den traditionella tyska eller ungerska 32-kortsleken; inga jokerkort
  • Spelare: Två till fyra; vanligtvis fyra spelare i par om två
  • Använd enhet: Poäng
  • Grundläggande regler: För ett spel för fyra spelare får varje spelare sex kort på handen och två kort med framsidan nedåt; spelare första bud för trumf färg; efter att trumf har bestämts tar de de två nedåtvända korten och lägger dem i sin hand; en deklarationsrunda följer, under vilken vissa kortkombinationer tillkännages för ytterligare poäng; spelet fortsätter tills alla kort har använts.
  • Möjliga spelaråtgärder: Pass, bud färg, deklaration, kastkort
  • Mål för handen: Att vinna mer än hälften av poängen
  • Segervillkor: Bli det första laget som får 1001 poäng eller mer

Preferens:

  • Däck: Oftast en traditionell tysk eller ungersk kortlek med 32 kort; inga jokerkort
  • Spelare: Tre
  • Enheter: Poäng
  • Grundläggande regler: Alla spelare tilldelas 10 kort; två "katt"- eller "talon"-kort placeras i mitten av bordet; spelare avgör om de vill bjuda på en färg; spelare bestämmer sig för att spela eller inte.
  • Möjliga spelaråtgärder: Passera, bjud färg, spela, spela inte, kasta kort
  • Mål: Beror på vilken variant av Préférence som spelas; i standardversionen måste budgivaren vinna totalt sex stick.
  • Segervillkor: När summan av alla tre spelarnas poäng är 0 vinner spelaren med lägst antal poäng.

Varför kombinera databaser och kortspel?

Vårt mål här är att designa en databasmodell som kan lagra all relevant data för dessa fyra kortspel. Databasen skulle kunna användas av en webbapplikation som en plats för att lagra all relevant data. Vi vill lagra initiala spelinställningar, speldeltagare, åtgärder som vidtas under spelet och resultatet av en enda affär, hand eller trick. Vi måste också tänka på att en match kan ha en eller flera affärer kopplade till sig.

Från det vi lagrar i vår databas ska vi kunna återskapa alla de handlingar som ägde rum under spelet. Vi kommer att använda textfält för att beskriva segerförhållanden, spelåtgärder och deras resultat. Dessa är specifika för varje spel och webbapplikationslogiken kommer att tolka texten och omvandla dem efter behov.

En snabb introduktion till modellen




Denna modell gör det möjligt för oss att lagra all relevant speldata, inklusive:

  • Spelegenskaper
  • Lista över spel och matcher
  • Deltagare
  • Åtgärder i spelet

Eftersom spel skiljer sig åt på många sätt kommer vi ofta att använda varchar(256) datatyp för att beskriva egenskaper, rörelser och resultat.

Spelare, matcher och deltagare

Denna del av modellen består av tre tabeller och används för att lagra data om registrerade spelare, de spelade matcherna och spelarna som deltog.

player tabellen lagrar data om registrerade spelare. username och email attribut är unika värden. nick_name attribut lagrar spelarnas skärmnamn.

match tabellen innehåller alla relevanta matchningsdata. I allmänhet består en match av en eller flera kortutdelningar (även känd som rundor, händer eller trick). Alla matcher har fastställda regler innan spelet börjar. Attributen är följande:

  • game_id – refererar till tabellen som innehåller listan över spel (poker, blackjack, belot och préférence, i det här fallet).
  • start_time och end_time är de faktiska tidpunkterna när en match startar och slutar. Lägg märke till att end_time kan vara NULL; vi kommer inte att ha dess värde förrän spelet är slut. Dessutom, om en match överges innan den är klar, är end_time värdet kan förbli NULL.
  • number_of_players – är antalet deltagare som krävs för att starta spelet
  • deck_id – refererar till kortleken som används i spelet.
  • decks_used – är antalet kortlekar som används för att spela spelet. Vanligtvis är detta värde 1, men vissa spel använder flera kortlekar.
  • unit_id – är enheten (poäng, marker, pengar, etc.) som används för att göra poäng i spelet.
  • entrance_fee – är antalet enheter som behövs för att gå med i spelet; detta kan vara NULL om spelet inte kräver att varje spelare börjar med ett visst antal enheter.
  • victory_conditions – avgör vilken spelare som vann matchen. Vi använder varchar datatyp för att beskriva varje matchs segertillstånd (dvs. det första laget som når 100 poäng) och lämna applikationen för att tolka det. Denna flexibilitet ger utrymme för många spel som kan läggas till.
  • match_result – lagrar resultatet av matchen i textformat. Som med victory_conditions , låter vi applikationen tolka värdet. Det här attributet kan vara NULL eftersom vi fyller det värdet samtidigt som vi infogar end_time värde.

participant tabellen lagrar data om alla deltagare i en match. match_id och player_id attribut är referenser till match och player tabeller. Tillsammans bildar dessa värden tabellens alternativa nyckel.

De flesta spelen roterar vilken spelare som bjuder eller spelar först. Vanligtvis i den första omgången bestäms spelaren som spelar först (öppningsspelaren) av spelreglerna. I nästa omgång kommer spelaren till vänster (eller ibland till höger) om den ursprungliga öppningsspelaren att gå först. Vi använder initial_player_order attribut för att lagra ordningsnumret för den första omgångens öppningsspelare. match_id och initial_player_order attribut bildar en annan alternativ nyckel eftersom två spelare inte kan spela samtidigt.

score attribut uppdateras när en spelare avslutar en match. Ibland kommer detta att vara i samma ögonblick för alla spelare (t.ex. i belot eller préférence) och ibland medan matchen fortfarande pågår (t.ex. poker eller blackjack).

Åtgärder och åtgärdstyper

När vi tänker på handlingar som spelare kan göra i ett kortspel, inser vi att vi måste lagra:

  • Vad åtgärden var
  • Vem utförde den åtgärden
  • När (i vilken affär) åtgärden ägde rum
  • Vilka kort användes i den åtgärden

action_type table är en enkel ordbok som innehåller namnen på spelarnas handlingar. Några möjliga värden inkluderar dra kort, spela kort, skicka kort till en annan spelare, checka och höja.

I action tabell lagrar vi alla händelser som hände under en affär. deal_id , card_id , participant_id och action_type_id är referenser till tabellerna som innehåller värden för deal, kortdeltagare och action_type. Lägg märke till att participant_id och card_id kan vara NULL-värden. Detta beror på det faktum att vissa åtgärder inte görs av spelare (t.ex. dealern drar ett kort och lägger det uppåt), medan vissa inte inkluderar kort (t.ex. en höjning i poker). Vi måste lagra alla dessa åtgärder för att kunna återskapa hela matchen.

action_order attribut lagrar ordningsnumret för en handling i spelet. Till exempel skulle ett öppningsbud få ett värde på 1; nästa bud skulle ha ett värde på 2, etc. Det kan inte hända mer än en åtgärd samtidigt. Därför är deal_id och action_order attribut tillsammans bildar den alternativa nyckeln.

action_notation attribut innehåller en detaljerad beskrivning av en åtgärd. I poker, till exempel, kan vi lagra en höjning åtgärd och ett godtyckligt belopp. Vissa åtgärder kan vara mer komplicerade, så det är klokt att lagra dessa värden som text och låta programmet tolka det.

Erbjudanden och erbjudanden

En match består av en eller flera kortutdelningar. Vi har redan diskuterat participant och match tabeller, men vi har tagit med dem i bilden för att visa deras relation till deal och deal_order tabeller.

deal Tabell lagrar all data vi behöver om en enda matchningsinstans.

match_id attribut relaterar den instansen till lämplig matchning, medan start_time och end_time ange den exakta tidpunkten när den instansen började och när den var klar.

move_time_limit och deal_result attribut är både textfält som används för att lagra tidsgränser (om tillämpligt) och en beskrivning av resultatet av den affären.

I participant tabellen, initial_player_order attribut lagrar spelarorder för den inledande matchinstansen. Att lagra beställningarna för efterföljande vändningar kräver ett helt nytt bord – deal_order bord.

Självklart, deal_id och participant_id är referenser till en matchinstans och en deltagare. Tillsammans bildar de den första alternativa nyckeln i deal_order tabell. player_order attributet innehåller värden som anger de order som spelarna deltog i den matchningsinstansen. Tillsammans med deal_id , bildar den den andra alternativa nyckeln i denna tabell. deal_result attribut är ett textfält som beskriver resultatet av matchen för en enskild spelare. score attribut lagrar ett numeriskt värde relaterat till affärens resultat.

Suits, Ranks and Cards

Det här avsnittet av modellen beskriver korten vi kommer att använda i alla spel som stöds. Varje kort har en färg och rang.

suit_type table är en ordbok som innehåller alla färgtyper vi kommer att använda. För suit_type_name , kommer vi att använda värden som "franska kostymer", "tyska kostymer", "schweizisk-tyska kostymer" och "latinska kostymer".

suit Tabellen innehåller namnen på alla färger som ingår i specifika däcktyper. Till exempel har den franska kortleken färger som heter "Spades", "Hearts", "Diamonds" och "Clubs".

I rank ordbok, hittar vi välkända kortvärden som "ess", "kung", "drottning" och "knekt".

card Tabellen innehåller en lista över alla möjliga kort. Varje kort kommer endast att visas i denna tabell en gång. Det är anledningen till att suit_id och rank_id attribut bildar den här tabellens alternativa nyckel. Båda attributens värden kan vara NULL eftersom vissa kort inte har en färg eller en rang (t.ex. jokerkort). is_joker_card är ett självförklarande booleskt värde. card_name attribut beskriver ett kort med text:"Spades ess".

Kort och kortlekar

Kort hör till kortlekar. Eftersom ett kort kan visas i flera kortlekar behöver vi ett n:n förhållandet mellan card och deck tabeller.

I deck tabell lagrar vi namnen på alla kortlekar som vi vill använda. Ett exempel på värden lagrade i deck_name attribut är:"Standard 52-kortslek (franska)" eller "32-kortslek (tyska)".

card_in_deck relation används för att tilldela kort till lämpliga kortlekar. card_iddeck_id par är den alternativa nyckeln för deck tabell.

Matchegenskaper, däck och använda enheter

Det här avsnittet av modellen innehåller några grundläggande parametrar för att starta ett nytt spel.

Huvuddelen av det här avsnittet är game tabell. Den här tabellen lagrar data om applikationsstödda spel. game_name attributet innehåller värden som "poker", "blackjack", "belot" och "préférence".

min_number_of_players och max_number_of_players är det minimala och maximala antalet deltagare i en match. Dessa attribut fungerar som gränser för spelet, och de visas på skärmen i början av en match. Personen som initierar matchningen måste välja ett värde från detta intervall.

min_entrance_fee och max_entrance_fee attribut anger intervallet för entréavgifter. Återigen, detta är baserat på spelet som spelas.

I possible_victory_condition , vi lagrar alla segervillkor som kan tilldelas en match. Värden separeras med en avgränsare.

unit ordboken används för att lagra varje enhet som används i alla våra spel. unit_name attribut kommer att innehålla värden som "point", "dollar", "euro" och "chip".

game_deck och game_unit tabeller använder samma logik. De innehåller listor över alla kortlekar och enheter som kan användas i en match. Därför är game_iddeck_id paret och game_idunit_id par bildar alternativa nycklar i sina respektive tabeller.

Poäng

I vår applikation vill vi lagra poängen för alla spelare som deltog i våra kortspel. För varje spel beräknas och lagras ett enda numeriskt värde. (Beräkningen baseras på spelarens resultat i alla spel av en enda typ.) Denna spelarpoäng liknar en ranking; det låter användarna veta ungefär hur bra en spelare är.

Tillbaka till beräkningsprocessen. Vi skapar en n:n relation mellan player och game tabeller. Det är player_score bord i vår modell. player_id och score_id ” bildar tillsammans tabellens alternativa nyckel. "score attribut används för att lagra det tidigare nämnda numeriska värdet.

Det finns olika kortspel som använder väldigt olika regler, kort och kortlekar. För att skapa en databas som lagrar data för mer än ett kortspel måste vi göra några generaliseringar. Ett sätt vi gör detta är genom att använda beskrivande textfält och låta applikationen tolka dem. Vi skulle kunna komma på sätt att täcka de vanligaste situationerna, men det skulle exponentiellt komplicera databasdesignen.

Som den här artikeln har visat kan du använda en databas för många spel. Varför skulle du göra det här? Tre skäl:1) du kan återanvända samma databas; 2) det skulle förenkla analysen; och detta skulle leda till 3) byggandet av bättre AI-motståndare.


  1. Hur man genererar testdata i SQL Server

  2. T-SQL Cast kontra Convert

  3. Generera en uppsättning eller sekvens utan loopar – del 1

  4. Hur man aktiverar alla CHECK &främmande nyckelbegränsningar för en tabell i SQL Server (T-SQL-exempel)