Comment concevoir une base de données suffisamment flexible pour accueillir plusieurs jeux de cartes très différents.
Récemment, nous avons montré comment une base de données pouvait être utilisée pour stocker les résultats des jeux de société. Les jeux de société sont amusants, mais ils ne sont pas la seule version en ligne des jeux classiques. Les jeux de cartes sont également très populaires. Ils introduisent un élément de chance dans le jeu, et il y a bien plus que de la chance dans un bon jeu de cartes !
Dans cet article, nous nous concentrerons sur la création d'un modèle de données pour stocker les matchs de jeu, les résultats, les joueurs et les scores. Le principal défi ici est de stocker des données liées à de nombreux jeux de cartes différents. Nous pourrions également envisager d'analyser ces données pour déterminer des stratégies gagnantes, améliorer nos propres compétences de jeu ou construire un meilleur adversaire IA.
Les quatre jeux de cartes que nous utiliserons dans notre base de données
Parce que les joueurs ne peuvent pas contrôler la main qui leur est distribuée, les jeux de cartes combinent stratégie, habileté et chance. Ce facteur de chance donne à un débutant la chance de battre un joueur expérimenté et rend les jeux de cartes addictifs. (Cela diffère des jeux comme les échecs, qui reposent fortement sur la logique et la stratégie. J'ai entendu de nombreux joueurs dire qu'ils ne sont pas intéressés à jouer aux échecs parce qu'ils ne peuvent pas trouver d'adversaires à leur niveau de compétence.)
Nous allons nous concentrer sur quatre jeux de cartes bien connus :le poker, le blackjack, le belot (ou belote) et la préférence. Chacun d'eux a des règles relativement complexes et nécessite un certain temps pour être maîtrisé. Le rapport chance / connaissance est également différent pour chaque jeu.
Nous allons jeter un coup d'œil aux règles simplifiées et aux spécificités des quatre jeux ci-dessous. Les descriptions de jeu sont assez rares, mais nous en avons inclus suffisamment pour montrer les différents modes de jeu et les diverses règles que nous rencontrerons au cours du processus de conception de la base de données.
Blackjack :
- Plateau : Un à huit jeux de 52 cartes chacun; pas de cartes joker
- Joueurs : Croupier et 1 ou plusieurs adversaires
- Unité utilisée : Généralement de l'argent
- Règles de base : Les joueurs reçoivent 2 cartes qu'eux seuls peuvent voir; le croupier reçoit deux cartes, une face visible et l'autre face cachée; chaque joueur décide de piocher plus de cartes (ou pas) ; le croupier tire en dernier. Les cartes ont des valeurs de points attribuées allant de 1 à 11.
- Actions de joueur possibles : Frapper, tenir, séparer, se rendre
- Objectif et condition de victoire : La somme des cartes d'un joueur est supérieure à celle du croupier; si un joueur dépasse 21, ce joueur perd.
Poker (Texas Hold'Em) :
- Plateau : Jeu de 52 cartes standard (également connu sous le nom de costume français); pas de cartes joker. Les cartes sont le plus souvent de couleur rouge et noire.
- Joueurs : Deux à neuf ; les joueurs distribuent à tour de rôle
- Unité utilisée :généralement puces
- Règles de base : Chaque joueur commence par recevoir deux cartes; les joueurs placent leurs paris ; trois cartes sont distribuées face visible au milieu de la table; les joueurs placent à nouveau leurs paris ; une quatrième carte est placée au milieu et les joueurs misent à nouveau ; puis la cinquième et dernière carte est placée et le dernier tour d'enchères est terminé.
- Actions de joueur possibles : Se coucher, suivre, relancer, petite blind, grosse blind, sur-relancer
- Objectif : Combinez la meilleure main possible de cinq cartes (des deux cartes dans la main du joueur et des cinq cartes au milieu de la table)
- Condition de victoire :généralement pour gagner tous les jetons sur la table
Belot (variante croate de la belote) :
- Plateau : Habituellement, le jeu traditionnel allemand ou hongrois de 32 cartes; pas de cartes joker
- Joueurs : Deux à quatre ; généralement quatre joueurs par paires de deux
- Unité utilisée : Points
- Règles de base : Pour une partie à quatre joueurs, chaque joueur reçoit six cartes en main et deux cartes face cachée; les joueurs enchérissent d'abord sur l'atout ; après que l'atout est déterminé, ils prennent les deux cartes face cachée et les placent dans leur main; un tour de déclaration suit, au cours duquel certaines combinaisons de cartes sont annoncées pour des points supplémentaires ; le jeu continue jusqu'à ce que toutes les cartes aient été utilisées.
- Actions de joueur possibles : Pass, Bid Suit, Declaration, Throw Card
- Objectif pour la main : Gagner plus de la moitié des points
- Condition de victoire : Soyez la première équipe à marquer 1001 points ou plus
Préférence :
- Plateau : Le plus souvent un jeu traditionnel allemand ou hongrois de 32 cartes; pas de cartes joker
- Joueurs : Trois
- Unités : Points
- Règles de base : Tous les joueurs reçoivent 10 cartes; deux cartes « minou » ou « serre » sont placées au milieu de la table; les joueurs déterminent s'ils veulent enchérir sur une couleur; les joueurs décident de jouer ou non.
- Actions de joueur possibles : Passer, enchérir, jouer, ne pas jouer, lancer une carte
- Objectif : Dépend de la variante de Préférence en cours de lecture ; dans la version standard, l'enchérisseur doit gagner un total de six levées.
- Condition de victoire : Lorsque la somme des scores des trois joueurs est de 0, le joueur avec le plus petit nombre de points gagne.
Pourquoi combiner bases de données et jeux de cartes ?
Notre objectif ici est de concevoir un modèle de base de données qui pourrait stocker toutes les données pertinentes pour ces quatre jeux de cartes. La base de données pourrait être utilisée par une application Web comme lieu de stockage de toutes les données pertinentes. Nous voulons stocker les paramètres de jeu initiaux, les participants au jeu, les actions prises pendant le jeu et le résultat d'une seule donne, main ou astuce. Nous devons également garder à l'esprit le fait qu'un match peut être associé à une ou plusieurs offres.
À partir de ce que nous stockons dans notre base de données, nous devrions pouvoir recréer toutes les actions qui ont eu lieu pendant le jeu. Nous utiliserons des champs de texte pour décrire les conditions de victoire, les actions de jeu et leurs résultats. Celles-ci sont spécifiques à chaque jeu et la logique de l'application Web interprétera le texte et le transformera au besoin.
Une introduction rapide au modèle
Ce modèle nous permet de stocker toutes les données de jeu pertinentes, notamment :
- Propriétés du jeu
- Liste des jeux et matchs
- Participants
- Actions en jeu
Étant donné que les jeux diffèrent à bien des égards, nous utiliserons fréquemment le varchar(256) type de données pour décrire les propriétés, les mouvements et les résultats.
Joueurs, matchs et participants
Cette section du modèle se compose de trois tables et est utilisée pour stocker des données sur les joueurs inscrits, les matchs joués et les joueurs qui ont participé.
Le player
table stocke des données sur les joueurs inscrits. Le username
et email
les attributs sont des valeurs uniques. Le nick_name
l'attribut stocke les noms d'écran des joueurs.
La match
table contient toutes les données de correspondance pertinentes. Généralement, un match est composé d'une ou plusieurs distributions de cartes (également appelées tours, mains ou tours). Tous les matchs ont des règles établies avant le début du jeu. Les attributs sont les suivants :
game_id
– référence le tableau contenant la liste des jeux (poker, blackjack, belot et préférence, dans ce cas).start_time
etend_time
sont les heures réelles de début et de fin d'un match. Notez que leend_time
peut être NULL ; nous n'aurons pas sa valeur avant la fin du jeu. De plus, si une correspondance est abandonnée avant qu'elle ne soit terminée, leend_time
la valeur peut rester NULL.number_of_players
– est le nombre de participants requis pour démarrer le jeudeck_id
– fait référence au deck utilisé dans le jeu.decks_used
– est le nombre de decks utilisés pour jouer au jeu. Habituellement, cette valeur sera 1, mais certains jeux utilisent plusieurs decks.unit_id
– est l'unité (points, jetons, argent, etc.) utilisée pour marquer le jeu.entrance_fee
– est le nombre d'unités nécessaires pour rejoindre le jeu ; cela peut être NULL si le jeu n'exige pas que chaque joueur commence avec un nombre défini d'unités.victory_conditions
– détermine quel joueur a remporté le match. Nous utiliserons le varchar type de données pour décrire la condition de victoire de chaque match (c'est-à-dire la première équipe à atteindre 100 points) et laisser l'application l'interpréter. Cette flexibilité permet d'ajouter de nombreux jeux.match_result
– stocke le résultat de la correspondance au format texte. Comme avecvictory_conditions
, nous laisserons l'application interpréter la valeur. Cet attribut peut être NULL car nous remplirons cette valeur en même temps que nous insèrerons leend_time
valeur.
Le participant
table stocke des données sur tous les participants à un match. Le match_id
et player_id
les attributs sont des références à la match
et player
les tables. Ensemble, ces valeurs forment la clé alternative de la table.
La plupart des jeux changent le joueur qui enchérit ou joue en premier. Habituellement, au premier tour, le joueur qui joue en premier (le premier joueur) est déterminé par les règles du jeu. Au tour suivant, le joueur à gauche (ou parfois à droite) du joueur d'ouverture d'origine jouera en premier. Nous utiliserons le initial_player_order
attribut pour stocker le numéro ordinal du premier joueur du premier tour. Le match_id
et le initial_player_order
les attributs forment une autre clé alternative car deux joueurs ne peuvent pas jouer en même temps.
Le score
L'attribut est mis à jour lorsqu'un joueur termine un match. Parfois, ce sera au même moment pour tous les joueurs (par exemple, en belot ou préférence) et parfois pendant que le match est toujours en cours (par exemple, poker ou blackjack).
Actions et types d'actions
Quand on pense aux actions que les joueurs peuvent faire dans un jeu de cartes, on se rend compte qu'il faut stocker :
- Quelle était l'action
- Qui a effectué cette action
- Quand (dans quel accord) l'action a eu lieu
- Quelle(s) carte(s) ont été utilisées pour cette action
Le action_type
table est un simple dictionnaire qui contient les noms des actions des joueurs. Certaines valeurs possibles incluent piocher une carte, jouer une carte, passer une carte à un autre joueur, vérifier et relancer.
Dans l'action
table, nous stockerons tous les événements qui se sont produits pendant une transaction. Le deal_id
, card_id
, participant_id
et action_type_id
sont des références aux tables contenant les valeurs de transaction, de participant à la carte et de type d'action. Notez que le participant_id
et card_id
peuvent être des valeurs NULL. Cela est dû au fait que certaines actions ne sont pas effectuées par les joueurs (par exemple, le croupier pioche une carte et la place face visible), tandis que d'autres n'incluent pas de cartes (par exemple, une relance au poker). Nous devons stocker toutes ces actions pour pouvoir recréer l'intégralité du match.
Le action_order
L'attribut stocke le nombre ordinal d'une action dans le jeu. Par exemple, une enchère d'ouverture recevrait une valeur de 1 ; la prochaine enchère aura une valeur de 2, etc. Il ne peut pas y avoir plus d'une action en même temps. Par conséquent, le deal_id
et action_order
les attributs forment ensemble la clé alternative.
La action_notation
L'attribut contient une description détaillée d'une action. Au poker, par exemple, on peut stocker une relance action et un montant arbitraire. Certaines actions pourraient être plus compliquées, il est donc sage de stocker ces valeurs sous forme de texte et de laisser l'application l'interpréter.
Offres et commande d'offres
Un match est composé d'une ou plusieurs distributions de cartes. Nous avons déjà parlé du participant
et la match
tableaux, mais nous les avons inclus dans l'image pour montrer leur relation avec l'deal
et deal_order
tableaux.
Le deal
table stocke toutes les données dont nous avons besoin sur une seule instance de correspondance.
Le match_id
l'attribut relie cette instance à la correspondance appropriée, tandis que start_time
et end_time
indiquent l'heure exacte à laquelle cette instance a démarré et l'heure à laquelle elle s'est terminée.
Le move_time_limit
et le deal_result
les attributs sont à la fois des champs de texte utilisés pour stocker les délais (le cas échéant) et une description du résultat de cette transaction.
Dans le participant
table, le initial_player_order
L'attribut stocke l'ordre des joueurs pour l'instance de match d'ouverture. Le stockage des commandes pour les tours suivants nécessite une table entièrement nouvelle - le deal_order
tableau.
Évidemment, deal_id
et participant_id
sont des références à une instance de correspondance et à un participant. Ensemble, ils forment la première clé alternative dans le deal_order
table. Le player_order
L'attribut contient des valeurs indiquant les ordres auxquels les joueurs ont participé dans cette instance de match. Avec deal_id
, il constitue la deuxième clé alternative de ce tableau. Le deal_result
L'attribut est un champ de texte qui décrit le résultat du match pour un joueur individuel. Le score
L'attribut stocke une valeur numérique liée au résultat de la transaction.
Costumes, grades et cartes
Cette section du modèle décrit les cartes que nous utiliserons dans tous les jeux pris en charge. Chaque carte a une couleur et un rang.
Le suit_type
table est un dictionnaire qui contient tous les types de combinaisons que nous utiliserons. Pour suit_type_name
, nous utiliserons des valeurs telles que "costumes français", "costumes allemands", "costumes suisses-allemands" et "costumes latins".
Le suit
table contient les noms de toutes les combinaisons contenues par des types de deck spécifiques. Par exemple, le jeu français a des couleurs appelées "Spades", "Hearts", "Diamonds" et "Clubs".
Dans le rank
dictionnaire, nous trouverons des valeurs de cartes bien connues comme "As", "King", "Queen" et "Jack".
La card
table contient une liste de toutes les cartes possibles. Chaque carte n'apparaîtra dans ce tableau qu'une seule fois. C'est la raison pour laquelle le suit_id
et rank_id
Les attributs forment la clé alternative de cette table. Les valeurs des deux attributs peuvent être NULL parce que certaines cartes n'ont pas de couleur ou de rang (par exemple, les cartes joker). La is_joker_card
est une valeur booléenne explicite. Le card_name
L'attribut décrit une carte par le texte :« As de pique ».
Cartes et decks
Les cartes appartiennent à des decks. Parce qu'une carte peut apparaître dans plusieurs decks, nous aurons besoin d'un n:n relation entre la card
et deck
tableaux.
Dans le deck
table, nous stockerons les noms de tous les jeux de cartes que nous voulons utiliser. Un exemple de valeurs stockées dans le deck_name
les attributs sont :« Jeu standard de 52 cartes (français) » ou « Jeu de 32 cartes (allemand) ».
Le card_in_deck
relation est utilisée pour assigner des cartes aux ponts appropriés. Le card_id
– deck_id
paire est la clé alternative du deck
table.
Faire correspondre les propriétés, les decks et les unités utilisées
Cette section du modèle contient quelques paramètres de base pour démarrer une nouvelle partie.
La partie principale de cette section est le game
table. Cette table stocke des données sur les jeux pris en charge par l'application. Le game_name
l'attribut contient des valeurs telles que "poker", "blackjack", "belot" et "préférence".
Le min_number_of_players
et max_number_of_players
sont le nombre minimal et maximal de participants à un match. Ces attributs servent de limites pour le jeu et ils sont affichés à l'écran au début d'un match. La personne qui initie la correspondance doit sélectionner une valeur dans cette plage.
Le min_entrance_fee
et le max_entrance_fee
attributs indique la fourchette des frais d'entrée. Encore une fois, cela est basé sur le jeu en cours.
Dans possible_victory_condition
, nous stockerons toutes les conditions de victoire qui pourraient être attribuées à un match. Les valeurs sont séparées par un délimiteur.
L'unit
dictionnaire est utilisé pour stocker chaque unité utilisée dans tous nos jeux. Le unit_name
l'attribut contiendra des valeurs telles que "point", "dollar", "euro" et "chip".
Le game_deck
et game_unit
les tables utilisent la même logique. Ils contiennent des listes de tous les decks et unités qui peuvent être utilisés dans un match. Par conséquent, le game_id
– deck_id
paire et le game_id
– unit_id
forment des paires de clés alternatives dans leurs tables respectives.
Scores
Dans notre application, nous voudrons stocker les scores de tous les joueurs qui ont participé à nos jeux de cartes. Pour chaque jeu, une seule valeur numérique est calculée et stockée. (Le calcul est basé sur les résultats du joueur dans tous les jeux d'un même type.) Ce score du joueur est similaire à un classement; il permet aux utilisateurs de savoir à peu près à quel point un joueur est bon.
Revenons au processus de calcul. Nous allons créer un n:n relation entre le player
et game
les tables. C'est le player_score
table dans notre modèle. Le player_id
et le score_id
” forment ensemble la clé alternative de la table. Le "score
L'attribut est utilisé pour stocker la valeur numérique mentionnée précédemment.
Il existe une variété de jeux de cartes qui utilisent des règles, des cartes et des jeux de cartes très différents. Pour créer une base de données qui stocke les données de plusieurs jeux de cartes, nous devons faire quelques généralisations. Pour ce faire, nous utilisons des champs de texte descriptifs et laissons l'application les interpréter. Nous pourrions trouver des moyens de couvrir les situations les plus courantes, mais cela compliquerait de manière exponentielle la conception de la base de données.
Comme cet article l'a montré, vous pouvez utiliser une base de données pour plusieurs jeux. Pourquoi voudriez-vous faire cela? Trois raisons :1) vous pouvez réutiliser la même base de données; 2) cela simplifierait l'analyse ; et cela conduirait à 3) la construction de meilleurs adversaires IA.