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


class SierpinskiCarpet {
  function : Main(args : String[]) ~ Nil {
    Carpet(3);
  }
 
  function : InCarpet(x : Int, y : Int) ~ Bool {
    while(x<>0 & y<>0) {
      if(x % 3 = 1 & y % 3 = 1) {
        return false;
      };
 
      x /= 3;
      y /= 3;
    };
 
    return true;
  }
 
  function : Carpet(n : Int) ~ Nil {
    power := 3.0->Power(n->As(Float));
    for(i := 0; i < power; i+=1;) {
      for(j := 0; j < power; j+=1;) {
        c := InCarpet(i, j) ? '*' : ' ';
        c->Print();
      };
      IO.Console->PrintLine();
    };
  }
}