Add winner feature to games

This commit is contained in:
Jesse C. Fisher 2016-02-24 05:19:39 -08:00
parent c0d84b30ba
commit eb2c38c9d3
9 changed files with 154 additions and 2 deletions

View File

@ -7,6 +7,7 @@ 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

View File

@ -7,9 +7,11 @@ class Play < ActiveRecord::Base
validates :game, presence: true validates :game, presence: true
validates :player, presence: true validates :player, presence: true
validate :hand_valid? validate :hand_valid?
validate :player_has_control?
after_save :update_play_to_beat
after_save :check_for_winner after_save :check_for_winner
after_save :update_play_to_beat
after_save :set_controlling_player
def check_for_winner def check_for_winner
if self.game.over? if self.game.over?
@ -30,8 +32,22 @@ class Play < ActiveRecord::Base
end end
end end
def set_controlling_player
self.game.set_controlling_player 'next'
self.game.save
end
# Validation methods # 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? def hand_valid?
return false if self.hand_type == nil return false if self.hand_type == nil
# Gather the truths about the hand # Gather the truths about the hand

View File

@ -18,4 +18,17 @@ class Player < ActiveRecord::Base
self.try(:user).try(:email) || "Guest#{self.soft_token[0..5]}" self.try(:user).try(:email) || "Guest#{self.soft_token[0..5]}"
end 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 end

View File

@ -20,6 +20,10 @@ class User < ActiveRecord::Base
self.email || "Guest#{self.soft_token[0..5]}" self.email || "Guest#{self.soft_token[0..5]}"
end end
def sit_in(seat)
seat.sit self
end
def stand_from(table) def stand_from(table)
@seats = [] @seats = []
if self.id if self.id

View File

@ -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

View File

@ -11,14 +11,35 @@ RSpec.describe Game, type: :model do
it { should respond_to(:title) } it { should respond_to(:title) }
it { should respond_to(:play_to_beat) } it { should respond_to(:play_to_beat) }
it { should respond_to(:winner) }
it '#title returns a string' do it '#title returns a string' do
expect(@game.title).to match 'Test Game' expect(@game.title).to match 'Test Game'
end 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 'validations' do
describe 'player_count' 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 it 'is startable' do
@game.add_player_from_user(@user1) @game.add_player_from_user(@user1)
@game.add_player_from_user(@user2) @game.add_player_from_user(@user2)

View File

@ -3,3 +3,6 @@ require 'rails_helper'
RSpec.describe Player, type: :model do RSpec.describe Player, type: :model do
pending "add some examples to (or delete) #{__FILE__}" pending "add some examples to (or delete) #{__FILE__}"
end end
#TODO: Player can play_hand cards
#TODO: Player can not play_hand if not game.controlling_player

View File

@ -47,4 +47,6 @@ RSpec.configure do |config|
# The different available types are documented in the features, such as in # The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs # https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location! config.infer_spec_type_from_file_location!
config.include GameHelpers
end end

View File

@ -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 module Features
#DEPRECATED Features module. Use top level GameHelpers
module GameHelpers module GameHelpers
def setup_game def setup_game
# Default game has 4 players # Default game has 4 players
@ -47,6 +95,7 @@ module Features
end end
end end
# DEPRECATED Models module. Use top level GameHelpers
# TODO: DRY up this repetition # TODO: DRY up this repetition
module Models module Models
module GameHelpers module GameHelpers