4
\$\begingroup\$

Given two input integers, a >= 4 and b >= 2, output an ASCII square of size a x a. The twist is the square must be constructed of b 3 x 3 squares formed like the following:

###
# #
###

You can use any ASCII printable character (except whitespace) to construct the smaller squares. I'm using # for visibility and consistency.

The first b square is always placed in the upper-left, and the remaining b squares must be as evenly spaced as possible, going clockwise, around the larger square. The overall a x a square size is calculated in characters based on the center of the b squares.

Here's an example for a=7 and b=3. Note the numbers around the outside are not part of the output, just used to illustrate the construction.

   1234567   
  ###        
1 # #       1
2 ###   ### 2
3       # # 3
4       ### 4
5           5
6   ###     6
7   # #     7
    ###      
   1234567

The first b square is placed in the upper-left corner. In the remaining possible areas on the perimeter of a x a, we need to place two more b squares. Note how the smaller squares are staggered -- how they're spaced as evenly as possible around the larger square. If a potential b square could be in one of two spaces, your code can pick either and does not need to be deterministic.

Here's another diagram explaining the spacing. I've drawn the a square with -+| and marked the center of the smaller b squares with *. If we count clockwise around the outside of the a square, we have 7 characters between the first and second centers -----+|, 7 between the second and third |||+---, and again 7 between the third and first -+|||||. This lines up mathematically as well, since we have 24 total characters making up the a square, minus 3 for the center of the b squares, must mean we have 7 characters between the centers. And, since the upper-left b square is fixed, this is the most evenly spaced arrangement possible.

   1234567   
  ###        
1 #*-----+  1
2 #|#   #|# 2
3  |    #*# 3
4  |    #|# 4
5  |     |  5
6  |###  |  6
7  +-*---+  7
    ###      
   1234567

Input

  • A two integers in any convenient format, a >= 4 and b >= 2.
  • You can take the input in either order -- your choice.
  • The input is guaranteed to be such that no b squares will overlap.

Output

The resulting ASCII art representation of the squares.

Rules

  • Leading or trailing newlines or whitespace are all optional, so long as the characters themselves line up correctly.
  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • If possible, please include a link to an online testing environment so people can try out your code!
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Examples

(note these are just examples, and depending upon how your code rounds the placement you may have slightly different output)

a=4, b=4
######
# ## #
######
######
# ## #
######

a=4, b=2
###
# #
###
   ###
   # #
   ###

a=7, b=4
###   ###
# #   # #
###   ###



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

a=5, b=3
###
# #
### ###
    # #
 ######
 # #
 ###

a=7, b=3
###       
# #       
###   ### 
      # # 
      ### 

  ###     
  # #     
  ###     

a=7, b=5
###  ### 
# #  # # 
###  ### 


###   ###
# ##### #
#### ####
   ###   
\$\endgroup\$
2
  • 3
    \$\begingroup\$ How do you determine what's "spaced as evenly as possible"? I would guess this is more evenly spaced than your example for a=7, b=3? pastebin.com/vkPxRh61 \$\endgroup\$
    – milk
    Dec 21, 2016 at 23:02
  • \$\begingroup\$ @milk Your paste has only five characters between the bottom left and upper left squares, significantly different than between the two left squares and the right square. I've added an additional diagram explaining the spacing. \$\endgroup\$ Dec 22, 2016 at 13:40

2 Answers 2

3
\$\begingroup\$

Befunge, 240 232 bytes

< vp62:&p01*4p00:-1&
-1<v3!-2\*g04!:::p04p03-\g00:%g00\/g00:/g62*g01\1:
p:|>0g*+\1-!00g*+2+\::1-!40g*\3-!30g*+\2-!00g*+9+
# >00g3+:00pv
g00p05-\g00:<v+g06%3:\!!-4::-1p07\<90p06-\g00:<
$55+,1-:!#@_^>\3/50g+7+g2%*70g+\:#^_$!3g,>1-:#^_

Try it online!

Explanation

There are two parts to this. The first part is mostly handled by the loop on lines 2 and 3, which calculates the positions of each block by dividing the route around the main square (of length (a-1)*n4) into b segments. For each division, d, in that length, we determine the x and y coordinates with:

side = d/(a-1)    // which side of the square (0 = top, 1 = right, 2 = bottom, 3 = left)
off  = d%(a-1)    // the offset along that side, in a clockwise direction
roff = a-1-off    // the reverse of that offset

x = (side==0)*off + (side==2)*roff + (side==1)*(a-1)
y = (side==1)*off + (side==3)*roff + (side==2)*(a-1)

i.e. depending on which side of the square we're on, the coordinate value will either be the offset along that side, the reverse offset, the width of the square, or zero. We use those coordinates to write a 1 into the lower half of the Befunge playfield to mark the spot for later output.

The second part, writing out the final pattern of squares, is handled by the triple loop on lines 5 and 6. We're looping over the y and x coordinates, and then for each point, we need to check if we've marked a spot in any of the surrounding 8 locations. This is achieved with a simple loop over a range of 9, basically summing the values it encounters in the playfield. In Python it would look something like this:

total = sum(playfield[y+i/3][x+i%3] * (i != 4) for i in range(9))

The multiplication by i != 4 is so that we exclude the centre point in the range. If this total is greater than 0 we need to output a #, otherwise we output a space. To avoid any branching, we simply use !total as an index into a character "table" (the at the start of line 3) to determine the character to output.

\$\endgroup\$
2
\$\begingroup\$

C, 350 302 253

i,j,x,y,a,b,c;main(){scanf("%d%d",&a,&b);a+=3;char*s,o[a*a];for(;c<a;)sprintf(o+c++*a,"%*s\n",a-1,"");for(;i<b;){x=y=0;for(j=(a-4)*i++*4/b;j--;)y>0&!x?y--:y>a-5?x--:x>a-5?y++:x++;s=o+y*a+x;s[2]=s[1]=*s|=3;s+=a;s[2]=*s|=3;s+=a;s[2]=s[1]=*s|=3;}puts(o);}

Ungolfed:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int i,j,x,y,a,b,c;
main(int n, char** v) {
    a = atoi(v[1])+3;
    b = atoi(v[2]);
    char o[a*a-a], *s;
    for (; c < a-1; c++) {
        sprintf(o+c*a, "%*s\n",a-1," ");
    }
    for (; i < b; i++) {
        x=y=1;
        for(j=(a-4)*i*4/b;j--;){ // Set the number of steps from 1,1
            if(y>1&x<2) y--; // We are on the left wall
            else if(y>a-4) x--; // We are on the bottom
            else if(x>a-4) y++; // We are on the right wall
            else x++; // We are on the top
        }
        s = o+(y-1)*a+x-1; // Find the output position
        bcopy("#x#",s,3);
        s+=a;
        bcopy("# #",s,3);
        s+=a;
        bcopy("#y#",s,3);
    }
    printf("%s\n", o);
}

This compiles with gcc under linux. Windows might substitute <windows.h> for the <stdlib.h> and <stdio.h> includes.

Explanation

We initialize the output string to an array of newline-terminated rows. sprintf takes care of null-terminating the string. We descend into a nested group of ternary operators to determine the wall. We then write out the square. We start each square counting from (1,1). This is less efficient but saves a few bytes over the step method. It also avoids rounding errors in integer division.

\$\endgroup\$

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.