It seems that it has the ability of inheritance that exists in object orientation. You can use it without writing the contents defined in the class, or you can modify the contents defined in the class to make it easier to use in the class.
merit
--Ability to create functional extensions, so-called pluggable mechanisms
Demerit
--Maintenance failure due to over-inheritance (the moment the origin is changed, problems frequently occur at the inheritance destination, etc.)
keishou.rb
class Ball
attr_accessor :x, :y, :x_way, :y_way, :step
def initialize(x: 1, y: 1, x_way: 1, y_way: 1, step: 1)
@x = x
@y = y
@x_way = x_way
@y_way = y_way
@step = step
end
def move
@x += @x_way
@y += @y_way
@step += 1
end
def reflect_x
if @x_way == 1
@x_way = -1
elsif @x_way == -1
@x_way = 1
end
end
def reflect_y
if @y_way == 1
@y_way = -1
elsif @y_way == -1
@y_way = 1
end
end
def goal?(x_max, y_max)
@x == x_max && y == 1 \
|| @x == 1 && @y == y_max \
|| @x == 1 && @y == 1 \
|| @x == x_max && @y == y_max
end
def boundary_x?(x_max)
@x == x_max || @x == 1
end
def boundary_y?(y_max)
@y == y_max || @y == 1
end
end
class BilliardTable
attr_accessor :length_x, :length_y, :ball
def initialize(length_x: nil, length_y: nil, ball: nil)
@length_x = length_x
@length_y = length_y
@ball = ball
end
def cue
print_status
loop do
@ball.move
print_status
if @ball.goal?(@length_x, @length_y)
puts "GOAL!!"
break
elsif @ball.boundary_x?(@length_x)
@ball.reflect_x
elsif @ball.boundary_y?(@length_y)
@ball.reflect_y
end
end
end
def print_status
puts "#{@ball.step}, (#{@ball.x}, #{@ball.y})"
end
end
class MyBilliardTable < BilliardTable
def print_status
puts "step = #{@ball.step}, x = #{@ball.x}, y = #{@ball.y}"
end
end
x_max = ARGV[0]
y_max = ARGV[1]
if !x_max || !y_max
puts "Please specify an argument"
exit 1
end
x_max = x_max.to_i
y_max = y_max.to_i
(6..16).each do |times|
puts "3 x #{times}Run on the pool table"
bt = MyBilliardTable.new(length_x: 3, length_y: times, ball: Ball.new)
bt.cue
end
I will continue to use the code I wrote before to inherit. In fact, the part of this code that is inherited is
keishoububun.rb
class MyBilliardTable < BilliardTable
def print_status
puts "step = #{@ball.step}, x = #{@ball.x}, y = #{@ball.y}"
end
end
This is the part here. You can inherit a class by specifying the parent class using the inequality sign. This time, the method of the output part is changed. Then, try to create an object using this defined class.
shori.rb
(6..16).each do |times|
puts "3 x #{times}Run on the pool table"
bt = MyBilliardTable.new(length_x: 3, length_y: times, ball: Ball.new)
bt.cue
end
The processing part is the above part. The output should be in a modified form, and you can see that the methods defined in the BilliardTabel class are working, although they are not defined in the MyBilliardTable class.
As an aside, by designing the class in an object-oriented manner, it is possible to make the BilliardTable an object, so that the board can have a pattern. This time, I'm expressing the board of 3 times x.
banmen.rb
puts "3 x #{times}Run on the pool table"
If you want to do solid code written in Previous article, you can do it, but it will create a double loop and loop. The more you make it, the larger the code will be, that is, the deeper the hierarchy of the code. As a result, it's hard to read and hard to fix. Just by imagining it, the code will be hard to fix and hard to read.
I think that the ease of expression and ease of writing when such conditions increase are also the advantages of object-oriented programming.
If it is a small scale, it is possible to extend the function using yield, which can be done in block units. Yield replaces the status method part as it means "replace".
yield.rb
class Ball
attr_accessor :x, :y, :x_way, :y_way, :step
def initialize(x: 1, y: 1, x_way: 1, y_way: 1, step: 1)
@x = x
@y = y
@x_way = x_way
@y_way = y_way
@step = step
end
def move
@x += @x_way
@y += @y_way
@step += 1
end
def reflect_x
if @x_way == 1
@x_way = -1
elsif @x_way == -1
@x_way = 1
end
end
def reflect_y
if @y_way == 1
@y_way = -1
elsif @y_way == -1
@y_way = 1
end
end
def goal?(x_max, y_max)
@x == x_max && y == 1 \
|| @x == 1 && @y == y_max \
|| @x == 1 && @y == 1 \
|| @x == x_max && @y == y_max
end
def boundary_x?(x_max)
@x == x_max || @x == 1
end
def boundary_y?(y_max)
@y == y_max || @y == 1
end
end
class BilliardTable
attr_accessor :length_x, :length_y, :ball
def initialize(length_x: nil, length_y: nil, ball: nil)
@length_x = length_x
@length_y = length_y
@ball = ball
end
def cue
print_status
loop do
@ball.move
print_status
if @ball.goal?(@length_x, @length_y)
puts "GOAL!!"
break
elsif @ball.boundary_x?(@length_x)
@ball.reflect_x
elsif @ball.boundary_y?(@length_y)
@ball.reflect_y
end
end
end
def cue_2
if block_given?
puts "There is a block"
else
puts "Please specify block"
return
end
loop do
@ball.move
yield status
if @ball.goal?(@length_x, @length_y)
puts "GOAL!!"
break
elsif @ball.boundary_x?(@length_x)
@ball.reflect_x
elsif @ball.boundary_y?(@length_y)
@ball.reflect_y
end
end
end
def status
{
"step" => @ball.step,
"x" => @ball.x,
"y" => @ball.y
}
end
end
x_max = ARGV[0]
y_max = ARGV[1]
if !x_max || !y_max
puts "Please specify an argument"
exit 1
end
x_max = x_max.to_i
y_max = y_max.to_i
ball = Ball.new()
bt = BilliardTable.new(length_x: x_max, length_y: y_max, ball: ball)
#bt.cue
bt.cue_2 do |status|
puts "The number of steps is#{status["step"]}And the x coordinate is#{status["x"]}, Y coordinate#{status["y"]}is"
end
Depending on the scale of the function you want to extend, it is a good idea to determine whether to use inheritance or use yield to pass blocks.
Recommended Posts