いくつかの非常に異なるカードゲームに対応するのに十分な柔軟性のあるデータベースを設計する方法。
最近、データベースを使用してボードゲームの結果を保存する方法を示しました。ボードゲームは楽しいですが、オンライン版のクラシックゲームはこれだけではありません。カードゲームも大人気です。彼らはゲームプレイに運の要素を導入し、良いカードゲームには運以上のものが含まれています!
この記事では、ゲームの試合、結果、プレーヤー、スコアを保存するためのデータモデルの構築に焦点を当てます。ここでの主な課題は、さまざまなカードゲームに関連するデータを保存することです。また、このデータを分析して、勝利戦略を決定したり、自分のプレイスキルを向上させたり、より優れたAI対戦相手を構築したりすることも検討できます。
データベースで使用する4つのカードゲーム
プレイヤーは配られるハンドをコントロールできないため、カードゲームは戦略、スキル、運を組み合わせたものです。その運の要素は、初心者に経験豊富なプレーヤーを打ち負かす機会を与え、それはカードゲームを中毒性にします。 (これは、論理と戦略に大きく依存するチェスのようなゲームとは異なります。多くのプレーヤーから、スキルレベルで対戦相手を見つけることができないため、チェスをプレイすることに興味がないと聞いています。)
ポーカー、ブラックジャック、ベロ(またはベロテ)、プレフェレンスの4つの有名なカードゲームに焦点を当てます。それぞれに比較的複雑なルールがあり、習得するには時間がかかります。運と知識の比率もゲームごとに異なります。
以下の4つのゲームすべての簡略化されたルールと詳細を簡単に見ていきます。ゲームの説明はかなりまばらですが、ゲームプレイのさまざまなモードと、データベース設計プロセス中に遭遇するさまざまなルールを示すのに十分なものが含まれています。
ブラックジャック:
- デッキ: それぞれ52枚のカードからなる1〜8枚のデッキ。ジョーカーカードはありません
- プレーヤー: ディーラーと1人以上の対戦相手
- 使用単位: 通常はお金
- 基本ルール: プレイヤーは自分だけが見ることができる2枚のカードを手に入れます。ディーラーは2枚のカードを受け取ります。1枚は表向きでもう1枚は裏向きです。各プレイヤーは、より多くのカードを引くかどうかを決定します。ディーラーが最後に引きます。カードには、1から11の範囲のポイント値が割り当てられています。
- 可能なプレーヤーアクション: ヒット、スタンド、スプリット、降伏
- 目標と勝利の条件: プレイヤーのカードの合計は、ディーラーのカードよりも多くなります。いずれかのプレーヤーが21を超えると、そのプレーヤーは負けます。
ポーカー(テキサスホールデム):
- デッキ: 標準(フレンチスーツとも呼ばれます)52枚のカードデッキ。ジョーカーカードはありません。カードの色はほとんどの場合赤と黒です。
- プレーヤー: 2から9;プレイヤーは交代で取引します
- 使用単位:通常はチップ
- 基本ルール: 各プレイヤーは2枚のカードを配られることから始めます。プレーヤーは賭けをします。テーブルの真ん中で3枚のカードが表向きに配られます。プレーヤーは再び賭けをします。 4枚目のカードが真ん中に置かれ、プレーヤーは再びベットします。次に、5枚目の最後のカードが配置され、最後の賭けが完了します。
- 可能なプレーヤーアクション: フォールド、コール、レイズ、スモールブラインド、ビッグブラインド、リレイズ
- 目標: 5枚のカードの可能な限り最高の手札を組み合わせます(プレーヤーの手札の2枚のカードとテーブルの真ん中の5枚のカードから)
- 勝利条件:通常、テーブル上のすべてのチップを獲得するため
Belot(Beloteのクロアチア語版):
- デッキ: 通常、伝統的なドイツ語またはハンガリー語の32枚のカードデッキ。ジョーカーカードはありません
- プレーヤー: 2〜4;通常、2人1組で4人のプレーヤー
- 使用単位: ポイント
- 基本ルール: 4人のプレイヤーのゲームの場合、各プレイヤーは6枚のカードを手札に、2枚のカードを裏向きに手に入れます。プレーヤーは最初にトランプスーツに入札します。トランプが決定された後、彼らは2枚の裏向きのカードを取り、それらを手札に置きます。宣言ラウンドが続き、その間に特定のカードの組み合わせが追加ポイントとして発表されます。すべてのカードが使用されるまでプレイは続きます。
- 可能なプレーヤーアクション: パス、ビッドスーツ、宣言、スローカード
- 手の目標: 半分以上のポイントを獲得するには
- 勝利条件: 1001ポイント以上を獲得した最初のチームになる
プレフェレンス:
- デッキ: ほとんどの場合、伝統的なドイツ語またはハンガリー語の32枚のカードデッキ。ジョーカーカードはありません
- プレーヤー: 3つ
- 単位: ポイント
- 基本ルール: すべてのプレイヤーに10枚のカードが配られます。 2枚の「キティ」または「タロン」カードがテーブルの中央に配置されます。プレーヤーは、スーツに入札するかどうかを決定します。プレイヤーはプレイするかどうかを決定します。
- 可能なプレーヤーアクション: パス、スート、プレイ、プレイしない、カードを投げる
- 目標: プレイされているプレフェレンスの変種によって異なります。標準バージョンでは、入札者は合計6つのトリックを獲得する必要があります。
- 勝利条件: 3人のプレーヤーのスコアの合計が0の場合、ポイント数が最も少ないプレーヤーが勝ちます。
データベースとカードゲームを組み合わせる理由
ここでの私たちの目標は、これら4つのカードゲームに関連するすべてのデータを格納できるデータベースモデルを設計することです。データベースは、関連するすべてのデータを格納する場所としてWebアプリケーションで使用できます。初期のゲーム設定、ゲーム参加者、プレイ中に実行されたアクション、および単一の取引、ハンド、またはトリックの結果を保存したいと思います。また、試合には1つ以上の取引が関連付けられている可能性があるという事実にも留意する必要があります。
データベースに保存されているものから、ゲーム中に発生したすべてのアクションを再現できるはずです。テキストフィールドを使用して、勝利条件、ゲームアクション、およびそれらの結果を説明します。これらは各ゲームに固有であり、Webアプリケーションロジックがテキストを解釈し、必要に応じて変換します。
モデルの簡単な紹介
このモデルにより、以下を含むすべての関連するゲームデータを保存できます。
- ゲームのプロパティ
- ゲームと試合のリスト
- 参加者
- ゲーム内アクション
ゲームはさまざまな点で異なるため、 varchar(256)を頻繁に使用します プロパティ、移動、および結果を記述するデータ型。
プレーヤー、試合、参加者
モデルのこのセクションは3つのテーブルで構成され、登録されたプレーヤー、プレイされた試合、参加したプレーヤーに関するデータを保存するために使用されます。
プレーヤー
テーブルには、登録済みのプレーヤーに関するデータが格納されます。 ユーザー名
およびemail
属性は一意の値です。 nick_name
属性はプレーヤーのスクリーン名を保存します。
一致
テーブルには、関連するすべての一致データが保持されます。通常、マッチは1つ以上のカードディール(ラウンド、ハンド、トリックとも呼ばれます)で構成されます。すべての試合には、プレーが始まる前にルールが設定されています。属性は次のとおりです。
-
game_id
–ゲームのリスト(この場合は、ポーカー、ブラックジャック、ベロット、プレフェレンス)を含むテーブルを参照します。 -
start_time
およびend_time
試合が開始および終了する実際の時間です。end_time
に注意してください NULLにすることができます。ゲームが終了するまで、その価値はありません。また、試合が終了する前に試合が中止された場合、end_time
値はNULLのままにすることができます。 -
number_of_players
–ゲームを開始するために必要な参加者の数です -
deck_id
–ゲームで使用されるデッキを参照します。 -
Decks_used
–はゲームをプレイするために使用されるデッキの数です。通常、この値は1になりますが、一部のゲームでは複数のデッキを使用します。 -
unit_id
–は、ゲームのスコアリングに使用される単位(ポイント、チップ、お金など)です。 -
entry_fee
–ゲームに参加するために必要なユニットの数です。ゲームで各プレーヤーが設定されたユニット数で開始する必要がない場合、これはNULLになる可能性があります。 -
Victory_conditions
–どのプレーヤーが試合に勝ったかを決定します。 varcharを使用します 各ゲームの勝利条件(つまり、100ポイントに到達した最初のチーム)を記述し、それを解釈するためにアプリケーションを離れるデータ型。この柔軟性により、多くのゲームを追加する余地があります。 -
match_result
–一致の結果をテキスト形式で保存します。Victory_conditions
と同様 、アプリケーションに値を解釈させます。end_time
を挿入すると同時にその値を入力するため、この属性はNULLになる可能性があります。 値。
参加者
テーブルには、試合のすべての参加者に関するデータが格納されます。 match_id
およびplayer_id
属性はmatchへの参照です
およびplayer
テーブル。これらの値が一緒になって、テーブルの代替キーを形成します。
ほとんどのゲームは、どのプレイヤーが最初に入札またはプレイするかをローテーションします。通常、最初のラウンドでは、最初にプレーするプレーヤー(オープニングプレーヤー)がゲームルールによって決定されます。次のラウンドでは、元のオープニングプレーヤーの左側(場合によっては右側)のプレーヤーが最初に進みます。 initial_player_order
を使用します 最初のラウンドのオープニングプレーヤーの序数を格納する属性。 match_id
およびinitial_player_order
2人のプレーヤーが同時にプレイすることはできないため、属性は別の代替キーを形成します。
スコアコード> プレイヤーが試合を終了すると、属性が更新されます。これは、すべてのプレーヤーにとって同時に行われる場合もあり(たとえば、ベロットやプレフェレンス)、場合によっては、試合がまだ進行中の場合(たとえば、ポーカーやブラックジャック)になります。
アクションとアクションタイプ
カードゲームでプレイヤーが実行できるアクションについて考えるとき、次のことを保存する必要があることに気付きます。
- アクションとは
- そのアクションを実行したのは誰か
- (どの取引で)アクションが発生したか
- そのアクションで使用されたカード
action_type
tableは、プレーヤーのアクションの名前を含む単純な辞書です。考えられる値には、ドローカード、プレイカード、カードを別のプレーヤーに渡す、チェックしてレイズするなどがあります。
アクション
テーブルには、取引中に発生したすべてのイベントが保存されます。 deal_id
、 card_id
、 participant_id
およびaction_type_id
取引、カード参加者、およびaction_typeの値を含むテーブルへの参照です。 participant_id
に注意してください およびcard_id
NULL値にすることができます。これは、一部のアクションがプレーヤーによって行われない(たとえば、ディーラーがカードを引いて表向きに置く)一方で、一部のアクションがカードを含まない(たとえば、ポーカーのレイズ)という事実によるものです。一致全体を再現できるようにするには、これらすべてのアクションを保存する必要があります。
action_order
属性は、ゲーム内アクションの序数を格納します。たとえば、最初の入札は1の値を受け取ります。次の入札の値は2などになります。同時に複数のアクションを実行することはできません。したがって、deal_id
およびaction_order
属性が一緒になって代替キーを形成します。
action_notation
属性には、アクションの詳細な説明が含まれています。たとえばポーカーでは、レイズを保存できます。 アクションと任意の量。一部のアクションはより複雑になる可能性があるため、これらの値をテキストとして保存し、アプリケーションに解釈を任せることをお勧めします。
取引と取引注文
試合は、1つ以上のカード取引で構成されます。 参加者についてはすでに説明しました
およびmatch
表ですが、取引との関係を示すために画像に含めています。
およびdeal_order
テーブル。
取引
テーブルには、単一の一致インスタンスについて必要なすべてのデータが格納されます。
match_id
属性はそのインスタンスを適切な一致に関連付け、 start_time
およびend_time
そのインスタンスが開始された正確な時刻と終了した時刻を示します。
move_time_limit
およびdeal_result
属性は、時間制限(該当する場合)を保存するために使用されるテキストフィールドと、その取引の結果の説明の両方です。
参加者
テーブル、 initial_player_order
属性は、オープニングマッチインスタンスのプレーヤーの順序を格納します。後続のターンの注文を保存するには、まったく新しいテーブル– deal_order が必要です
テーブル。
明らかに、deal_id
およびparticipant_id
一致インスタンスと参加者への参照です。これらは一緒になって、 deal_orderの最初の代替キーを形成します
テーブル。 player_order
属性には、プレーヤーがそのマッチインスタンスに参加した注文を示す値が含まれます。 deal_id
と一緒に 、このテーブルの2番目の代替キーを形成します。 deal_result
属性は、個々のプレーヤーの試合結果を説明するテキストフィールドです。 スコアコード> 属性には、取引結果に関連する数値が格納されます。
スーツ、ランク、カード
モデルのこのセクションでは、サポートされているすべてのゲームで使用するカードについて説明します。各カードにはスーツとランクがあります。
スーツタイプ
tableは、使用するすべてのスーツタイプを含む辞書です。 suite_type_name
の場合 、「フランスのスーツ」、「ドイツのスーツ」、「スイスドイツのスーツ」、「ラテンのスーツ」などの値を使用します。
スーツ
テーブルには、特定のデッキタイプに含まれるすべてのスーツの名前が含まれています。たとえば、フランスのデッキには「スペード」、「ハート」、「ダイヤ」、「クラブ」と呼ばれるスーツがあります。
ランク
辞書には、「エース」、「キング」、「クイーン」、「ジャック」などの有名なカードの値があります。
カード
表には、考えられるすべてのカードのリストが含まれています。各カードは、このテーブルに1回だけ表示されます。それがsuit_id
が およびrank_id
属性は、このテーブルの代替キーを形成します。一部のカードにはスーツやランクがないため、両方の属性の値がNULLになる可能性があります(ジョーカーカードなど)。 is_joker_card
自明のブール値です。 card_name
属性は、カードをテキストで説明します:「スペードのエース」。
カードとデッキ
カードはデッキに属します。 1枚のカードが複数のデッキに表示される可能性があるため、 n:nが必要になります カード間の関係
およびデッキ
テーブル。
デッキ
テーブルには、使用するすべてのカードデッキの名前を保存します。 deck_name
に保存されている値の例 属性は、「標準の52カードデッキ(フランス語)」または「32カードデッキ(ドイツ語)」です。
card_in_deck
リレーションは、カードを適切なデッキに割り当てるために使用されます。 card_id
– deck_id
ペアはデッキの代替キーです
テーブル。
一致するプロパティ、デッキ、使用するユニット
モデルのこのセクションには、新しいゲームを開始するためのいくつかの基本的なパラメータが含まれています。
このセクションの主要部分は、ゲームです。
テーブル。このテーブルには、アプリケーションでサポートされているゲームに関するデータが格納されています。 game_name
属性には、「poker」、「blackjack」、「belot」、「préférence」などの値が含まれています。
min_number_of_players
およびmax_number_of_players
試合の参加者の最小数と最大数です。これらの属性はゲームの境界として機能し、試合の開始時に画面に表示されます。試合を開始する人は、この範囲から値を選択する必要があります。
min_entrance_fee
およびmax_entrance_fee
属性は入場料の範囲を示します。繰り返しますが、これはプレイ中のゲームに基づいています。
possible_victory_condition
で 、試合に割り当てることができるすべての勝利条件を保存します。値は区切り文字で区切られます。
ユニット
辞書は、すべてのゲームで使用されるすべてのユニットを格納するために使用されます。 unit_name
属性には、「ポイント」、「ドル」、「ユーロ」、「チップ」などの値が格納されます。
game_deck
およびgame_unit
テーブルは同じロジックを使用します。試合で使用できるすべてのデッキとユニットのリストが含まれています。したがって、 game_id
– deck_id
ペアとgame_id
– unit_id
ペアは、それぞれのテーブルで代替キーを形成します。
スコア
このアプリケーションでは、カードゲームに参加したすべてのプレーヤーのスコアを保存します。ゲームごとに、1つの数値が計算されて保存されます。 (計算は、単一タイプのすべてのゲームでのプレーヤーの結果に基づいています。)このプレーヤーのスコアはランクに似ています。プレーヤーがどれだけ優れているかをユーザーに知らせます。
計算プロセスに戻ります。 n:nを作成します player
間の関係 およびgame
テーブル。それがplayer_score です
モデルのテーブル。 player_id
およびscore_id
」が一緒になって、テーブルの代替キーを形成します。 「スコア
属性は、前述の数値を格納するために使用されます。
非常に異なるルール、カード、デッキを使用するさまざまなカードゲームがあります。複数のカードゲームのデータを格納するデータベースを作成するには、いくつかの一般化を行う必要があります。これを行う1つの方法は、説明テキストフィールドを使用し、アプリケーションにそれらを挿入させることです。最も一般的な状況をカバーする方法を考え出すことはできますが、それはデータベース設計を指数関数的に複雑にします。
この記事が示しているように、多くのゲームで1つのデータベースを使用できます。なぜあなたはこれをしますか? 3つの理由:1)同じデータベースを再利用できる。 2)分析を簡素化します。これにより、3)より優れたAI対戦相手の構築につながります。