Add game winner feature

This commit is contained in:
Jesse C. Fisher 2016-02-28 03:25:27 -08:00
parent eb2c38c9d3
commit ab12e96879
6 changed files with 92 additions and 54 deletions

View File

@ -7,7 +7,6 @@ class Game < ActiveRecord::Base
has_many :player_cards, through: :players has_many :player_cards, through: :players
has_many :plays, through: :players has_many :plays, through: :players
has_one :controlling_player has_one :controlling_player
has_one :winner, :class_name => "Player", :primary_key => "winner_player_id"
belongs_to :play_to_beat belongs_to :play_to_beat
accepts_nested_attributes_for :players accepts_nested_attributes_for :players
#validates :title, presence: true #validates :title, presence: true
@ -45,6 +44,14 @@ class Game < ActiveRecord::Base
save save
end end
def winner
begin
self.players.find(self.winner_player_id)
rescue
nil
end
end
def validate_startable def validate_startable
@player_count = players.count @player_count = players.count
errors[:players] = 'Must be at least 2 players.' if @player_count < 2 errors[:players] = 'Must be at least 2 players.' if @player_count < 2
@ -159,10 +166,7 @@ class Game < ActiveRecord::Base
def over? def over?
return false unless self.started? return false unless self.started?
@inventory_counts = [] @inventory_counts = self.players.map {|p| p.player_cards.count > 0 ? player.inventory.count : nil}
self.players.each do |player|
@inventory_counts << player.inventory.count
end
@inventory_counts.include? 0 @inventory_counts.include? 0
end end

View File

@ -205,7 +205,7 @@ class Play < ActiveRecord::Base
def contains_lowest_card? def contains_lowest_card?
# Cards being played must include the lowest card # Cards being played must include the lowest card
if (self.player_cards.include? self.game.lowest_card) == false if (self.player_cards.first.value != self.game.lowest_card.value)
errors.add(:player_cards, "First hand must contain the lowest card: #{game.lowest_card.to_s}") errors.add(:player_cards, "First hand must contain the lowest card: #{game.lowest_card.to_s}")
return false return false
else else

View File

@ -33,7 +33,7 @@ class User < ActiveRecord::Base
@seats << table.seats.where(user_soft_token: self.soft_token) @seats << table.seats.where(user_soft_token: self.soft_token)
end end
@seats.flatten.each do |seat| @seats.flatten.each do |seat|
seat.player.destroy seat.try(:player).try(:destroy)
seat.user_id = nil seat.user_id = nil
seat.player_id = nil seat.player_id = nil
seat.user_soft_token = nil seat.user_soft_token = nil

View File

@ -2,7 +2,7 @@ require 'rails_helper'
RSpec.feature "EndOfGames", type: :feature, js: true do RSpec.feature "EndOfGames", type: :feature, js: true do
# Given I am in a started game # Given I am in a started game
before do before(:each) do
@game = setup_game @game = setup_game
@game.reload @game.reload
@player = @game.controlling_player @player = @game.controlling_player
@ -13,26 +13,36 @@ RSpec.feature "EndOfGames", type: :feature, js: true do
# And I play my last cards # And I play my last cards
# Then I win the game # Then I win the game
scenario 'I win the game' do scenario 'I win the game' do
# Play lowest card # Play lowest card
# Other players always pass # Other players always pass
# Play next lowest card # Play next lowest card
# Repeat until out of cards # Repeat until out of cards
@player.inventory.each do |card| while (@player.inventory.count > 0) do
card = @player.inventory.first
find_card(card).click find_card(card).click
# Try to click the Play Hand button
# If this fails, reload the page
begin
click_button "Play Hand" click_button "Play Hand"
sleep 1
visit current_url visit current_url
@game.reload @game.reload
@game.controlling_player_id = @player.id rescue
@game.save
@game.reload @game.reload
sleep 1
visit current_url visit current_url
end end
# Play my last card(s) if @game.controlling_player_id != @player.id
# Simulate other players passing
@game.controlling_player_id = @player.id
@game.save
@game.reload
end
end
# After I play my last card(s)
# Expect that I am the winner # Expect that I am the winner
@game.reload
expect(@game.winner).to eq @player expect(@game.winner).to eq @player
end end

View File

@ -1,20 +1,7 @@
RSpec.describe Play, type: :model do RSpec.describe Play, type: :model do
before(:all) do before(:each) do
@game = setup_game @game = setup_game
@play = @game.controlling_player.plays.new @play = @game.controlling_player.plays.new(game_id: @game.id)
@play.game_id = @game.id
@play.save
end
after(:each) do
#reset game
@game.reload
@game.play_to_beat_id = nil
# reset play
@play.reload
@play.errors[:player_cards].clear
@play.game = @game
end end
subject { @play } subject { @play }
@ -71,17 +58,22 @@ RSpec.describe Play, type: :model do
describe 'wins?' do describe 'wins?' do
context 'it does not beat the hand_to_beat' do context 'it does not beat the hand_to_beat' do
it 'single' do it 'single' do
# TODO: Refactor "lowest card first" to FactoryGirl.create :game, hand_to_beat: @cards
# First hand must contain lowest card
@cards_to_play = @play.player.player_cards.order(:value).first
@play.player_cards = [@cards_to_play]
@play.save
@game.reload
# Play a high single card # Play a high single card
@play = @game.controlling_player.plays.new(game_id: @game.id)
@cards_to_play = @play.player.player_cards.order(:value).last @cards_to_play = @play.player.player_cards.order(:value).last
@play.reload @play.player_cards = [@cards_to_play]
@play.player_cards << @cards_to_play
@play.save @play.save
@game.reload @game.reload
# Try to play a losing card # Try to play a losing card
@losing_play = Play.new @losing_play = @game.controlling_player.plays.new(game_id: @game.id)
@losing_play.player = @game.players.where.not(id: @game.controlling_player_id).last
@losing_play.game = @game
@losing_play.player_cards << @losing_play.player.player_cards.order(:value).first @losing_play.player_cards << @losing_play.player.player_cards.order(:value).first
expect(@losing_play.beats? @play).to eq(false) expect(@losing_play.beats? @play).to eq(false)
expect(@losing_play.hand_valid?).to eq(false) expect(@losing_play.hand_valid?).to eq(false)
@ -92,6 +84,12 @@ RSpec.describe Play, type: :model do
end end
it 'double' do it 'double' do
# First hand must contain low card
@cards_to_play = @play.player.player_cards.order(:value).first
@play.player_cards = [@cards_to_play]
@play.save
@game.reload
@deck = Deck.new @deck = Deck.new
@cards_to_beat = [ @cards_to_beat = [
@spade5 = PlayerCard.new(@deck.cards[8].instance_values), @spade5 = PlayerCard.new(@deck.cards[8].instance_values),
@ -116,9 +114,7 @@ RSpec.describe Play, type: :model do
expect(play.player_cards.length).to eq(2) expect(play.player_cards.length).to eq(2)
end end
@play.reload
@game.reload @game.reload
binding.pry unless !@play.valid?
expect(@play.valid?).to eq(false) expect(@play.valid?).to eq(false)
expect(@play.beats? @play_to_beat).to eq(false) expect(@play.beats? @play_to_beat).to eq(false)
@ -144,9 +140,7 @@ RSpec.describe Play, type: :model do
@spade5 = PlayerCard.new(@deck.cards[8].instance_values) @spade5 = PlayerCard.new(@deck.cards[8].instance_values)
] ]
@play.reload
@game.reload @game.reload
binding.pry unless !@play.valid?
expect(@play.valid?).to eq(false) expect(@play.valid?).to eq(false)
@ -161,6 +155,7 @@ RSpec.describe Play, type: :model do
@play.save @play.save
@game.reload @game.reload
@play = @game.controlling_player.plays.new(game_id: @game.id)
# next player plays their lowest card and beats the previous play # next player plays their lowest card and beats the previous play
@cards_to_play = @play.player.player_cards.order(:value).first @cards_to_play = @play.player.player_cards.order(:value).first
@play.player_cards << @cards_to_play @play.player_cards << @cards_to_play
@ -183,7 +178,8 @@ RSpec.describe Play, type: :model do
@club3 @club3
] ]
@play.player_cards << @cards_to_beat @play = @game.controlling_player.plays.new(game_id: @game.id)
@play.player_cards = @cards_to_beat
expect(@play.save).to be true expect(@play.save).to be true
@game.reload @game.reload
@game.controlling_player_id = @game.next_player_id @game.controlling_player_id = @game.next_player_id
@ -288,16 +284,26 @@ RSpec.describe Play, type: :model do
context 'when four cards are played' do context 'when four cards are played' do
it 'valid bomb against a 2' do it 'valid bomb against a 2' do
# TODO: Refactor "lowest card first" to FactoryGirl.create :game, hand_to_beat: @cards
# First hand must contain lowest card
@spade3 = @game.lowest_card
first_play = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: [@spade3])
first_play.save
@game.reload
# Setup play to beat
@heart2 = PlayerCard.new(rank: '2', suit: 'Heart', value: 52, player_id: @game.next_player_id) @heart2 = PlayerCard.new(rank: '2', suit: 'Heart', value: 52, player_id: @game.next_player_id)
@play_to_beat = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: [@heart2]) @play_to_beat = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: [@heart2])
@play_to_beat.save @play_to_beat.save
@game.play_to_beat_id = @play_to_beat.id @game.reload
@spade3 = PlayerCard.new(value: 1, rank: "3", suit: "Spade") @spade3 = PlayerCard.new(value: 1, rank: "3", suit: "Spade")
@club3 = PlayerCard.new(value: 2, rank: "3", suit: "Club") @club3 = PlayerCard.new(value: 2, rank: "3", suit: "Club")
@diamond3 = PlayerCard.new(value: 3, rank: "3", suit: "Diamond") @diamond3 = PlayerCard.new(value: 3, rank: "3", suit: "Diamond")
@heart3 = PlayerCard.new(value: 4, rank: "3", suit: "Heart") @heart3 = PlayerCard.new(value: 4, rank: "3", suit: "Heart")
@cards_to_play = [@spade3, @club3, @diamond3, @heart3] @cards_to_play = [@spade3, @club3, @diamond3, @heart3]
@play.player_cards << @cards_to_play @play = @game.controlling_player.plays.new(game_id: @game.id)
@play.player_cards = @cards_to_play
expect(@play.hand_type).to eq('bomb') expect(@play.hand_type).to eq('bomb')
expect(@play.valid?).to eq(true) expect(@play.valid?).to eq(true)
end end
@ -311,6 +317,7 @@ RSpec.describe Play, type: :model do
@play_to_beat = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: @cards_to_beat) @play_to_beat = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: @cards_to_beat)
@play_to_beat.save @play_to_beat.save
@game.play_to_beat_id = @play_to_beat.id @game.play_to_beat_id = @play_to_beat.id
@game.reload
# Setup the play # Setup the play
@spade4 = PlayerCard.new(rank: "4", suit: "Spade", value: 5) @spade4 = PlayerCard.new(rank: "4", suit: "Spade", value: 5)
@ -318,6 +325,7 @@ RSpec.describe Play, type: :model do
@diamond4 = PlayerCard.new(rank: "4", suit: "Diamond", value: 7) @diamond4 = PlayerCard.new(rank: "4", suit: "Diamond", value: 7)
@heart4 = PlayerCard.new(rank: "4", suit: "Heart", value: 8) @heart4 = PlayerCard.new(rank: "4", suit: "Heart", value: 8)
@cards_to_play = [@spade4, @club4, @diamond4, @heart4] @cards_to_play = [@spade4, @club4, @diamond4, @heart4]
@play = @game.controlling_player.plays.new(game_id: @game.id)
@play.player_cards = @cards_to_play @play.player_cards = @cards_to_play
expect(@play.hand_type).to eq('bomb') expect(@play.hand_type).to eq('bomb')
@ -326,16 +334,27 @@ RSpec.describe Play, type: :model do
end end
it 'invalid bomb against a greater bomb' do it 'invalid bomb against a greater bomb' do
# Play lowest card first
@spade3 = @game.lowest_card
first_play = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: [@spade3])
first_play.save
@game.reload
# Create an Open Table, so every hand is valid.
@game.controlling_player_id = first_play.player_id
@game.save
#@game.reload
#
# Setup the play to beat # Setup the play to beat
@spade4 = PlayerCard.new(rank: "4", suit: "Spade", value: 5) @spade4 = PlayerCard.new(rank: "4", suit: "Spade", value: 5)
@club4 = PlayerCard.new(rank: "4", suit: "Club", value: 6) @club4 = PlayerCard.new(rank: "4", suit: "Club", value: 6)
@diamond4 = PlayerCard.new(rank: "4", suit: "Diamond", value: 7) @diamond4 = PlayerCard.new(rank: "4", suit: "Diamond", value: 7)
@heart4 = PlayerCard.new(rank: "4", suit: "Heart", value: 8) @heart4 = PlayerCard.new(rank: "4", suit: "Heart", value: 8)
@cards_to_beat = [@spade4, @club4, @diamond4, @heart4] @cards_to_beat = [@spade4, @club4, @diamond4, @heart4]
@play_to_beat = Play.new(game_id: @game.id, player_id: @game.next_player_id, player_cards: @cards_to_beat) @play_to_beat = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: @cards_to_beat)
@play_to_beat.save expect(@play_to_beat.save).to eq true
@game.play_to_beat_id = @play_to_beat.id @game.reload
@play.reload
# Setup the play # Setup the play
@spade3 = PlayerCard.new(rank: "3", suit: "Spade", value: 1) @spade3 = PlayerCard.new(rank: "3", suit: "Spade", value: 1)
@ -343,9 +362,13 @@ RSpec.describe Play, type: :model do
@diamond3 = PlayerCard.new(rank: "3", suit: "Diamond", value: 3) @diamond3 = PlayerCard.new(rank: "3", suit: "Diamond", value: 3)
@heart3 = PlayerCard.new(rank: "3", suit: "Heart", value: 4) @heart3 = PlayerCard.new(rank: "3", suit: "Heart", value: 4)
@cards_to_play = [@spade3, @club3, @diamond3, @heart3] @cards_to_play = [@spade3, @club3, @diamond3, @heart3]
@play.player_cards = @cards_to_play @play = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: @cards_to_beat)
expect(@play.hand_type).to eq('bomb') expect(@play.hand_type).to eq('bomb')
#TODO: Refactor this test to only test the @play.beats? method
#TODO: Move other expectations to another test
#TODO: Test every validation of a play
#TODO: Refactor @play.valid? method
expect(@play.beats? @play_to_beat).to eq(false) expect(@play.beats? @play_to_beat).to eq(false)
expect(@play.valid?).to eq(false) expect(@play.valid?).to eq(false)
end end

View File

@ -11,5 +11,6 @@ if ENV['RAILS_ENV'] == 'staging'
Capybara.app_host = asset_hosts[ENV['RAILS_ENV'].to_sym] Capybara.app_host = asset_hosts[ENV['RAILS_ENV'].to_sym]
end end
Capybara.asset_host = asset_hosts[ENV['RAILS_ENV'].to_sym] Capybara.asset_host = asset_hosts[ENV['RAILS_ENV'].to_sym]
#Capybara.asset_host = 'http://localhost:3000'
Capybara.javascript_driver = :poltergeist # :selenium Capybara.javascript_driver = :poltergeist
#Capybara.javascript_driver = :selenium