Reputation: 392
I have two models:
A Game
that keeps track of the game state in a card game.
A Deck
that manages how cards are stored, shuffled, dealt, etc.
The Game
has many different Decks
that it has to keep track of at once. For example, two separate different draw decks and a discard deck.
I'm a little stumped on how I should define these relationships. Ideally, I would have Game.draw_type_a Game.draw_type_b and Game.discard that I could work with, and they would each point to a single Deck
. I've experimented with has_one :through
relationships and traditional one-to-one relationships with defined foreign_keys and classes, but I haven't been able to get this working.
I'd really like to keep all the decks as a single model, since there is so much overlap in how they behave. How should I define the relationships between the three types of deck in the Game
and the Deck
model. What should the migrations look like to implement them?
Upvotes: 0
Views: 66
Reputation: 6603
I've done something similar in my Adj game. This is what I would do:
class Game < ApplicationRecord
has_many :decks
has_one :discard_deck, -> { where(deck_type: :discard) }, foreign_key: :game_id, class_name: 'Deck'
has_one :draw_deck, -> { where(deck_type: :draw) }, foreign_key: :game_id, class_name: 'Deck'
# example attributes:
# is_finished:boolean(default: false)
def start
# populate the decks
draw_deck.create!
discard_deck.create!
# populate random cards to be a draw_deck
total_draw_deck_cards = 50
# pick 50 random cards. `RANDOM()` is for Postgresql; else check online
random_cards = Card.order('RANDOM()').limit(total_draw_deck_cards)
random_cards.each do |random_card|
draw_deck.deck_cards.create!(card: random_card)
end
end
def finish
update!(is_finished: true)
end
# `deck` can be any deck_type. Add conditions here if you must for each different deck_type
def draw_from(deck)
# or if you have multiple players:
# def draw_from(deck, player)
deck_card = deck.deck_cards.first
# then do something with this deck_card that you just drawed
# i.e. you might want to put this into a "Hand" (Player), so you'll need a separate PlayerCard model
# PlayerCard.create!(card: deck_card.card)
# or if you have multiple players:
# PlayerCard.create!(card: deck_card.card, player: player)
# then lastly remove this deck_card as you've already put it in your hand
deck_card.destroy
end
end
class Deck < ApplicationRecord
enum deck_type: { draw: 0, discard: 1 }
belongs_to :game
has_many :deck_cards, -> { order(created_at: :desc) }
has_many :cards, through: :deck_cards
# example attributes:
# deck_type:integer
end
class DeckCard < ApplicationRecord
belongs_to :deck
belongs_to :card
# example attributes:
# is_faced_down:boolean(default: true)
end
class Card < ApplicationRecord
enum card_type: { monster: 0, magic: 1, trap: 2 }
has_many :deck_cards
has_many :decks, through: :deck_cards
# example attributes:
# name:string
# image:string
# card_type:integer
end
Upvotes: 1
Reputation: 366
I would use a three table solution, namely: games, decks, game_decks(?).
Games has many game_decks. GameDecks have a game_id, deck_id, and deck_type (draw_type_a, draw_type_b, etc.), so it belongs to games and belongs to decks Decks has many GameDecks.
Additionally, Games has many Decks through GameDecks, and Decks has many Games through GameDecks.
This allows you to do things like game.decks
to retreive all game decks and game.decks.where(deck_type: :draw_type_a)
for all of the game's draw_type_a decks (this can be further refined with scopes).
As a side note, I would use a rails enum for the GameDecks.deck_type field.
Upvotes: 0