Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sophie gilder RPS #2136

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ source 'https://rubygems.org'
ruby '3.0.2'

gem 'sinatra'
gem 'sinatra-reloader'
gem 'sinatra-contrib'

group :test do
gem 'capybara'
Expand Down
13 changes: 12 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ GEM
docile (1.4.0)
mini_mime (1.1.1)
mini_portile2 (2.6.1)
multi_json (1.15.0)
mustermann (1.1.1)
ruby2_keywords (~> 0.0.1)
nokogiri (1.12.3)
Expand Down Expand Up @@ -76,6 +77,14 @@ GEM
rack (~> 2.2)
rack-protection (= 2.1.0)
tilt (~> 2.0)
sinatra-contrib (2.1.0)
multi_json
mustermann (~> 1.0)
rack-protection (= 2.1.0)
sinatra (= 2.1.0)
tilt (~> 2.0)
sinatra-reloader (1.0)
sinatra-contrib
terminal-table (3.0.1)
unicode-display_width (>= 1.1.1, < 3)
tilt (2.0.10)
Expand All @@ -93,9 +102,11 @@ DEPENDENCIES
simplecov
simplecov-console
sinatra
sinatra-contrib
sinatra-reloader

RUBY VERSION
ruby 3.0.2p107

BUNDLED WITH
2.2.26
2.3.15
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
# RPS Challenge
# Rock paper scissors

This is a fun app made during week 3 of Makers Academy. The user/s can play a single player or multiplayer game of rock paper scissors

_Tech used_

Languages: Ruby, CSS, HTML
Framework: Sinatra
Testing: RSpec, Capybara

_Notes on design_

To make the multi-player more secretive, I used CSS to hide player one's weapon selection after they had clicked on it.

![Landing page](./docs/welcome.png?raw=true "Landing page")
![Choose weapon multi-player page](./docs/choose.png?raw=true "Choose weapon multi-player page")
![First player selected](./docs/selected.png?raw=true "First player seleted")
![Result](./docs/wins.png?raw=true "Result")

# CHALLENGE INSTRUCTIONS


Instructions
-------
Expand Down
62 changes: 62 additions & 0 deletions app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
require 'sinatra/base'
require 'sinatra/reloader'
require './lib/player.rb'
require './lib/game.rb'
require './lib/computer.rb'

class RockPaperScissors < Sinatra::Base
configure :development do
register Sinatra::Reloader
end

get "/" do
erb :index
end

get '/single' do
erb :single
end

get '/multi' do
erb :multi
end

post "/names_single" do
player_1 = Player.new(params[:name])
player_2 = Computer.new
$game = Game.new(player_1, player_2)
redirect "/play"
end

post "/names_multi" do
player_1 = Player.new(params[:name])
player_2 = Player.new(params[:name2])
$game = Game.new(player_1, player_2)
redirect "/play"
end

get "/play" do
@game = $game
erb @game.select_type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually it's best to enforce the view name to be something specific, rather than the return of a method that you might not fully control — for example, tomorrow you (or someone else) might modify select_type to return a different value, but might also forget to add a new view to cover this case here, which would break the program. Rather than coupling tightly the return value to the view name, it might be better to add some condition and specifically select the correct view — or better, to have a generic single view that is always used, but using an instance variable and some dynamic ERB tags to display a slightly different portion of the HTML, depending on the value

end

post "/weapon" do
@game = $game
@game.player_1.weapon = params[:weapon]
redirect '/result'
end

post "/weapon_multi" do
@game = $game
@game.player_1.weapon = params[:weapon]
@game.player_2.weapon = params[:weapon2]
redirect '/result'
end

get "/result" do
@game = $game
erb @game.result
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark than above here — you could set the result in an instance variable and display something different in the view depending on this

end

run! if app_file == $0
end
2 changes: 2 additions & 0 deletions config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require "./app"
run RockPaperScissors
Binary file added docs/choose.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
158 changes: 158 additions & 0 deletions docs/rsp_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
### User Stories

As a marketeer
So that I can see my name in lights
I would like to register my name before playing an online game

As a marketeer
So that I can enjoy myself away from the daily grind
I would like to be able to play rock/paper/scissors

### Routes

````ruby
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good you've designed the routes beforehand here — it probably helped a lot your decisions in terms of routing, and how the application would behave, HTTP-wise

get "/" do
# registration page
end

post "/name" do
# processes the names and redirects
end

get "/play" do
# user sees their name here
# game play happens here
# user selects their weapon
end

post "/result" do
# takes the weapon choice that was selected
# selects the correct erb dependng on the result
end

get "/win" do
# winner page
end

get "/draw" do
# page for draws
end

get "/lose" do
# page for losing
end

````

### Classes

````ruby
class App
# stores the routes etc
end

class Player
attr_reader :name
attr_accessor :weapon

def initialize(name)
@name = name
@weapon = nil
end
end

class Computer
def weapon
# sample from the GAMES::WEAPONS array
end
end

class Game
attr_reader :players
def initialize(player_1, player_2)
# weapons constant
# rules constant
# players array
end

def player_1
end

def player_2
end

def result
# returns a symbol for selecting correct erb
# based on the players weapons
end
end
````

### Unit tests

````ruby
# Game
describe Game do
subject(:game) { described_class.new(player_1, player_2) }
let(:player_1) { double :player }
let(:player_2) { double :computer }

it "returns the players" do
expect(game.players).to eq [player_1, player_2]
expect(game.player_1).to eq player_1
expect(game.player_1).to eq player_2
end

it "returns win if player_1 wins"
allow(player_1).to receive(weapon).and_return(:rock)
allow(player_2).to receive(weapon).and_return(:scissors)
expect(game.result).to eq :win
end

it "returns lose if player_1 wins"
allow(player_1).to receive(weapon).and_return(:rock)
allow(player_2).to receive(weapon).and_return(:paper)
expect(game.result).to eq :lose
end

it "returns draw if a draw"
allow(player_1).to receive(weapon).and_return(:rock)
allow(player_2).to receive(weapon).and_return(:rock)
expect(game.result).to eq :draw
end

# Player
describe Player do
subject(:player) { described_class.new("Rosie") }

it "constructs and returns name" do
expect(player.name).to eq "Rosie"
end

it "can have a weapon assigned to it" do
game.weapon == :rock
expect(game.weapon).to eq :rock
end
end

# Computer
describe Computer do
subject(:computer) { described_class.new }

it "randomly selects a weapon" do # not entirely sure this will work
expect(computer.weapon).to eq :paper
computer.weapon
end
end
````

### Features tests

````ruby
# displays name

# selects a weapon

# shows the correct screen depending on who won
````

Binary file added docs/selected.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/welcome.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/wins.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions lib/computer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Computer
attr_reader :name, :weapon, :type

def initialize
@weapon = Game::WEAPONS.sample
@name = :Computer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor one - usually symbol names are always lowercase

end
end
41 changes: 41 additions & 0 deletions lib/game.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
class Game
WEAPONS = [:rock, :paper, :scissors]
RULES = {rock: :scissors, scissors: :paper, paper: :rock}

attr_reader :players

def initialize(player_1, player_2)
@players = [player_1, player_2]
same_name_setter if player_1.name == player_2.name
end

def player_1
@players.first
end

def player_2
@players.last
end

def select_type
single_player ? :game : :game_multi
end

def result
if player_2.weapon == RULES[player_1.weapon]
:win
elsif player_1.weapon == RULES[player_2.weapon]
:lose
else
:draw
end
end

def single_player
player_2.name == :Computer
end

def same_name_setter
player_2.name=("#{player_2.name} 2")
end
end
13 changes: 13 additions & 0 deletions lib/player.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Player
attr_reader :weapon, :type
attr_accessor :name

def initialize(name)
@name = name
@weapon = nil
end

def weapon=(weapon)
@weapon = weapon.downcase.to_sym
end
end