Reputation: 25
I know macros are not possible in Ruby, however, I've run into a situation where I don't know of a workaround.
I have two methods (and I may have more) that are almost identical, and differ only in a couple variable names. Specifically, I swapped the |n|
and |m|
in the outer and inner upto
loops.
def self.check_across
0.upto(4) do |n|
test = 0
0.upto(4) { |m| if @@bingo_board[n][m] == "X" then test += 1 end }
if test == 5 then return true end
end
return false
end
def self.check_down
0.upto(4) do |m|
test = 0
0.upto(4) { |n| if @@bingo_board[n][m] == "X" then test += 1 end }
if test == 5 then return true end
end
return false
end
In the first method I'm checking a 5x5 bingo board for a complete row of "X" values across, and the second method checks for a complete column of "X" values.
I know that in SAS you can just wrap this method in a %macro
(if you know what I mean). In Ruby, I know this doesn't work, but what I'm TRYING to do is this:
def self.check(x, y)
0.upto(4) do |x|
test = 0
0.upto(4) { |y| if @@bingo_board[n][m] == "X" then test += 1 end }
if test == 5 then return true end
end
return false
end
example.check(n, m) # same as .check_across
example.check(m, n) # same as .check_down
Of course, this doesn't work since n
and m
would be treated as variable names that exist outside of the method.
Upvotes: 0
Views: 249
Reputation: 160551
You might want to try this untested code:
def self.check_across
@@bingo_board.each do |n|
return true if n.all?{ |m| m == 'X' }
end
false
end
def self.check_down
@@bingo_board.transpose.each do |m|
return true if m.all?{ |n| n == 'X' }
end
false
end
transpose
is a nice method that is useful for this sort of problem. all?
makes it easy to see if all elements in an array are the same, and returns true if it does.
It looks like those can be DRY'd to:
def self.check_across
@@bingo_board.any?{ |n|
n.all?{ |m| m == 'X' }
}
end
def self.check_down
@@bingo_board.transpose.any?{ |m|
m.all?{ |n| n == 'X' }
}
end
any?
is useful to find whether any element matches a condition and returns true. In this case it's whether a row or column is all 'X'.
Upvotes: 1
Reputation: 4982
You can use a block to accomplish something similar.
For example,
def check
0.upto(4) do |i|
test = 0
0.upto(4) do |j|
# hand control of how to deal with indices over to the calling method
if yield(i,j) == 'X'
test += 1
end
end
return true if test == 5
end
false
end
def check_across(board)
check do |i,j|
# implementing logic for accessing rows
board[i][j]
end
end
def check_down(board)
check do |i,j|
# implementing logic for accessing columns
board[j][i]
end
end
And a quick sanity check:
a = [
%w(O O O O O),
%w(O O O O O),
%w(O O O O O),
%w(O O O O O),
%w(O O O O O)
]
b = [
%w(O O O O O),
%w(O O O O O),
%w(X X X X X),
%w(O O O O O),
%w(O O O O O)
]
c = [
%w(O O O X O),
%w(O O O X O),
%w(O O O X O),
%w(O O O X O),
%w(O O O X O)
]
check_across(a) #=> false
check_across(b) #=> true
check_across(c) #=> false
check_down(a) #=> false
check_down(b) #=> false
check_down(c) #=> true
Upvotes: 2