#sql #database #data-representation
#sql #База данных #представление данных
Вопрос:
Я работаю над приложением, которому необходимо сохранить колоду карт в базе данных. Я не уверен, какой наилучший способ представить это в базе данных.
Приложение предварительно раздаст колоду на 4 руки, в каждой из которых будет по 13 карт. После этого мне нужно сохранить раздачи и дополнительные данные, такие как распределение мастей и т.д…
Лучше ли создавать отдельную строку для каждой раздачи и связывать ее с колодой? Или, может быть, было бы лучше хранить их в одном ряду?
Также я не уверен, следует ли мне сохранять их в виде текста или числа. Вот пример:
Sorted by suit and separated by dot
AK.32.6543.AKQ98
Или
(52 = Largest rank or largest suit or 02 = 2 of smallest suit)
405251282717161514012322200908
Есть идеи?
PS: Есть причина хранить карты. Нам нужно проанализировать распределение рук, старшие очки карт и т.д…
Комментарии:
1. Определите «наилучший». Вы имеете в виду «наилучший способ сохранить комбинацию в наименьшем количестве байт» или «наилучший способ сохранить комбинацию так, чтобы она была легко читаема человеком»?
2. В конечном итоге приложение преобразует раздачи в понятные для человека, но что более важно, мне нужно иметь возможность сортировать и извлекать раздачи в зависимости от их свойств. Я не думаю, что количество байтов должно быть проблемой.
3. Почему необходимо хранить все перечисления раздач в базе данных? Почему бы не сгенерировать их по мере необходимости?
4. Это будет база данных для раздач в бридж. После создания их нужно будет извлекать для различных нужд
5. Нет ли c (52,7) (52 выбрать 7) возможных комбинаций? Кажется, что хранить нужно огромное количество раздач. Кажется, было бы лучше сгенерировать комбинацию, когда это необходимо.
Ответ №1:
Я думаю, самым естественным было бы создать таблицу для карт, в которой было бы по одной записи для каждой карты в колоде, а затем запись для раздач, в которой было бы по одной записи для каждой карты в раздаче. Если есть данные о раздаче в целом — имя игрока? где он сидит за столом? сколько у него фишек? неважно — тогда вам понадобится отдельная таблица для раздачи, в отличие от карт в раздаче. Я бы также создал таблицу поиска для мастей.
(Мы могли бы обсудить использование синтетических ключей по сравнению с естественными ключами здесь, но это другая тема.)
card (cardid, suitid, rank)
suit (suitid, suitname)
hand (handid, playername, whatever)
handcard (handcardid, handid, cardid)
Моим первым побуждением было бы присвоить «рангу» число от 1 до 13 и перевести 1 в «Туз», а 11-13 — в «Валет», «Дама» и «Король» во время вывода. Вы могли бы сохранить их в виде текста, но тогда было бы сложно сравнивать ранги, если в этом есть какая-то необходимость. т.Е. решить, легко ли для базы данных 13> 10; Король> 10, не так много.
Я определенно не стал бы пытаться втиснуть идентификацию нескольких карт в одно поле, разделенное точками, идентификаторами фиксированной длины или чем-то еще. Для этого вашей программе потребуется код, который разбирает это поле на части, чтобы получить нужные вам данные, вместо того, чтобы просто позволять базе данных извлекать нужные вам данные, для чего и существуют базы данных.
Я не знаю, что вы хотите делать с этими комбинациями карт, но большинство вещей, которые вы, вероятно, захотите сделать, довольно просты при структуре, подобной описываемой мной, и довольно сложны, если вы втиснете список карт в одно поле. Например, «У кого король пик?» Легко:
select playername
from hand
join handcard using (handid)
join card using (cardid)
join suit using (suitid)
where suit.name='Spades' and card.rank=13
Или: «Сколько лицевых карт у каждого игрока?»
select playername, count(*)
from hand
join handcard using (handid)
join card using (cardid)
where card.rank between 11 and 13
Конечно, «Какие карты у игрока № 3?» — это тоже просто:
select rank, suitname
from handcard
join card using (cardid)
join suit using (suitid)
where handid=3
Выполнение этих запросов в упакованном формате потребует сложных вызовов извлечения строк. А манипулирование строками — это всегда неприятности. Как вы всегда сталкиваетесь с проблемами, например, если я ищу 2 в тексте, как мне исключить 2, которые являются частью ’12’? и т.д.
Комментарии:
1. отличный ответ. Спасибо. Но я чувствую, что мне нужно прояснить некоторые моменты. Прежде всего, мне не нужно выбирать материал, подобный вашим примерам. (Хотя теперь я вижу новый потенциал) Все, что мне нужно выбрать, это либо всю комбинацию, либо только руку одного игрока. Я говорю это, потому что, возможно, это может изменить дизайн базы данных. Также сравнение рангов не должно быть проблемой (по крайней мере, большую часть времени).
2. Что вы подразумеваете под «выбрать… вся рука»? Что вы хотите сделать с данными? Если вкратце ответить, что все, что вы когда-либо хотели сделать, это отобразить содержимое руки игрока, то вам даже не нужна база данных: просто плоский файл с одной строкой на руку, каждая из которых состоит из содержимого руки в формате отображения, например «Туз пик, 3 бубны и пара лицевых карт». Но если вы действительно хотите каким-то образом с ней манипулировать, то, конечно, ответ изменится.
Ответ №2:
Это зависит от вида анализа, который вы хотите выполнить. На моем месте я бы, вероятно, по умолчанию использовал что-то вроде (игнорируя неосновные ограничения)
CREATE TABLE card (
card_id NUMBER PRIMARY KEY,
suit VARCHAR2(10) NOT NULL,
value VARCHAR2(1) NOT NULL
);
CREATE TABLE hand (
hand_id NUMBER PRIMARY KEY,
player_id NUMBER NOT NULL
);
CREATE TABLE hand_element (
hand_element_id NUMBER PRIMARY KEY,
hand_id NUMBER NOT NULL,
card_id NUMBER NOT NULL
);
В каждой HAND
было бы по 13 строк HAND_ELEMENT
. Я бы не стал утруждать себя сохранением информации о распределении мастей, я бы просто вычислил распределение рук, т.Е.
SELECT suit, count(*)
FROM hand JOIN hand_element USING (hand_id)
JOIN card USING (card_id)
WHERE hand_id = :some_hand_id
Ответ №3:
Я также работаю над аналогичным проектом для 3-карточного покера. Я настроил свой SQL следующим образом:
CREATE TABLE cards
(
id int AUTO_INCREMENT,
suite varchar(30) NOT NULL,
rank int NOT NULL,
dealt BOOLEAN DEFAULT false,
PRIMARY KEY (id)
);
Затем запустите команды для заполнения базы данных таким образом:
INSERT INTO cards (suite,rank) VALUES ('spades',1);
Таким образом, вы можете выполнять цикл по базе данных и изменять значение ‘true’ по мере раздачи карт. Также упрощает сравнение рангов.