Changing elements in multi-dimensional array - ruby
Inside arrays, I have 0s and one 1.
class Image
def initialize(rows)
#rows = rows
end
end
image = Image.new([
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
])
I want the numbers that are located up, down, left, and right to turn 1 as well. I tried to do this by manipulating column_index and row_index. The code is:
class Image
def blur
#rows_copy = Array.new(#rows.size) {Array.new(#rows.first.size)}
#rows.each_with_index do |row, row_index|
row.each_with_index do |cell, column_index|
blur_location(row_index,column_index)
end
end
#rows = #rows_copy
end
def blur_location (row_index, column_index)
if #rows[row_index][column_index] == 1
#rows_copy[row_index][column_index] = 1
#rows_copy[row_index + 1][column_index] = 1
#rows_copy[row_index - 1][column_index] = 1
#rows_copy[row_index][column_index + 1] = 1
#rows_copy[row_index][column_index - 1] = 1
else
#rows_copy[row_index][column_index] = 0
end
end
def output_image
#rows.each_with_index do |row, row_index|
puts row.join('')
end
end
end
image.blur
image.output_image
But only half of the code is working (i.e., the top and left turns to 1, but not the other two).
the code almost works as expected but you are a victim of the following piece of code:
else
#rows_copy[row_index][column_index] = 0
end
What happens is the when you hit the '1' you set everything as expected, but when you move on and you hit the zeros that are near the '1' (to the right and down as you're processing) you are resetting the rows_copy to zero.
Here is a revised version of the code the does the right thing (notice how the copy is all first set to 0 and after that only 1s are marked):
#!/usr/bin/env ruby
class Image
def initialize(rows)
#rows = rows
end
def blur
#rows_copy = Array.new(#rows.size) {Array.new(#rows.first.size)}
#rows.each_with_index do |row, row_index|
row.each_with_index do |cell, column_index|
set_zero(row_index,column_index)
end
end
#rows.each_with_index do |row, row_index|
row.each_with_index do |cell, column_index|
blur_location(row_index,column_index)
end
end
#rows = #rows_copy
end
def set_zero(row_index, column_index)
#rows_copy[row_index][column_index] = 0
end
def blur_location (row_index, column_index)
if #rows[row_index][column_index] == 1
#rows_copy[row_index][column_index] = 1
#rows_copy[row_index + 1][column_index] = 1
#rows_copy[row_index - 1][column_index] = 1
#rows_copy[row_index][column_index + 1] = 1
#rows_copy[row_index][column_index - 1] = 1
end
end
def output_image
#rows.each_with_index do |row, row_index|
puts row.join('')
end
end
end
image = Image.new([
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
])
image.blur
image.output_image
Related
Prepare the Bunnies Escape - Foobar
I've been at this for a while and for the life of me I cannot figure out why I cannot pass test cases 4 and 5. My code is below, including my own custom test cases that all execute and pass in under 5ms. Basically I added a third dimension to each node's position that represents whether a wall has already been traversed or not. When analyzing each current node's neighbor, if it's a wall and the current node has a zero for its third coordinate, then moving to the wall and to a 1 on the third coordinate becomes an option. On paper, it works great. In my own IDE, it works great. I'm starting to wonder if there's something in here that's Python 3 and not working correctly in foobar or something. I'd appreciate any help. class Node(): def __init__(self, position): self.position = position self.gCost = 1 self.hCost = 0 self.fCost = 0 def __eq__(self, other): return self.position == other.position def solution(map): startNode = Node((0, 0, 0)) endNode = Node((len(map[0]) - 1, len(map) - 1, 0)) openList = [startNode] closedList = [] while openList: currentNode = openList[0] currentIndex = 0 for i in range(len(openList)): if openList[i].fCost < currentNode.fCost: currentNode = openList[i] currentIndex = i openList.pop(currentIndex) closedList.append(currentNode) if currentNode.position[0] == endNode.position[0] and currentNode.position[1] == endNode.position[1]: return currentNode.gCost for offset in [(1, 0), (-1, 0), (0, 1), (0, -1)]: neighborPosition = (currentNode.position[0] + offset[0], currentNode.position[1] + offset[1], currentNode.position[2]) if neighborPosition[0] < 0 or neighborPosition[0] >= len(map[0]) or neighborPosition[1] < 0 or neighborPosition[1] >= len(map): continue if map[neighborPosition[0]][neighborPosition[1]] == 1: if currentNode.position[2] == 1: continue neighborPosition = (neighborPosition[0], neighborPosition[1], 1) neighbor = Node(neighborPosition) if neighbor in closedList: continue if neighbor in openList: openNodeIndex = openList.index(neighbor) if openList[openNodeIndex].gCost < currentNode.gCost + 1: continue openList.pop(openNodeIndex) openList.append(neighbor) else: openList.append(neighbor) neighbor.gCost = currentNode.gCost + 1 neighbor.hCost = endNode.position[0] - neighbor.position[0] + endNode.position[1] - neighbor.position[1] neighbor.fCost = neighbor.gCost + neighbor.hCost return -1 import time start = time.time() map1 = [[0, 0, 0, 1], [1, 0, 0, 1], [1, 0, 0, 0], [0, 0, 0, 0]] sol1 = solution(map1) print("Result: ", sol1, "Expected: ", 7) map2 = [[0,1,0,0,0], [0,1,0,1,0], [0,1,0,1,0], [0,1,0,1,0], [0,0,0,1,0]] sol2 = solution(map2) print("Result: ", sol2, "Expected: ", 9) map3 = [[0,0,0,0,0,0,1,0,0,0], [0,0,0,0,1,0,1,0,1,0], [0,0,0,0,1,0,1,0,1,0], [0,0,0,0,1,0,1,0,1,0], [0,0,0,0,1,0,1,0,1,0], [0,0,0,0,1,0,1,0,1,0], [0,0,0,0,1,0,1,0,1,0], [0,0,0,0,1,0,1,0,1,0], [0,0,0,0,1,0,1,0,1,0], [0,0,0,0,1,0,0,0,1,0]] sol3 = solution(map3) print("Result: ", sol3, "Expected: ", 19) map4 = [[0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0]] sol4 = solution(map4) print("Result: ", sol4, "Expected: ", 11) map5 = [[0, 1, 1, 0], [0, 0, 0, 1], [1, 1, 0, 0], [1, 1, 1, 0]] sol5 = solution(map5) print("Result: ", sol5, "Expected: ", 7) map6 = [[0,1,0], [0,1,0], [0,1,0]] sol6 = solution(map6) print("Result: ", sol6, "Expected: ", 5) map7 = [[0,1,1,0,0,0,0,1,0,1,0,0,0,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,0,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0], [0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,0]] sol7 = solution(map7) print("Result: ", sol7, "Expected: ", 123) map8 = [[0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0],[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],[0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0],[0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0],[0,1,0,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1],[0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0],[0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1],[0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0],[0,1,0,1,0,1,0,1,0,0,0,1,1,1,0,1,1,1,1,1],[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0],[1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1],[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0],[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0],[0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0],[0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,1,1,1],[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,1,1,0,0]] sol8 = solution(map8) print("Result: ", sol8, "Expected: ", 89) end = time.time() print("Time: ", end - start) Edit: Quick update - converted the closedList to a set and now it solves my test cases in under 1ms, still fails Google's test cases 4 and 5 though.
So I figured it out. The line if map[neighborPosition[0]][neighborPosition[1]] == 1: had the x and y coordinates backwards. It should have been if map[neighborPosition[1]][neighborPosition[0]] == 1: In cases where the map was not square it was going out of bounds. Just needed to add a test case that wasn't square and figured it out pretty quick from there.
Battlefield game in ruby [closed]
Closed. This question needs details or clarity. It is not currently accepting answers. Want to improve this question? Add details and clarify the problem by editing this post. Closed 4 years ago. Improve this question This is a classic battleship game for two players: #board1 and board2 arrays are boards that players see only dots (not bumped yet), O (not ship part) and X (bumped ship part) board1 = [] board2 = [] #Create the board that players can see through with terminal for i in 0..4 board1.append("O") end for i in 0..4 board2.append("O") end def print_board(board1) for row in board1 puts board1.map { |k| "#{k}" }.join(" ") end end def print_board(board2) for row in board2 puts board2.map { |k| "#{k}" }.join(" ") end end print_board(board1) puts "\n" print_board(board2) #array1 and array2 are obvious boards of player1 and player2 respectly array1 = [ [0, 1, 1, 1, 0], [1, 0, 0, 0, 0], [1, 0, 1, 0, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0] ] array2 = [ [1, 0, 1, 1, 0], [0, 0, 0, 0, 1], [0, 1, 0, 0, 1], [0, 1, 0, 0, 1], [0, 0, 0, 0, 0] ] #Starting of the game and the printing the board while true do puts "Welcome to the game!!!" puts "Do you want to start? (start/reset):" a = gets.chomp if a == 'start' for i in 0..100 puts "Turn - Player1: " puts "Enter row: " q = gets.chomp p1_row = q.to_i puts "Enter coloumn: " w = gets.chomp p1_col= w.to_i if array2[p1_row][p1_col] == 1 array2[p1_row][p1_col] ="X" board2[p1_row][p1_col] ="X" elsif array2[p1_row][p1_col] == 0 array2[p1_row][p1_col] ="-" board2[p1_row][p1_col] ="-" elsif array2[p1_row][p1_col] =="X" or array2[p1_row][p1_col] =="-" next end print_board(board2) puts "Turn - Player2: " puts "Enter row: " e = gets.chomp p2_row = e.to_i puts "Enter coloumn: " r = gets.chomp p2_col= r.to_i if array1[p2_row][p2_col] == 1 array1[p2_row][p2_col] ="X" board1[p2_row][p2_col] ="X" elsif array1[p2_row][p2_col] == 0 array1[p2_row][p2_col] ="-" board1[p2_row][p2_col] ="-" elsif array1[p2_row][p2_col] =="X" or array1[p2_row][p2_col] =="-" next end print_board(board1) end elsif a == 'reset' puts "You are off the game" break else puts "\n" puts "Answer can be only {start} or {reset}" end end I have two problems with this code. When I entered index 4 for player 2, I get "index 4 out of string (IndexError)", but I did not find why. The other problem is that, when if statement finds 1 or 0, it changes all columns, and does not change only the element of the array.
The main problem is in your board set-up. You have for i in 0..4 board1.append("O") end But that only creates one dimension. Try this: for i in 0..4 board1[i] = [] (0..4).each do board1[i].append("O") end end A secondary problem is the subroutine print_board. First, you only need one definition of the subroutine, then second, the map needs to apply to "row" not "board", like this: def print_board(board) for row in board puts row.map { |k| "#{k}" }.join(" ") end end There are many other problems with your code. I assume you are learning Ruby and this is an exercise to learn the Array API. In such case, it will be best for you continue the exercise yourself, learning as you go. However, one additional hint: Learn about rubocop and run it on your code. Doing this consistently will teach you about good Ruby style while also improving your code. To be specific: Install the rubocop gem, then run rubocop against your code like this: rubocop -SEa battleship.rb
How do I get this each loop to apply to every item?
I'm working on a problem called Image Blur. I need to have my code take items (either 1s or 0s) from a 2D array and, for every 1, change the adjacent 0s to 1s. My code thus far does this well to the first 1 that it comes across, but for some reason it does not loop over the others. class Image def initialize(image) #values = image end def find_ones ones = [] #values.each_with_index do |row, row_index| row.each_with_index do |pixel, column_index| if pixel == 1 coord = [row_index, column_index] ones << coord end puts "#{pixel} #{row_index} #{column_index}" if pixel == 1 end end ones end def transform ones = find_ones ri = ones[0][0] ci = ones[0][1] ones.each do #values[ri + 1][ci] = 1 if (ri + 1) <= 3 #values[ri - 1][ci] = 1 if (ri - 1) >= 0 #values[ri][ci + 1] = 1 if (ci + 1) <= 3 #values[ri][ci - 1] = 1 if (ci - 1) >= 0 end end def output_image #values.each do |row| puts row.join end end end image = Image.new([ [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 0, 0] ]) image.transform image.output_image Thanks for the help in advance!
Well your ones.each do goes through the ones but ignores them, since your block doesn't have parameters. You essentially just use ones to determine how often to run the block. Your ri = ones[0][0] ci = ones[0][1] ones.each do should be ones.each do |ri, ci| I'm surprised you got find_ones right (where you do something similar) but do something so strange in transform (setting ri and ci like that).
Multidimestional Array - `initialize': wrong number of arguments (1 for 0)
I'm still new in Ruby on Rails. Today I'm trying to write some codes which can run the the following: image = Image.new([ [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0] ]) image.output_image And I'm having trouble setup the initialize. My codes is as below, can someone help me? Thanks a lot class Subary attr_accessor :num1, :num2, :num3, :num4 def initialize (num1, num2, num3, num4) self.num1 = num1 self.num2 = num2 self.num3 = num3 self.num4 = num4 end def output_subary puts "#{num1}#{num2}#{num3}#{num4}" end end # subary = Subary.new(0,0,0,0) # puts subary.output_subary class Image def initialize #subarys = [] #subarys << Subary.new(:num1, :num2, :num3, :num4) #subarys << Subary.new(:num1, :num2, :num3, :num4) #subarys << Subary.new(:num1, :num2, :num3, :num4) #subarys << Subary.new(:num1, :num2, :num3, :num4) end def output_image #subarys.each do |list| list.output_subary end end end image = Image.new([ [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0] ]) image.output_image
`initialize': wrong number of arguments (1 for 0) This error means that, initialize method does not take any argument (0), but you passed one argument to it. Change the initialize method's definition in your Image class. Then, it should work. class Subary attr_accessor :num1, :num2, :num3, :num4 def initialize(sub_array) self.num1 = sub_array[0] self.num2 = sub_array[1] self.num3 = sub_array[2] self.num4 = sub_array[3] end def output_subary puts "#{num1}#{num2}#{num3}#{num4}" end end # subary = Subary.new(0,0,0,0) # puts subary.output_subary class Image def initialize(array_of_arrays) #subarys = [] #subarys << Subary.new(array_of_arrays[0]) #subarys << Subary.new(array_of_arrays[1]) #subarys << Subary.new(array_of_arrays[2]) #subarys << Subary.new(array_of_arrays[3]) end def output_image #subarys.each do |list| list.output_subary end end end image = Image.new([ [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0] ]) image.output_image # => 0000 # => 0100 # => 0001 # => 0000
Nested if else inside .each iteration
I'm wondering if this makes sense or if the syntax is wrong and basically if this is acceptable. I wanted to nest an if/else condition within my iteration of the array. def change_numbers(first_array, second_array) second_array.each do |index| if first_array[index] == 0 first_array[index] = 1 else first_array[index] = 0 end end end The array is a simple (binary) array and will only consist of 0s and 1s and I want to use the second array's elements as the indices of the first array that I am going to change. Example: first_array = [0, 0, 0, 0, 1, 1, 1, 1, 1] second_array = [3, 5, 7] Result: first_array = [0, 0, 0, 1, 1, 0, 1, 0, 1]
If you don't want to use an if/else you can do: second_array.each do |index| first_array[index] = (first_array[index] + 1) % 2 end
def change_numbers(first_array, second_array) second_array.each { |index| first_array[index] = 1 - first_array[index] } end
A bit-wise XOR: ar = [0, 0, 0, 0, 1, 1, 1, 1, 1] indices = [3, 5, 7] indices.each{|i| ar[i] ^= 1 }
You can try this - def change_numbers(first_array, second_array) second_array.each do |index| first_array[index] = ((first_array[index] == 0) ? 1 : 0) end end