ruby packing variables and monkey patching - ruby

Okay so this is the code:
class Board
attr_reader :size
def initialize n
#grid = Array.new(n) {Array.new(n,:N)}
#size = n * n
end
def [] position
row, col = position
#grid[row][col]
end
def []= position, val
row, col = position
#grid[row][col] = val
end
def num_ships
#grid.flatten.count(:S)
end
def attack position
if self[position] == :S
self[position] = :H
puts "you sunk my battleship"
return true
else
self[position] = :X
return false
end
end
def place_random_ships
max_ships = #size * 0.25
while self.num_ships < max_ships
row = rand(0...#grid.length)
col = rand(0...#grid.length)
position = [row,col]
self[position] = :S
end
end
end
But,
def place_random_ships
max_ships = #size * 0.25
while self.num_ships < max_ships
row = rand(0...#grid.length)
col = rand(0...#grid.length)
position = [row,col]
self[position] = :S
end
end
this works, and does what it's suppose to, but when I avoid packing [row,col] and add it directly it does not work.
def place_random_ships
max_ships = #size * 0.25
while self.num_ships < max_ships
row = rand(0...#grid.length)
col = rand(0...#grid.length)
self[row,col] = :S
end
end
I'm still new to programming, so please try to explain the issue to where I can understand it, or tell me the problem, so I can google it to get a better understanding please.

The issue is that you defined []= to take 2 argument, and array and a value.
def []= position, val
row, col = position
#grid[row][col] = val
end
With your current implementation you would need to call it like this
foo[[row,col]] = :S
What you might want to to is define []= like this:
def []= row, col, val
#grid[row][col] = val
end
then when you want to pass the array position you can use the array spread operator. With this implementation both of these calls will work.
position = [1,2]
foo[1,2] = :S
foo[*position] = :S
if you do that you probably would want to define [] the same way.
def [] row,col
#grid[row][col]
end

Related

Creating sort visualiser in Ruby

I'm trying to make a sort visualiser using Ruby and Gosu. When the user left clicks it will sort the numbers out using a insertion sort. When the user right clicks it will sort the numbers out using a bubble sort. So far the only the insertion sort works but the bubble sort crashes after sorting out the first number. Does anyone know why? Thanks.
require 'gosu'
module ZOrder
BACKGROUND, MIDDLE, TOP = *0..2
end
SCREEN_WIDTH = 600 # needs to be COUNT * COLUMN_WIDTH
SCREEN_HEIGHT = 200 # Should be multiple of 100
MAX_VALUE = 100 # the range of the data 1 to 100
COUNT = 30 # Number of items
COL_WIDTH = 20 # suggested at least 10
class Column
# have a pointer to the neighbouring cells
attr_accessor :height, :value
def initialize(value)
#value = value
#height = (SCREEN_HEIGHT/MAX_VALUE) * value
end
end
class GameWindow < Gosu::Window
def initialize
super SCREEN_WIDTH, SCREEN_HEIGHT, false
self.caption = "Sort Visualiser"
#path = nil
#do_insert = false
#do_bubble = false
#columns = Array.new(COUNT)
column_index = 0
while (column_index < COUNT)
col = Column.new(rand(MAX_VALUE + 1))
#columns[column_index] = col
column_index += 1
end
#text_font = Gosu::Font.new(10)
end
def needs_cursor?
true
end
def insertion_sort(loop)
j = loop
done = false
while ((j > 0) and (!done))
if (#columns[j].value < #columns[j - 1].value)
temp = #columns[j - 1]
#columns[j - 1] = #columns[j]
#columns[j] = temp
else
done = true
end
j = j - 1
end
end
def bubble_sort(loop2)
j = loop2
i = loop2 + 1
done = false
while ((j > 0) and (!done))
if (#columns[j].value > #columns[i].value)
temp = #columns[j]
#columns[j] = #columns[i]
#columns[i] = temp
else
done = true
end
j = j - 1
end
end
def button_down(id)
case id
when Gosu::MsLeft
#do_insert = true
#loop = 0
#do_bubble = false
when Gosu::MsRight
#do_bubble = true
#loop2 = 0
#do_insert = false
end
end
def update
if (#do_insert)
puts "Doing insert #{#loop}"
if #loop < (COUNT)
insertion_sort(#loop)
#loop += 1
sleep(0.5)
else
#do_insert = false
end
end
if (#do_bubble)
puts "Doing bubble #{#loop2}"
if #loop2 < (COUNT)
bubble_sort(#loop2)
#loop2 += 1
sleep(0.5)
else
#do_bubble = false
end
end
end
def draw
column_index = 0
while (column_index < #columns.length)
color = Gosu::Color::GREEN
Gosu.draw_rect((column_index * COL_WIDTH), SCREEN_HEIGHT - #columns[column_index].height, COL_WIDTH, #columns[column_index].height, color, ZOrder::MIDDLE, mode=:default)
#text_font.draw("#{#columns[column_index].value}", (column_index * COL_WIDTH) + 5, SCREEN_HEIGHT - 10, ZOrder::TOP, 1.0, 1.0, Gosu::Color::RED)
column_index += 1
end
end
end
window = GameWindow.new
window.show
EDIT: Added in the rest of the code and removed some tags

Keeping track of the path, Knights travel

So far my shortest path method will stop when it reaches the goal position, printing out everything it did along the way. I would like to know how I could go about implementing parent positions so I can print the path along with the goal. This is an assignment.
class Knight
attr_accessor :x, :y, :prev_position, :moves
def initialize(position)
#x = position[0]
#y = position[1]
#prev_position = nil
#moves = [
[-1,-2],
[-2,-1],
[-2,+1],
[-1,+2],
[+1,-2],
[+2,-1],
[+2,+1],
[+1,+2]]
end
def possible
move_list = Array.new
#moves.each do |moves|
x = #x + moves[0]
y = #y + moves[1]
if x.between?(0,7)
if y.between?(0,7)
move_list << [x,y]
end
end
end
move_list
end
end
def shortest_path(position,goal)
paths = Array.new
#start_knight = Knight.new(position)
until #start_knight.x == goal[0] and
#start_knight.y == goal[1]
#start_knight.possible.each do |p| paths << p end
shifted = paths.shift
#start_knight.x = shifted[0]
#start_knight.y = shifted[1]
puts "[#{#start_knight.x},#{#start_knight.y}]"
end
end
shortest_path([0,0],[7,7])

What is the correct way to write this in Ruby?

I am needing to write few methods: value(x), zero(a,b,e), area(a,b), derivative(x)
class Funkcja
def initialize(funkcja)
#funkcja = funkcja
end
def value(x)
#funkcja.call(x)
end
end
This class will have to work over block which is an object from Proc
This is how I create that new object
f = Funkcja.new (Proc.new{|x| x*x*Math.sin(x)})
What is the correct way and in Ruby style (if not please show me that i
newbie in Ruby) to do this right Funkcja.new (Proc.new x) and
initialize #funkcja = funkcja
def zero(a, b, eps)
x = (a+b)/2.0
val = value(x)
if val >= -eps and val <= eps
x
else
left = value(a)
rigth = value(b)
if left < 0 and val > 0
zero(a,x,eps)
elsif left > 0 and val < 0
zero(a,x,eps)
elsif rigth > 0 and val < 0
zero(x,b,eps)
elsif rigth < 0 and val > 0
zero(x,b,eps)
elsif value == 0
x
else
nil
end
end
end
def area(a,b)
pole = 0
while a < b
if (self.value(a) > self.value( a + 0.00001))
pole = pole + (self.value( a) * 0.00001)
else
pole = pole + (self.value( a + 0.00001) * 0.00001 )
end
a += 0.00001
end
pole
end
def derivative(x)
eps = 0.00000001
return (self.value(x) - self.value(x - eps))/eps
end
Area is calculated area between a and b and OX, zero is find where
F (x)=0 derivative is calculated as derivative in point.
The main thing that's non-idiomatic is this:
f = Funkcja.new (Proc.new{|x| x*x*Math.sin(x)})
What would be more normal is to do this:
f = Funkcja.new { |x| x*x*Math.sin(x) }
This is a normal block, and you could split it up among multiple lines as usual:
f = Funkcja.new do |x|
x*x*Math.sin(x)
end
However, this wouldn't work with your initialize definition and that's because of one minor detail. You'd just need to change def initialize(funkcja) to def initialize(&funkja) - this converts the passed block into a proc that you can assign to a variable, use call with, etc:
def initialize(&funjka)
#funkja = funkja
end
Another way to do the same thing would be this:
def initialize
#funkja = yield
end
Other than that, your code seems fine with one other glaring non-idiomatic thing, which that you use self.value. The self is unnecessary unless you're using a setter method (i.e. self.value =), which you're not here.
Here's an idea of adapting one of your methods to a more Ruby style:
def area(a,b)
pole = 0
while a < b
if (yield(a) > yield(a + 0.00001))
pole = pole + (yield(a) * 0.00001)
else
pole = pole + (yield(a + 0.00001) * 0.00001)
end
a += 0.00001
end
pole
end
You'd use it like this:
area(a, b) do |a|
a ** 2
end
Now it's one thing to be handling Proc objects, that's fine, the do ... end method of appending blocks to method calls generates those by default. It's very not Ruby to put extra methods on Proc itself. I can't see anything here that can't be covered by defining these inside a simple module:
module CalculationModule
def area(a, b)
# ... Implementation
end
extend self
end
That way you can use those methods like CalculationModule.area or you can always include it into another class or module and use them like area.

Ruby Code-Cutting (few lines as possible)

So the code below is what I'm trying to cut down to as few lines as possible. Any other ruby tricks out there I could use to shorten it? I appreciate all help anyone can offer.
Article Class:
class Article
attr_accessor :id, :price, :quantity
def initialize(id, price, quantity)
#id, #price, #quantity = id, Float(price), quantity.to_i
end
end
Order Class:
class Order
def initialize(name)
#a, i = [], 0
input = File.open(name, "r")
while(id = input.gets.chomp)
j, price = 0, input.gets.chomp
while(j<#a.length)
if(#a[j].id.eql?(id.to_i))
#a[j].quantity += 1
end
end
else
#a[i] = new Article(id,price,1)
i+=1
end
end
end
def orderCost
sum = 0
#a.each { |e| sum+=(e.price * e.quantity)}
sum = ((sum*1.07) + 2.99)
end
def displaySelectArticles
min, max = #a[0], #a[0]
#a.each do |e|
if(min.cost > e.cost)
min = e
end
if(max.cost < e.cost)
max = e
end
sum += e.cost*e.quantity and q += e.quantity
end
puts "Min: #{min.cost} | Max: #{max.cost} | Avg: #{Float(sum)/q}"
end
end
I did my best here but your initialize method didnt make any logical sense to me. Hopefully this can at least guide you into the right direction. Disclaimer: None of this was tested and I wrote it off of what methods I could remember.
class Order
def initialize(name)
#a, i = [], 0
File.readlines(name) do |line|
# This while loop makes no sense to me
# Seems like a surefire infiniteloop because if id = 3, it is always true
# Maybe you meant to do an operator like == for comparison
while(id = line)
j, price = 0, line
while j < #a.length
#a[j].quantity += 1 if(#a[j].id.eql?(id.to_i))
end
else
#a[i] = new Article(id, price, 1)
i += 1
end
end
end
def orderCost
# I would probably make this two lines because its unreadable
(#a.inject(0) { |accum, e| accum + (e.price * e.quantity) } * 1.07) + 2.99
end
def displaySelectArticles
min, max = #a[0], #a[0]
#a.each do |e|
min = e if min.cost > e.cost
max = e if max.cost < e.cost
sum += e.cost * e.quantity
q += e.quantity # I have no idea how you got a q
end
puts "Min: #{min.cost} | Max: #{max.cost} | Avg: #{Float(sum)/q}"
end
end
The Article class needs serious attention because of that jumble of junk where
three variables are assigned at the same time. Split that out into three very
simple assignments:
class Article
attr_accessor :id, :price, :quantity
def initialize(id, price, quantity)
#id = id
#price = price.to_f
#quantity = quantity.to_i
end
end
Using x.to_f is preferable to Float(x), it's a gentler approach to
converting. If you're doing financial calculations I'd stronly encourage
you to use something like BigDecimal
as floating point numbers are notoriously problematic. $1.99 has a way of
becoming $1.989999423489 which when rounded can appear to "lose" a cent here
or there. The BigDecimal class avoids this by representing values as exact.
The rest is basically attacking the problem of not using Enumerable
effectively and instead writing your own routines to do what should be simple:
class Order
def initialize(name)
#items = [ ]
File.open(name, "r") do |input|
while(id = input.gets.chomp)
price = input.gets.chomp
# find locates the first matching thing in the array, if any.
existing = #items.find do |item|
item.id == id
end
if (existing)
existing.quantity += 1
else
items << Article.new(id, price, 1)
end
end
end
def item_cost
# Inject is good at iterating and accumulating
#items.inject(0.0) do |sum, item|
sum + item.price * item.quantity
end
end
def item_count
#items.inject(0) do |sum, item|
sum + item.quantity
end
end
def order_cost
item_cost * 1.07 + 2.99
end
def display_select_articles
# minmax_by finds min and max entries based on arbitrary criteria
min, max = #items.minmax_by { |item| item.price }
sum = item_cost
count = item_count
puts "Min: %f | Max: %f | Avg: %f" % [
min ? min.cost : 0.0,
max ? max.cost : 0.0,
count > 0.0 ? (sum / count) : 0.0
]
end
end
Whenever possible go with the grain, and that means using Ruby's structures and their native methods. The more you deviate from this the more code you'll have to write, and the uglier your code will get. Sometimes you're solving a difficult problem and you have no choice, but this example is not one of those cases. Everything here is simpler if you just do it the Ruby way.

Ruby wrong result durning vectors calculations

We are trying to implement "Calculating coefficients of interpolating polynomial using Neville's algorithm."
This is our Vector Class:
class Wektor < Array
attr_accessor :coordinatesAmount
def initialize(length)
super(length, 0)
#coordinatesAmount = length
end
def SetVector(w)
for i in (0...coordinatesAmount) do
self[i] = w[i]
end
return self
end
def MultiplyBy(n)
for i in (0...coordinatesAmount) do
self[i] *= n
end
return self
end
def DivideBy(n)
for i in (0...coordinatesAmount) do
self[i] /= n
end
return self
end
def Sub(w)
for i in (0...coordinatesAmount) do
self[i] -= w[i]
end
return self
end
def Add(w)
for i in (0...coordinatesAmount) do
self[i] += w[i]
end
return self
end
def ShiftRight
coordinatesAmount.downto(1) { |i|
self[i-1] = self[i-2]
}
self[0] = 0
return self
end
This is our calculation part:
require_relative 'wektor.rb'
#Coefficients
def Coefficients(i, j, tabX, tabY, pyramid)
#mnozymy przez Xj
length = pyramid[i][j-1].length
temp = Wektor.new(length).SetVector(pyramid[i][j-1])
temp.MultiplyBy(tabX[j])
pyramid[i][j].SetVector(temp)
#odjęcie Pi,j-1 przesuniętego o 1 w prawo
temp = Wektor.new(length).SetVector(pyramid[i][j-1])
temp.ShiftRight
pyramid[i][j].Sub(temp)
#dodanie Pi+1, j przesuniętego o 1 w prawo
temp = Wektor.new(length).SetVector(pyramid[i+1][j])
temp.ShiftRight
pyramid[i][j].Add(temp)
#odjęcie Pi+1, j pomnożonego przez Xi
temp = Wektor.new(length).SetVector(pyramid[i+1][j])
temp.MultiplyBy(tabX[i])
pyramid[i][j].Sub(temp)
#podzielenie przez (Xj - Xi)
pyramid[i][j].DivideBy(tabX[j] - tabX[i])
return pyramid[i][j]
end
#CalculateResult
def CalculatePolynomialResult(x,y,n)
pyramid = Hash.new {|h,k| h[k] = Wektor.new(n)}
for i in 0...n do
for j in 0...n-i do
if (j != i+j) then
next
end
pyramid[j][j] = Wektor.new(n)
pyramid[j][j].push(y[j])
end
end
for i in 0...n do
for j in 0...n-i do
if (j == i+j) then
next
end
pyramid[j][i+j] = Wektor.new(n)
Coefficients(j, i+j, x, y, pyramid)
end
end
return pyramid[0][n-1]
end
We are facing the problem when the Coefficients method is calculating something we still get zeros. There is no exception error but our Vector are zeros. I added a link for our Source at Math Overflow to explain what is going on.
This is the same code but written in C#, to play with .NET.
Any ideas why our vectors are useless? Like something is overwriting them or maybe with some value/reference? We are unable to track that issue.

Resources