179 lines
4.3 KiB
Ruby
179 lines
4.3 KiB
Ruby
# The game class
|
|
class Game < ActiveRecord::Base
|
|
belongs_to :table
|
|
has_many :seats
|
|
has_many :players, dependent: :destroy
|
|
has_many :users, through: :players
|
|
has_many :player_cards, through: :players
|
|
has_many :plays, through: :players
|
|
belongs_to :play_to_beat
|
|
accepts_nested_attributes_for :players
|
|
#validates :title, presence: true
|
|
after_create :add_table
|
|
|
|
# Returns the newest joinable game or creates a new game if none are found
|
|
scope :play_now, lambda { |user|
|
|
where(status:nil).joins("LEFT OUTER JOIN players ON players.game_id = games.id").group("games.id").having("count(players) < 4").last || Game.create(title: "Game " + user.soft_token[0..4])
|
|
}
|
|
|
|
def start
|
|
validate_startable
|
|
return false unless startable?
|
|
|
|
# Start the game
|
|
self.status = 'Game Started'
|
|
|
|
# Create a deck
|
|
d = Deck.new
|
|
# Shuffle the deck
|
|
d.cards.shuffle!
|
|
# Deal the cards
|
|
players.each do |player|
|
|
13.times do
|
|
card = d.cards.shift
|
|
player.player_cards.new(card.instance_values)
|
|
end
|
|
player.save
|
|
end
|
|
|
|
# Set status to first turn
|
|
# Player with the lowest card
|
|
self.status = 'First Play at: ' + self.lowest_card.player.display_name
|
|
self.controlling_player_id = self.lowest_card.player.id
|
|
save
|
|
end
|
|
|
|
def winner
|
|
self.players.find_by_id(self.winner_player_id)
|
|
end
|
|
|
|
def validate_startable
|
|
@player_count = players.count
|
|
errors[:players] = 'Must be at least 2 players.' if @player_count < 2
|
|
errors[:players] = 'Must be less than 5 players.' if @player_count > 4
|
|
errors[:status] = 'Game already started...' if self.status.nil? == false
|
|
errors[:player_cards] = 'Cards already dealt...' unless player_cards.empty?
|
|
fail StandardError, errors if errors.count > 0
|
|
return true
|
|
end
|
|
|
|
def current_hand
|
|
return nil
|
|
end
|
|
|
|
def startable?
|
|
begin
|
|
self.validate_startable
|
|
rescue
|
|
return false
|
|
end
|
|
end
|
|
|
|
def lowest_card
|
|
self.player_cards.order(:value).first
|
|
end
|
|
|
|
def add_player_from_user(user)
|
|
return false unless self.joinable?(user)
|
|
new_player = self.players.create(user: user, soft_token: user.soft_token)
|
|
end
|
|
|
|
def remove_player_from_user(user)
|
|
return false unless self.has_user? user
|
|
|
|
if self.players.exists?(user_id: user.id)
|
|
@player = self.players.find_by(user_id: user.id)
|
|
elsif self.players.exists?(soft_token: user.soft_token)
|
|
@player = self.players.find_by(soft_token: user.soft_token)
|
|
end
|
|
|
|
if @player
|
|
@player.user_id = nil
|
|
end
|
|
|
|
end
|
|
|
|
def can_accomodate(user)
|
|
!(already_has?(user) || full?)
|
|
end
|
|
|
|
#TODO: Which has_user? method is better? Probably has_user?.
|
|
def already_has?(user)
|
|
self.players.pluck(:user_id, :soft_token).flatten.compact.to_set.intersect? ([user.id, user.soft_token].to_set)
|
|
end
|
|
|
|
def has_user? user
|
|
if user.id
|
|
return true if self.players.exists?(user_id: user.id)
|
|
end
|
|
if user.soft_token
|
|
return true if self.players.exists?(soft_token: user.soft_token)
|
|
end
|
|
return false
|
|
end
|
|
|
|
|
|
def full?
|
|
players.count >= 4
|
|
end
|
|
|
|
def set_controlling_player(arg)
|
|
case arg
|
|
when 'next'
|
|
self.controlling_player_id = self.next_player_id
|
|
end
|
|
end
|
|
|
|
def joinable? user
|
|
!self.has_user?(user) && !self.full?
|
|
end
|
|
|
|
def player_ids_by_seat_order
|
|
player_ids = self.seats.order(:position).select {|s| s.player_id}.map {|s| s.player_id}
|
|
end
|
|
|
|
def next_player_id
|
|
@controlling_player_index = self.player_ids_by_seat_order.index(controlling_player_id)
|
|
player_ids_by_seat_order[(@controlling_player_index + 1) % self.player_ids.length]
|
|
end
|
|
|
|
# The player whose turn it is
|
|
def controlling_player
|
|
if self.controlling_player_id
|
|
self.players.find_by_id(self.controlling_player_id)
|
|
end
|
|
end
|
|
|
|
# The user whose turn it is
|
|
def controlling_user
|
|
self.players.find(self.controlling_player_id).user
|
|
end
|
|
|
|
def hand_to_beat
|
|
self.play_to_beat.try(:play).try(:hand)
|
|
end
|
|
|
|
def player_to_beat
|
|
self.play_to_beat.try(:play).try(:player)
|
|
end
|
|
|
|
def started?
|
|
!self.status.nil?
|
|
end
|
|
|
|
def over?
|
|
return false unless self.started?
|
|
@inventory_counts = self.players.map {|p| p.player_cards.count > 0 ? p.inventory.count : nil}
|
|
@inventory_counts.include? 0
|
|
end
|
|
|
|
private
|
|
|
|
def add_table
|
|
self.table ||= Table.create current_game_id: self.id
|
|
self.seats = self.table.seats
|
|
self.save
|
|
end
|
|
|
|
end
|