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