diff --git a/app/controllers/pieces_controller.rb b/app/controllers/pieces_controller.rb index cd1aba7..708727f 100644 --- a/app/controllers/pieces_controller.rb +++ b/app/controllers/pieces_controller.rb @@ -23,6 +23,12 @@ def valid_moves render json: selected_piece.valid_moves end + def promote + render(text: 'Piece is not promotable', status: :forbidden) && return unless selected_piece.promotable? + selected_piece.promote_to!(params[:type]) + redirect_to current_game + end + private def authorize_player diff --git a/app/models/chess_piece.rb b/app/models/chess_piece.rb index f242b73..100ae14 100644 --- a/app/models/chess_piece.rb +++ b/app/models/chess_piece.rb @@ -77,6 +77,10 @@ def load_potential_moves potential_moves end + def promotable? + false + end + private def move_for(coordinates) diff --git a/app/models/pawn.rb b/app/models/pawn.rb index 8769bc8..12609ad 100644 --- a/app/models/pawn.rb +++ b/app/models/pawn.rb @@ -16,11 +16,25 @@ def move_to!(coordinates) two_step_move = diff_in_y(coordinates.y) == FIRST_MOVE_FACTOR capture_en_passant(coordinates) if game.can_en_passant?(coordinates) super - game.update(en_passant_position: "#{coordinates.x},#{backward_one(coordinates.y)}") if two_step_move + update_en_passant(coordinates) if two_step_move + game.update_current_player!(opposite_color) if promotable? + end + + def promotable? + position_y == 8 || position_y == 1 + end + + def promote_to!(type) + update(type: type) + game.update_current_player!(color) end private + def update_en_passant(coordinates) + game.update(en_passant_position: "#{coordinates.x},#{backward_one(coordinates.y)}") + end + def capture_en_passant(coordinates) game.chess_pieces.find_by( position_x: coordinates.x, diff --git a/config/routes.rb b/config/routes.rb index b09c8f7..9ab89c2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,10 @@ devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' } root 'static_pages#index' resources :pieces, only: [:show, :update] do - get 'valid_moves', on: :member + member do + get 'valid_moves' + put 'promote' + end end resources :users, only: [:show, :update] do get '/username', to: 'users#username' diff --git a/spec/controllers/pieces_controller_spec.rb b/spec/controllers/pieces_controller_spec.rb index 5a142a3..acbdf14 100644 --- a/spec/controllers/pieces_controller_spec.rb +++ b/spec/controllers/pieces_controller_spec.rb @@ -1,16 +1,15 @@ require 'rails_helper' RSpec.describe PiecesController, type: :controller do - describe 'GET pieces#show' do - before do - @black_player = create(:user) - @game = create(:game, black_player: @black_player) - end + let(:white_player) { create(:user) } + let(:black_player) { create(:user) } + let(:game) { create(:game, white_player: white_player, black_player: black_player) } + describe 'GET pieces#show' do it 'responds successfully with an HTTP 200 status code' do - sign_in @black_player - @game.update_current_player!('white') - piece_id = @game.chess_pieces.find_by(position_x: 1, position_y: 7) + sign_in black_player + game.update_current_player!('white') + piece_id = game.chess_pieces.find_by(position_x: 1, position_y: 7) get :show, id: piece_id expect(response).to be_success @@ -18,7 +17,7 @@ end it 'redirects to login if not signed in' do - piece_id = @game.chess_pieces.first.id + piece_id = game.chess_pieces.first.id get :show, id: piece_id expect(response).to redirect_to new_user_session_path @@ -26,9 +25,6 @@ end describe 'PUT pieces#update' do - let(:white_player) { create(:user) } - let(:game) { create(:game, white_player: white_player) } - it 'responds successfully with an HTTP 302 status code' do sign_in white_player piece_id = game.chess_pieces.find_by(position_x: 1, position_y: 2).id @@ -65,8 +61,6 @@ end describe 'GET pieces#valid_moves' do - let(:game) { create(:game) } - it 'returns valid moves for the piece' do pawn = create(:game).chess_pieces.find_by(position_x: 1, position_y: 2) sign_in pawn.game.white_player @@ -86,4 +80,17 @@ expect(response).to have_http_status(:forbidden) end end + + describe 'PUT pieces#promote' do + it 'promotes the pawn to the specified piece' do + sign_in white_player + pawn = create(:pawn, position_x: 1, position_y: 8, color: :white, game: game) + game.current_player_is_white_player! + + put :promote, id: pawn, type: 'Queen' + + expect(Queen.find(pawn.id)).to be_a Queen + expect(game.reload.current_player_is_black_player?).to eq true + end + end end diff --git a/spec/models/pawn_spec.rb b/spec/models/pawn_spec.rb index 98420d3..a9d45fc 100644 --- a/spec/models/pawn_spec.rb +++ b/spec/models/pawn_spec.rb @@ -98,4 +98,28 @@ expect(Pawn.find_by(id: pawn.id)).to be_nil end end + + describe '#promotable?' do + it 'is false when not in rank 1 or 8' do + pawn = build(:pawn, position_x: 1, position_y: 4) + + expect(pawn.promotable?).to eq false + end + + it 'is true when promotion is available' do + pawn = build(:pawn, position_x: 1, position_y: 8) + + expect(pawn.promotable?).to eq true + end + end + + describe '#promote_to!' do + it 'promotes the pawn to the specified type' do + pawn = build(:pawn, position_x: 1, position_y: 8) + + pawn.promote_to!('Queen') + + expect(pawn.type).to eq 'Queen' + end + end end