Homework Review

Warmup Exercise

Write a program that asks the user for all U.S. states they have visited (followed by a return). Typing "done" should terminate the program. Print all states to the screen.

 

Warmup Solution:

Let's set up an empty array of visited states and prompt the user for input.

visited = []

puts "Enter all the states you've been to! Type 'done' when you're finished:"

Warmup Solution:

Get the states from the user, then check to see if they entered "done". If so stop collecting input, otherwise push to the visited array.

state = gets.chomp.upcase

if state != 'DONE'
  visited.push(state)
end


Warmup Solution:

We need a loop to keep collecting states from the user. But...

keep_going = true

while keep_going
  state = gets.chomp.upcase 

  if state != 'DONE'
    visited.push(state)
  end
end

Warmup Solution:

... we need a way to exit the loop.  So set 'keep_going' to false when the user enters done.

keep_going = true

while keep_going
  state = gets.chomp.upcase 

  if state != 'DONE'
    visited.push(state)
  else
    keep_going = false
  end
end

Warmup Solution:

Finally we need to print out the states the user has visited. We can either join a comma separated array...

puts "You have visited the following states:"
puts visited.join(', ')
visited.each do |state|
  puts state 
end

...or loop through and print each state.

Warmup Solution:

# Write a program that asks the user for all U.S. states they have visited
# (followed by a return) 
# Typing "done" should terminate the program. 
# Print all states to the screen.

visited = []
puts "Enter all the states you've been to! Type 'done' when you're finished:"
keep_going = true

while keep_going
  state = gets.chomp.upcase 

  if state != 'DONE'
    visited.push(state)
   else
    keep_going = false
  end
end

puts "You have visited the following states:"
puts visited.join(', ')

Ruby Exercise:

Write a program that splits the class into teams of 2. If there's an odd number of students the last group should be a group of 3.

 

Jaime's Process

Let's walk through this exercise together from scratch!

 

I like to start simple. First let's set up an array of students, assign it to a variable and print it to the terminal to make sure it's working.

 

 

# Write a program that splits the class into teams of 2. 
# If there's an odd number of students the last group should be a group of 3.

students = ['Daniele', 'Alesia','Anita', 
            'Ben', 'Thomas', 'Matthew', 
            'Mark', 'Jennifer', 'Cameron']

puts students
student_shuffle.rb

2 Legit 2 Git

It's a good habit to push your code to Github once you get something working. Let's walk through the steps once more.

 

Push to Github

 

 

Push to Github

 

  • Name your repository something meaningful like "ruby" to indicate this is the home for your ruby programs.
     
  • Note the green checkmark indicating approval for your naming skills
     
  • Click the green "Create repository" button at the bottom. 

Push to Github

Sweet! You set up your repo remotely!
Next we have to link it to your local Ruby folder.

  • ​Fortunately Github provides a list of instructions that we can loosely follow




 

  • Let's start with #2 and run "git init" in our terminal to initialize our repository. We only have to do this once per repo.
$ git init

Push to Github

 

 

 

  • (We'll deviate from the third instruction a bit)
  • Let's add ALL our files to the staging area by typing: 

     
  • Sadly we get no feedback.
    PRO TIP: Check the status of your files by running:


     
$ git status
$ git add .

Push to Github

 

 

 

  • Now we have to commit to our local repository


     
  • And then add the hook to the remote repo. This is
    another one of those things we only have to do once



    This adds a hidden file to your ruby folder so github can track your files. Don't be scared; it's legit!
$ git commit -m "first commit"
$ git remote add origin https://github.com/jpanaia/ruby.git

Push to Github

 

 

 

  • The last step is pushing to the remote repository







     
  • Good job! Let's go back to github.com and see how it's changed...
$ git push origin master

We're published!

Our file is officially stored in version control. Let's practice pushing to Github as we work. You should get in the habit of committing early and often.

 

GITHUB = RESUME

Do the Shuffle

Back to our code.... 

 

Next we want to randomize our student array. There are several ways to do this. Let's use the ".shuffle!" method and test it.

Curious about methods you can use with arrays? 
http://www.ruby-doc.org/core-2.2.0/Array.html

 

 

students = ['Daniele', 'Alesia','Anita', 
            'Ben', 'Thomas', 'Matthew', 
            'Mark', 'Jennifer', 'Cameron']

# shuffle the student array
students.shuffle!

puts students

Back to Git

We got something else working! This is so exciting I think we should push to Github.

 

 

$ git status

Let's add to the staging area.

 

$ git add .

2 Legit 2 Git

$ git status

We see our file has been staged.
 

Next step is committing to the local repo w/ a message

 

$ git commit -m "shuffled student array"

And check the status again.

 

2 Legit 2 Git

Finally we'll push to the remote repository.

 

$ git push origin master

Now we have 2 commits saved.

Students

Let's refocus on our array of students. Using an until loop we can iterate through our array. We can simply print out the count to make sure it's working.

 

# set an array of students
students = ['Daniele', 'Alesia', 'Anita', 'Ben', 'Thomas', 'Matthew', 'Mark', 'Jennifer', 'Cameron']

# shuffle student array
students.shuffle!

# set a count
count = 0

# until count is the number of students
until count == students.length
 
  # Test loop
  puts count
  
  # increase the count
  count += 1
end # end until

Students

Now, instead of counting let's print each student.

 

# set a count
count = 0

# until count is the number of students
until count == students.length

  # output each student
  puts "#{students[count]}"
  
  # increase the count
  count += 1
  
end # end until

How would we output students in pairs?

Students

We can add 1 to the array's index to print the next student.

# set a count
count = 0

# until count is the number of students
until count == students.length

  # output students in pairs
  puts "#{students[count]} & #{students[count+1]}"
  
  # increase the count
  count += 1
  
end # end until

Hm..this still isn't quite right. How can we fix it?

Students

We increase the count by 2 to account for pairs of students. We're very close but still missing that 9th student. 

# set a count
count = 0

# number of students
num_students = students.length - 1

# until count is the number of students
until count == num_students

  # output students in pairs
  puts "#{students[count]} & #{students[count+1]}"
  
  # increase the count
  count += 2
  
end # end until

Git Real

This is a great time to push to Github. Remember how?

 

$ git add .
$ git commit -m "paired up students"
$ git push origin master

Looks Good

We'll need to set up a condition to output different results depending on our position in the loop. Once it hits the 6th spot (3 from the end) we assign that group 3 members.

# set an array of students
students = ['Daniele', 'Alesia', 'Anita', 'Ben', 'Thomas', 'Matthew', 'Mark', 'Jennifer', 'Cameron']

# shuffle student array
students.shuffle!

# set a count
count = 0

# number of students
num_students = num_students - 1

until count == num_students
  if count < num_students - 3
    # output pairs of students
    puts "#{students[count]} & #{students[count+1]}"
  else
    puts "#{students[count]}, #{students[count+1]} & #{students[count+2]}"
  end
  
  # increase the count
  count += 2  
end # end until

A Bug

BUT...what happens if we only have 8 students instead of 9 (sorry Cam).

# set an array of students
students = ['Daniele', 'Alesia', 'Anita', 'Ben', 'Thomas', 'Matthew', 'Mark', 'Jennifer']

Even vs Odd

At this point it's clear that we have to test for even and odd numbers of students.

 

How would we do this in real life?

A Snag

We'll use the modulus (%) operator to
determine evenness / oddness.

  • If the number of students divided by 2 has a remainder of 1 it's ODD

  • If the number of students divided by 2 has a remainder of 0 it's EVEN

 

We can see this demonstrated in irb.

Hooray!

We can fix the bug by adding a condition for odd vs even number of students.

until count == number_of_students 

  # odd # students
  if number_of_students % 2 == 1
    if count < num_students - 3
      # output pairs of students
      puts "#{students[count]} & #{students[count+1]}"
    else
      puts "#{students[count]}, #{students[count+1]} & #{students[count+2]}"
      break
    end
  else # even # students
    # output pairs of students
    puts "#{students[count]} & #{students[count+1]}"
  end

  # increase the count
  count += 2 

end # end until

Ruby Challenge

How could we modify this code to take user input instead of hard-coding a student array?

Think back to our warmup exercise...

My Solution

# empty student array
students = []
student = ''

# prompt user
puts "Who showed up to class today? Type 'done' when finished:"

while student != 'done' 
  student = gets.chomp
  # push student into students array
  students.push(student)
end

# pop off last element 'done'
students.pop

# shuffle student array
students.shuffle!

# set a count
count = 0

puts "\nYour teams are:"
until count == students.length
  # Odd # students
  if number_of_students % 2 == 1 
	  if count < number_of_students - 3
	    # output pairs of students
	    puts "#{students[count]} & #{students[count+1]}"
	  else
	    puts "#{students[count]}, #{students[count+1]} & #{students[count+2]}"
	    break
	  end
	else # even # students
		# output pairs of students
	    puts "#{students[count]} & #{students[count+1]}"
	end

	# increase the count
	count += 2 

end # end until

new code!

Git Out

Are you sick of git puns yet?

 

Go ahead and add, commit and push to Github.

Another Snag

Anyone see the bug in this code? There's one special case that I've completely neglected.

What happens if only one student comes to class?

See if you can add some logic to fix this. 

1 Lonely Student

until count == students.length 
  # One student
  if number_of_students == 1    	
    puts "#{students[0]} is a team of 1"
    break
  else
    # Odd # students
    if number_of_students % 2 == 1
      # 3 students or more
      if count < students.length - 3
        # output pairs of students
        puts "#{students[count]} & #{students[count+1]}"
      else
        puts "#{students[count]}, #{students[count+1]} & #{students[count+2]}"
        break
      end
    else # even # students
      # output pairs of students
      puts "#{students[count]} & #{students[count+1]}"
    end
  end

  # increase the count
  count += 2 

end # end until

Push to Github

# Write a program that prints the lyrics 
# to 99 Bottles of Beer on the Wall

# example output:
# 99 bottles of beer on the wall
# 99 bottles of beer
# Take one down pass it around
# 
# 98 bottles of beer on the wall
# 98 bottles of beer on the wall
# 98 bottles of beer 
# Take one down, pass it around

99 Bottles Program

Write a program that prints the lyrics to 99 Bottles of Beer on the Wall

# N number of bottles
number_of_bottles = 99

until number_of_bottles == 0

# Do something

end

99 Bottles Program

Let's define the number of bottles to start with (99, duh!). Then we'll loop until we're out of beer!

# N number of bottles
number_of_bottles = 99

until number_of_bottles == 0

# print 2 lines using number of bottles

# print refrain (doesn’t change)

# print a line using number - 1

end

99 Bottles Program

Let's outline our solution 

# N number of bottles
number_of_bottles = 99

until number_of_bottles == 0
  # print 2 lines using number of bottles
  puts "#{number_of_bottles} bottles of beer on the wall"
  puts "#{number_of_bottles} bottles of beer"

  # print refrain (doesn’t change)
  puts "Take one down, pass it around"

  #print a line using N -1
  puts "#{number_of_bottles - 1} bottles of beer on the wall\n\n"

end

99 Bottles Program

Now print a bunch of strings (with interpolation!)  to sing our song. What happens when we run this code? 

number_of_bottles = 99

until number_of_bottles == 0

  # print 2 lines using N
  puts "#{number_of_bottles} bottles of beer on the wall"
  puts "#{number_of_bottles} bottles of beer"

  # print refrain (doesn’t change)
  puts "Take one down, pass it around\n\n"

  #print a line using N -1
  puts "#{number_of_bottles - 1} bottles of beer on the wall"

  number_of_bottles -= 1

end

99 Bottles Program

A pesky infinite loop!

We need to decrement (-=). Now we're pretty close. How would we ensure correct grammar at 1 bottle of beer? 

  if number_of_bottles == 1
  	puts "#{number_of_bottles} bottle of beer on the wall"
	puts "#{number_of_bottles} bottle of beer"

	# print refrain (doesn’t change)
	puts "Take it down, pass it around"
	puts "No more bottles of beer on the wall!"
  else 
	# print 2 lines using N
	puts "#{number_of_bottles} bottles of beer on the wall"
	puts "#{number_of_bottles} bottles of beer"

	# print refrain (doesn’t change)
	puts "Take one down, pass it around"
    
    if number_of_bottles == 2
      puts "1 bottle of beer on the wall\n\n"
     else
	  #print a line using N -1
	  puts "#{number_of_bottles - 1} bottles of beer on the wall\n\n"
    end
  end

99 Bottles Program

Here it is! We have to add a few special cases.

if number_of_bottles > 1
  # print 2 lines using N
  puts "#{number_of_bottles} bottles of beer on the wall"
  puts "#{number_of_bottles} bottles of beer"

  # print refrain (doesn’t change)
  puts "Take one down, pass it around"

  # print a line using N -1
  puts "#{number_of_bottles - 1} bottles of beer on the wall\n\n"
else
  # print 2 lines using N
  puts "1 bottle of beer on the wall"
  puts "1 bottle of beer"

  # print refrain (doesn’t change)
  puts "Take it down, pass it around"

  # print a line using N -1
  puts "No more bottles of beer on the wall!"
end

99 Bottles Program

Let's also add logic to ensure correct grammar when we get down to 1 bottle.

We're close here but it still needs more love...

A few different ways to solve a Ruby problem

5 Questions Problem

  • Ask the user 5 yes or no questions
  • Compare their answer to a list of correct answers
  • Print the number of correct answers

 


# Ask the user 5 yes or no questions 
# Compare their answers to a list of correct answers
# Print the number of correct answers

Ways to approach this

  • Arrays

  • Hashes

  • Methods

Array Approach

questions = [ 'Are narwhals real?', 
              'Is today Halloween?', 
              'Do dogs say meow?', 
              'Does 2+2 = 4?',
              'Is Jaime awesome?']
correct_answers =   ['Y', 'N', 'N', 'Y', 'Y']

Let's create 2 arrays to hold our questions & correct answers

Array Approach

puts "Please answer Y or N to the following questions!"

Let's first prompt the user ...

questions.each do |question|
  puts "Q: #{question}"

  user_answer = gets.chomp.upcase

end

Array Approach

Now we print out each question using a loop and save the user's answer in a variable.

Array Approach

index = 0
score = 0

Let's initialize some variables at the top of our code to keep track of our score and the array index.

Array Approach

questions.each do |question|
  puts "Q: #{question}"

  user_answer = gets.chomp.upcase
  
  if user_answer == correct_answers[index]
   # Do Something
  end

end
    

Let's compare the user's answer against the correct answer using the array index

Array Approach

questions.each do |question|
  puts "Q: #{question}"

  user_answer = gets.chomp.upcase

  if user_answer == correct_answers[index]
    score += 1
  end
  index += 1
end

We increase the score by 1 point each time the answers match. We also  increment the index variable in order to work our way through array of answers

Array Approach

puts "You got #{score}/5 correct answers!"

Now that we have our score let's print it out to let the user know how they did

Array Approach

if user_answer == 'Y' || user_answer == 'N'
    if user_answer == correct_answers[index]
      score += 1
    end
    index += 1
else
  puts "Try again: Y or N?"
end

Let's add some validation to make sure we're only accepting "Y" or "N" answers from the user

Array Approach

questions.each do |question|
  puts "Q: #{question}"

  user_answer = gets.chomp.upcase

  if user_answer == 'Y' || user_answer == 'N'
    if user_answer == correct_answers[index]
      score += 1
    end
    index += 1
  else
    puts "Try again: Y or N?" 
    redo
  end
end

Don't forget "redo" to start the loop over again if their answer was invalid.

Array Approach

questions = [ 'Are narwhals real?', 
              'Is today Halloween?', 
              'Do dogs say meow?', 
              'Does 2+2 = 4?',
              'Is Jaime awesome?']

correct_answers = ['Y', 'N', 'N', 'Y', 'Y']

index = 0
score = 0

puts "Please answer Y or N to the following questions!"

questions.each do |question|
  puts "Q: #{question}"
  user_answer = gets.chomp.upcase

  if user_answer == 'Y' || user_answer == 'N'
    if user_answer == correct_answers[index]
      score += 1
    end
    index += 1
  else
    puts "Try again: Y or N?"
    redo
  end
end

puts "You got #{score}/5 correct answers!"

Hash Approach

Another approach is to set up a hash that holds the questions and correct answers in key value pairs.

questions_answers = {'Are narwhals real?'=> 'Y', 
                     'Is today Halloween?'=> 'N', 
                     'Do dogs say meow?' => 'N',
                     'Does 2+2 = 4?' => 'Y', 
                     'Is Jaime awesome?' => 'Y'}
score = 0

puts "Please answer Y or N to the following questions!"

Hash Approach

Again we prompt the user to answer the question and also initialize a score variable.

Hash Approach

Then we loop over the hash using the key and value, print the question and get the user's answer.

questions_answers.each do |question, correct_answer|
  puts "Q: #{question}"
  user_answer = gets.chomp.upcase
end

Hash Approach

Add in the same validation and scoring we used in the array approach.

if user_answer == 'Y' || user_answer == 'N'
    if user_answer == correct_answer
      score += 1
    end
  else
    puts "Try again: Y or N?"
    redo
  end

Hash Approach

Finally we output the user's score!

puts "You got #{score}/#{questions_answers.count} correct answers!"

Hash Approach

questions_answers = {'Are narwhals real?' => 'Y', 
                     'Is today Halloween?' => 'N', 
                     'Do dogs say meow?' => 'N', 
                     'Does 2+2 = 4?' => 'Y', 
                     'Is Jaime awesome?' => 'Y'}
score = 0

puts "Please answer Y or N to the following questions!"

questions_answers.each do |question, correct_answer|
  puts "Q: #{question}"

  user_answer = gets.chomp.upcase

  if user_answer == 'Y' || user_answer == 'N'
    if user_answer == correct_answer
      score += 1
    end
  else
    puts "Try again: Y or N?"
    redo
  end
end

puts "You got #{score}/#{questions_answers.count} correct answers!"

Making Methods

What if we wanted to break this into methods? We could start by declaring instance variables at the top.

@questions_answers = {'Are narwhals real?' => 'Y', 
                     'Is today Halloween?' => 'N', 
                     'Do dogs say meow?' => 'N', 
                     'Does 2+2 = 4?' => 'Y', 
                     'Is Jaime awesome?' => 'Y'}
@score = 0

Making Methods

Next we can break out the prompt into its own method.

def prompt
  puts "Please answer Y or N to the following questions!"
end

Making Methods

def put_score
 # Do something
end

We can also break out a method to print the score.

Making Methods

def put_score(s,q_a)
  puts "You got #{s}/#{q_a.count} correct answers!"
end

Don't forget to pass in local score and question/answer variables!

Making Methods

def ask_questions 
  @questions_answers.each do |question, correct_answer|
    puts "Q: #{question}"

    user_answer = gets.chomp.upcase

    if user_answer == 'Y' || user_answer == 'N'
       if user_answer == correct_answer
         @score += 1
      end
    else
      puts "Try again: Y or N?"
      redo
    end
  end
end

Now let's put the bulk of our code in it's own method. Remember we're using instance variables.

Making Methods

Add a main method to call the prompt, ask_questions and put_score methods. Then call "main."

def main
  prompt
  ask_questions
  put_score(@score)
end

main
@questions_answers = {'Are narwhals real?' => 'Y', 
                      'Is today Halloween?' => 'N', 
                      'Do dogs say meow?' => 'N', 
                      'Does 2+2 = 4?' => 'Y', 
                      'Is Jaime awesome?' => 'Y'}
@score = 0

def prompt
  puts "Please answer Y or N to the following questions!"
end

def ask_questions 
  @questions_answers.each do |question, correct_answer|
    puts "Q: #{question}"

    user_answer = gets.chomp.upcase

    if user_answer == 'Y' || user_answer == 'N'
       if user_answer == correct_answer
         @score += 1
      end
    else
      puts "Try again: Y or N?"
      redo
    end
  end
end

def put_score(s,q_a)
  puts "You got #{s}/#{q_a.count} correct answers!"
end

def main
  prompt
  ask_questions
  put_score(@score,@questions_answers) 
end

main

Method Solution

Homework

Build a quiz program that gets a few inputs from the user including:

  • number of questions
  • questions
  • answers

Then clear the screen and begin the quiz. Keep score!

Ruby Exercises

By tts-jaime

Ruby Exercises

FT

  • 1,267