How to use .map in Rails - ruby-on-rails

Pig Latin
Rule 1: If a word begins with a vowel sound, add an "ay" sound to
the end of the word.
Rule 2: If a word begins with a consonant sound, move it to the end
of the word, and then add an "ay" sound to the end of the word.
The following program works in ruby. But I'm confused on how to use the "map" function? Please see the code as follows:
def translate(sentence)
if sentence.include?(" ")
words = sentence.split(" ").map do |word|
translate_word(word)
end
return words.join(" ")
else single_word = sentence
translate_word(single_word)
end
end
The above sentences works! but if I use:
words = sentence.split(" ")
words.map do |word|
translate_word(word)
end
It DOESN'T work! Why? I thought they were the same...
def translate_word(w)
vowels = %w[a e i o u]
consonants = ("a".."z").to_a - vowels
if vowels.include?(w[0])
w + "ay"
elsif consonants.include?(w[0]) && vowels.include?(w[1]) && w[1] != "u"
w[1..-1] + w[0] + "ay"
elsif (consonants.include?(w[0]) && consonants.include?(w[1]) && vowels.include?(w[2]) && w[2] != "u") || (w[0] == "q" && w[1] == "u")
w[2..-1] + w[0..1] + "ay"
elsif (consonants.include?(w[0]) && consonants.include?(w[1]) && consonants.include?(w[2]) && vowels.include?(w[3]))
w[3..-1] + w[0..2] + "ay"
elsif consonants.include?(w[0]) && w[1] == "q" && w[2] == "u"
w[3..-1] + w[0..2] + "ay"
end
end

#map function returns a new object which you are dismissing.
To save the result you should assign it back to words like this:
words = sentence.split(" ")
words = words.map do |word|
translate_word(word)
end
Or use #map! instead.

Related

Ruby : Loop, Case and iterations problems ( Rock , Paper, Scissors )

I´m ruby student since 1 month and i´m stuck with one part of my code. The project is based on a game ( rock, paper, scissor) but i´m facing of a problem that i cannot solve for moment. I would like to add one parameters to this game especially when the user enter a wrong input by displaying a message but with the condition i added it´s not working.
elsif player_choice != 'r' || player_choice != 'p' || player_choice != 's' || player_choice != 'q' || player_choice != 'x'
puts "wrong input"
So if you have some advice or some hint to share with me it will be great ! ( see below the entire code ).
Thank you very much.
#intro
puts "***** WELCOME TO PAPER SCISSORS ROCKS GAME *****"
puts "Input p = Paper, r = Rocks, s = Scissors, x = Display your score , q = Quit the game. "
25.times { print "-" }
puts
#scores
playerScore = 0
cpuScore = 0
CHOICES = {'p' => 'Paper', 'r' => 'Rock', 's' => 'Scissors', 'x' => 'score','q' => 'quit' }
CHOICE_CPU = {'p' => 'Paper', 'r' => 'Rock', 's' => 'Scissors'}
loop do
# player picks
begin
puts "Select your pick: (p/r/s/x/q)"
player_choice = gets.chomp.downcase
end until CHOICES.keys.include?(player_choice)
# computer picks
cpu_choice = CHOICE_CPU.keys.sample
def throw_message(winning_choice)
case winning_choice
when 'p'
puts "Paper wraps Rock!"
when 'r'
puts "Rock smashes Scissors!"
when 's'
puts "Scissors cuts Paper!"
when 'x'
puts "Live score"
when 'q'
puts "you decide to quit the game"
end
end
#display scores
if player_choice == 'x'
throw_message(player_choice)
puts "PLAYER : #{playerScore} CPU : #{cpuScore}"
#quit the game
elsif player_choice == 'q'
throw_message(player_choice)
break
# tie result
elsif player_choice == cpu_choice
puts "It's a Tie ! "
#player win
elsif (player_choice == 'p' && cpu_choice == 'r') || (player_choice == 'r' && cpu_choice == 's') || (player_choice == 's' && cpu_choice == 'p')
throw_message(playe·r_choice)
puts "You Win"
playerScore +=1
#display invalid input
elsif player_choice != 'r' || player_choice != 'p' || player_choice != 's' || player_choice != 'q' ||
player_choice != 'x'
puts "wrong input"
#cpu win
else throw_message(cpu_choice)
puts "Computer Win"
cpuScore +=1
end
end
Move the CHOICES.keys.include?(player_choice) check to the top of the main if/else logic. If you validate your input as early as possible, the rest of the code can assume the input is good; there's no need to spell out all the possible choices again.
I'm using a case/when because it's easier to read than if/elsif. throw_message is defined outside the loop, inside the loop its being redefined repeatedly. And I've removed choices from throw_message which don't have to do with the game; this avoids repeating the full set of choices.
def throw_message(winning_choice)
case winning_choice
when 'p'
puts "Paper wraps Rock!"
when 'r'
puts "Rock smashes Scissors!"
when 's'
puts "Scissors cuts Paper!"
end
end
def player_wins?(player_choice, cpu_choice)
return player_choice == 'p' && cpu_choice == 'r') ||
player_choice == 'r' && cpu_choice == 's') ||
player_choice == 's' && cpu_choice == 'p')
end
loop do
# player picks
puts "Select your pick: (p/r/s/x/q)"
player_choice = gets.chomp.downcase
# cpu picks
cpu_choice = CHOICE_CPU.keys.sample
case
when !CHOICES.keys.include?(player_choice)
puts "wrong input"
when player_choice == 'x'
puts "Live score"
puts "PLAYER : #{playerScore} CPU : #{cpuScore}"
when player_choice == 'q'
puts "you decide to quit the game"
break
when player_choice == cpu_choice
puts "It's a tie!"
when player_wins?(player_choice, cpu_choice)
throw_message(player_choice)
puts "You Win"
playerScore +=1
else
throw_message(cpu_choice)
puts "Computer Win"
cpuScore +=1
end
end

longest palindrome in Ruby on Rails

Write a method that takes in a string of lowercase letters (no uppercase letters, no repeats). Consider the substrings of the string: consecutive sequences of letters contained inside the string.
Find the longest such string of letters that is a palindrome.
Based on local method Palindrome?(string), I implemented longest-palindrome(string) as below with test cases:
def palindrome?(string)
i = 0
while i < string.length
if string[i] != string[(string.length - 1) - i]
return false
end
i += 1
end
return true
end
def longest_palindrome(string)
dix = 0
lstr = ""
lstrc = nil
while dix < string.length
dix2 = 1
while dix2 < string.length
str = string.slice(dix,dix2)
count = str.length
if palindrome?(str)
if lstrc == nil || lstrc < count
lstr = str
lstrc = count
end
end
dix2 += 1
end
dix += 1
end
puts(lstr)
return lstr
end
# These are tests to check that your code is working. After writing
# your solution, they should all print true.
puts(
'longest_palindrome("abcbd") == "bcb": ' +
(longest_palindrome('abcbd') == 'bcb').to_s
)
puts(
'longest_palindrome("abba") == "abba": ' +
(longest_palindrome('abba') == 'abba').to_s
)
puts(
'longest_palindrome("abcbdeffe") == "effe": ' +
(longest_palindrome('abcbdeffe') == 'effe').to_s
)
Test results as below:
bcb
longest_palindrome("abcbd") == "bcb": true
bb
longest_palindrome("abba") == "abba": false
effe
longest_palindrome("abcbdeffe") == "effe": true
Why did the second test failed?
... this line is preventing you from considering the entire string
while dix2 < string.length
So when dix is the whole string, you're not doing any testing for palindromes
Change the line to...
while dix2 <= string.length
It would actually be slightly more efficient if you did...
while dix2 <= string.length - dix
Which would prevent you from testing (for, say, a string of length 10), string(7,3) and string(7,4) and string(7,5) etc. etc., which are all basically the same string.

How do I deal with when a user enters a taken coordinate in tic-tac-toe?

I am writing a tic-tac toe program. Right now the user can override a taken square. Also, when the user enters a coordinate not on the board, it skips that persons turn. I would like to make my program say something like "the coordinate you have entered has already been taken or is invalid" when the user enters a taken coordinate or a coordinate not on the board. The program would then need to give the user another chance to enter his/her coordinate. Any suggestions?
This is my code:
class Game
def initialize
#board=Array.new
#board[1]=" 1 2 3\n" + "1 __|"
#board[2]="__"
#board[3]="|__"
#board[4]="\n2 __|"
#board[5]="__"
#board[6]="|__"
#board[7]="\n3 |"
#board[8]=" "
#board[9]="| "
#turn="x"
#win_status = false
end
def turn
#turn
end
def show_board
#board.each do |i|
print i
end
puts ""
end
def set_turn #switches turns
if #turn == "x"
#turn = "o"
else #turn == "o"
#turn = "x"
end
end
def make_move
puts "Enter x coordinate"
x=gets.to_i
puts "Enter y coordinate"
y=gets.to_i
#board[1]="1 _"+#turn+"|" if y==1 && x==1
#board[2]="_"+#turn if y==2 && x==1
#board[3]="|_"+#turn if y==3 && x==1
#board[4]="\n_"+#turn+"|" if y==1 && x==2
#board[5]="_"+#turn if y==2 && x==2
#board[6]="|_"+#turn if y==3 && x==2
#board[7]="\n "+#turn+"|" if y==1 && x==3
#board[8]=" "+#turn if y==2 && x==3
#board[9]="|"+#turn+" \n" if y==3 && x==3
end
def win_combo
return [[#board[1][1] + #board[2][1] + #board[3][2]], [#board[4][2] + #board[5][1] + #board[6][2]], [#board[7][1] + #board[8][1] + #board[9][1]],[#board[1][1] + #board[4][2] + #board[7][1]], [#board[2][1] + #board[5][1] + #board[8][1]], [#board[3][2] + #board[6][2] + #board[9][1]], [#board[1][1] + #board[5][1] + #board[9][1]], [#board[3][2] + #board[5][1] + #board[7][1]]]
end
def check_win
#if some row or column or diagonal is "xxx" or "ooo" then set #win_status = true
self.win_combo.each do |arr|
str = arr.join
if str == "xxx" or str == "ooo"
return true
end
end
return false
end
end
g = Game.new
while g.check_win != true
g.show_board
g.set_turn
g.make_move
end
puts "won"
Try changing each of these lines that you have
#board[1]="1 _"+#turn+"|" if y==1 && x==1
to:
if y==1 && x==1 && #board[1].eql?(" 1 2 3\n" + "1 _|")
#board[1] = "1 _" +#turn + "|"
and use elsif for #board[2-9]. The #board[1].eql?() part is what you initialized those values to. At the end of all that put this line:
else
make_move
end
Now it will only let you change the value of #board[x] if it hasn't been changed already. And if none of the conditions are satisfied to change that value, it will run the make_move method again. The final code should look something like this
if y==1 && x==1 && #board[1].eql?(" 1 2 3\n" + "1 _|")
#board[1] = "1 _" +#turn + "|"
elsif y==2 && x==1 && ...
...
else
make_move
end

How do I let the user know whether X or O won? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 8 years ago.
Improve this question
I am writing a tic-tac-toe program. Right now when someone gets three in a row, the game just ends. I would like to let the user know whether X or O won the game before it ends. Any suggestions?
Here is my code:
class Game
def initialize
#board=Array.new
#board[1]="1 __|"
#board[2]="__"
#board[3]="|__"
#board[4]="\n2 __|"
#board[5]="__"
#board[6]="|__"
#board[7]="\n3 |"
#board[8]=" "
#board[9]="| "
#turn="x"
#win_status = false
end
def turn
#turn
end
def show_board
puts " 1 2 3"
#board.each do |i|
print i
end
puts ""
end
def set_turn #switches turns
if #turn == "x"
#turn = "o"
else #turn == "o"
#turn = "x"
end
end
def make_move
puts "Enter x coordinate"
x=gets.to_i
puts "Enter y coordinate"
y=gets.to_i
#board[1]="1 _"+#turn+"|" if y==1 && x==1
#board[2]="_"+#turn if y==2 && x==1
#board[3]="|_"+#turn if y==3 && x==1
#board[4]="\n2 _"+#turn+"|" if y==1 && x==2
#board[5]="_"+#turn if y==2 && x==2
#board[6]="|_"+#turn if y==3 && x==2
#board[7]="\n3 "+#turn+"|" if y==1 && x==3
#board[8]=" "+#turn if y==2 && x==3
#board[9]="|"+#turn+" \n" if y==3 && x==3
end
def win_combo
return [[#board[1][1] + #board[2][1] + #board[3][2]], [#board[4][2] + #board[5][1] + #board[6][2]], [#board[7][1] + #board[8][1] + #board[9][1]],[#board[1][1] + #board[4][2] + #board[7][1]], [#board[2][1] + #board[5][1] + #board[8][1]], [#board[3][2] + #board[6][2] + #board[9][1]], [#board[1][1] + #board[5][1] + #board[9][1]], [#board[3][2] + #board[5][1] + #board[7][1]]]
end
def check_win
#if some row or column or diagonal is "xxx" or "ooo" then set #win_status = true
self.win_combo.each do |arr|
str = arr.join
if str == "xxx" or str == "ooo"
return true
end
end
return false
end
end
g = Game.new
while g.check_win != true
g.show_board
g.set_turn
g.make_move
end
I recommend that you create a Board class that knows how to draw itself based on the turns. This would remove a lot of the code from Game and make it easier to follow.
To answer your question, the code you have here:
if str == "xxx" or str == "ooo"
return true
end
doesn't distinguish between X winning or O winning. Here you can modify the code to check separately for X win and O win, and display the appropriate message.
There are a lot of things you could do. One way might be to change the check_win method to return a string. For example it could return "X", "O", or "none". Then use
while g.check_win.eql?("none")
...
end
puts g.check_win + " WINS!"

Help refactoring this nasty Ruby if/else statement

So I have this big, hairy if/else statement. I pass a tracking number to it, and then it determines what type of tracking number it is.
How can I simplify this thing? Specifically wanting to reduce the number of lines of codes.
if num_length < 8
tracking_service = false
else
if number[1, 1] == 'Z'
tracking_service = 'ups'
elsif number[0, 1] == 'Q'
tracking_service = 'dhl'
elsif number[0, 2] == '96' && num_length == 22
tracking_service = 'fedex'
elsif number[0, 1] == 'H' && num_length == 11
tracking_service = 'ups'
elsif number[0, 1] == 'K' && num_length == 11
tracking_service = 'ups'
elsif num_length == 18 || num_length == 20
check_response(number)
else
case num_length
when 17
tracking_service = 'dhlgm'
when 13,20,22,30
tracking_service = 'usps'
when 12,15,19
tracking_service = 'fedex'
when 10,11
tracking_service = 'dhl'
else
tracking_service = false
end
end
end
Yes, I know. It's nasty.
Try this. I rewrote it using case and regular expressions. I also used :symbols instead of "strings" for the return values, but you can change that back.
tracking_service = case number
when /^.Z/ then :ups
when /^Q/ then :dhl
when /^96.{20}$/ then :fedex
when /^[HK].{10}$/ then :ups
else
check_response(number) if num_length == 18 || num_length == 20
case num_length
when 17 then :dhlgm
when 13, 20, 22, 30 then :usps
when 12, 15, 19 then :fedex
when 10, 11 then :dhl
else false
end
end
Depending on whether or not the tracking code is a ruby object, you could also put helper's in it's class definition:
class TrackingCode < String
# not sure if this makes sense for your use case
def ups?
self[1,1] == 'Z'
end
def dhl?
self[0,1] == 'Q'
end
def fedex?
self.length == 22 && self[0, 2] == '96'
end
# etc...
end
Then your conditional becomes:
if number.ups?
# ...
elsif number.dhl?
# ...
elseif number.fedex?
end
One simplified conditional where you are operating on the implied feature of the tracking code. Likewise, if you were to take a looping approach, your loop would also be cleaner:
%w(ups? dhl? fedex?).each do |is_code|
return if number.send(is_code)
end
or even:
%w(ups? dhl? fedex?).each do |is_code|
yield if number.send(is_code)
end
This method looks like it was written for speed. You can use a minhash as a substitute, but I think the code is fairly clean and doesn't require a refactor. Rubyists tend to be disgusted by needless structure, but oftentimes it's needed to model real-world situations and/or provides a performance boost. The keyword should be needless.
Whilst longer than jtbandes solution, you might like this as it's a bit more declarative:
class Condition
attr_reader :service_name, :predicate
def initialize(service_name, &block)
#service_name = service_name
#predicate = block
end
end
CONDITIONS = [
Condition.new('ups') { |n| n[1] == 'Z' },
Condition.new('dhl') { |n| n[0] == 'Q' },
Condition.new('fedex') { |n| n[0..1] == '96' && n.size == 22 },
Condition.new('ups') { |n| n[0] == 'H' && n.size == 11 },
Condition.new('ups') { |n| n[0] == 'K' && n.size == 11 },
Condition.new('dhlgm') { |n| n.size == 17 },
Condition.new('usps') { |n| [13, 20, 22, 30].include?(n.size) },
Condition.new('fedex') { |n| [12, 15, 19].include?(n.size) },
Condition.new('dhl') { |n| [10, 11].include?(n.size) },
]
def tracking_service(tracking_number)
result = CONDITIONS.find do |condition|
condition.predicate.call(tracking_number)
end
result.service_name if result
end
I haven't dealt with the check_response method call here as I feel you should probably handle that elsewhere (assuming it does something other than return a tracking service name).
I believe this is sufficiently complex to deserve its own method.
BTW, if the length is 20 then the original function returns whatever check_response(n) returns, yet then attempts (and will always fail) to return 'usps'.
#lenMap = Hash.new false
#lenMap[17] = 'dhlgm'
#lenMap[13] = #lenMap[20] = #lenMap[22] = #lenMap[30] = 'usps'
#lenMap[12] = #lenMap[15] = #lenMap[19] = 'fedex'
#lenMap[10] = #lenMap[11] = 'dhl'
def ts n
len = n.length
return false if len < 8
case n
when /^.Z/
return 'ups'
when /^Q/
return 'dhl'
when /^96....................$/
return 'fedex'
when /^[HK]..........$/
return 'ups'
end
return check_response n if len == 18 or len == 20
return #lenMap[len]
end
# test code...
def check_response n
return 'check 18/20 '
end
%w{ 1Zwhatever Qetcetcetc 9634567890123456789012 H2345678901
K2345678901 hownowhownowhownow hownowhownowhownow90
12345678901234567
1234567890123
12345678901234567890
1234567890123456789012
123456789012345678901234567890
123456789012
123456789012345
1234567890123456789
1234567890
12345678901 }.each do |s|
puts "%32s %s" % [s, (ts s).to_s]
end

Resources