Draw a cuboid

const dirs = Hash("-" => [1,0], "|" => [0,1], "/" => [1,1])
 
func cuboid(nx, ny, nz) {
  say("cuboid %d %d %d:" % [nx, ny, nz])
  var(x, y, z) = (8*nx, 2*ny, 4*nz)
  var area = []
  var line = func(n, sx, sy, c) {
    var(dx, dy) = dirs{c}...
    for i (0..n) {
      var (xi, yi) = (sx + i*dx, sy + i*dy)
      area[yi] \\= [" "]*(x+y+1)
      area[yi][xi] = (area[yi][xi] == " " ? c : '+')
    }
  }
 
  0 .. nz-1 -> each {|i| line(x,       0,     4*i, "-") }
  0 .. ny   -> each {|i| line(x,     2*i, z + 2*i, "-") }
  0 .. nx-1 -> each {|i| line(z,     8*i,       0, "|") }
  0 .. ny   -> each {|i| line(z, x + 2*i,     2*i, "|") }
  0 .. nz-1 -> each {|i| line(y,       x,     4*i, "/") }
  0 .. nx   -> each {|i| line(y,     8*i,       z, "/") }
 
  area.reverse.each { |line|
     say line.join('')
  }
}
 
cuboid(2, 3, 4)
cuboid(1, 1, 1)
cuboid(6, 2, 1)
cuboid(2, 4, 1)

A faster approach:

func cuboid (x=1,y=1,z=1,s=' ',c='+',h='-',v='|',d='/') {
    say("cuboid %d %d %d:" % (x, y, z))
    ' ' * z+1 + c + h*x + c -> say

    { |i|
        ' ' * (z - i + 1) + d + s*x + d +
              (s * (i - (i > y ? i-: 1))) +
              (i - 1 == y ? c : (i > y ? d : v)) -> say
    }.for(1..z)

    c + h*x + c + (s * (z < y ? z : y) +
        (z < y ? v : (z == y ? c : d))) -> say

    { |i|
        v + s*x + v + (z > y
            ? (i >= z ? (s*x + c) : (s * y-i + d))
            : (y - i > z
                ? (s * z + v)
                : (s * y-i + (y-i == z ? c : d))
               )
        ) -> say;
    }.for(1..y)

    c + h*x + c -> say
}

cuboid(2, 3, 4)
cuboid(1, 1, 1)
cuboid(6, 2, 1)
cuboid(2, 4, 1)

Output:

cuboid 2 3 4:
     +--+
    /  /|
   /  / |
  /  /  |
 /  /   +
+--+   /
|  |  /
|  | /
|  |/
+--+
cuboid 1 1 1:
  +-+
 / /|
+-+ +
| |/
+-+
cuboid 6 2 1:
  +------+
 /      /|
+------+ |
|      | +
|      |/
+------+
cuboid 2 4 1:
  +--+
 /  /|
+--+ |
|  | |
|  | |
|  | +
|  |/
+--+

Last updated