Ruby rand function in method - ruby

Using Ruby why can't I pass random variable here? I tried different combinations such as removing numbers.
money= rand(100)
def paycheck(money)
"Lets make this amount, #{money} today"
end
puts paycheck("100")
puts paycheck("200")
puts paycheck("500")

You can:
money= rand(100)
puts paycheck(money)
When you define your method paycheck(money) - it is different variable money that the one on this line: money = rand(100)

You can do something like this:
def paycheck(limit)
money = rand(limit.to_i)
"Lets make this amount, #{money} today"
end
puts paycheck("100") #=> Lets make this amount, 14 today
puts paycheck("200") #=> Lets make this amount, 111 today
puts paycheck("500") #=> Lets make this amount, 119 today

Related

List in Ruby gem cli

I am making a ruby cli that outputs a list of game deals scraped from a site.
The list prints out promptly using
def games_sales
Deal.all.each_with_index do |deal, index|
puts "#{index + 1}. #{deal.title}"
end
puts "What game do you want to see?"
input = gets.strip
game_selection(input.to_i)
end
My problem comes when asking the user to select an item from the list.
def game_selection(input)
deal = Deal.find_by_index(input)
#binding.pry
deal.each do |deal|
puts "#{deal.index}"
puts " Name: #{deal.title}"
puts " Price: #{deal.price}"
puts " Store: #{deal.store}"
puts " Expiration: #{deal.expiration}"
end
deal
end
It returns the int input but only the first item on the list every time.
I forgot my find_by_index method:
def self.find_by_index(input)
all.select do |deal|
end
end
which is incomplete
Not 100% sure if I got your question right and if you're using Rails, but Deals.all let me think of this.
I had to replace Deals.all with DEALS for testing as I haven't got a rails app running. So I used an Array of OpenStructs to fake your Model result.
# this fakes Deals.all
require 'ostruct'
DEALS = [
# add any more properties the same way as title, separated by comma
OpenStruct.new(title: 123),
OpenStruct.new(title: 456)
]
def games_sales
DEALS.each_with_index do |deal, index|
puts "#{index + 1}. #{deal.title}"
end
puts "What game do you want to see?"
input = gets.strip
game_selection(input.to_i)
end
def game_selection(input)
deal = DEALS.at(input-1)
p deal[:title]
end
def self.find_by_index(input)
all.select do |deal|
deal.index == input
end
end
games_sales
Result when choosing 1 is 123, choosing 2 you'll get 456, due to p deal[:title] above in the code.
I think your find_by_index need to get the right index and in my example I had to use at(index) as at(input-1) in order to get the right result.
I really hope this helps somehow and I suggest that you add the expected result to your question, in case my answer does not help you.

Confused about using reduce and what it's actually trying to do

I have done Rails development a bit but haven't for a while.
I have never used reduce / inject other than to sum up values (which seems to be the main example I've seen online) but would like to understand better what it does (and to be honest, just its syntax). I have heard it referred to as the functional part of Ruby but based upon examples, not sure what that means.
Looking at the example in the docs (the longest word example) https://ruby-doc.org/core-2.4.0/Enumerable.html#method-i-reduce seems to imply that it is useful for selecting a value out of a series at end but this doesn't seem very functional.
My understanding is that it accumulates to the initial value passed into reduce. But in this code fragment, I'm not sure why it's not accumulating (I'm expecting "some joe birds joe bees" or some variation).
# expect 'some joe birds joe bees'
def say_joe(name)
puts "within say_joe #{name}"
" joe #{name}"
end
a = %w(birds bees)
starting = "some"
b = a.reduce(starting) do |total, x|
puts x
say_joe(x)
end
puts "-----"
puts "starting: #{starting}"
puts "a: #{a}"
puts "b: #{b}"
with output:
birds
within say_joe birds
bees
within say_joe bees
-----
starting: some
a: ["birds", "bees"]
b: joe bees
What is the magic of reduce?
The accumulation (in this case a string concatenation) doesn’t happen automatically. You still need to return the new accumulator value (remember in Ruby the last statement is also implicitly the return value).
This does what you’d expect:
def say_joe(name)
puts "within say_joe #{name}"
" joe #{name}"
end
a = %w(birds bees)
starting = "some"
b = a.reduce(starting) do |total, x|
puts x
total << say_joe(x)
end
puts "-----"
puts "starting: #{starting}"
puts "a: #{a}"
puts "b: #{b}” # some joe birds joe bees

need help spliting a list into 2 different list

This is my code it creates a list of 20 items and I want to split it into 2 lists of 10 and only display one list at a time. How can I make this happen in ruby?
def list_dogs
counter = 0
if counter <= 10
Dogs::DogsPopularity.all.each do |dog|
puts "#{counter +=1}. #{dog.name}"
#binding.pry
end
elsif counter > 10 && counter <= 20
Dogs::DogsPopularity.all.each do |dog|
puts "#{counter +=1}. #{dog.name}"
# binding.pry
end
end
#binding.pry
end
This is what it prints out.....
Labrador Retriever
Golden Retriever
Bulldog
Beagle
French Bulldog
Poodle
Yorkshire Terrier
Boxer
Dachshund
Australian Shepherd
Pembroke Welsh Corgi
Cavalier King Charles Spaniel
Shih Tzu
Boston Terrier
Havanese
Brittany
American Cocker Spaniel
Chihuahua
Pug
Maltese
We have to assume that your class/module returns 20 dogs, and if so:
def list_dogs
Dogs::DogsPopularity.all.each_slice(10).each do |dog_arr|
dog_arr.each_with_index do |dog, i|
puts "#{i+1}. #{dog.name}"
end
end
end
To see that this works on a basic array see:
[*1..100].each_slice(10).each_with_index{|arr, i| puts "#{i+1}: #{arr}"}

Comparing values in a card game

I want to make a card game program that compares the values of cards assigned to player_value and dealer_value. If player_value is greater than dealer_value, it should display "you win". Here is my code:
def get_card (card)
type = case ((card-1)/13)
when 0 then "of clubs"
when 1 then "of diamonds"
when 2 then "of hearts"
when 3 then "of spades"
end
card = case (card%13)
when 0 then "king #{type}"
when 1 then "ace #{type}"
when 11 then "jack #{type}"
when 12 then "queen #{type}"
else card%13
end
"#{card} #{type}"
end
def deal_cards
total_cards = (1..52).to_a.shuffle
player_value = [total_cards.pop, total_cards.pop]
dealer_value = [total_cards.pop, total_cards.pop]
puts "Your cards are #{get_card(player_value[0]).to_s} and #{get_card(player_value[1]).to_s}"
puts "The dealer shows #{get_card(dealer_value[0])}"
if(dealer_value > player_value)
puts "You lose"
else (player_value > dealer_value)
puts "You win"
end
end
deal_cards()
It is not clear to me why this is not working, and I would appreciate any help with this.
I don't really understand why you assign an array to player_value and dealer_value, but you can't compare an array using > or <.
You have to retrieve the element from the array that you want to compare, and then use it in the if-else clause.
Also an else clause does not take another condition. An else will be used if all previous conditions fail. In your case, you should use elsif.
e.g.:
if(dealer_value[0] > player_value[0])
puts "You lose"
elsif (player_value[0] > dealer_value[0])
puts "You win"
end
Let me offer this object oriented solution to the same problem, since this is where Ruby really shines, and seeing it used in a procedural way really irks me. Object orientation adds a few more lines for scaffolding, but adds so much more in terms of legibility, reusability, and conceptual clarity.
We can represent the domain using three basic building blocks.
First, we need a Card object, able to hold some data (a rank and a suit) about itself, as well as the ability to represent itself as a string:
class Card
SUITS = [:clubs, :diamonds, :spades, :hearts]
RANKS = [:ace, *2..10, :jack, :queen, :king]
attr_reader :suit, :rank
def initialize(n)
#suit = (n - 1) / 13
#rank = (n - 1) % 13
end
def to_s
"#{ RANKS[#rank] } of #{ SUITS[#suit] }"
end
end
Next, we need a Hand object. Basically a collection of cards that can compare its strength to other hands, and also represent itself as a string:
class Hand
attr_reader :cards
def initialize(cards)
#cards = cards
end
def <=>(other_hand)
#cards.strength <=> other_hand.strength
end
def to_s
#cards.map(&:to_s).join(", ")
end
private
def strength
#cards.map(&:rank).inject(:+)
end
end
It is not clear from the question, how hand strength is determined. In this primitive implementation, it is simply the sum of the ranks of the cards in the hand.
Lastly, we need a Deck object. Something from which we can draw cards. We'll go with a standard 52-card deck:
class Deck
def initialize
#cards = (1..52).map { |n| Card.new(n) }.shuffle
end
def draw(number_of_cards = 1)
[*#cards.pop(number_of_cards)]
end
end
Now that we have our basic building blocks set up, using them is trivial:
def deal_cards
deck = Deck.new
player_hand = Hand.new(deck.draw(2))
dealer_hand = Hand.new(deck.draw(2))
puts "Your have: #{ player_hand }"
puts "The dealer has: #{ dealer_hand }"
if(player_hand > dealer_hand)
puts "You win!"
elsif(dealer_hand < player_hand)
puts "Aw. You lose."
else
puts "Woah! It's a tie!"
end
end
Notably this solution lacks error handling, for cases like passing an unknown n to the Card constructor, or drawing from an empty deck, but can easily be added in.

ruby strategy to convert floating point number with linguistics

So I'm writing what I thought was a simple .rb file to convert a float number into a string. The string returns my floating point number in words. So if I have 11.11 then I would have eleven dollars and eleven cents So far I've extended the float class which has worked alright. I'm having trouble with how to convert the 11 cents into eleven cents. en.numwords would kick back eleven point one one. I've thought about trying out a hash to solve my problem where 11=>eleven cents. Any thoughts how I could implement this? Perhaps a better way to implement this?
Here's what I have so far:
require 'rubygems'
require 'linguistics'
Linguistics::use( :en )
class Float
def to_test_string
puts self #check
puts self.en.numwords
self.en.numwords
end
end
puts "Enter two great floating point numbers for adding"
puts "First number"
c = gets.to_f
puts "Second number"
d = gets.to_f
e = c+d
# puts e
puts e.to_test_string
puts "Enter a great floating number! Example 10.34"
a = gets.to_f
# puts a
puts a.to_test_string
Thanks for the help! Post some code so I can try ideas out!
Here's one solution: divide the number into two substrings based on the decimal point delimiter, call en.numwords on each substring separately, and then join the resulting strings with "point" between them. Something along the lines of:
require "rubygems"
require "linguistics"
Linguistics::use(:en)
class Float
def my_numwords
self.to_s.split('.').collect { |n| n.en.numwords }.join(' point ')
end
end
(11.11).my_numwords # => eleven point eleven
This problem can be solved by splitting the float into two values: dollars and cents.
require 'rubygems'
require 'linguistics'
Linguistics::use( :en )
class Float
def to_test_string
puts self #check
#Split into dollars and cents
cents = self % 1
dollars = self - cents
cents = cents * 100
text = "#{dollars.to_i.en.numwords} dollars and #{cents.to_i.en.numwords} cents"
puts text
text
end
end
puts "Enter two great floating point numbers for adding"
puts "First number"
c = gets.to_f
puts "Second number"
d = gets.to_f
e = c+d
# puts e
puts e.to_test_string
puts "Enter a great floating number! Example 10.34"
a = gets.to_f
# puts a
puts a.to_test_string

Resources