Skip to content

Commit

Permalink
Implement replaying the same game
Browse files Browse the repository at this point in the history
For logged in users (still shadow shipped), when a game
is finished they can chose to replay the same board from
the start.
  • Loading branch information
radanskoric committed Aug 26, 2024
1 parent fc0a9d4 commit 31111e0
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 14 deletions.
14 changes: 14 additions & 0 deletions app/controllers/games_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ def my

def show
@game = Game.find(params[:id])
if @game.private?
rodauth.require_account
head :not_found unless @game.owner == current_account
end
end

def new
Expand Down Expand Up @@ -48,6 +52,16 @@ def update
end
end

def replay
rodauth.require_account
game = Game.find(params[:id])
if game.finished?
redirect_to game.replay_for(current_account)
else
head :forbidden
end
end

private

def game_params
Expand Down
5 changes: 5 additions & 0 deletions app/models/game.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,9 @@ def click!(x:, y:, mark_as_mine: false)
update!(status: new_game_object.status)
end
end

# @param owner [Account] the account to replay the game for as a new private game.
def replay_for(owner)
Game.create!(board: board, owner:)
end
end
4 changes: 4 additions & 0 deletions app/views/games/_game.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,7 @@
</table>
<% end %>
<% end %>

<% if game.finished? && rodauth.logged_in? %>
<%= link_to "Replay This Game", replay_game_path(game), class: "btn bg-gray-300 hover:bg-gray-400", data: {turbo_method: :post, turbo_frame: "_top"} %>
<% end %>
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
collection do
get :my
end

member do
post :replay
end
end

# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
Expand Down
14 changes: 14 additions & 0 deletions spec/models/game_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,18 @@
expect(result).to be_a(Minesweeper::Game)
end
end

describe "#replay_for" do
before { game } # make sure it's created

it "creates a game" do
expect { game.replay_for(accounts(:freddie)) }.to change(Game, :count).by(1)
end

it "keeps the same board but sets the new owner" do
new_game = game.replay_for(accounts(:freddie))
expect(new_game.board).to eq game.board
expect(new_game.owner).to eq accounts(:freddie)
end
end
end
36 changes: 36 additions & 0 deletions spec/requests/games_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require 'rails_helper'

RSpec.describe "Games Controller" do
fixtures :accounts

let(:account) { accounts(:freddie) }
let(:public_game) { Game.create!(board:) }
let(:private_game) { Game.create!(board:, owner: account) }
let(:board) do
Board.create!(
width: 10,
height: 10,
mines: [Mine.new(x: 2, y: 2)],
)
end

describe "show" do
it "doesn't allow viewing other's private game" do
post "/#", params: { email: accounts(:brian).email, password: "password"}

get "/games/#{private_game.id}"

expect(response).to be_not_found
end
end

describe '#replay' do
it "doesn't allow replaying an unfinished game" do
post "/#", params: { email: account.email, password: "password" }

post "/games/#{public_game.id}/replay"

expect(response).to be_forbidden
end
end
end
62 changes: 48 additions & 14 deletions spec/system/play_private_game_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,25 @@ def lose_the_game!(game)
expect(page).to have_no_content('Reloading to new game in')
end

context "when logged in with existing private games" do
it "allows to replay a communal game privately, after it's finished" do
Game.create!(board: Board.create!( width: 10, height: 10, mines: [Mine.new(x: 2, y: 2)]))
visit "/#"
login_with(email: accounts(:freddie).email, password: "password")

visit "/"
expect(page).not_to have_content("Replay this game")

click_cell(5, 5)
expect(page).to have_content("Humanity won!")
expect(page).to have_content("Refresh Now")

click_on "Replay This Game"
expect(page).not_to have_content("Refresh Now")
click_cell(5, 5)
expect(page).to have_content("You won!")
end

context "with an existing private games" do
let!(:private_game) do
Game.create!(
board: Board.create!(
Expand All @@ -72,23 +90,39 @@ def lose_the_game!(game)
end
let(:owner) { accounts(:freddie) }

before do
visit "/#"
login_with(email: owner.email, password: "password")
expect(page).to have_content("You have been logged in")
end
context "when logged in as owner" do
before do
visit "/#"
login_with(email: owner.email, password: "password")
expect(page).to have_content("You have been logged in")
end

it "allows browsing existing private games" do
visit "/games/my"

expect(page).to have_content("My Games")
expect(page).to have_content("Game ##{private_game.id}: In progress")

click_on "Game ##{private_game.id}"

it "allows browsing existing private games" do
visit "/games/my"
expect(page).to have_content("Mines left: 1")
click_cell(4, 4)
expect(page).to have_content("You won!")
end

expect(page).to have_content("My Games")
expect(page).to have_content("Game ##{private_game.id}: In progress")
it "allows replaying it after its finished" do
visit "/games/my"
click_on "Game ##{private_game.id}"

click_on "Game ##{private_game.id}"
expect(page).to have_content("Mines left: 1")
click_cell(2, 2)
expect(page).to have_content("You lost.")

expect(page).to have_content("Mines left: 1")
click_cell(4, 4)
expect(page).to have_content("You won!")
click_on "Replay This Game"
expect(page).to have_content("Mines left: 1")
click_cell(4, 4)
expect(page).to have_content("You won!")
end
end
end
end

0 comments on commit 31111e0

Please # to comment.