online card gameを作ろうとしているのですが、題の通りdatabaseの設計で悩んでいます。
課題
例えば太郎
,花子
という二人のclientと虎
.狼
,羊
という三種類のcardがあったとして、二人が各cardを何枚もっているか以下のように管理したとします。
python
1import sqlite3 2from textwrap import dedent as dd 3from contextlib import closing 4 5 6with closing(sqlite3.connect(':memory:')) as conn: 7 cur = conn.cursor() 8 cur.executescript(dd(''' 9 CREATE TABLE card ( 10 id TEXT, 11 name TEXT, 12 PRIMARY KEY (id) 13 ); 14 CREATE TABLE user ( 15 name TEXT, 16 cards_owned TEXT, 17 PRIMARY KEY (name) 18 ); 19 INSERT INTO card VALUES ('tiger', '虎'); 20 INSERT INTO card VALUES ('wolf', '狼'); 21 INSERT INTO card VALUES ('sheep', '羊'); 22 INSERT INTO user VALUES ('太郎', 'tiger 0, wolf 2, sheep 1'); 23 INSERT INTO user VALUES ('花子', 'tiger 3, wolf 1, sheep 1'); 24 ''')) 25 for name, cards_owned in cur.execute('SELECT * FROM user'): 26 print(f"{name}の所持カード") 27 for v in cards_owned.split(', '): 28 card_id, n = v.split() 29 for card_name, in conn.cursor().execute(f'SELECT name FROM card WHERE id = "{card_id}"'): 30 print(f"{card_name}: {n}枚")
# 標準出力 太郎の所持カード 虎: 0枚 狼: 2枚 羊: 1枚 花子の所持カード 虎: 3枚 狼: 1枚 羊: 1枚
この設計は良いとは思いません。理由はtiger 0, wolf 2, sheep 1
を自力でparseしているからです。せっかくdatabaseを使っているのにこのような事を自分でするのは無駄に思えます。後このような文字列にFOREIGN KEY
を持たせる方法があるのかどうかも分かりません。
なので代わりに思いついたのが以下のようにclientの数だけ所持card用のtableを作る方法なのですが
python
1import sqlite3 2from textwrap import dedent as dd 3from contextlib import closing 4 5 6with closing(sqlite3.connect(':memory:')) as conn: 7 cur = conn.cursor() 8 cur.executescript(dd(''' 9 CREATE TABLE card ( 10 id TEXT, 11 name TEXT, 12 PRIMARY KEY (id) 13 ); 14 CREATE TABLE user ( 15 name TEXT, 16 PRIMARY KEY (name) 17 ); 18 INSERT INTO card VALUES ('tiger', '虎'); 19 INSERT INTO card VALUES ('wolf', '狼'); 20 INSERT INTO card VALUES ('sheep', '羊'); 21 INSERT INTO user VALUES ('太郎'); 22 INSERT INTO user VALUES ('花子'); 23 24 CREATE TABLE 太郎の所持card ( 25 card_id TEXT, 26 n INT, 27 FOREIGN KEY (card_id) REFERENCES card(id) 28 ); 29 INSERT INTO 太郎の所持card VALUES ('tiger', 3); 30 INSERT INTO 太郎の所持card VALUES ('wolf', 2); 31 INSERT INTO 太郎の所持card VALUES ('sheep', 1); 32 CREATE TABLE 花子の所持card ( 33 card_id TEXT, 34 n INT, 35 FOREIGN KEY (card_id) REFERENCES card(id) 36 ); 37 INSERT INTO 花子の所持card VALUES ('tiger', 0); 38 INSERT INTO 花子の所持card VALUES ('wolf', 3); 39 INSERT INTO 花子の所持card VALUES ('sheep', 2); 40 ''')) 41 for name, in cur.execute('SELECT * FROM user'): 42 print(f"{name}の所持カード") 43 for card_id, n in conn.cursor().execute(f'SELECT * FROM {name}の所持card'): 44 for card_name, in conn.cursor().execute(f'SELECT name FROM card WHERE id = "{card_id}"'): 45 print(f"{card_name}: {n}枚")
このような設計がそもそも良いのかどうかが分かりません。何かより良い方法を知っている方 教えていただけたら嬉しいですm(_ _)m。
環境
- Python: 3.7.1
- OS: LinuxMint 18.2 (Ubuntu 16.04 LTS派生)
追記
cardのPRIMARY KEY
を序数にする事で一つ目のコードの'tiger 0, wolf 2, sheep 1'
は021
に置き換える事ができました。こちらの方が一つ目の物より優れていると思うので追記します。
python
1import sqlite3 2from textwrap import dedent as dd 3from contextlib import closing 4 5 6with closing(sqlite3.connect(':memory:')) as conn: 7 cur = conn.cursor() 8 cur.executescript(dd(''' 9 CREATE TABLE card ( 10 id INTEGER, 11 name TEXT, 12 PRIMARY KEY (id) 13 ); 14 CREATE TABLE user ( 15 name TEXT, 16 cards_owned TEXT, 17 PRIMARY KEY (name) 18 ); 19 INSERT INTO card (name) VALUES ('虎'); 20 INSERT INTO card (name) VALUES ('狼'); 21 INSERT INTO card (name) VALUES ('羊'); 22 INSERT INTO user VALUES ('太郎', '021'); 23 INSERT INTO user VALUES ('花子', '311'); 24 ''')) 25 for row in cur.execute('SELECT * FROM card'): 26 print(row) 27 for name, cards_owned in cur.execute('SELECT * FROM user'): 28 print(f"{name}の所持カード") 29 for id, name in conn.cursor().execute('SELECT * FROM card'): 30 print(f"{name}: {cards_owned[id - 1]}枚")
(1, '虎') (2, '狼') (3, '羊') 太郎の所持カード 虎: 0枚 狼: 2枚 羊: 1枚 花子の所持カード 虎: 3枚 狼: 1枚 羊: 1枚
追記2
説明が不十分な気がするので追記します。私が作ろうとしているのは対戦型のcard gameで、あらかじめ各playerがデッキを組んでから対戦します。私が使っている所持カード
という言葉はデッキを組む際の元となる物であって、対戦中に変動することはありません。ゲーム内の店でカードを買うなどした時に初めて変動する類の物です。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/09/05 15:06
2019/09/05 15:15
2019/09/05 15:38 編集
2019/09/05 17:27
2019/09/06 01:28
2019/09/06 14:43
2019/09/06 15:01
2019/09/06 15:24
2019/09/06 20:50
2019/09/07 01:50