How to draw a square grid of size n to console?

Viewed 464

I need to draw a square grid of size n to the console. The grid uses - for horizontal cell boundaries, | for vertical cell boundaries, and + for corners of each cell.

As an example, a size 3 grid should look like the following:

+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+

I was thinking of using a double for loop with outer loop iterating through rows and inner loop iterating through cols. each iteration of inner loop would be processing an individual cell. drawing | characters doesn't seem to hard but I'm not sure how I'd go about printing the - chars above and below a cell.

4 Answers

You could use Integer#times and String#*:

def print_grid(n)
  n.times { print "+-"*n, "+\n", "| "*n, "|\n" }
  print "+-"*n, "+\n"
end

print_grid(3)
+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+
=> nil

Alternatively:

def print_grid(n)
  puts n.times.map{ "+-"*n + "+\n" + "| "*n + "|\n" }.join + "+-"*n + "+\n"
end

For a width of 3, you have a separator-row like this:

+-+-+-+

This can be sees as either:

  • 3 - connected by and surrounded by +
  • 4 + connected by -

The latter is a bit easier to express in Ruby:

width = 3
Array.new(width + 1, '+').join('-')
#=> "+-+-+-+"

The same works for the cell-row:

Array.new(width + 1, '|').join(' ')
#=> "| | | |"

Vertically, you have 3 cell-rows connected by and surrounded by separator-rows. (that should ring a bell) Just like before, this can also be expressed as 4 separator-rows connected by cell-rows.

Let's store our separator-row and cell-row in variables: (we also have to append newlines)

width = 3
separator_row = Array.new(width + 1, '+').join('-') << "\n"
cell_row      = Array.new(width + 1, '|').join(' ') << "\n"

And define the grid:

height = 3
grid = Array.new(height + 1, separator_row).join(cell_row)
#=> "+-+-+-+\n| | | |\n+-+-+-+\n| | | |\n+-+-+-+\n| | | |\n+-+-+-+\n"

put grid

Output:

+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+

Here are two ways to do that.

Determine each character depending on whether the row and column indices are even or odd

def grid(n)
  sz = 2*n+1
  Array.new(sz) do |i|
    Array.new(sz) do |j|
      if i.even?
        j.even? ? '+' : '-'
      else # i is odd
        j.even? ? '|' : ' ' 
      end
    end.join
  end
end
puts grid(3)
+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+
puts grid(4)
+-+-+-+-+
| | | | |
+-+-+-+-+
| | | | |
+-+-+-+-+
| | | | |
+-+-+-+-+
| | | | |
+-+-+-+-+

Use an enumerator

def pr_grid(n)
  enum = [*['+','-']*n, "+", "\n", *['|',' ']*n, "|", "\n"].cycle 
  ((2+2*n)*(1+2*n)).times { print enum.next }
end
pr_grid(3)
+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+
| | | |
+-+-+-+
pr_grid(4)
+-+-+-+-+
| | | | |
+-+-+-+-+
| | | | |
+-+-+-+-+
| | | | |
+-+-+-+-+
| | | | |
+-+-+-+-+

For n = 3 the steps are as follows.

a = [*['+','-']*n, "+", "\n", *['|',' ']*n, "|", "\n"]
  #=> ["+", "-", "+", "-", "+", "-", "+", "\n",
  #    "|", " ", "|", " ", "|", " ", "|", "\n"] 
enum = a.cycle 
  #=> #<Enumerator: ["+", "-", "+", "-", "+", "-", "+", "\n",
  #                  "|", " ", "|", " ", "|", " ", "|", "\n"]:cycle
enum.next #=> "+"
enum.next #=> "-" 
enum.next #=> "+" 
enum.next #=> "-" 
enum.next #=> "+" 
enum.next #=> "-" 
enum.next #=> "+" 
enum.next #=> "\n" 
enum.next #=> "|" 
enum.next #=> " "

and so on.

Just for fun and just as an example, here is a list of methods (to be optimized and debugged and maybe used within a class) that you can use also for filling a table.

@cell = '|'
@line = '-'
@cross = '+'

def build_row(content)
  (content.zip [@cell]* content.size).flatten.prepend(@cell).join
end

def separator_from_content(content)
  content.map { |e| @line * e.size + @cross }.prepend(@cross).join
end

def adjust_content_in(lines)
  width = lines.flatten.max_by(&:size).size
  lines.map { |line| line.map { |e| e << ' ' * (width - e.size) } }
end

def build_table(lines)
  lines = adjust_content_in(lines)
  separator = separator_from_content(lines.first)
  mapped = lines.map { |line| build_row(line) }.zip([separator] * (lines.size) )
  return mapped.flatten.prepend(separator).join("\n")
end

def empty_squared_table(n)
  lines = n.times.map { n.times.map { ' ' } }
  build_table(lines)
end


So, if you want to draw an empty table, can call:

n = 3
puts empty_squared_table(n)

# +-+-+-+
# | | | |
# +-+-+-+
# | | | |
# +-+-+-+
# | | | |
# +-+-+-+


Or you can fill in some text (more lines inside a cell not supported):

lines = [['so', 'you can', 'fill'], ['a table', 'given the content', '']]
puts build_table(lines)

# +-----------------+-----------------+-----------------+
# |so               |you can          |fill             |
# +-----------------+-----------------+-----------------+
# |a table          |given the content|                 |
# +-----------------+-----------------+-----------------+
Related