I'm trying to evaluate whether every space value is equal to either "X" or "O". Can I use each to do that? Is there a better way?
if #spaces.each {|x| x=="O" || x=="X"}
#winner = true
puts "It's a tie!"
break
end
ETA: all? doesn't seem to be working, either. I got this error referring to the line with the block:
tictac.rb:47: syntax error, unexpected '|', expecting '}'
{|x| x=="O" || x=="X"}
^
tictac.rb:47: syntax error, unexpected '}', expecting keyword_end
Here is the entire TicTacToe I'm working on:
class Board
def initialize
#spaces = [1, 2, 3, 4, 5, 6, 7, 8, 9]
self.print_board
#winner = false
#turn = "X"
end
def print_board
puts
puts " " + #spaces[0].to_s + " " + #spaces[1].to_s + " " + #spaces[2].to_s
puts " " + #spaces[3].to_s + " " + #spaces[4].to_s + " " + #spaces[5].to_s
puts " " + #spaces[6].to_s + " " + #spaces[7].to_s + " " + #spaces[8].to_s
puts
end
def mark(turn, move)
space = #spaces.index(move)
#spaces[space] = turn
self.print_board
end
def play
while #winner == false
puts "where would you like to put your #{#turn}?"
move = gets.chomp.to_i
self.mark(#turn, move)
if
#spaces[0] == #turn && #spaces[1] == #turn && #spaces[2] == #turn ||
#spaces[3] == #turn && #spaces[4] == #turn && #spaces[5] == #turn ||
#spaces[6] == #turn && #spaces[7] == #turn && #spaces[8] == #turn ||
#spaces[0] == #turn && #spaces[3] == #turn && #spaces[6] == #turn ||
#spaces[1] == #turn && #spaces[4] == #turn && #spaces[7] == #turn ||
#spaces[2] == #turn && #spaces[5] == #turn && #spaces[8] == #turn ||
#spaces[0] == #turn && #spaces[4] == #turn && #spaces[8] == #turn ||
#spaces[2] == #turn && #spaces[4] == #turn && #spaces[6] == #turn
#winner = true
puts "#{#turn} is the winner!"
break
elsif #spaces.all?
{|x| x=="O" || x=="X"}
#winner = true
puts "It's a tie!"
break
else
#turn == "X"? #turn = "O" : #turn = "X"
end
end
end
end
game = Board.new
game.play
I marked an answer that worked, and I guess all? was better than my each, but I'm still curious why changing it to all? didn't seem to work.
#spaces.all? { |x| x=="O" || x=="X" }
You cannot put a newline between a method call and its block. That makes Ruby think you're calling the method without a block and defining a Hash.
All elements of #spaces will be "O" or "X" if
(#spaces - ["O", "X"]).empty?
is true.
#spaces = ["O", "X", "X", "O"]
(#spaces - ["O", "X"]).empty?
#=> true
#spaces = ["O", "X", "X", "O", "cat"]
(#spaces - ["O", "X"]).empty?
#=> false
Chain Array#Uniq and Array#Size
Refactor your check into a method which takes an array of box entries (e.g. "X" or "O"), or a variable holding such an array. The method will return true if all letters in the array are the same, because there will only be one unique character. For example:
def check_spaces letters
true if letters.uniq.size == 1
end
check_spaces %w[X X X] #=> true
check_spaces %w[O O O] #=> true
check_spaces %w[O X O] #=> nil
If you do this, you can even assign the result of #check_spaces directly to #winner, like so:
#winner = check_spaces %w[X X X]
#=> true
#winner = check_spaces %w[X O X]
#=> nil
Related
I have written the logic for the program to perform FizzBuzz operations:
fizzbuzz
module FizzBuzz
class Operation
def input
puts 'Enter a number upto which Fizz/Buzz needs to be printed'
num = gets.chomp.to_i
fizzbuzz_function(num)
end
def fizzbuzz_function(num)
for i in 1..num
if i % 3 == 0 && i % 5 == 0
puts 'FizzBuzz'
elsif i % 3 == 0
puts 'Fizz'
elsif i % 5 == 0
puts 'Buzz'
else
puts i
end
end
end
end
res = Operation.new
res.input
end
But I am trying to print the output in form of a table.
Here is FizzBuzz in form of a table:
def fizzbuzz_gen(num)
Enumerator.new do |y|
(1..num).each do |i|
if i % 3 == 0 && i % 5 == 0
y << 'FizzBuzz'
elsif i % 3 == 0
y << 'Fizz'
elsif i % 5 == 0
y << 'Buzz'
else
y << i.to_s
end
end
end
end
def fill_to_width(width, e)
result = ""
future_length = -1
while result.length + future_length < width
result << e.next
result << " "
future_length = e.peek.length
end
result.center(width)
end
def format_table(num)
fb = fizzbuzz_gen(num)
begin
puts fill_to_width(75, fb)
puts fill_to_width(75, fb)
loop do
puts "%10s%s%31s%s" % ["", fill_to_width(12, fb), "", fill_to_width(12, fb)]
end
rescue StopIteration
end
end
format_table(100)
There may be less numbers output than specified, in order for one leg not to be shorter than another.
I have written two functions where in one of the the break if array.length == num statements works, while the other does not. Here are the methods and their tests, starting with the working:
def primes(n)
ret = []
return [] if n < 1
for num in 2..+1.0/0.0
ret << num if prime?(num)
break if ret.count == n
end
ret
end
def prime?(num)
(1..num).select {|x| num % x == 0}.count == 2
end
puts "\nPrimes:\n" + "*" * 15 + "\n"
puts primes(0) == []
puts primes(1) == [2]
puts primes(2) == [2,3]
puts primes(6) == [2,3,5,7,11,13]
I need to turn a string that contains (among other letters) a sequence of 3 letters consisting of a non-vowel, an "o" and the same non-vowel again
into
a string that contains (other letters and) only that non-vowel.
like
"kok" #=> "k"
"mom" #=> "m"
"lol" #=> "l"
"kokmomloljk" #=> "kmljk"
I would like my code to be as compact as possible and only use string methods.
str.each_char { | i | if i == /[^aeiou]/ and i == str[i.index + 2] and str[i.index + 1] == "o"
str = str.delete(str.slice(str[i.index + 1], 2))
end
}
The output is the unchanged string. Thank you in advance.
R = /
([^aeiou]) # match a consonant in capture group 1
o # match an 'o'
\1 # match the contents of capture group 1
/x # free-spacing regex definition mode
def my_method(str)
str.gsub(R,'\1')
end
my_method "my dog kok has fleas"
#=> "my dog k has fleas"
my_method "much momentum"
#=> "much mentum"
my_method "'plolly' is not a word"
#=> "'plly' is not a word"
my_method "abkokcmomloljkde"
#=> "abkcmljkde"
my_method "bub"
#=> "bub"
I was wondering if you could do this in a more functional non-destructieve way with map and, yes you can, but not more compact than the other answers:
str = "iskakmomlol"
VOWEL = /[aeiou]/
RESONANT = /[^aeiou]/
str.chars.map.with_index { |c, i|
prevb, prev, nxt, scnd = str[i - 2], str[i - 1], str[i + 1], str[i + 2]
if i > str.length - 1 || i == 0 then c
elsif c =~ RESONANT && nxt =~ VOWEL && c == scnd then c
elsif c =~ VOWEL && prev =~ RESONANT && nxt =~ RESONANT
elsif c =~ RESONANT && prevb == c && prev =~ VOWEL
else c
end
}.compact.join # "iskmljk"
Actually, this can be shorter:
R = /([^aeiou])[aeiou]\1/
str.chars.map.with_index { |c, i|
c unless str[i-1..i+1][R] || str[i-2..i][R]
}.compact.join # "iskmljk"
i figured since the "o" is a fix character in the sequence to be accepted, i can just go through with a count var and see if the characters next to it are equal to each other and non-vowels. also i found that slice can be also passed two parameters so that it slices starting at an offset and stopping after the given length.
index = 0
while index < str.length
index = index + 1
if str[index] == "o" and str[index-1] == str[index+1] and str[index-1] != /[^aeiou]/
str.slice!(index, 2)
The objective is to move each letter to the next letter in the alphabet,
within the map, it successfully changed the letter but once i'm out of there the value disappears, except the vowels. How come?
def LetterChanges(str)
abc = [*("a".."z")]
result = str.split(//)
result.map! do |x|
if abc.include?(x)
if x == "z"
x = "A"
else
x = abc[abc.index(x)+1]
# if you puts x here, you can see it changes value correctly
if x == "a" || x == "e" || x == "i" || x == "o" || x == "u"
x.capitalize!
end
end
end
#However here, the changed values that are not vowels disappear
# WHY is that happening, is the second if (vowel) affecting it? How?
end
puts "#{result.join}" #<--- its only putting the vowels
return result.join
end
LetterChanges("what the hell is going on?")
The block passed to map! needs to return a value in all cases for this to work.
http://www.ruby-doc.org/core-2.2.0/Array.html#method-i-map-21
def LetterChanges(str)
abc = [*("a".."z")]
result = str.split(//)
result.map! do |x|
if abc.include?(x)
if x == "z"
x = "A"
else
x = abc[abc.index(x)+1]
if x == "a" || x == "e" || x == "i" || x == "o" || x == "u"
x.capitalize!
end
end
end
x
end
result.join
end
The problem is your if. When x is a not a vowel that return nil.
Just Change this line
if x == "a" || x == "e" || x == "i" || x == "o" || x == "u"
x.capitalize!
end
With this
x = %w{a e i o u}.include?(x) ? x.capitalize : x
Is there a better way of handling this in Ruby, while continuing to use the symbols?
pos = :pos1 # can be :pos2, :pos3, etc.
if pos == :pos1 || pos == :pos2 || pos == :pos3
puts 'a'
end
if pos == :pos1 || pos == :pos2
puts 'b'
end
if pos == :pos1
puts 'c'
end
The obvious way would be swapping out the symbols for number constants, but that's not an option.
pos = 3
if pos >= 1
puts 'a'
end
if pos >= 2
puts 'b'
end
if pos >= 3
puts 'c'
end
Thanks.
EDIT
I just figured out that Ruby orders symbols in alpha/num order. This works perfectly.
pos = :pos2 # can be :pos2, :pos3, etc.
if pos >= :pos1
puts 'a'
end
if pos >= :pos2
puts 'b'
end
if pos >= :pos3
puts 'c'
end
Not sure if this is the best way......
I would make use of the include? method from array:
puts 'a' if [:pos1, :pos2, :pos3].include? pos
puts 'b' if [:pos1, :pos2].include? pos
puts 'c' if [:pos1].include? pos
Just use the case statement
pos = :pos1 # can be :pos2, :pos3, etc.
case pos
when :pos1 then %w[a b c]
when :pos2 then %w[a b]
when :pos3 then %w[a]
end.each {|x| puts x }
There are lots of different ways to get your output. Which one you
want depends on your specific objections to your if statements.
I've added a bunch of extra formatting to make the output easier
to read.
If you don't like the logical ORs and how they separate the results
from the output, you can use a lookup table:
puts "Lookup table 1:"
lookup_table1 = {
:pos1 => %w{a b c},
:pos2 => %w{a b },
:pos3 => %w{a },
}
[:pos1, :pos2, :pos3].each { |which|
puts "\t#{which}"
lookup_table1[which].each { |x| puts "\t\t#{x}" }
}
Or, if you want all the "work" in the lookup table:
puts "Lookup table 2:"
lookup_table2 = {
:pos1 => lambda do %w{a b c}.each { |x| puts "\t\t#{x}" } end,
:pos2 => lambda do %w{a b }.each { |x| puts "\t\t#{x}" } end,
:pos3 => lambda do %w{a }.each { |x| puts "\t\t#{x}" } end,
}
[:pos1, :pos2, :pos3].each { |which|
puts "\t#{which}"
lookup_table2[which].call
}
If your problem is that symbols aren't ordinals, then you can
ordinalize them by converting them to strings:
puts "Ordinals by .to_s and <="
[:pos1, :pos2, :pos3].each { |which|
puts "\t#{which}"
if which.to_s <= :pos3.to_s
puts "\t\ta"
end
if which.to_s <= :pos2.to_s
puts "\t\tb"
end
if which.to_s <= :pos1.to_s
puts "\t\tc"
end
}
Or you could monkey patch a comparison operator into the Symbol
class (not recommended):
puts "Ordinals by Symbol#<="
class Symbol
def <= (x)
self.to_s <= x.to_s
end
end
[:pos1, :pos2, :pos3].each { |which|
puts "\t#{which}"
if which <= :pos3
puts "\t\ta"
end
if which <= :pos2
puts "\t\tb"
end
if which <= :pos1
puts "\t\tc"
end
}
Or you could use a lookup table to supply your ordinal values:
puts "Ordinals through a lookup table:"
ordinal = {
:pos1 => 1,
:pos2 => 2,
:pos3 => 3,
}
[:pos1, :pos2, :pos3].each { |which|
puts "\t#{which}"
if ordinal[which] <= 3
puts "\t\ta"
end
if ordinal[which] <= 2
puts "\t\tb"
end
if ordinal[which] <= 1
puts "\t\tc"
end
}
Those are the obvious ones off the top of my head. It is hard to say what would be best without more specifics on what your problem with your if approach is; your second example indicates that what you really want is a way to make symbols into ordinals.
More generically, you can use this:
pos = :pos3
arr = [:pos1,:pos2,:pos3]
curr = 'a'
idx = arr.length
while idx > 0
puts curr if arr.last(idx).include? pos
curr = curr.next
idx -= 1
end
Or this, for your specific example:
puts 'a'
puts 'b' if pos != :pos3
puts 'c' if pos == :pos1