diff --git a/app/models/game.rb b/app/models/game.rb index 9627ab88..46b78378 100644 --- a/app/models/game.rb +++ b/app/models/game.rb @@ -7,6 +7,7 @@ class Game < ActiveRecord::Base has_many :player_cards, through: :players has_many :plays, through: :players has_one :controlling_player + has_one :winner, :class_name => "Player", :primary_key => "winner_player_id" belongs_to :play_to_beat accepts_nested_attributes_for :players #validates :title, presence: true diff --git a/app/models/play.rb b/app/models/play.rb index eab57c10..512f86ae 100644 --- a/app/models/play.rb +++ b/app/models/play.rb @@ -7,9 +7,11 @@ class Play < ActiveRecord::Base validates :game, presence: true validates :player, presence: true validate :hand_valid? + validate :player_has_control? - after_save :update_play_to_beat after_save :check_for_winner + after_save :update_play_to_beat + after_save :set_controlling_player def check_for_winner if self.game.over? @@ -30,8 +32,22 @@ class Play < ActiveRecord::Base end end + def set_controlling_player + self.game.set_controlling_player 'next' + self.game.save + end + # Validation methods + def player_has_control? + if self.player == self.game.controlling_player + return true + else + errors.add(:player, "it's not your turn") + return false + end + end + def hand_valid? return false if self.hand_type == nil # Gather the truths about the hand diff --git a/app/models/player.rb b/app/models/player.rb index 9485a338..f6621ef1 100644 --- a/app/models/player.rb +++ b/app/models/player.rb @@ -18,4 +18,17 @@ class Player < ActiveRecord::Base self.try(:user).try(:email) || "Guest#{self.soft_token[0..5]}" end + def play_hand(cards) + self.plays.create(game_id: self.game.id, player_cards: cards) + end + + def pass + #TODO: Create a Play instead of modifying the controlling player directly + # Then you won't need this return/fail validation + return false unless self.game.controlling_player == self + + self.game.set_controlling_player 'next' + self.game.save + end + end diff --git a/app/models/user.rb b/app/models/user.rb index 1fb78bd1..02db516d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -20,6 +20,10 @@ class User < ActiveRecord::Base self.email || "Guest#{self.soft_token[0..5]}" end + def sit_in(seat) + seat.sit self + end + def stand_from(table) @seats = [] if self.id diff --git a/spec/features/end_of_games_spec.rb b/spec/features/end_of_games_spec.rb new file mode 100644 index 00000000..44c47894 --- /dev/null +++ b/spec/features/end_of_games_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +RSpec.feature "EndOfGames", type: :feature, js: true do + # Given I am in a started game + before do + @game = setup_game + @game.reload + @player = @game.controlling_player + signin(@player.user.email,'password') + visit table_path @game.table + end + # And it is my turn + # And I play my last cards + # Then I win the game + scenario 'I win the game' do + + # Play lowest card + # Other players always pass + # Play next lowest card + # Repeat until out of cards + @player.inventory.each do |card| + find_card(card).click + click_button "Play Hand" + sleep 1 + visit current_url + @game.reload + @game.controlling_player_id = @player.id + @game.save + @game.reload + sleep 1 + visit current_url + end + + # Play my last card(s) + # Expect that I am the winner + expect(@game.winner).to eq @player + end + + describe 'I lose the game' do + # Another player plays their last card(s) + # Expect that they are the winner + end +end diff --git a/spec/models/game_spec.rb b/spec/models/game_spec.rb index 6cc44011..4bc3ef45 100644 --- a/spec/models/game_spec.rb +++ b/spec/models/game_spec.rb @@ -11,14 +11,35 @@ RSpec.describe Game, type: :model do it { should respond_to(:title) } it { should respond_to(:play_to_beat) } + it { should respond_to(:winner) } it '#title returns a string' do expect(@game.title).to match 'Test Game' end + it 'has a winner' do + # Start the game + @player1 = @user1.sit_in(@game.seats.first) + @player2 = @user2.sit_in(@game.seats.last) + @game.start + + # controlling player plays all their cards + @player = @game.controlling_player + @player.inventory.each do |card| + @player.play_hand [card] + @game.reload + while (@game.controlling_player != @player) do + @game.controlling_player.pass + @game.reload + end + end + + expect(@game.winner).to eq @player + end + describe 'validations' do describe 'player_count' do - context 'when there are between 2 and 4 players' do + context 'when there are 2 to 4 players' do it 'is startable' do @game.add_player_from_user(@user1) @game.add_player_from_user(@user2) diff --git a/spec/models/player_spec.rb b/spec/models/player_spec.rb index 9aa96a29..63272423 100644 --- a/spec/models/player_spec.rb +++ b/spec/models/player_spec.rb @@ -3,3 +3,6 @@ require 'rails_helper' RSpec.describe Player, type: :model do pending "add some examples to (or delete) #{__FILE__}" end + +#TODO: Player can play_hand cards +#TODO: Player can not play_hand if not game.controlling_player diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d93c9ee7..3389b8b1 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -47,4 +47,6 @@ RSpec.configure do |config| # The different available types are documented in the features, such as in # https://relishapp.com/rspec/rspec-rails/docs config.infer_spec_type_from_file_location! + + config.include GameHelpers end diff --git a/spec/support/helpers/game_helpers.rb b/spec/support/helpers/game_helpers.rb index a4d47122..0f94f400 100644 --- a/spec/support/helpers/game_helpers.rb +++ b/spec/support/helpers/game_helpers.rb @@ -1,4 +1,52 @@ +module GameHelpers + def setup_game + # Default game has 4 players + game = FactoryGirl.create :game + user1 = FactoryGirl.create :user + user2 = FactoryGirl.create :user + user3 = FactoryGirl.create :user + user4 = FactoryGirl.create :user + game.seats[0].sit user1 + game.seats[1].sit user2 + game.seats[2].sit user3 + game.seats[3].sit user4 + game.start + return game + end + + def setup_visitor_game + # Default game has 3 players + game = FactoryGirl.create :game + + u = FactoryGirl.build :user + game.seats[0].sit u + + u = FactoryGirl.build :user + game.seats[1].sit u + + u = FactoryGirl.build :user + game.seats[2].sit u + + return game + end + + def find_card card + find("[data-card-name='#{card.to_s}'] ~ img") + end + + def cards_to_beat + @cards = find("#cards-to-beat") + if @cards + @cards = @cards.find_all('img') + end + @array = [] + @cards.map {|c| @array << c[:alt]} + return @array.join " " + end +end + module Features + #DEPRECATED Features module. Use top level GameHelpers module GameHelpers def setup_game # Default game has 4 players @@ -47,6 +95,7 @@ module Features end end +# DEPRECATED Models module. Use top level GameHelpers # TODO: DRY up this repetition module Models module GameHelpers