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

Resources