Ruby - How to populate a 2d array? - ruby

I have this rspec test:
it 'has a populated chessboard' do
expect(ChessBoard.new.populate_new_board).to eq [
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn']]
end
For this code:
class ChessBoard
def initialize
#board=Array.new(7){Array.new(7)}
end
def populate_new_board
(0..7).each do |row|
(0..7).each do |cell|
#board[row][cell]='pawn'
end
end
#board
end
end
but I'm getting:
1) least number of moves from x to y has a populated chessboard
Failure/Error: expect(ChessBoard.new.populate_new_board).to eq [
NoMethodError:
undefined method `[]=' for nil:NilClass
# ./code.rb:10:in `block (2 levels) in populate_new_board'
# ./code.rb:9:in `each'
# ./code.rb:9:in `block in populate_new_board'
# ./code.rb:8:in `each'
# ./code.rb:8:in `populate_new_board'
# ./code_spec.rb:12:in `block (2 levels) in <top (required)>'
how can I fix this?
btw pawns in every space is not the final result but it's what I want for this test right now (then I can modify it further).

class ChessBoard
def populate_new_board
#board = [['pawn'] * 7] * 7
end
end

Change it to:
def populate_new_board
(0...7).each do |row|
(0...7).each do |cell|
#board[row][cell]='pawn'
end
end
#board
end

As it was denoted that you did a mistake in range, but a strongly advice you to reduce usage of index ranges. You can use :each, and :map methods instead:
class ChessBoard
def initialize
#board = Array.new( 7 ){ Array.new( 7 ) }
end
def populate_new_board
#board.each {| row | row.map! {| _ | 'pawn' } }
end
end
But I'd use more the simple code:
class ChessBoard
def populate_new_board
#board = Array.new( 7 ){Array.new( 7 ) { 'pawn' } }
end
end

Related

How to wrap a method that yields in Ruby 1.9

I have a method that prints out a numbered list, yielding to a code block to print a prefix.
arr = %w(a b c)
def print_lines(array)
array.each_with_index do |item, index|
prefix = yield index
puts "#{prefix} #{item}"
end
end
print_lines(arr) do |index|
"(#{index})"
end
This produces the following output:
(0) a
(1) b
(2) c
Now I want to wrap print_lines in another method and call it.
def print_lines_wrapped(array)
puts 'print_lines_wrapped'
print_lines(array)
end
print_lines_wrapped(arr) do |index|
"(#{index})"
end
However, this gives me a LocalJumpError
test_yield.rb:5:in `block in print_lines': no block given (yield) (LocalJumpError)
from test_yield.rb:4:in `each'
from test_yield.rb:4:in `each_with_index'
from test_yield.rb:4:in `print_lines'
from test_yield.rb:16:in `print_lines_wrapped'
from test_yield.rb:19:in `<main>'
Why do I get a LocalJumpError?
How can I implement print_lines_wrapped such that I can call it like this:
print_lines_wrapped(arr) do |index|
"(#{index})"
end
and get the following output:
print_lines_wrapped
(0) a
(1) b
(2) c
?
Your wrapper method also has to accept a block and pass it to the wrapped method. There is no implicit passing of the block:
def print_lines_wrapped(array, &block)
puts 'print_lines_wrapped'
print_lines(array, &block)
end
Example:
def asdf(&block) puts yield(2) end
def qwer(&block)
puts "I am going to call asdf"
asdf &block
end
asdf { |x| x * 3 }
6
=> nil
qwer { |x| x * 5 }
I am going to call asdf
10
=> nil
The & operator converts its operand into a block if possible
qwer &Proc.new { |x| x * 2 }
I am going to call asdf
4

How to implement Ruby utility class methods?

Need help implementing Ruby utility class methods to get this test to pass. Can someone break this down for me please?
My Code
class Temperature
class << self
def from_fahrenheit temp
Temperature.new({f: temp})
end
def from_celsius temp
Temperature.new({c: temp})
end
end
def initialize(options={})
#f = options[:f]
#c = options[:c]
end
def in_fahrenheit
return #f if #f
(#c * (9.0 / 5.0)) + 32
end
def in_celsius
return #c if #c
(#f - 32) * 5.0 / 9.0
end
end
class Celsius < Temperature
def initialize temp
#temp = temp
end
end
class Fahrenheit < Temperature
def initialize temp
#temp = temp
end
end
Failures:
1) Temperature Temperature subclasses Celsius subclass is constructed in degrees celsius
Failure/Error: (#f - 32) * 5.0 / 9.0
NoMethodError:
undefined method `-' for nil:NilClass
# ./ct.rb:1118:in `in_celsius'
# ./ct.rb:1219:in `block (4 levels) in <top (required)>'
2) Temperature Temperature subclasses Fahrenheit subclass is constructed in degrees fahrenheit
Failure/Error: (#c * (9.0 / 5.0)) + 32
NoMethodError:
undefined method `*' for nil:NilClass
# ./ct.rb:1113:in `in_fahrenheit'
# ./ct.rb:1230:in `block (4 levels) in <top (required)>'
Rspec Test
describe "utility class methods" do
end
# Here's another way to solve the problem!
describe "Temperature subclasses" do
describe "Celsius subclass" do
it "is constructed in degrees celsius" do
Celsius.new(50).in_celsius.should == 50
Celsius.new(50).in_fahrenheit.should == 122
end
it "is a Temperature subclass" do
Celsius.new(0).should be_a(Temperature)
end
end
describe "Fahrenheit subclass" do
it "is constructed in degrees fahrenheit" do
Fahrenheit.new(50).in_fahrenheit.should == 50
Fahrenheit.new(50).in_celsius.should == 10
end
it "is a Temperature subclass" do
Fahrenheit.new(0).should be_a(Temperature)
end
end
end
end
You aren't using the Temperature class how you defined it. You take an options hash with :f and :c keys in it in the Temperature class, but don't set those in your sub-classes.
Try this:
class Celsius < Temperature
def initialize temp
super(c: temp)
end
end
class Fahrenheit < Temperature
def initialize temp
super(f: temp)
end
end
Is this for an exercise or something? It's an ... interesting design.

Ruby undefined method `each'

i can't figure out what's wrong with my code, can you help me please?
this is constructor of my class:
def initialize(hash_table_size)
#size = hash_table_size
#table = Array.new(hash_table_size) { LinkedList.new }
end
this is method in that class:
def to_a
arr = Array.new
#table.each { |list| list.each { |o| arr << o } }
arr
end
this is my "each" method in LinkedList class:
def each
if #length > 0
item = #head
begin
yield item.object
item = item.next
end until item.nil?
end
end
and this is what i get from unittest:
1) Error:
test_initial_size_3(HashSetTest):
NoMethodError: undefined method `each' for 3:Fixnum
C:/Users/Ajax/My Documents/Aptana Studio 3 Workspace/alg_du1_jan_svec/hash_set.rb:34:in `block in to_a'
C:/Users/Ajax/My Documents/Aptana Studio 3 Workspace/alg_du1_jan_svec/hash_set.rb:34:in `each'
C:/Users/Ajax/My Documents/Aptana Studio 3 Workspace/alg_du1_jan_svec/hash_set.rb:34:in `to_a'
C:/Users/Ajax/My Documents/Aptana Studio 3 Workspace/alg_du1_jan_svec/hash_set_test.rb:14:in `test_initial_size_3'
1 tests, 3 assertions, 0 failures, 1 errors, 0 skips
It means that LinkedList.new in the method initialize is returning 3, which becomes an element of #table, and is substituted into the block variable list of the method to_a.

Error no block given when used yield inside a block

I'm getting this error
LocalJumpError: no block given (yield)
from fops.rb:52:in `block (2 levels) in gen_list'
from /home/phanindra/.gem/ruby/1.9.1/gems/mp3info-0.6.18/lib/mp3info.rb:306:in `open'
from fops.rb:51:in `block in gen_list'
from fops.rb:46:in `each'
from fops.rb:46:in `gen_list'
from fops.rb:48:in `block in gen_list'
from fops.rb:46:in `each'
from fops.rb:46:in `gen_list'
from fops.rb:48:in `block in gen_list'
from fops.rb:46:in `each'
from fops.rb:46:in `gen_list'
from fops.rb:48:in `block in gen_list'
from fops.rb:46:in `each'
from fops.rb:46:in `gen_list'
from (irb):2
from /usr/bin/irb:12:in `<main>
when used yield inside another block which is inside a begin statement which is inside a if statement,
for a simple understanding here is the prototype
def test
if 1 then
begin
test2(5) do |x|
yield x
end
rescue
end
end
end
def test2(n)
n.times do |k|
yield k
end
end
test() do |y|
puts y
end
The problem is there is no error with the prototype, it worked fine so I dont understand why I'm getting this error, here is my actual code
require "mp3info"
module MusicTab
module FOps
def self.gen_list(dir)
prev_pwd=Dir.pwd
begin
Dir.chdir(dir)
rescue Errno::EACCES
end
Dir[Dir.pwd+'/*'].each{|x|
if File.directory?(x) then
self.gen_list(x)
else
begin
Mp3Info.open(x) do |y|
yield "#{y.tag.title},#{y.tag.album},#{y.tag.artist},#{x}"
end
rescue Mp3InfoError
end
end
}
Dir.chdir(prev_pwd)
end
end
end
I was testing this code using irb
[phanindra#pahnin musictab]$ irb
irb(main):001:0> load 'fops.rb'
/usr/share/rubygems/rubygems/custom_require.rb:36:in `require': iconv will be deprecated in the future, use String#encode instead.
=> true
irb(main):002:0> MusicTab::FOps.gen_list('/fun/Music') do |l|
irb(main):003:1* puts l
irb(main):004:1> end
Any help?
regards
The problem is that you are calling gen_list recursively and at the call site for the recursive descent there really is no block.
What you can do is either:
capture the block as a proc with a & parameter and then forward it, or
add a block that does another yield to the recursive call
So...
def f1 x, &block
block.call(x)
if x > 0
f1 x - 1, &block
end
end
# ...or...
def f2 x
yield x
if x > 0
f2 x - 1 do |y|
yield y
end
end
end
f1 2 do |q|
p ['b1', q]
end
f2 2 do |q|
p ['b2', q]
end

Recursive lambdas in Ruby

I have the following code which correctly generates all possible trees of size num:
class Tree
attr_accessor :left, :right
def initialize left = nil, right = nil
#left = left
#right = right
end
# Don't ever specify any arguments, it will make me very angry.
# Tilt your head 90 degrees to the side to see the tree when viewing.
def print level = 0
#right.pretty_print(level + 1) if #right
puts (' ' * level) + to_s
#left.pretty_print(level + 1) if #left
end
def self.generate num
trees = []
generate_subtrees(num) { |tree| trees << tree } if num > 0
trees
end
private
def self.generate_subtrees num, &block
if num == 0
yield nil
else
(1..num).each do |root_position|
generate_subtrees(root_position - 1) do |left|
generate_subtrees(num - root_position) do |right|
yield Tree.new nil, left, right
end
end
end
end
end
end
I’m trying to (for the sake of it) “condense” this into one method, utilizing lambda recursion. My current attempt (of several iterations) is below:
def self.generate num
trees = []
gen = ->(num, &block) do
if num == 0
yield nil # L61
else
(1..num).each do |root_position| # L63
gen.call(root_position - 1) do |left| # L64
gen.call(num - root_position) do |right|
block.call { Tree.new nil, left, right }
end
end
end
end
end
gen.call(num) { |tree| trees << tree } # L73
trees
end
This results in the error (referenced lines noted above):
LocalJumpError: no block given (yield)
from tree.rb:61:in `block in generate'
from tree.rb:64:in `call'
from tree.rb:64:in `block (2 levels) in generate'
from tree.rb:63:in `each'
from tree.rb:63:in `block in generate'
from tree.rb:73:in `call'
from tree.rb:73:in `generate'
from (irb):4
from /Users/amarshall/.rbenv/versions/1.9.2-p290/bin/irb:12:in `<main>'
What am I doing wrong? Alternative solutions to this mostly academic problem are also welcome.
The yield keyword does not work from inside a lambda. The alternative is to use &block, in the same way that you are already doing on line 64 and 65:
gen = ->(num, &block) do
if num == 0
block.call(nil)
else
# ...
end
gen.call(num) { |tree| trees << tree }

Resources