Hello I'm new to programming and I started with ruby. I'm trying to do my first program. I found online this code that generate a dice roll
class Die
def initialize(sides)
#sides = sides
end
def generate_die_roll
rand(#sides) + 1
end
def roll(number=1)
roll_array = []
number.times do
roll_array << generate_die_roll
end
total = 0
roll_array.each do |roll|
new_total = total + roll
total = new_total
end
total
end
end
and I would like to use in they way that if the number generated is inferior o equal to another print something otherwise something else.
It's probably very easy but i'm trying in every way and now I will need some help please.
that's my code:
require "./newdado.rb"
energia_vitale = 30
puts "Lancia un dado scrivendo (D) da sommare alla tua Energia Vitale iniziale di #{energia_vitale} punti"
scelta = gets.chomp
case scelta
when "D"
SIX_SIDED_DIE = "#{Die.new(6)}"
values = Array[]
values.push(SIX_SIDED_DIE.roll)
puts values
if values < 2
puts "c"
else puts "b"
end
end
when I run it i receive this error
C:/Users/fix/workspace/D&D Ruby/energia vitale.rb:11:in <main>': undefined methodroll' for "#":String (NoMethodError)
Sorry to bother the community with this beginner problem
Why as string?
this line
SIX_SIDED_DIE = "#{Die.new(6)}"`
should be something like
die = Die.new(6)
then you can do die.roll
Related
I have this method where it gets an input from the user and it checks it against a while condition. if the user inputted anything that isnt a string or if the user inputted a character that was longer than 1 the method would prompt the user again for a valid input, basically adhering to the hangman rules. Heres the code
class Hangman
def initialize
dictionary = File.open('5desk.txt',"r")
line = dictionary.readlines
#word = line[rand(1..line.length)]
#length = #word.length
random = #word.length - rand(#word.length/2)
random.times do
#word[rand(#word.length)] = "_"
end
end
This method fails to function properly.
def get_input
puts #word
puts "Letter Please?"
#letter = gets.chomp
while !#letter.kind_of? String || #letter.length != 1
puts "Invalid input,try again!"
#letter = gets.chomp
end
end
end
Game = Hangman.new
Game.get_input
class Hangman
Stop right there! Why create a class considering that you would only create a single instance of it? There's no need for one. A few methods and one instance variable are sufficient.
Generate secret words randomly
I assume the file '5desk.txt' contains one secret words per line and you will be selecting one randomly. So begin by gulping the entire file into an array held by an instance variable (as opposed to reading the file line-by-line). I assume '5desk.txt1' contains the three words shown below.
#secret_words = File.readlines('5desk.txt', chomp: true)
#=> ["cat", "violin", "whoops"]
See the doc for the class method IO::readlines1,2. The option chomp: true removes the newline character from the end of each line.
This method closes the file after it has been read. (You used File::open. When doing so you need to close the file when you are finished with it: f = File.open(fname)...f.close.)
You need a method to randomly choose a secret_word.
def fetch_secret_word
#secret_words.sample
end
fetch_secret_word
#=> "violin"
See Array#sample. You could have instead used
#secret_words[rand(#secret_words.size)]
See Kernel#rand. The first and last words in #secret_words are #secret_words[0] and #secret_words[#secret_words.size-1]. Therefore, where you wrote
#word = line[rand(1..line.length)]
it should have been
#word = line[rand(0..line.length-1)]
which is the same as
#word = line[rand(line.length)]
Now let's create a method for playing the game, passing an argument that equals the maximum number of incorrect guesses the player has before losing.
def play_hangman(max_guesses)
First get a secret word:
secret_word = fetch_secret_word
Let us suppose that secret_word #=> "violin"
Initialize objects
Next, initialize the number of incorrect guesses and an image of the secret word:
incorrect_guesses = 0
secret_word_image = "-" * secret_word.size
#=> "------"
So we now have
def play_hangman(max_guesses)
secret_word = fetch_secret_word
incorrect_guesses = 0
secret_word_image = "-" * secret_word.size
Loop over guesses
Now we need to loop over the player's guesses. I suggest you use Kernel#loop, in conjuction with the keyword break for all your looping needs. (For now, forget about while and until, and never use for.) The first thing we will do in the loop is to obtain the guess of a letter from the player, which I'll do by calling a method:
loop do
guess = get_letter(secret_word_image)
...<to be completed>
end
def get_letter(secret_word_image)
loop do
puts secret_word_image
print "Gimme a letter: "
letter = gets.chomp.downcase
break letter if letter.match?(/[a-z]/)
puts "That's not a letter. Try again."
end
end
guess = secret_letter(secret_word_image)
#=> "b"
Here this method returns "b" (the guess) and displays:
------
Gimme a letter: &
That's not a letter. Try again.
------
Gimme a letter: 3
That's not a letter. Try again.
------
Gimme a letter: b
See if letter guessed is in secret word
Now we need to see which if any of the hidden letters equal letter. Again, let's make this a method3.
def hidden_letters(guess, secret_word, secret_word_image)
(0..secret_word.size-1).select do |i|
guess == secret_word[i] && secret_word_image[i] = '-'
end
end
Suppose guess #=> "i". Then:
idx = hidden_letters(guess, secret_word, secret_word_image)
#=> [1,4]
There are two "i"'s, at indices 1 and 4. Had there been no hidden letters "i" the method would have returned an empty array.
Before continuing let's look at our play_hangman is coming along.
def play_hangman(max_guesses)
secret_word = fetch_secret_word
incorrect_guesses = 0
secret_word_image = "-" * secret_word.size
loop do
unless secret_word_image.include?('-')
puts "You've won. The secret word is '#{secret_word}'!"
break
end
guess = get_letter(secret_word_image)
idx = hidden_letters(guess, secret_word, secret_word_image)
...<to be completed>
end
Process a guess
We now have to carry out one course of action if the array idx is empty and another if it is not.
case idx.size
when 0
puts "Sorry, no #{guess}'s"
incorrect_guesses += 1
if incorrect_guesses == max_guesses
puts "Oh, my, you've used up all your guesses, but"
puts "we'd like you take home a bar of soap"
break
else
puts idx.size == 1 ? "There is 1 #{guess}!" :
"There are #{idx} #{guess}'s!"
idx.each { |i| secret_word_image[i] = guess }
if secret_word_image == secret_word
puts "You've won!! The secret word is '#{secret_word}'!"
break
end
end
Complete method
So now let's look at the full method (which calls fetch_secret_word, get_letter and hidden_letters).
def play_hangman(max_guesses)
secret_word = fetch_secret_word
incorrect_guesses = 0
secret_word_image = "-" * secret_word.size
loop do
guess = get_letter(secret_word_image)
idx = hidden_letters(guess, secret_word, secret_word_image)
case idx.size
when 0
puts "Sorry, no #{guess}'s"
incorrect_guesses += 1
if incorrect_guesses == max_guesses
puts "Oh, my, you've used up all your guesses,\n" +
"but we'd like you take home a bar of soap"
return
end
else
puts idx.size == 1 ? "There is 1 #{guess}!" :
"There are #{idx.size} #{guess}'s!"
idx.each { |i| secret_word_image[i] = guess }
if secret_word_image == secret_word
puts "You've won!! The secret word is '#{secret_word}'!"
return
end
end
end
end
Play the game!
Here is a example play of the game.
play_hangman(4)
------
Gimme a letter: #
That's not a letter. Try again.
------
Gimme a letter: e
Sorry, no e's
------
Gimme a letter: o
There is 1 o!
--o---
Gimme a letter: i
There are 2 i's!
-io-i-
Gimme a letter: l
There is 1 l!
-ioli-
Gimme a letter: v
There is 1 v!
violi-
Gimme a letter: r
Sorry, no r's
violi-
Gimme a letter: s
Sorry, no s's
violi-
Gimme a letter: t
Sorry, no t's
Oh, my, you've used up all your guesses,
but we'd like you take home a bar of soap
1 The class File has no (class) method readlines. So how can we write File.readlines? It's because File is a subclass of IO (File.superclass #=> IO) and therefore inherits IO's methods. One commonly sees IO class methods invoked with File as the receiver.
2 Ruby's class methods are referenced mod::meth (e.g., Array::new), where mod is the name of a module (which may be a class) and meth is the method. Instance methods are referenced mod#meth (e.g., Array#join).
3 Some Rubyists prefer to write (0..secret_word.size-1) with three dots: (0...secret_word.size). I virtually never use three dots because I find it tends to create bugs. The one exception is when creating an infinite range that excludes the endpoint (e.g., 1.0...1.5).
I'm sure it would be hard to find an easier question, but I'm a complete newbie. I have searched extensively and for some reason can't find the answer to this. Here's my code:
puts "Enter F for Fahrenheit and C for Celsius."
x = gets.chomp.downcase
def ftoc(fahrenheit)
(fahrenheit.to_f - 32.0) * (5.0 / 9.0)
end
if x == "f"
puts "Enter your temp:"
temp = gets.chomp.to_i
ftoc temp
elsif x == "c"
puts "Enter your temp:"
temp = gets.chomp.to_i
ctof temp
else
puts "That does not compute."
end
I'm just trying to get the returned result of the method into a variable so I can use it elsewhere....
Remember that calls like ctof temp just initiate a method and then, as you're not putting the result anywhere, discard it immediately.
To clean up this code let's organize it better:
# Temperature conversion method
def ftoc(fahrenheit)
(fahrenheit.to_f - 32.0) * (5.0 / 9.0)
end
# User input method
def temperature_prompt!
puts "Enter F for Fahrenheit and C for Celsius."
x = gets.chomp.downcase
case (x)
when "f"
puts "Enter your temp:"
temp = gets.chomp.to_i
ftoc temp
when "c"
puts "Enter your temp:"
temp = gets.chomp.to_i
ctof temp
else
puts "That does not compute."
end
end
Now you can make use of the fact that in Ruby things like if and case actually return values. In this case it's the value of the last thing to execute in each block, so that result isn't discarded, it's just passed along:
temp = temperature_prompt!
If you enter an invalid value you get the result of puts which is conveniently nil.
Here's something to consider: Ruby is very good at parsing arbitrary text if you can describe the patterns. Here's a simple input routine:
def temperature_prompt!
puts "Enter degrees (e.g. 8F, 2C)"
case (input = gets.chomp.downcase)
when /(\d+)f/
ftoc $1
when /(\d+)c/
ctof $1
else
puts "That does not compute."
end
end
You could add to those patterns to allow things like -2C and 3.4°F if you wanted.
I'm working on Chris Pine's Ruby tutorial. I have to write a cheat method that allows me to set which side of the die I want to show: https://pine.fm/LearnToProgram/?Chapter=09
I have two instance variables: #numberShowing and #numberCheat. #numberCheat receives an input from the user and I want to set #numberShowing to take the value of #numberCheat. However, #numberShowing always outputs some random number. Any tips?
Here's my code so far:
class Die
def initialize
roll
end
def roll
#numberShowing = 1 + rand(6)
end
def showing
#numberShowing
end
def cheat
puts "cheat by selecting your die number between 1 and 6"
#numberCheat = gets.chomp
end
#numberShowing = #numberCheat
end
puts Die.new.cheat
puts Die.new.showing
Thanks!
Move #numberShowing = #numberCheat into the cheat method. But your test is not going to prove it worked. Try something like:
die = Die.new
puts "Currently showing #{die.showing}"
puts "Cheating to change showing number to #{die.cheat}"
I wrote a program to simulate the rolling of polyhedral dice but every time I run it I get the error shown below. It displays my prompts and lets me input my numbers, but after that it screws up. I've been trying to find a fix online but I only find people talking about different problems with the times method being undefined. I'm new to Ruby, so any help would be appreciated.
My program:
p = 0
while p < 1
puts "Choose your die type"
die_type = gets.chomp
puts "Choose your number of die"
die_number = gets.chomp
total = 0
i = 1
die_number.times do
random_int = 1 + rand(die_type)
total += random_int
i += 1
end
puts total
end
The error I get:
/dieroll.rb:13: undefined method 'times' for "5":String (NoMethodError)
Change die_number = gets.chomp to die_number = gets.to_i. die_number = gets.chomp, assigns a string to the local variable die_number( Because Kernel#gets gives us a string object). String don't have any method called #times, rather Fixnum class has that method.
Change also die_type = gets.chomp to die_type = gets.to_i, to avoid the next error waiting for you, once you will fix the first one.
1.respond_to?(:times) # => true
"1".respond_to?(:times) # => false
In you case die_number was "5", thus your attempt "5".times raised the error as undefined method 'times' for "5":String (NoMethodError).
I need to generate a unique six digit alpha-numeric code. To save in my database as voucher no: for every transaction.
I used this
require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,6]
How to generate a random string in Ruby This link was useful
A better way is to let the database handle the ids(incrementing). But if you insisting on generating them your self, you can use a random generator to generate an code, check it against db for uniqueness. then either accept or regenerate
I'd use the database to generate unique keys, but if you insist on doing it the hard way:
class AlnumKey
def initialize
#chars = ('0' .. '9').to_a + ('a' .. 'z').to_a
end
def to_int(key)
i = 0
key.each_char do |ch|
i = i * #chars.length + #chars.index(ch)
end
i
end
def to_key(i)
s = ""
while i > 0
s += #chars[i % #chars.length]
i /= #chars.length
end
s.reverse
end
def next_key(last_key)
to_key(to_int(last_key) + 1)
end
end
al = AlnumKey.new
puts al.next_key("ab")
puts al.next_key("1")
puts al.next_key("zz")
Of course, you'll have to store your current key somewhere, and this is in no way thread / multisession-safe etc.
With the following restrictions:
Valid only until 2038-12-24 00:40:35 UTC
Generates no more than once within a second
you can use this simple code:
Time.now.to_i.to_s(36)
# => "lks3bn"
class IDSequence
attr_reader :current
def initialize(start=0,digits=6,base=36)
#id, #chars, #base = start, digits, base
end
def next
s = (#id+=1).to_s(#base)
#current = "0"*(#chars-s.length) << s
end
end
id = IDSequence.new
1234.times{ id.next }
puts id.current
#=> 0000ya
puts id.next
#=> 0000yb
9876543.times{ id.next }
puts id.current
#=> 05vpqq
This would eleviate the time collision issue by getting the milli seconds
(Time.now.to_f*1000.0).to_i