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

Jimmy Lyons RPS challenge #2119

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ source 'https://rubygems.org'
ruby '3.0.2'

gem 'sinatra'
gem 'sinatra-contrib'

group :test do
gem 'capybara'
Expand Down
8 changes: 8 additions & 0 deletions 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,12 @@ 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)
terminal-table (3.0.1)
unicode-display_width (>= 1.1.1, < 3)
tilt (2.0.10)
Expand All @@ -93,6 +100,7 @@ DEPENDENCIES
simplecov
simplecov-console
sinatra
sinatra-contrib

RUBY VERSION
ruby 3.0.2p107
Expand Down
64 changes: 64 additions & 0 deletions README_JL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
## Rock, Paper, Scissors

# How to install
Fork this repo, and clone to your local machine
Run the command gem install bundler (if you don't have bundler already)
When the installation completes, run bundle

# How to Run and Play
Run rackup in the command line to start the server
Open the browser and go to http://localhost:4567/
Enter the player's name in the "Player Name:" box
Click on "Submit!" to start playing
Select your action by clicking on "rock", "paper" or "scissors" and then hitting submit.
See the result of your action against the computer.

# How to test your code
Run RSpec from the rps-challenge directory.

# Introduction

This project is the weekend task following the third week at Makers Academy.
The project comprises the construction of an online rock, paper, scissors game, where you can play against the automated computer.
The code of for this program is divied into a Model, a Controller and Views. The only class used was Game, which ran the mechanics of
an automated RPS game.

### Classes

class Game: Initialises with the players move as an argument.
random_choice: selects a random action for the computer from rock, paper, scissors.
return_winner: compares the two moves and chooses a winner.

### Views

index: The index view is associated with the homepage. It renders a form for the player to infill with their name.
play: The play view renders a form with the options of 'rock', 'paper' or 'scissors' on the '/play' page.
result: The result view renders the outcome of the RPS game, comparing the user move against the computer and announcing the result.

# Motivation

The motivation behind this project is to introduce the concept of creating an application available on the internet. The application itself simple, because the emphasis of this project is to learn about writing a program that runs online. The new concepts to me in this project were:

* Creating a local server.
* Writing code to direct users to different web pages.
* Splitting the code into a Model, Controller and Views.
* Writing tests for web pages using Capybara.
* Using HTML and CSS to format a website.
* Integrating Ruby code into HTML.

# Brief

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

# Key Thoughts and Issues

* Things to add include a "play again" button (which would re-route back to the '/play' page), the ability for two players to play the game and further complexity by introducing 'rock', 'paper', 'scissors', 'lizard', 'spock'.
* I had issues getting certain methods to work between the Model, Controller and Views. This led me to abandoning certain methods.
* I successfully managed to stub the random_choice method to check all outcomes of the game.

37 changes: 37 additions & 0 deletions app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'sinatra/base'
require 'sinatra/reloader'
# couldn't get relative path to work for this. need to find cause
require '/Users/jimmylyons/Documents/Programming/Makers/Projects/week3/rps-challenge/lib/game.rb'

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

get '/' do
erb :index
end

post '/names' do
$player_name = params[:name]

Choose a reason for hiding this comment

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

Global variables are apparently evil - player should be split out into separate class to be injected into Game

redirect '/play'
end

get '/play' do
erb :play
end

post '/choice' do
$player_choice = params[:choice].downcase

Choose a reason for hiding this comment

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

You're using a button input in the form so the choice shouldn't= need to use .downcase

redirect '/result'
end

get '/result' do
game = Game.new($player_choice)

Choose a reason for hiding this comment

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

Consider initialising the Game when the choice is created so that you can store the choice within a player and within the Game and avoid the evil global variables

@result = game.return_winner
@computer_choice = game.computer_action
erb :result
end

run! if app_file == $0
end
26 changes: 26 additions & 0 deletions lib/game.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Game

attr_reader :computer_action

def initialize(choice)
@player_action = choice
@pairs = { rock: 'paper', paper: 'scissors', scissors: 'rock' }

Choose a reason for hiding this comment

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

Think this is for the return_winner method, so why is it stored as an instance variable for the class?

end

def random_choice
['rock', 'paper', 'scissors'].sample

Choose a reason for hiding this comment

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

Could store this as a constant as the three options won't change. Also consider using symbols as they are immutable and are an identifier of an action rather than a typed user input.

end

def return_winner
@computer_action = random_choice
winning_choice = @pairs[@player_action.to_sym]
if @computer_action == winning_choice
'Computer Wins!'
elsif @computer_action == @player_action
'Draw'
else
'Player Wins!'
end
end

end
40 changes: 40 additions & 0 deletions spec/features/game_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'game'

describe Game do

subject(:game) { Game.new('rock') }

it 'creates instances of game' do

Choose a reason for hiding this comment

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

describe Game tests that there is a Game class and that it can be initialised so don't think you need this test as well

expect(game).to be_instance_of Game
end

describe '# random_choice' do
it 'randomly selects an action from rock, paper or scissors' do
expect(game.random_choice).to eq('rock').or eq('paper').or eq('scissors')
end
end

describe '# return_winner' do

Choose a reason for hiding this comment

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

Add tests for all possible outcomes, as only three are tested here

context 'when player picks rock and computer picks rock' do
it 'calls a draw' do
allow(game).to receive(:random_choice).and_return('rock')
expect(game.return_winner).to eq 'Draw'
end
end

context 'when player picks rock and computer picks paper' do
it 'returns that computer has won' do
allow(game).to receive(:random_choice).and_return('paper')
expect(game.return_winner).to eq 'Computer Wins!'
end
end

context 'when player picks rock and computer picks scissors' do
it 'returns that player has won' do
allow(game).to receive(:random_choice).and_return('scissors')
expect(game.return_winner).to eq 'Player Wins!'
end
end
end

end
8 changes: 8 additions & 0 deletions spec/features/player_choice_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
feature 'Player choice' do
scenario 'Player choice is printed on /result' do
sign_in_and_submit_name
page.choose('rock')
click_button 'Submit'
expect(page).to have_content 'Jimmy picked rock'
end
end
6 changes: 6 additions & 0 deletions spec/features/player_name_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
feature 'Display player name' do
scenario 'Players name is printed on /play' do
sign_in_and_submit_name
expect(page).to have_content 'Pick an action Jimmy:'
end
end
9 changes: 9 additions & 0 deletions spec/features/result_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
feature 'Game result' do
scenario 'Prints the outcome of the game on /result' do
sign_in_and_submit_name
page.choose('rock')
click_button 'Submit'

expect(has_expected_output).to be true
end
end
15 changes: 15 additions & 0 deletions spec/features/web_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
def sign_in_and_submit_name
visit '/'
fill_in :name, with: 'Jimmy'
click_button 'Submit'
end

def has_expected_output
outputs = ['Computer Wins!', 'Player Wins!', 'Draw']

Choose a reason for hiding this comment

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

Nice use of an array for outputs rather than expecting on multiple individual strings - I hadn't though to do that

outputs.each do |output|
if page.has_content?(output)
@check = true
end
end
@check
end
8 changes: 8 additions & 0 deletions spec/features/web_page_function_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require '/Users/jimmylyons/Documents/Programming/Makers/Projects/week3/rps-challenge/app.rb'

feature 'Testing infrastructure' do
scenario "Asks for player name" do
visit '/'
expect(page).to have_content 'Player Name:'
end
end
12 changes: 11 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
require 'capybara/rspec'
require 'simplecov'
require 'simplecov-console'

Expand All @@ -11,6 +10,17 @@

# For accurate test coverage measurements, require your code AFTER 'SimpleCov.start'

ENV['RACK_ENV'] = 'test'

require File.join(File.dirname(__FILE__), '..', 'app.rb')

require 'capybara'
require 'capybara/rspec'
require 'rspec'
require 'features/web_helpers'

Capybara.app = Online_Game

RSpec.configure do |config|
config.after(:suite) do
puts
Expand Down
6 changes: 6 additions & 0 deletions views/index.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<h1>rock, paper, scissors</h1>
<form action='/names' method='post'>
<h2>Player Name:</h2>
<input type='text' name="name">
<input type='submit' value='Submit'>
</form>
11 changes: 11 additions & 0 deletions views/play.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<h1>Pick an action <%=$player_name%>:</h1>

<form action='/choice' method='post'>
<input type="radio" id="rock" name="choice" value="Rock">

Choose a reason for hiding this comment

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

Why set value to 'Rock' when you then use value.downcase in the app to convert to lowercase? Could refactor that out

<label for="rock">Rock</label><br>
<input type="radio" id="paper" name="choice" value="Paper">
<label for="paper">Paper</label><br>
<input type="radio" id="scissors" name="choice" value="Scissors">
<label for="scissors">Scissors</label>
<input type='submit' value='Submit'>
</form>
3 changes: 3 additions & 0 deletions views/result.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<h2><%=$player_name%> picked <%=$player_choice%></h2>
<h2>Computer picked <%=@computer_choice%> </h2>
<h1> <%=@result%> </h1>