133 lines
4.1 KiB
Ruby
133 lines
4.1 KiB
Ruby
class Play < ActiveRecord::Base
|
|
belongs_to :game, foreign_key: 'game_id'
|
|
belongs_to :player, foreign_key: 'player_id'
|
|
has_many :player_cards, foreign_key: 'play_id'
|
|
|
|
validates :game, presence: true
|
|
validates :player, presence: true
|
|
validate :hand_valid?
|
|
|
|
after_save :update_play_to_beat
|
|
|
|
def update_play_to_beat
|
|
if hand_valid?
|
|
@pb = PlayToBeat.new
|
|
@pb.game = self.game
|
|
@pb.play = self
|
|
@pb.save
|
|
end
|
|
end
|
|
|
|
# Validation methods
|
|
|
|
def hand_valid?
|
|
if has_player_cards
|
|
first_play?
|
|
# Open table / first play / no play to beat OR hand type matches OR play is back to the original active player
|
|
self.game.play_to_beat == nil || self.hand_type == self.game.play_to_beat.play.hand_type || self.player == self.game.play_to_beat.player
|
|
end
|
|
end
|
|
|
|
# TODO: Recognize all valid hand types
|
|
def hand_type
|
|
case self.player_cards.length
|
|
when 1
|
|
@hand_type = 'single'
|
|
when 2
|
|
@hand_type = 'pair'
|
|
if (self.player_cards[0].rank != self.player_cards[1].rank)
|
|
errors.add(:player_cards, "Invalid pair. Rank must match.")
|
|
end
|
|
when 3
|
|
@hand_type = 'triple'
|
|
@ranks = Array.new << self.player_cards.map {|pc| pc.rank}
|
|
@ranks.flatten!
|
|
@suits = Array.new << self.player_cards.map {|pc| pc.suit}
|
|
@suits.flatten!
|
|
# TODO: Does not work for face cards :(
|
|
if (@ranks[0].to_i + 1 == @ranks[1].to_i) && (@ranks[1].to_i + 1 == @ranks[2].to_i)
|
|
@hand_type += ' run'
|
|
# Check if suited
|
|
if (@suits.uniq.length == 1)
|
|
@hand_type += ' suited'
|
|
end
|
|
elsif @ranks.uniq.length != 1
|
|
errors.add(:player_cards, "Invalid triple. Rank must match.")
|
|
end
|
|
when 4
|
|
@ranks = Array.new << self.player_cards.map {|pc| pc.rank}
|
|
@ranks.flatten!
|
|
@suits = Array.new << self.player_cards.map {|pc| pc.suit}
|
|
@suits.flatten!
|
|
|
|
if (@ranks.uniq.length == 1)
|
|
@hand_type = 'bomb'
|
|
end
|
|
|
|
# TODO: Does not work for face cards :(
|
|
if (@ranks[0].to_i + 1 == @ranks[1].to_i) && (@ranks[1].to_i + 1 == @ranks[2].to_i) & (@ranks[2].to_i + 1 == @ranks[3].to_i)
|
|
@hand_type = 'run of 4'
|
|
end
|
|
|
|
if (@suits.uniq.length == 1)
|
|
@hand_type += ' suited'
|
|
end
|
|
when 5..13
|
|
@hand_type = "run of #{self.player_cards.length}"
|
|
|
|
@ranks = Array.new << self.player_cards.map {|pc| pc.rank}
|
|
@ranks.flatten!
|
|
@suits = Array.new << self.player_cards.map {|pc| pc.suit}
|
|
@suits.flatten!
|
|
|
|
# double? && length?
|
|
if (@ranks.uniq.length == (@ranks.length/2)) && ([6,8,10].include? @ranks.length)
|
|
@hand_type = "double " + @hand_type
|
|
# run?
|
|
# iterate over each unique rank; except for the last rank
|
|
@ranks.uniq.sort[0...-1].each.with_index do |rank, i|
|
|
# each rank one away from each other?
|
|
if (rank.to_i + 1) == @ranks.uniq.sort[i+1].to_i
|
|
else
|
|
@hand_type = "Invalid " + @hand_type
|
|
errors.add(:player_cards, "Invalid double run of #{@ranks.length}")
|
|
end
|
|
end
|
|
else
|
|
# normal run?
|
|
# For each card except for the last card
|
|
@ranks.sort[0...-1].each_with_index do |r, i|
|
|
# If cards are not a single run
|
|
if (r.to_i + 1) != @ranks[i+1].to_i
|
|
# And if cards are not a double run
|
|
errors.add(:player_cards, "Invalid run of #{@ranks.length}")
|
|
end
|
|
end
|
|
end
|
|
|
|
# Check if suited
|
|
if (@suits.uniq.length == 1)
|
|
@hand_type += ' suited'
|
|
end
|
|
|
|
else
|
|
errors.add(:player_cards, "Unrecognized hand type.")
|
|
end
|
|
return @hand_type
|
|
end
|
|
|
|
def first_play?
|
|
# First play of the game
|
|
if self.game.plays.empty? || ( self.game.plays.length == 1 && self.game.plays.first == self )
|
|
# Cards being played must include the lowest card
|
|
if (self.player_cards.include? self.game.lowest_card) == false
|
|
errors.add(:player_cards, "First hand must contain the lowest card: #{game.lowest_card.to_s}")
|
|
end
|
|
end
|
|
end
|
|
|
|
def has_player_cards
|
|
true unless self.player_cards.empty?
|
|
end
|
|
end
|