Posted: Fri Aug 05, 2005 7:19 pm Post subject: 2D Arrays
I'm having difficulty working with 2D arrays in Ruby.
Ruby:
grid = [5, 5]#I'm just guessing at the syntax here 5.timesdo |j|
5.timesdo |k|
grid [j, k] = j * k
end
end
=> 5
grid.display 0481216=>nil
grid [0, 4]
=> [0, 4, 8, 12]
grid [4, 0]
=> []
Would someone kindly shed some light on what is going on here, and how to use 2D arrays properly?
Thanks
Sponsor Sponsor
wtd
Posted: Fri Aug 05, 2005 7:38 pm Post subject: (No subject)
There's no such thing as a two dimensional array in Ruby. An array can hold any kind of object, including other arrays, so you just have an array of arrays.
code:
grid = Array.new(5) do | j |
Array.new(5) do | k |
j * k
end
end
I think that does what you want.
Then to access, (3, 2):
code:
puts grid[3][2]
Cervantes
Posted: Fri Aug 05, 2005 7:44 pm Post subject: (No subject)
Intriguing Thanks wtd! That works just fine.
wtd
Posted: Fri Aug 05, 2005 10:34 pm Post subject: (No subject)
Embrace the power of blocks.
wtd
Posted: Fri Aug 05, 2005 10:40 pm Post subject: (No subject)
Or in "I hate whitespace" mode...
code:
grid=Array.new(5){|j|Array.new(5){|k|j*k}}
Cervantes
Posted: Sat Aug 06, 2005 7:01 am Post subject: (No subject)
Using my newfound knowledge of the make-shift 2D array, I tried to convert the N-Queen's solver into Ruby. I failed:
Ruby:
class NQueensSolver
def initialize
@N = 3
@solutions = 0
@grid = Array.new(@N)do |x|
Array.new(@N)do |y|
false end end end
def display
@N.timesdo |x|
@N.timesdo |y|
if @grid [x][y] print"1" else print"0" end end puts"" end end
def clearSpot (x, y)
@N.timesdo |i|
if @grid[i][y] == true returnfalse elsif x + i <= @N - 1and y + i <= @N - 1and @grid[x + i][ y + i] returnfalse elsif x - i >= 0and y + i <= @N - 1and @grid[x - i][ y + i] returnfalse elsif x + i <= @N - 1and y - i >= 0and @grid[x + i][ y - i] returnfalse elsif x - i >= 0and y - i >= 0and @grid[x - i][ y - i] returnfalse end end returntrue end
def displaySolutions
"Number of solutions found on a #{@N} by #{@N} grid: #{@solutions}" end
def solve(col) if col >= @N - 1 return0 endif
@N.timesdo |i|
if clearSpot(col, i) == true
@grid[col][i] = true if col == @N
@solutions += 1 end end
solve(col + 1)
@grid[col][i] = false end end
end
puts NQueensSolver.new.solve(0).displaySolutions
When run, this program says:
Quote:
n_queens.rb:52in 'solve': stack level too deep (SystemStackError)
Then if goes through "from this method, from that method" a lot of times, then it says 1038 levels later, and lists the last three methods that it traced.
I can't understand why this isn't working, especially since I've got @N set to a measily 3! A 3x3 grid should be very simple to solve. I've lifted this code from zylum's NQueen's solver in Turing, which does work. Here's his code:
const N :=8 const gridSize :=maxxdiv(N + 2) var grid :array1.. N, 1.. N ofboolean var solutions :int:=0 colorback(grey)
fcn clearSpot (i, j :int):boolean for k :1.. N
if grid (k, j)then resultfalse elsif i + k <= N and j + k <= N and grid (i + k, j + k)then resultfalse elsif i - k > 0and j - k > 0and grid (i - k, j - k)then resultfalse elsif i + k <= N and j - k > 0and grid (i + k, j - k)then resultfalse elsif i - k > 0and j + k <= N and grid (i - k, j + k)then resultfalse endif endfor resulttrue end clearSpot
proc drawGrid
drawfillbox(0, 0, maxx, maxy, grey) for i :1.. N
for j :1.. N
if grid (i, j)then drawfillbox(i * gridSize, j * gridSize, i * gridSize + gridSize, j * gridSize + gridSize, black) else drawfillbox(i * gridSize, j * gridSize, i * gridSize + gridSize, j * gridSize + gridSize, white) endif drawbox(i * gridSize, j * gridSize, i * gridSize + gridSize, j * gridSize + gridSize, black) endfor endfor end drawGrid
proc Solve (col :int) if col > N then return endif for i :1.. N
if clearSpot (col, i)then
grid (col, i):=true if col = N then
solutions +=1 %/* <- take out '%' to comment this block (may need to hit F2)
drawGrid
put"SOLUTION!!! (", solutions, ")" View.Update cls Input.Pause %*/ endif %/* <- take out '%' to comment this block (may need to hit F2) cls
drawGrid
View.Update delay(250) %*/
Solve (col + 1)
grid (col, i):=false endif endfor end Solve
for i :1.. N
for j :1.. N
grid (i, j):=false endfor endfor
Also, are there any other ways I can shorten/simplify my program? I was wondering about this bit:
Ruby:
if @grid [x][y] print"1" else print"0" end
Since if statements can return a value, I was looking to do something like this:
Ruby:
print if @grid [x][y] "1" else "0" end
But that is printing "nil" instead of 1's and 0's.
Once again, thanks in advance!
zylum
Posted: Sat Aug 06, 2005 7:21 am Post subject: (No subject)
one mistake i see:
code:
def solve(col)
if col >= @N - 1
return 0
end if
@N.times do |i|
if clearSpot(col, i) == true
@grid[col] [i] = true
if col == @N
@solutions += 1
end
end
solve(col + 1)
@grid[col][i] = false
end
end
you should not call solve(col + 1) unless you have successfully placed a peice in the current column. it should be:
code:
def solve(col)
if col >= @N - 1
return 0
end if
@N.times do |i|
if clearSpot(col, i) == true
@grid[col] [i] = true
if col == @N
@solutions += 1
end
solve(col + 1)
@grid[col][i] = false
end
end
end
also, there are no solutions for 3x3 board, so that may cause some issues as well although i doubt it.
Cervantes
Posted: Sat Aug 06, 2005 10:47 am Post subject: (No subject)
Thanks for pointing that out zylum. Unfortunately, I've still got some problems, though that fixes the stack overflow.
The next error wrote:
n_queens.rb:33:in 'clearSpot': undefined method '[]' for nil:NilClass (NoMethodError)
Then it lists about 20 levels of methods.
I don't understand where the nil is coming in. If I have an array
Ruby:
my_arr = Array.new(5){ |j| j }
then calling
Ruby:
my_arr [6]
yields nil. But I don't see why I should be encountering nil, because my checks should be within the bounds of the array. Right now I've switched from using "and" to "&&". Is "&&" similar to as it is in Java? That is, if an if statement is set up like this
code:
if condition1 && condition2
and condition1 fails, will condition2 even be checked? I hope not.
Thoughts? Thanks once again.
Sponsor Sponsor
wtd
Posted: Sat Aug 06, 2005 2:30 pm Post subject: (No subject)
Ruby's arrays are indexed starting at zero, not one.
Cervantes
Posted: Sat Aug 06, 2005 3:48 pm Post subject: (No subject)
I know. That's why you see a bunch of minus one after @N in my code. That's also why I start the solve at column 0, and why I check if x - i or y - i is >= 0, not 1. Aah, I just discovered I forgot to subtract one from @N in my check for victory. That doesn't make any difference though. That just changes the number of solutions found, which, so far, has been none.
wtd
Posted: Sat Aug 06, 2005 4:25 pm Post subject: (No subject)
Can you please post your current code, exactly as you're using it?
Cervantes
Posted: Sat Aug 06, 2005 5:04 pm Post subject: (No subject)
Sure.
Ruby:
class NQueensSolver
def initialize
@N = 4
@solutions = 0
@grid = Array.new(@N)do |x|
Array.new(@N)do |y|
false end end end
def display
@N.timesdo |x|
@N.timesdo |y|
print @output =
if @grid [x][y] "1" else "0" end end puts"" end end
def clearSpot (x, y)
@N.timesdo |i|
if @grid[i][y] returnfalse elsif x + i <= @N - 1 && y + i <= @N - 1 && @grid[x + i][ y + i] returnfalse elsif x - i >= 0 && y + i <= @N - 1 && @grid[x - i][ y + i] returnfalse elsif x + i <= @N - 1 && y - i >= 0 && @grid[x + i][ y - i] returnfalse elsif x - i >= 0 && y - i >= 0 && @grid[x - i][ y - i] returnfalse end end returntrue end
def displaySolutions
"Number of solutions found on a #{@N} by #{@N} grid: #{@solutions}" end
def solve(col) if col >= @N - 1 return0 endif
@N.timesdo |i|
if clearSpot(col, i)
@grid[col][i] = true if col == @N - 1
@solutions += 1 end
solve(col + 1)
@grid[col][i] = false end end end
end
NQueensSolver.new.solve(0).displaySolutions
wtd
Posted: Sat Aug 06, 2005 5:39 pm Post subject: (No subject)
code:
elsif x - i >= 0 && y + i <= @N - 1 && @grid[x - i] [ y + i]
Something's happening here. I don't think your bounds checking is sufficient, though my head hurts too much right now to rewrite it.
Cervantes
Posted: Sat Aug 06, 2005 7:07 pm Post subject: (No subject)
I just did a check and the && works as in Java. If the first condition is false then the second condition will not be checked. Since this rules the possibility of checking outside the grid's bounds, I'm stunped as well.
wtd
Posted: Sat Aug 06, 2005 7:27 pm Post subject: (No subject)
Are you certain? In each of those checks it looks like you're only checking one boundary. For instance: