sql >> Base de Datos >  >> RDS >> Database

¿Qué tienen que ver el póquer, el blackjack, el belot y la preferencia con las bases de datos?

Cómo diseñar una base de datos lo suficientemente flexible para acomodar varios juegos de cartas muy diferentes.

Recientemente, mostramos cómo se puede usar una base de datos para almacenar resultados de juegos de mesa. Los juegos de mesa son divertidos, pero no son la única versión en línea de los juegos clásicos. Los juegos de cartas también son muy populares. Introducen un elemento de suerte en el juego, ¡y hay mucho más que suerte en un buen juego de cartas!

En este artículo, nos centraremos en crear un modelo de datos para almacenar partidos, resultados, jugadores y puntajes. El principal desafío aquí es almacenar datos relacionados con muchos juegos de cartas diferentes. También podríamos considerar analizar estos datos para determinar estrategias ganadoras, mejorar nuestras propias habilidades de juego o construir un mejor oponente de IA.

Los cuatro juegos de cartas que usaremos en nuestra base de datos

Debido a que los jugadores no pueden controlar la mano que reciben, los juegos de cartas combinan estrategia, habilidad y suerte. Ese factor suerte le da a un principiante la oportunidad de vencer a un jugador experimentado y hace que los juegos de cartas sean adictivos. (Esto difiere de juegos como el ajedrez, que se basan en gran medida en la lógica y la estrategia. He escuchado de muchos jugadores que no están interesados ​​en jugar al ajedrez porque no pueden encontrar oponentes en su nivel de habilidad).

Nos centraremos en cuatro juegos de cartas muy conocidos:póquer, blackjack, belot (o belote) y préférence. Cada uno de ellos tiene reglas relativamente complejas y requiere algún tiempo para dominar. La relación entre suerte y conocimiento también es diferente para cada juego.

Echaremos un vistazo rápido a las reglas simplificadas y los detalles de los cuatro juegos a continuación. Las descripciones de los juegos son bastante escasas, pero hemos incluido suficientes para mostrar los diferentes modos de juego y las diversas reglas que encontraremos durante el proceso de diseño de la base de datos.

Veintiuna:

  • Mazo: De uno a ocho mazos de 52 cartas cada uno; sin cartas de comodín
  • Jugadores: Repartidor y 1 o más oponentes
  • Unidad utilizada: Generalmente dinero
  • Reglas básicas: Los jugadores obtienen 2 cartas que solo ellos pueden ver; el crupier recibe dos cartas, una boca arriba y la otra boca abajo; cada jugador decide sacar más cartas (o no); el crupier saca el último. Las tarjetas tienen valores de puntos asignados que van del 1 al 11.
  • Posibles acciones del jugador: Golpear, Plantarse, Dividir, Rendirse
  • Objetivo y condición de victoria: La suma de las cartas de un jugador es mayor que la del crupier; si algún jugador pasa de 21, ese jugador pierde.

Póker (Texas Hold'Em):

  • Mazo: Mazo estándar (también conocido como palo francés) de 52 cartas; sin cartas de comodín. Las tarjetas suelen ser de color rojo y negro.
  • Jugadores: de dos a nueve; los jugadores se turnan para repartir
  • Unidad utilizada:generalmente chips
  • Reglas básicas: Cada jugador comienza recibiendo dos cartas; los jugadores hacen sus apuestas; se reparten tres cartas boca arriba en el centro de la mesa; los jugadores vuelven a hacer sus apuestas; se coloca una cuarta carta en el medio y los jugadores vuelven a apostar; luego se coloca la quinta y última carta y se completa la última ronda de apuestas.
  • Posibles acciones del jugador: Retirarse, Igualar, Subir, Ciega pequeña, Ciega grande, Resubir
  • Objetivo: Combina la mejor mano posible de cinco cartas (de las dos cartas en la mano del jugador y las cinco cartas en el medio de la mesa)
  • Condición de victoria:normalmente para ganar todas las fichas de la mesa

Belot (variante croata de Belote):

  • Mazo: Por lo general, la baraja tradicional alemana o húngara de 32 cartas; sin cartas de comodín
  • Jugadores: dos a cuatro; normalmente cuatro jugadores en parejas de dos
  • Unidad utilizada: Puntos
  • Reglas básicas: Para un juego de cuatro jugadores, cada jugador recibe seis cartas en la mano y dos cartas boca abajo; los jugadores ofertan primero por el palo de triunfo; después de determinar el triunfo, toman las dos cartas boca abajo y las colocan en su mano; sigue una ronda de declaración, durante la cual se anuncian ciertas combinaciones de cartas para obtener puntos adicionales; el juego continúa hasta que se hayan usado todas las cartas.
  • Posibles acciones del jugador: Pase, palo de oferta, declaración, tarjeta de lanzamiento
  • Gol de la mano: Ganar más de la mitad de los puntos
  • Condición de victoria: Sé el primer equipo en anotar 1001 puntos o más

Preferencia:

  • Mazo: La mayoría de las veces, una baraja tradicional alemana o húngara de 32 cartas; sin cartas de comodín
  • Jugadores: tres
  • Unidades: Puntos
  • Reglas básicas: Todos los jugadores reciben 10 cartas; se colocan dos cartas de "gatito" o "garra" en el centro de la mesa; los jugadores determinan si quieren pujar por un palo; los jugadores deciden jugar o no.
  • Posibles acciones del jugador: Pasar, Decir Palo, Jugar, No Jugar, Tirar Carta
  • Objetivo: Depende de la variante de Préférence que se esté reproduciendo; en la versión estándar, el postor debe ganar un total de seis bazas.
  • Condición de victoria: Cuando la suma de las puntuaciones de los tres jugadores es 0, gana el jugador con el menor número de puntos.

¿Por qué combinar bases de datos y juegos de cartas?

Nuestro objetivo aquí es diseñar un modelo de base de datos que pueda almacenar todos los datos relevantes para estos cuatro juegos de cartas. La base de datos podría ser utilizada por una aplicación web como un lugar para almacenar todos los datos relevantes. Queremos almacenar la configuración inicial del juego, los participantes del juego, las acciones realizadas durante el juego y el resultado de un solo trato, mano o baza. También debemos tener en cuenta el hecho de que un partido puede tener una o más ofertas asociadas.

A partir de lo que almacenamos en nuestra base de datos, deberíamos poder recrear todas las acciones que tuvieron lugar durante el juego. Usaremos campos de texto para describir las condiciones de victoria, las acciones del juego y sus resultados. Estos son específicos para cada juego y la lógica de la aplicación web interpretará el texto y lo transformará según sea necesario.

Una introducción rápida al modelo




Este modelo nos permite almacenar todos los datos relevantes del juego, incluidos:

  • Propiedades del juego
  • Lista de juegos y partidos
  • Participantes
  • Acciones en el juego

Dado que los juegos difieren en muchos aspectos, usaremos con frecuencia el varchar(256) tipo de datos para describir propiedades, movimientos y resultados.

Jugadores, Partidos y Participantes

Esta sección del modelo consta de tres tablas y se utiliza para almacenar datos sobre los jugadores registrados, los partidos jugados y los jugadores que participaron.

El player tabla almacena datos sobre los jugadores registrados. El username y email Los atributos son valores únicos. El nick_name El atributo almacena los nombres de pantalla de los jugadores.

El match la tabla contiene todos los datos de coincidencia relevantes. Generalmente, una partida se compone de uno o más repartos de cartas (también conocidos como rondas, manos o bazas). Todos los partidos tienen reglas establecidas antes de que comience el juego. Los atributos son los siguientes:

  • game_id – hace referencia a la tabla que contiene la lista de juegos (póker, blackjack, belot y préférence, en este caso).
  • start_time y end_time son los tiempos reales cuando comienza y termina un partido. Observe que el end_time puede ser NULL; no tendremos su valor hasta que termine el juego. Además, si se abandona una partida antes de que finalice, el end_time el valor puede permanecer NULL.
  • number_of_players – es el número de participantes necesarios para iniciar el juego
  • deck_id – hace referencia al mazo utilizado en el juego.
  • decks_used – es el número de barajas utilizadas para jugar el juego. Por lo general, este valor será 1, pero algunos juegos usan varios mazos.
  • unit_id – es la unidad (puntos, fichas, dinero, etc.) utilizada para puntuar el juego.
  • entrance_fee – es el número de unidades necesarias para unirse al juego; esto puede ser NULL si el juego no requiere que cada jugador comience con un número determinado de unidades.
  • victory_conditions – determina qué jugador ganó el partido. Usaremos el varchar tipo de datos para describir la condición de victoria de cada juego (es decir, el primer equipo en alcanzar los 100 puntos) y dejar que la aplicación lo interprete. Esta flexibilidad deja espacio para que se agreguen muchos juegos.
  • match_result – almacena el resultado del partido en formato de texto. Al igual que con victory_conditions , dejaremos que la aplicación interprete el valor. Este atributo puede ser NULL porque llenaremos ese valor al mismo tiempo que insertamos el end_time valor.

El participant tabla almacena datos sobre todos los participantes en un partido. El match_id y player_id los atributos son referencias a la match y player mesas. Juntos, estos valores forman la clave alternativa de la tabla.

La mayoría de los juegos rotan qué jugador hace una oferta o juega primero. Por lo general, en la primera ronda, el jugador que juega primero (el jugador de apertura) está determinado por las reglas del juego. En la siguiente ronda, el jugador a la izquierda (oa veces a la derecha) del jugador inicial original irá primero. Usaremos el initial_player_order atributo para almacenar el número ordinal del jugador de apertura de la primera ronda. El match_id y el initial_player_order los atributos forman otra clave alternativa porque dos jugadores no pueden jugar al mismo tiempo.

La score El atributo se actualiza cuando un jugador termina un partido. A veces, esto será en el mismo momento para todos los jugadores (p. ej., en belot o préférence) y, a veces, mientras la partida aún está en curso (p. ej., póquer o blackjack).

Acciones y tipos de acciones

Cuando pensamos en las acciones que pueden realizar los jugadores en un juego de cartas, nos damos cuenta de que debemos almacenar:

  • Cuál fue la acción
  • Quién realizó esa acción
  • Cuándo (en qué trato) tuvo lugar la acción
  • Qué carta(s) se usaron en esa acción

El action_type table es un diccionario simple que contiene los nombres de las acciones del jugador. Algunos valores posibles incluyen robar carta, jugar carta, pasar carta a otro jugador, pasar y subir.

En la action tabla, almacenaremos todos los eventos que ocurrieron durante un trato. El deal_id , card_id , participant_id y action_type_id son referencias a las tablas que contienen valores de trato, participante de tarjeta y tipo de acción. Observe que el participant_id y card_id pueden ser valores NULL. Esto se debe al hecho de que algunas acciones no las realizan los jugadores (p. ej., el crupier saca una carta y la coloca boca arriba), mientras que otras no incluyen cartas (p. ej., una subida en el póquer). Necesitamos almacenar todas estas acciones para poder recrear todo el partido.

El action_order El atributo almacena el número ordinal de una acción en el juego. Por ejemplo, una oferta de apertura recibiría un valor de 1; la siguiente oferta tendría un valor de 2, etc. No puede haber más de una acción al mismo tiempo. Por lo tanto, el deal_id y action_order los atributos juntos forman la clave alternativa.

La action_notation El atributo contiene una descripción detallada de una acción. En el póquer, por ejemplo, podemos almacenar un aumento acción y una cantidad arbitraria. Algunas acciones pueden ser más complicadas, por lo que es aconsejable almacenar estos valores como texto y dejar que la aplicación los interprete.

Ofertas y orden de ofertas

Un partido se compone de uno o más repartos de cartas. Ya hemos discutido el participant y la match tablas, pero las hemos incluido en la imagen para mostrar su relación con el deal y deal_order mesas.

El deal table almacena todos los datos que necesitamos sobre una única instancia de coincidencia.

El match_id El atributo relaciona esa instancia con la coincidencia apropiada, mientras que start_time y end_time indicar la hora exacta en que se inició esa instancia y cuando finalizó.

El move_time_limit y el deal_result los atributos son campos de texto utilizados para almacenar límites de tiempo (si corresponde) y una descripción del resultado de ese trato.

En el participant tabla, el initial_player_order El atributo almacena el orden de los jugadores para la instancia del partido de apertura. Almacenar las órdenes para turnos posteriores requiere una tabla completamente nueva:la deal_order mesa.

Obviamente, deal_id y participant_id son referencias a una instancia de coincidencia y un participante. Juntos, forman la primera clave alternativa en el deal_order mesa. El player_order El atributo contiene valores que indican los órdenes en los que los jugadores participaron en esa instancia de partido. Junto con deal_id , forma la segunda clave alternativa en esta tabla. El deal_result El atributo es un campo de texto que describe el resultado del partido para un jugador individual. La score El atributo almacena un valor numérico relacionado con el resultado del trato.

Palos, Rangos y Cartas

Esta sección del modelo describe las tarjetas que usaremos en todos los juegos compatibles. Cada carta tiene un palo y un rango.

El suit_type table es un diccionario que contiene todos los tipos de palos que usaremos. Para suit_type_name , usaremos valores como "palos franceses", "palos alemanes", "palos suizo-alemanes" y "palos latinos".

El suit La tabla contiene los nombres de todos los palos contenidos en tipos de mazos específicos. Por ejemplo, la baraja francesa tiene palos llamados “Picas”, “Corazones”, “Diamantes” y “Tréboles”.

En el rank diccionario, encontraremos valores de cartas conocidos como “As”, “King”, “Queen” y “Jota”.

La card La tabla contiene una lista de todas las cartas posibles. Cada carta aparecerá en esta tabla solo una vez. Esa es la razón por la que suit_id y rank_id los atributos forman la clave alternativa de esta tabla. Los valores de ambos atributos pueden ser NULOS porque algunas cartas no tienen un palo o un rango (por ejemplo, cartas de comodín). La is_joker_card es un valor booleano que se explica por sí mismo. El card_name El atributo describe una carta con el texto:"As of Spades".

Cartas y Barajas

Las cartas pertenecen a los mazos. Debido a que una carta puede aparecer en varios mazos, necesitaremos un n:n relación entre la card y deck mesas.

En el deck tabla, almacenaremos los nombres de todos los mazos de cartas que queremos usar. Un ejemplo de valores almacenados en el deck_name Los atributos son:"Mazo estándar de 52 cartas (francés)" o "Mazo de 32 cartas (alemán)".

La card_in_deck La relación se utiliza para asignar cartas a los mazos apropiados. El card_iddeck_id par es la clave alternativa del deck mesa.

Propiedades de coincidencia, mazos y unidades utilizadas

Esta sección del modelo contiene algunos parámetros básicos para comenzar un nuevo juego.

La parte principal de esta sección es el game mesa. Esta tabla almacena datos sobre juegos compatibles con aplicaciones. El game_name El atributo contiene valores como "poker", "blackjack", "belot" y "préférence".

El min_number_of_players y max_number_of_players son el número mínimo y máximo de participantes en un partido. Estos atributos sirven como límites para el juego y se muestran en la pantalla al comienzo de un partido. La persona que inicia la coincidencia debe seleccionar un valor de este rango.

La min_entrance_fee y la max_entrance_fee atributos denota el rango de tarifa de entrada. Nuevamente, esto se basa en el juego que se está jugando.

En possible_victory_condition , almacenaremos todas las condiciones de victoria que podrían asignarse a un partido. Los valores están separados por un delimitador.

La unit El diccionario se utiliza para almacenar cada unidad utilizada en todos nuestros juegos. El unit_name El atributo albergará valores como "punto", "dólar", "euro" y "chip".

El game_deck y game_unit las tablas usan la misma lógica. Contienen listas de todos los mazos y unidades que se pueden usar en una partida. Por lo tanto, el game_iddeck_id par y el game_idunit_id par formar claves alternativas en sus respectivas tablas.

Puntuaciones

En nuestra aplicación, querremos almacenar las puntuaciones de todos los jugadores que participaron en nuestros juegos de cartas. Para cada juego, se calcula y almacena un único valor numérico. (El cálculo se basa en los resultados del jugador en todos los juegos de un solo tipo). La puntuación de este jugador es similar a un rango; permite a los usuarios saber aproximadamente qué tan bueno es un jugador.

Volvamos al proceso de cálculo. Crearemos un n:n relación entre el player y game mesas. Ese es el player_score mesa en nuestro modelo. El player_id y el score_id ” juntos forman la clave alternativa de la tabla. La “score El atributo se utiliza para almacenar el valor numérico mencionado anteriormente.

Hay variedad de juegos de cartas que utilizan reglas, cartas y barajas muy diferentes. Para crear una base de datos que almacene datos para más de un juego de cartas, necesitamos hacer algunas generalizaciones. Una forma de hacer esto es usando campos de texto descriptivos y dejando que la aplicación los interprete. Podríamos encontrar formas de cubrir las situaciones más comunes, pero eso complicaría exponencialmente el diseño de la base de datos.

Como se muestra en este artículo, puede usar una base de datos para muchos juegos. ¿Por qué harías esto? Tres razones:1) puede reutilizar la misma base de datos; 2) simplificaría el análisis; y esto conduciría a 3) la construcción de mejores oponentes de IA.