Task
Produce a graphical or ASCII-art representation of a Sierpinski carpet of order   N.



For example, the Sierpinski carpet of order   3   should look like this:

###########################
# ## ## ## ## ## ## ## ## #
###########################
###   ######   ######   ###
# #   # ## #   # ## #   # #
###   ######   ######   ###
###########################
# ## ## ## ## ## ## ## ## #
###########################
#########         #########
# ## ## #         # ## ## #
#########         #########
###   ###         ###   ###
# #   # #         # #   # #
###   ###         ###   ###
#########         #########
# ## ## #         # ## ## #
#########         #########
###########################
# ## ## ## ## ## ## ## ## #
###########################
###   ######   ######   ###
# #   # ## #   # ## #   # #
###   ######   ######   ###
###########################
# ## ## ## ## ## ## ## ## #
###########################

The use of the   #   character is not rigidly required for ASCII art.

The important requirement is the placement of whitespace and non-whitespace characters.



Related task

   Sierpinski triangle


path across(path p, real node) {
    return
        point(p, node + 1/3) + point(p, node - 1/3) - point(p, node);
}
 
path corner_subquad(path p, real node) {
    return
        point(p, node) --
        point(p, node + 1/3) --
        across(p, node) --
        point(p, node - 1/3) --
        cycle;
}
 
path noncorner_subquad(path p, real node1, real node2) {
    return
        point(p, node1 + 1/3) --
        across(p, node1) --
        across(p, node2) --
        point(p, node2 - 1/3) --
        cycle;
}
 
void carpet(path p, int order) {
    if (order == 0)
        fill(p);
    else {
        for (real node : sequence(0, 3)) {
            carpet(corner_subquad(p, node), order - 1);
            carpet(noncorner_subquad(p, node, node + 1), order - 1);
        }
    }
}
 
path q =
   // A square
   unitsquare
   // An oblong rhombus
   // (0, 0) -- (5, 3) -- (0, 6) -- (-5, 3) -- cycle
   // A trapezoid
   // (0, 0) -- (4, 2) -- (6, 2) -- (10, 0) -- cycle
   // A less regular quadrilateral
   // (0, 0) -- (4, 1) -- (9, -4) -- (1, -1) -- cycle
   // A concave shape
   // (0, 0) -- (5, 3) -- (10, 0) -- (5, 1) -- cycle
   ;
 
size(9 inches, 6 inches);
 
carpet(q, 5);