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