15
\$\begingroup\$

Given a positive integer N, output this doubling pattern of slash squares/rectangles.

For N=1, the base is:

/\
\/

The next square is added in the bottom right direction for N=2:

/\
\/\
 \/

After that, a 2x1 rectangle is added in the bottom left direction for N=3:

 /\
/\/\
\ \/
 \/

Then a 2x2 square is added in the top left direction for N=4:

 /\
/  \
\  /\
 \/\/\
  \ \/
   \/

A 2x4 rectangle is added in the top right:

   /\
  /  \
 /\   \
/  \   \
\  /\  /
 \/\/\/
  \ \/
   \/

And so on. The direction in which squares and rectangles are added cycles counterclockwise, and the shape which is added alternates between squares and rectangles.

You may output as an array of lines / matrix of characters, and input may be 0-indexed or 1-indexed. Trailing whitespace in the output is allowed.

Reference implementation

Testcases:

1: 
/\
\/
2:
/\
\/\
 \/
4:
 /\
/  \
\  /\
 \/\/\
  \ \/
   \/
7:
       /\       
      /  \      
     /\   \     
    /  \   \    
   /\  /\  /\   
  /  \/\/\/  \  
 /    \ \/    \ 
/      \/      \
\       \      /
 \       \    / 
  \       \  /  
   \       \/   
    \      /    
     \    /     
      \  /      
       \/       
10:
               /\
              /  \
             /    \
            /      \
           /        \
          /          \
         /            \
        /              \
       /\               \
      /  \               \
     /    \               \
    /      \               \
   /        \               \
  /          \               \
 /            \               \
/              \               \
\              /\              /\
 \            /  \            /  \
  \          /\   \          /    \
   \        /  \   \        /      \
    \      /\  /\  /\      /        \
     \    /  \/\/\/  \    /          \
      \  /    \ \/    \  /            \
       \/      \/      \/              \
        \       \      /                \
         \       \    /                  \
          \       \  /                    \
           \       \/                      \
            \      /                        \
             \    /                          \
              \  /                            \
               \/                              \
                \                              /
                 \                            /
                  \                          /
                   \                        /
                    \                      /
                     \                    /
                      \                  /
                       \                /
                        \              /
                         \            /
                          \          /
                           \        /
                            \      /
                             \    /
                              \  /
                               \/
\$\endgroup\$
6
  • 6
    \$\begingroup\$ You might want to translate the reference implementation to something more people will understand. \$\endgroup\$
    – Razetime
    Dec 25, 2021 at 2:11
  • 1
    \$\begingroup\$ @Razetime I didn't intend for people to understand it, I just added it in case people wanted more testcases. \$\endgroup\$
    – emanresu A
    Dec 25, 2021 at 6:32
  • \$\begingroup\$ Rules on extra whitespace? \$\endgroup\$
    – Jonah
    Dec 25, 2021 at 20:12
  • 1
    \$\begingroup\$ @Jonah Trailing whitespace is allowed. \$\endgroup\$
    – emanresu A
    Dec 25, 2021 at 20:12
  • 1
    \$\begingroup\$ The reference implementation doesn't seem work properly... \$\endgroup\$
    – att
    Dec 26, 2021 at 0:14

7 Answers 7

10
\$\begingroup\$

Charcoal, 21 bytes

↶⁴FNF⁵«↷¹X²÷⁺﹪κ²ι²↷¹¶

Try it online! Link is to verbose version of code. Explanation:

↶⁴

Make the output upside-down relative to the output Charcoal would like to produce.

FN

Loop over each quadrilateral.

F⁵«

Draw five sides, so that the cursor is in the correct place to draw the next one.

↷¹X²÷⁺﹪κ²ι²↷¹¶

Draw one diagonal of the quadrilateral. The pivots and newline conspire to place the cursor in the correct place to draw the next diagonal.

\$\endgroup\$
5
\$\begingroup\$

JavaScript (ES6), 240 bytes

  1. Make it work without giving a dime about leading whitespace.
  2. Realize that leading whitespace is not allowed.
  3. Add an insane amount of code to start drawing the smallest square at the correct coordinates.
  4. Oh well ... post it anyway. :-)

Returns a matrix of characters.

n=>(x=1<<(h=n=>n-=n&1||n&3)(n)/2,y=(g=k=>k<4?k:-~g(k-4)*4)(h(n-1)),F=i=>i<n?F(-~i,(g=k=>k--?g(k,(h=Y=>m[Y+=y+k]=m[Y]||Array(1<<n/2+1).fill` `)``[x+k]=h(d)[x+k-d]='\\',h``[X=x+~k]=h(d)[X+d]='/'):x+=i%4%3?-d:d)(d=1<<i/2),y+=i%4?-d:d):m)(m=[])

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Python/NumPy, 154 bytes

from numpy import*
r=rot90
def f(n):
 a=diag([1,1]);y=x=2-a
 for i in r_[:n]:x=pad(r(x),a);y=pad(r(y),a)|x.T;x^=x.T;a<<=i&1
 return r(choose(y," /\\"),-n)

Attempt This Online!

Old Python/NumPy, 156 bytes

from numpy import*
a=c_[:3]==[1,2]
r=rot90
def f(n):
 y=x=2-a[1:]
 for i in r_[:n]:y,x=pad([r(y),r(x)],a<<i//2);y|=x.T;x^=x.T
 return r(choose(y," /\\"),-n)

Attempt This Online!

Old Python/Numpy, 159 bytes

from numpy import*
a=c_[:3]==[1,2]
r=rot90
def f(n):
 y=x=2-a[1:]
 for i in r_[:n]:y,x=pad([r(y),r(x)],a<<i//2);y|=x.T;x^=x.T
 return r(choose(y,[*" /\\"]),-n)

Attempt This Online!

Old Python/NumPy, 163 bytes

from numpy import*
a=c_[:3]==[1,2]
def f(n):
 y=x=2-a[1:]
 for i in r_[:n]:y,x=pad([rot90(y),rot90(x)],a<<i//2);y|=x.T;x^=x.T
 return rot90(choose(y,[*" /\\"]),-n)

Attempt This Online!

Old Python/NumPy, 168 bytes

from numpy import*
a=c_[:3]==[1,2]
def f(n,o=2*[a[1:]+1]):
 for i in r_[:n]:y,x=b=pad(o,a<<i//2);y|=x.T;x^=x.T;o=rot90(b.T,3).T
 return rot90(choose(o[0],[*" /\\"]),~n)

Attempt This Online!

Old Python/NumPy, 173 bytes

from numpy import*
def f(n,o=2*[mat("2 1;1 2")]):
 for i in r_[:n]:y,x=b=pad(o,eye(3,2,-1,int)<<i//2);y|=x.T;x^=x.T;o=rot90(b.T,3).T
 return rot90(choose(o[0],[*" /\\"]),~n)

Attempt This Online!

How it works

It loops up to size n maintaining a full (y) and an outline only (x) version of the pattern at each size. The patterns are rotated 90° in each step such that the next larger rectangle always is added bottom left. In each step x and y are padded with whitespace such that the transpose of x can serve as the new rectangle. And we can simply or x.T and y to create the next y. The new x is obtained similarly, only we erase the joining line by using xor instead of or.

\$\endgroup\$
4
\$\begingroup\$

Python 3, 328 239 bytes

  • Merged the two fors thanks to @oupson and added v=i//h (-3)
  • Changed to one space indentation (-2)
  • Changed v=i//h to v=i//h*(t+1) (-2)
  • Changed the for to a while (-1)
  • Removed the space before and (-1)
  • Added z=i%h*-~-t-t (-5)
  • And much more, done with @oupson (-75)
def f(n):
 t=(1<<~-n//2)*(3-n%2)+1;l=list((" "*~-t+"\n")*t);s=0
 while n:
  w=1<<n//2;h=w>>~n%2;a=h*t;i=w*h
  while i:i-=1;v=i%w*-~t+s;z=i%h*-~-t-t+s;l[v+h],l[a+z]=l[a+v],l[w*t+a+w+z]="\\/"
  s+=(w*t+w,a,0,h)[n%4]//2;n-=1
 print(*l,sep="")

Try it online!

I would like to learn from this first experience, so please give me advice and golf bytes away. (Looks like a lot had to be golfed)

I probably took the wrong approach (as in lengthy/inefficient), but still decided to make the best of it.

  • The f function creates the matrix and then the string to print.
  • The q fonction draws a rectangles of size n to the list l. It is recursive, and for each subsequent call we offset the origin (s in the first version, x and y in the second).

Output of f for n=4 without the recursive call in q:

 /\   
/  \  
\   \ 
 \   \
  \  /
   \/ 

Moving the origin - where to write the next rectangle - is certainly the part of the program that needs the most improvements.

Original ungolfed version:

def f(n):
  t = 2**(n//2) + 2**((n-1)//2)
  lines = [[" "]*t for _ in range(t)]
  def squares(n, x=0, y=0):
    w = 2**(n//2)
    h = 2**((n-1)//2)
    for i in range(w):
      lines[y+i][x+i+h] = lines[y+i+h][x+i] = "\\"
    for i in range(h):
      lines[y+h-i-1][x+i] = lines[y+w+h-i-1][x+w+i] = "/"
    if n>1:
      squares(n-1, x + w//2 * (n%4==0) + h//2*(n%4==3), y + (w//2) * (n%4==0) + (h//2) * (n%4==1))
  squares(n)
  print("\n".join(map("".join, lines)))
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Welcome to Code Golf, and nice first answer! Be sure to check out our Tips for golfing in Python page for ways you can golf your program \$\endgroup\$ Dec 30, 2021 at 19:01
  • \$\begingroup\$ Thanks for the welcome! I already went through those tips a while ago, but I might be a good refresher \$\endgroup\$
    – Vélimir
    Dec 30, 2021 at 20:27
3
\$\begingroup\$

JavaScript (Node.js), 216 bytes

n=>[...Array(h(n)+h(n-1))].map((_,y,a)=>a.map((_,x)=>g(n,x,y)))
g=(n,x,y,p=h(n),q=h(--n),r=p+q)=>x>=0&y>=0&x<r&y<r&(x==q+~y|x==q+y|x==y-q|x==r+p+~y)?'\\/'[(x+y+q)%2]:n?g(n,n--&2?x-h(n):x,n&2?y-h(n):y):' '
h=n=>1<<n/2

Try it online!

\$\endgroup\$
3
\$\begingroup\$

J, 135 bytes

' /\\/'{~[:p:inv@{.@q:"+@>({.!.1*[({.!.1|.~*@[*$@])](*+1-])1 p:])&.>/@((<p:1+i.2 2)}.@|.@, ::[[:;/$&(4 2$1|.4#1 _1)*]{.3*/\@,$&4r3 3r2)

Try it online!

the idea

Notice that each iteration is a diagonal rotation of the previous one, layered on top of it. Let's draw this out to clarify. We'll use . instead of space in our drawings:

  /\.
  \/.   Initial state layer, expanded with spaces down and right.
  ...

  ...
  ./\   Initial state layer, diagonally rotated down and right.
  .\/

  /\.
  \/\   The two layers stacked and "added" together elementwise.
  .\/

The "addition" of those two layers (3rd picture) is the new state, with the center / repeated. We need to track that, because we want to remove repeats when we iterate again:

  ./\.
  .\/\   Current iteration, expanded with spaces down and left.
  ..\/
  ....

  ....
  /\..   Current iteration, diagonally rotated down and left, with all
  \.\.   previous "repeats" removed.
  .\/.

  ./\.
  /\/\   Those two layers stacked and added elementwise.
  \.\/   
  .\/.

Note that now, in the 3rd picture, we have 3 "repeat" slashes. I'll highlight their locations with *:

  ./\.
  /**\   Elements that have been added to themselves in any previous
  \.*/   iteration.
  .\/.

We continue this process -- expanding, rotating and removing repeats, and "adding" layers. The next direction will be up and left, then up and right, then down and right again, continuing cylically:

down & right   down & left   up & left   up & right
\                /           *              *
 \              /             \            /
  *            *               \          /

implementation notes

The entire calculation is a single fold, which begins with the initial 2x2 diamond matrix, and precalculates the magnitude and direction of all the diagonal rotations:

  • ]{.3*/\@,$&4r3 3r2 Precalculates the new side of each iteration's square matrix:

    3 4 6 8 12 16 24 32
    

    This is a geomtric series, with an alternating multiplier: Start with 3, multiply by 4/3, then multiply that result by 3/2, then that result by 4/3, and so on.

  • 4 2$1|.4#1 _1 A golf for the directions of the diagonal rotations. It evaluates to:

     1  1     down/right
     1 _1     down/left
    _1 _1     up/left
    _1  1     up/right
    
  • (<p:1+i.2 2) To track repeats, we encode the starting matrix using primes:

    ┌────┐
    │3  5│   corresponds to  /\
    │7 11│                   \/
    └────┘
    
    • And when we "add" the layers we'll use multiplication, with spaces encoded as ones. This lets us detect repeats by checking if a cell is prime.
  • [:p:inv@{.@q:"+ At the very end, each element will either be a prime or a prime power. So we can take the first factor {.@q: to recover the "non-repeat" version of each cell. Finally, we use the inverse prime function p:inv to turn the pries back into the numbers 1 2 3 4, which we use to index into /\\/.

\$\endgroup\$
1
\$\begingroup\$

Ruby, 339 bytes

f=->n{a,j,v={0=>r=t=[0,1],1=>r},[[1,-1],[-2,2]],[1,1]
n.times{|q|a.merge!(a.to_h{|y,x|[y+v[0],[x[0]+v[1],x[-1]+v[1]]]}){|k,x,y|t|=x|=y
x.sort}
v=v.zip(j[q%2]).map{|x,y|x*y}
r,t=[a.keys,t].map &:minmax}
o=(0..r[1]-r[0]).map{" "*(t[1]-t[0])}
a=a.to_h{|y,x|[y-r[0],x.map{|z|z-t[0]}]}
a.each{|y,c|c.map{|x|o[y][x]="/\\"[(x+y+(n>1?1:0))%2]}}
o}

Attempt This Online!

  • Not the best answer around but I tried at least to do the job.

  • Thanks @emanresu A for providing an online compiler(Tio Ruby version didn't work ).

  • Returns an array of strings.

We generate an Hash where Keys are row indexes(allowing negative keys) and Value is an Array of written indexes on each row(also negative allowed)

/\  0(0,1) > We get bounds.
\/  1(0,1) > Pivot starts at 1,1

Add Pivot to Bounds
Add to Hash

/\   0(0,1)   H<= (1,1)+S
\/\  1(0,1,2)
 \/  2(1,2)    B=0(0,1)1(0,2)2(1,2)

next pivot is P* [1,-1]or[-2,2] alternately

 /\   0(0,1)        H<=(1,-1)+B=
/\/\  1(-1,0,1,2)   1(-1,0)2(-1,1)
\ \/  2(-1,1,2)     3(0,1)
 \/   3(0,1)
B=0(0,1)1(-1,2)2(-1,2)3(0,1)

To draw the pattern we take an array of strings of spaces of minMax(Keys,values) dimensions and we iterate our Hash to overwrite / or \ based on modulo2(x+y)

  • n=0 and 1 require to invert
\$\endgroup\$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.