From 3d46e5b80600d3bcfe786d0ea51a42e95894bdf7 Mon Sep 17 00:00:00 2001 From: "Jesse C. Fisher" Date: Wed, 17 Nov 2021 07:56:39 -0800 Subject: [PATCH] Add seat management fix new game button --- app/controllers/seats_controller.rb | 14 ++++++++- app/controllers/tables_controller.rb | 17 +++++++++-- app/models/game.rb | 24 ++++++++------- app/models/seat.rb | 30 +++++++++++++++++++ app/views/tables/_seat.html.haml | 11 +++++-- app/views/tables/show.html.haml | 3 ++ config/environments/development.rb | 1 + config/routes.rb | 3 ++ spec/features/bots/add_bot_players_spec.rb | 1 + spec/features/bots/bot_play_spec.rb | 35 ++++++++++++++++++++++ spec/features/end_of_games_spec.rb | 20 +++++++++---- spec/features/plays_spec.rb | 7 +++-- spec/features/seats/seats_sit_spec.rb | 20 +++++++------ spec/features/tables/table_join_spec.rb | 14 +++++---- spec/features/visitors/navigation_spec.rb | 6 ++-- spec/rails_helper.rb | 1 + 16 files changed, 161 insertions(+), 46 deletions(-) create mode 100644 spec/features/bots/bot_play_spec.rb diff --git a/app/controllers/seats_controller.rb b/app/controllers/seats_controller.rb index 13805d2a..4c546e02 100644 --- a/app/controllers/seats_controller.rb +++ b/app/controllers/seats_controller.rb @@ -1,5 +1,7 @@ class SeatsController < ApplicationController - before_action :set_seat, only: [:show, :edit, :update, :destroy, :sit, :stand, :add_bot, :remove_bot] + before_action :set_seat, only: [:show, :edit, :update, :destroy, + :sit, :stand, :add_bot, :remove_bot, :empty, + :remove_player] respond_to :html, :json @@ -90,6 +92,16 @@ class SeatsController < ApplicationController redirect_to @seat.table, notice: @message end + def empty + @message = @seat.empty + redirect_to @seat.table, notice: @message + end + + def remove_player + @message = @seat.remove_player + redirect_to @seat.table, notice: @message + end + private # Use callbacks to share common setup or constraints between actions. def set_seat diff --git a/app/controllers/tables_controller.rb b/app/controllers/tables_controller.rb index 38d4552c..c211529e 100644 --- a/app/controllers/tables_controller.rb +++ b/app/controllers/tables_controller.rb @@ -30,9 +30,16 @@ class TablesController < ApplicationController # GET /tables/1 # GET /tables/1.json def show - # TODO move this to the game.rb model - # Clear play to beat if play returns to owner # TODO refactor to ensure play for 2nd and 3rd place + + if @game.controlling_player.try("is_bot?") + flash[:notice] = "Bot is passes" + @game.controlling_player.pass + @game.save + @game.reload + end + + # Clear play to beat if play returns to owner if @game.play_to_beat.try(:player).try(:id) == @game.controlling_player_id @game.play_to_beat_id = nil @game.save @@ -41,7 +48,11 @@ class TablesController < ApplicationController def new_game @game = @table.add_game - @game.start + begin + @game.start + rescue + flash[:errors] = @game.errors + end redirect_to @table end diff --git a/app/models/game.rb b/app/models/game.rb index c956ad35..b92db62d 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 belongs_to :play_to_beat + belongs_to :controlling_player, class_name: "Player", foreign_key: "controlling_player_id" accepts_nested_attributes_for :players #validates :title, presence: true after_create :add_table @@ -79,6 +80,12 @@ class Game < ActiveRecord::Base new_player = self.players.create(user: user, soft_token: user.soft_token) end + def add_player_bot + # todo return if game is full + # return false unless self.joinable?(user) + new_player = self.players.create(is_bot: true) + end + def remove_player_from_user(user) return false unless self.has_user? user @@ -116,7 +123,7 @@ class Game < ActiveRecord::Base def full? - players.count >= 4 + # players.count >= 4 end def set_controlling_player(arg) @@ -132,7 +139,8 @@ class Game < ActiveRecord::Base end def joinable? user - !self.has_user?(user) && !self.full? + # !self.has_user?(user) && !self.full? + !self.full? end def player_ids_by_seat_order @@ -146,13 +154,6 @@ class Game < ActiveRecord::Base player_ids_by_seat_order[(@controlling_player_index + 1) % self.player_ids_by_seat_order.length] end - # The player whose turn it is - def controlling_player - if self.controlling_player_id - self.players.find_by_id(self.controlling_player_id) - end - end - # The user whose turn it is def controlling_user self.players.find(self.controlling_player_id).user @@ -182,8 +183,9 @@ private self.table ||= Table.create current_game_id: self.id self.seats = self.table.seats self.seats.each do |seat| - if (seat.user_id || seat.user_soft_token) - new_player = self.players.create(user_id: seat.user_id, soft_token: seat.user_soft_token) + # if (seat.user_id || seat.user_soft_token) + if (seat.occupied?) + new_player = self.players.create(user_id: seat.user_id, soft_token: seat.user_soft_token, is_bot: seat.player.is_bot) seat.player = new_player seat.save end diff --git a/app/models/seat.rb b/app/models/seat.rb index 461f5e11..8b9f23bf 100644 --- a/app/models/seat.rb +++ b/app/models/seat.rb @@ -51,10 +51,15 @@ class Seat < ActiveRecord::Base if self.player == nil # add player to game @bot_player = self.table.current_game.players.new(is_bot: true) + # @bot_player = self.table.current_game.add_player_from_user(current_user).id self.player = @bot_player self.player.save self.save return "Added Bot" + else + self.player.is_bot = true + self.player.save + return "Added Bot" end return "Failed to add Bot" @@ -75,6 +80,31 @@ class Seat < ActiveRecord::Base end end + def empty + self.player.user = nil + self.player.soft_token = nil + self.player.is_bot = false + self.player.save + self.user_id = nil + self.user_soft_token = nil + # self.player_id = nil + self.save + return "Successfully stood up." + end + + def remove_player + if !self.player + return "No player to remove" + else + self.player.destroy + self.user_id = nil + self.user_soft_token = nil + # self.player_id = nil + self.save + return "Successfully removed player" + end + end + def occupied? self.user_id.present? || self.user_soft_token.present? || self.try("player").try("is_bot?") == true end diff --git a/app/views/tables/_seat.html.haml b/app/views/tables/_seat.html.haml index ee618daa..c0851498 100644 --- a/app/views/tables/_seat.html.haml +++ b/app/views/tables/_seat.html.haml @@ -3,18 +3,23 @@ .seat-controls - if seat.occupied? - if seat.player.is_bot? - = button_to remove_bot_seat_path(seat) do + -# = button_to remove_bot_seat_path(seat) do - "- Bot" - if seat.occupied_by? current_user = button_to stand_seat_path(seat), :data => { :confirm => 'Are you sure you want to leave this seat?' } do - - "Stand" + - "Leave" + - else + = button_to empty_seat_path(seat), :data => { :confirm => 'Are you sure you want to empty this seat?' } do + - "Empty" - else = button_to sit_seat_path(seat) do - "Sit" = button_to add_bot_seat_path(seat) do - "+ Bot" - + - if seat.player + = button_to remove_player_seat_path(seat), :data => { :confirm => 'Are you sure you want to remove this player?' } do + - "Remove Player" .player{id: "player-#{seat.player.id}", class: @game.controlling_player == seat.player ? "taking-turn" : "", data: {soft_token: seat.player.soft_token} } .user-name= seat.player.display_name diff --git a/app/views/tables/show.html.haml b/app/views/tables/show.html.haml index a4f3db9f..816db2c4 100644 --- a/app/views/tables/show.html.haml +++ b/app/views/tables/show.html.haml @@ -15,6 +15,9 @@ - if @game.winner_player_id || @game.nil? = button_to 'New Game', new_game_table_path(@table) + -# - if @game && !@game.startable? + = button_to 'New Game', new_game_table_path(@table) + #game-component - if @game.winner_player_id %h1= @game.status diff --git a/config/environments/development.rb b/config/environments/development.rb index e6d41c22..b1f597fb 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -54,4 +54,5 @@ Rails.application.configure do # Add Rack::LiveReload to the bottom of the middleware stack with the default options. config.middleware.insert_after ActionDispatch::Static, Rack::LiveReload + BetterErrors::Middleware.allow_ip! '10.0.0.0/16' end diff --git a/config/routes.rb b/config/routes.rb index fc11115c..6ff0abde 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,6 +3,7 @@ Rails.application.routes.draw do resources :tables do member do post 'new_game' + post 'end_game' end resources :seats do member do @@ -23,6 +24,8 @@ Rails.application.routes.draw do post 'stand' post 'add_bot' post 'remove_bot' + post 'empty' + post 'remove_player' end end diff --git a/spec/features/bots/add_bot_players_spec.rb b/spec/features/bots/add_bot_players_spec.rb index 70d5c8da..37890e0c 100644 --- a/spec/features/bots/add_bot_players_spec.rb +++ b/spec/features/bots/add_bot_players_spec.rb @@ -14,6 +14,7 @@ feature 'Add bot', type: :feature do scenario 'visitor can add a bot if the seat is empty' do @button = page.find_button('+ Bot', match: :first).click expect(page).to have_content "BotPlayer" + end scenario 'visitor can not add a bot if the seat is occupied by bot' do diff --git a/spec/features/bots/bot_play_spec.rb b/spec/features/bots/bot_play_spec.rb new file mode 100644 index 00000000..d518e81d --- /dev/null +++ b/spec/features/bots/bot_play_spec.rb @@ -0,0 +1,35 @@ +# Feature: Bot takes turns +# As a player +# I want bots to take turns +# So I can play against the computer +feature 'Bot takes turn', type: :feature do + before(:each) do + @table = FactoryGirl.create :table + @game = @table.current_game + visit table_path @table + end + + scenario 'bot player passes' do + @button = page.find_button('+ Bot', match: :first).click + expect(page).to have_content "BotPlayer" + @button = page.find_button('Sit', match: :first).click + click_button "Start" + click_button 'Pass' + expect(page).to have_content "Bot is passes" + end + + scenario 'bot player plays single' do + @button = page.find_button('+ Bot', match: :first).click + expect(page).to have_content "BotPlayer" + @button = page.find_button('Sit', match: :first).click + click_button "Start" + @game = @table.current_game + if @game.controlling_player.soft_token == page.current_user.soft_token + @card_to_play = @game.controlling_player.inventory.first + find("[data-card-name='#{@card_to_play.to_s}']").click + click_button 'Play Hand' + end + expect(@game.play_to_beat.player.is_bot?).to eq true + expect(@game.play_to_beat.hand_type).to eq "single" + end +end diff --git a/spec/features/end_of_games_spec.rb b/spec/features/end_of_games_spec.rb index 9d9681bb..ac1adb94 100644 --- a/spec/features/end_of_games_spec.rb +++ b/spec/features/end_of_games_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' RSpec.feature "EndOfGames", type: :feature do # Given I am in a started game - before(:each) do + before(:all) do # If test is unable to click correct card, use wider window # page.driver.browser.manage.window.resize_to(1640, 1090) @game = setup_game @@ -10,11 +10,7 @@ RSpec.feature "EndOfGames", type: :feature do @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 @@ -41,11 +37,23 @@ RSpec.feature "EndOfGames", type: :feature do @game.reload end end + end + # And it is my turn + # And I play my last cards + # Then I win the game + scenario 'I win the game' do # After I play my last card(s) # Expect that I am the winner @game.reload expect(@game.winner).to eq @player + click_button "New Game" + expect(page).to have_content "Game started" + end + + scenario 'I start a new game at the same table' do + click_button "New Game" + expect(page).to have_content "Game started" end describe 'I lose the game' do diff --git a/spec/features/plays_spec.rb b/spec/features/plays_spec.rb index 76f0e151..1a9d205a 100644 --- a/spec/features/plays_spec.rb +++ b/spec/features/plays_spec.rb @@ -168,11 +168,12 @@ feature 'Play a hand', type: :feature do # Given I am the active player # When I pass # Then I see an successful pass message - scenario 'active player can pass', js: true do + # scenario 'active player can pass', js: true do + scenario 'active player can pass' do @current_user = @game.controlling_player - accept_confirm do + # accept_confirm do click_button 'Pass' - end + # end # click_button "pass_hand_button_#{@player.id}" ## TODO: Flash messages expect(page).to have_content 'Successfully passed.' diff --git a/spec/features/seats/seats_sit_spec.rb b/spec/features/seats/seats_sit_spec.rb index a4f4ba06..9ee0760c 100644 --- a/spec/features/seats/seats_sit_spec.rb +++ b/spec/features/seats/seats_sit_spec.rb @@ -28,7 +28,7 @@ feature 'Seats', :devise do @button = page.find_button('Sit', match: :first) @button.click expect(page).to have_content "Guest" - @buttons = page.find_all('button', text: 'Stand') + @buttons = page.find_all('button', text: 'Leave') expect(@buttons.length).to eq 1 end @@ -62,13 +62,14 @@ feature 'Seats', :devise do find_all(:button, "Sit") end - scenario 'visitor can leave the current game', js: true do + # scenario 'visitor can leave the current game', js: true do + scenario 'seated visitor can leave the current game' do click_button 'Sit', match: :first expect(page).to have_content 'Guest' expect(page.text.scan('Guest').count).to eq 1 - accept_confirm do - click_button 'Stand', match: :first - end + # accept_confirm do + click_button 'Leave', match: :first + # end expect(page.find('.seat.position-1')).to have_content 'Sit' expect(sit_buttons.length).to eq 4 expect(page.text.scan('Guest').count).to eq 0 @@ -95,13 +96,14 @@ feature 'Seats', :devise do expect(page.text.scan(@user.email).count).to eq 1 end - scenario 'user can leave the current game', js: true do + # scenario 'user can leave the current game', js: true do + scenario 'user can leave the current game' do click_button 'Sit', match: :first expect(page).to have_content @user.email expect(page.text.scan(@user.email).count).to eq 1 - accept_confirm do - click_button 'Stand', match: :first - end + # accept_confirm do + click_button 'Leave', match: :first + # end expect(page.text.scan(@user.email).count).to eq 0 end diff --git a/spec/features/tables/table_join_spec.rb b/spec/features/tables/table_join_spec.rb index 6661621c..394e8592 100644 --- a/spec/features/tables/table_join_spec.rb +++ b/spec/features/tables/table_join_spec.rb @@ -21,13 +21,14 @@ feature 'Table show', :devise do expect(page.text.scan('Guest').count).to eq 1 end - scenario 'visitor can leave the current game', js: true do + # scenario 'visitor can leave the current game', js: true do + scenario 'visitor can leave the current game' do click_button 'Sit', match: :first expect(page).to have_content "Guest" expect(page.text.scan('Guest').count).to eq 1 - accept_confirm do + # accept_confirm do click_button 'Stand', match: :first - end + # end expect(page.find('.seat.position-1')).to have_content "Sit" expect(page.text.scan('Guest').count).to eq 0 end @@ -56,14 +57,15 @@ feature 'Table show', :devise do expect(page.text.scan(@user.email).count).to eq 1 end - scenario 'user can leave the current game', js: true do + # scenario 'user can leave the current game', js: true do + scenario 'user can leave the current game' do expect(page).to have_content "Sit" click_button 'Sit', match: :first expect(page).to have_content @user.email expect(page.text.scan(@user.email).count).to eq 1 - accept_confirm do + # accept_confirm do click_button 'Stand', match: :first - end + # end expect(page.find('.seat.position-1')).to have_content "Sit" expect(page.text.scan(@user.email).count).to eq 0 end diff --git a/spec/features/visitors/navigation_spec.rb b/spec/features/visitors/navigation_spec.rb index 03ebfc1a..95858b9a 100644 --- a/spec/features/visitors/navigation_spec.rb +++ b/spec/features/visitors/navigation_spec.rb @@ -17,7 +17,8 @@ feature 'Navigation links', :devise do # Given I am a visitor # When I click a navigation link # Then I see the proper web page - scenario 'follow navigation links', js: :true do + # scenario 'follow navigation links', js: :true do + scenario 'follow navigation links' do visit root_path @links = { 'Play Now': '"/tables/1"', @@ -26,9 +27,6 @@ feature 'Navigation links', :devise do } @links.each do |link| click_link link[0] - #TODO: Remove race condition - sleep 4 - page.save_screenshot expect(page.current_path).to eq(eval(link[1])) visit root_path end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 3d61e4d1..2d0fceba 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -4,6 +4,7 @@ require 'spec_helper' require File.expand_path('../../config/environment', __FILE__) require 'rspec/rails' # Add additional requires below this line. Rails is not loaded until this point! +`trash tmp/capybara/*` require 'capybara-screenshot/rspec' # Requires supporting ruby files with custom matchers and macros, etc, in