-
Notifications
You must be signed in to change notification settings - Fork 2k
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
base: main
Are you sure you want to change the base?
Changes from all commits
3a2bc5a
055c012
6179a95
f092bf9
517f0fd
59d2e73
6e0cfaa
fe20d09
70b9987
8ee1ec4
0b14170
d54313a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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. | ||
|
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] | ||
redirect '/play' | ||
end | ||
|
||
get '/play' do | ||
erb :play | ||
end | ||
|
||
post '/choice' do | ||
$player_choice = params[:choice].downcase | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
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' } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
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 |
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 |
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 |
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'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
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 |
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> |
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"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> |
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> |
There was a problem hiding this comment.
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