From 2c678b1a9d84a6ab13dc864f0c655c1a38df13bd Mon Sep 17 00:00:00 2001 From: "Jesse C. Fisher" Date: Mon, 17 Aug 2015 13:40:20 -0700 Subject: [PATCH] Play hand validations --- app/controllers/games_controller.rb | 17 +++- app/models/game.rb | 4 + app/models/play.rb | 36 ++++--- spec/models/play_spec.rb | 134 ++++++++++++++++++++------- spec/support/helpers/play_helpers.rb | 4 + 5 files changed, 148 insertions(+), 47 deletions(-) diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb index 3476d71..3173571 100644 --- a/app/controllers/games_controller.rb +++ b/app/controllers/games_controller.rb @@ -23,13 +23,20 @@ class GamesController < ApplicationController def play_hand # TODO: validate player's turn, current_user == @game.current_player.user # TODO: move this logic out of controller maybe to model(s) - @cards_to_play = @game.current_player.player_cards.find(params[:player_card_ids]) + + # If cards are played + if params[:player_card_ids] + @cards_to_play = @game.current_player.player_cards.order(:value).find(params[:player_card_ids]) + else + # No cards are played + @cards_to_play = [] + end # Instantiate the play @play = @game.current_player.plays.new @play.game_id = @game.id - @play.save @play.player_cards << @cards_to_play + @play.save #@cards_to_play.each do |card| #@play.player_cards << card @@ -41,12 +48,12 @@ class GamesController < ApplicationController @game.save else # If play is invalid, remove the cards from the play - @play.player_cards.map {|card| card.play_id = nil; card.save} + #@play.player_cards.map {|card| card.play_id = nil; card.save} # Delete play - @play.destroy + #@play.destroy end - @play.save + #@play.save @play.errors.messages.each do |key, msg| flash[key] = msg.join end diff --git a/app/models/game.rb b/app/models/game.rb index ed51e19..465823a 100644 --- a/app/models/game.rb +++ b/app/models/game.rb @@ -111,4 +111,8 @@ class Game < ActiveRecord::Base def hand_to_beat self.play_to_beat.play.hand end + + def player_to_beat + self.play_to_beat.play.player unless self.play_to_beat.play.nil? + end end diff --git a/app/models/play.rb b/app/models/play.rb index 99f436f..0eb6332 100644 --- a/app/models/play.rb +++ b/app/models/play.rb @@ -26,6 +26,16 @@ class Play < ActiveRecord::Base def hand_valid? @truths = [] + # Is there a hand_to_beat ? + if self.game.play_to_beat + # current player is not the player to beat + if (self.game.player_to_beat != self.player) + @truths << (self.hand_type == self.game.play_to_beat.play.hand_type) + # Compare this hand to the hand_to_beat, + @truths << (self.beats? self.game.play_to_beat.play) + end + end + if has_player_cards @truths << !hand_type.empty? @@ -34,27 +44,26 @@ class Play < ActiveRecord::Base @truths << contains_lowest_card? end - # Is there a hand_to_beat ? - if self.game.play_to_beat - # current player is not the player to beat - if (self.game.play_to_beat.try('play').player != self.player) - @truths << (self.hand_type == self.game.play_to_beat.hand_type) - # Compare this hand to the hand_to_beat, - @truths << (self.beats? self.game.play_to_beat) - end - end + end + if @truths.include? false + errors.add(:player_cards, "invalid hand") end return (!@truths.include? false) end # Check if the value of this hand is higher than the hand_to_beat def beats?(play_to_beat) - @truth = self.high_card.value > play_to_beat.high_card.value + @truth = self.high_card_value > play_to_beat.high_card_value return @truth end def high_card - self.hand.order(:value).last + self.hand.last unless self.hand.empty? + end + + def high_card_value + return self.hand.last.value unless self.hand.empty? + 0 end # TODO: Recognize face cards @@ -167,4 +176,9 @@ class Play < ActiveRecord::Base def has_player_cards true unless self.player_cards.empty? end + + def to_s + player_cards.join ' ' + end + end diff --git a/spec/models/play_spec.rb b/spec/models/play_spec.rb index b22c750..f632062 100644 --- a/spec/models/play_spec.rb +++ b/spec/models/play_spec.rb @@ -1,5 +1,3 @@ -require 'rails_helper' - RSpec.describe Play, type: :model do before(:each) do @game = FactoryGirl.create(:game) @@ -17,32 +15,107 @@ RSpec.describe Play, type: :model do subject { @play } it { should respond_to(:game_id) } + it { should respond_to(:game) } + it { should respond_to(:player_id) } + it { should respond_to(:player) } it { should respond_to(:player_cards) } + it { should respond_to(:hand) } it { should respond_to(:hand_type) } + it { should respond_to(:to_s) } - it '#game_id returns an integer' do - expect(@play.game_id).to match @game.id + it '#game_id returns a game id' do + expect(@play.game).to eq Game.find(@play.game_id) + end + + it '#player_id return a player id' do + expect(@play.player).to eq Player.find(@play.player_id) + + end + it '#player_cards returns a PlayerCard collection' do + expect(@play.player_cards.class).to eq(PlayerCard::ActiveRecord_Associations_CollectionProxy) + end + + it '#hand returns a PlayerCard collection' do + expect(@play.hand.class).to eq(PlayerCard::ActiveRecord_Associations_CollectionProxy) + end + + it '#hand_type returns a string' do + @play.player_cards << create_hand(1, 'single') + expect(@play.hand_type).to eq 'single' + end + + it '#to_s returns a string of the hand' do + @play.player_cards << create_hand(1, 'single') + expect(@play.to_s).to eq '3 Spade' end describe 'validations' do describe 'first_play' do - context 'when there have been no plays yet' do - it 'valid if it contains the lowest card' do - # expect(@game.plays.count).to eq(1) - # Active player is the lowest card holder - expect(@game.current_player).to eq(@game.lowest_card.player) - # Play the lowest card - @cards_to_play = @game.current_player.player_cards.order(:value).first - @play.player_cards << @cards_to_play - @play.save - expect(@play.player_cards.include? @game.lowest_card).to eq true - #expect(@game.play_to_beat.play).to eq subject - expect(subject.valid?).to eq(true) - end + it 'valid if it contains the lowest card' do + # expect(@game.plays.count).to eq(1) + # Active player is the lowest card holder + expect(@game.current_player).to eq(@game.lowest_card.player) + # Play the lowest card + @cards_to_play = @game.current_player.player_cards.order(:value).first + @play.player_cards << @cards_to_play + @play.save + expect(@play.player_cards.include? @game.lowest_card).to eq true + expect(subject.valid?).to eq(true) end end describe 'wins?' do - context 'valid if it beats the hand_to_beat' do + context 'it does not beat the hand_to_beat' do + it 'single' do + @play_to_beat = Play.new + @play_to_beat.player = @game.players.where.not(id: @game.active_player.id).last + @play_to_beat.game = @game + @play_to_beat.player_cards << @play_to_beat.player.player_cards.order(:value).last + @play_to_beat.save + @play.game.reload + + expect(@play.game.play_to_beat.play).to eq(@play_to_beat) + # Losing card + @cards_to_play = @play.player.player_cards.order(:value).first + @play.player_cards << @cards_to_play + @play.save + expect(@game.player_to_beat).to_not eq(@play.player) + expect(@play.hand_valid?).to eq(false) + expect(@play.errors[:player_cards].include?('invalid hand')).to eq(true) + end + + it 'double' do + @deck = Deck.new + @cards_to_beat = [ + @spade5 = PlayerCard.new(@deck.cards[8].instance_values), + @club5 = PlayerCard.new(@deck.cards[9].instance_values) + ] + + @play_to_beat = Play.new + @play_to_beat.player = @game.players.first + @play_to_beat.player_cards << @cards_to_beat + @play_to_beat.game = @game + @play_to_beat.save + + @play.player_cards = [ + @spade4 = PlayerCard.new(@deck.cards[4].instance_values), + @club4 = PlayerCard.new(@deck.cards[5].instance_values) + ] + + # Shared tests + [@play_to_beat,@play].each do |play| + expect(play.errors[:player_cards]).to eq([]) + expect(play.valid?).to eq(true) + expect(play.player_cards.count).to eq(2) + expect(play.hand_type).to eq('double') + end + + expect(@play.beats? @play_to_beat).to eq(false) + + end + + + end + context 'it beats the hand_to_beat' do it 'single' do @play_to_beat = Play.new @play_to_beat.player = @game.players.last @@ -79,7 +152,6 @@ RSpec.describe Play, type: :model do [@play_to_beat,@play].each do |play| expect(play.errors[:player_cards]).to eq([]) expect(play.valid?).to eq(true) - puts play expect(play.player_cards.count).to eq(2) expect(play.hand_type).to eq('double') end @@ -87,20 +159,19 @@ RSpec.describe Play, type: :model do expect(@play.beats? @play_to_beat).to eq(true) end + + it 'becomes the new play_to_beat' do + expect(@game.play_to_beat).to eq(nil) + # Play the hand + @cards_to_play = @game.current_player.inventory[0] + @play.hand << @cards_to_play + @play.save + expect(@play.hand_valid?).to eq(true) + @game.reload + expect(@game.play_to_beat.play).to eq(@play) + end end end - - it 'becomes the new play_to_beat' do - expect(@game.play_to_beat).to eq(nil) - # Play the hand - @cards_to_play = @game.current_player.inventory[0] - @play.hand << @cards_to_play - @play.save - expect(@play.hand_valid?).to eq(true) - @game.reload - expect(@game.play_to_beat.play).to eq(@play) - end - end describe 'hand_type' do @@ -254,4 +325,5 @@ RSpec.describe Play, type: :model do end end end + end diff --git a/spec/support/helpers/play_helpers.rb b/spec/support/helpers/play_helpers.rb index 636f6a3..0c34550 100644 --- a/spec/support/helpers/play_helpers.rb +++ b/spec/support/helpers/play_helpers.rb @@ -7,6 +7,9 @@ module Models end case type + when /single/ + cards[0].rank = Card::RANKS[0] + cards[0].suit = Card::SUITS[0] when /run/ cards.each.with_index(3) do |c, i| @@ -26,6 +29,7 @@ module Models end end + return cards end end end