class Circle def initialize(radius) @radius = radius @points = [] 0.upto(radius) do |x| 0.upto(radius / 2) do |y| @points << [x , y] if lies_on_circle?(x, y) end end end def draw unless @canvas @canvas = Array.new(diameter + 1){ Array.new(2 * (diameter + 1)){ ' ' } } @points.each do |p| set_symmetric_points(p[0], p[1]) end end puts @canvas.map(&:join).join "\n" end def diameter @diameter ||= 2 * @radius end private # Detects if point is closest to the circle edge by checking the devitaion of points above and below def lies_on_circle?(x, y) cx, cy = @radius, @radius dx2, r2 = (x - cx) ** 2, @radius ** 2 [y - 1, y, y + 1].min_by {|y| (dx2 + (y - cy) ** 2 - r2) ** 2 } == y end # Sets 8 points symmetrically to circle center def set_symmetric_points(x, y) [x, diameter - x].product([y, diameter - y]).each do |p| @canvas[p[0]][2 * p[1]] = @canvas[p[1]][2 * p[0]] = '*' end end end Circle.new(15).draw