17
\$\begingroup\$

Given a positive integer N, output a grid with area N and height and width dimensions as close together as possible, so as for the output to be an almost-square.

The output can be a 2d array of characters/numbers/etc. or be a single string of characters separated by newlines. You may use any value for the elements of the grid but every element should have that same value. The value doesn't need to be consistent for different inputs.

The order of the ranks in your output does not matter; the width and height may be swapped arbitrarily.

Here are some examples of almost-squares for various areas:

1
O

24
OOOOOO
OOOOOO
OOOOOO
OOOOOO

8
OOOO
OOOO

17
OOOOOOOOOOOOOOOOO

30
OOOOOO
OOOOOO
OOOOOO
OOOOOO
OOOOOO

40
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO

49
OOOOOOO
OOOOOOO
OOOOOOO
OOOOOOO
OOOOOOO
OOOOOOO
OOOOOOO

This is a modified version of an older challenge which was closed because it included some unclear bonuses.

For brownie points, see if you can beat or match my 15 bytes of Uiua (or 16 with no experimental functions).

\$\endgroup\$
4
  • \$\begingroup\$ Can we use spaces? \$\endgroup\$
    – Shaggy
    Commented Nov 11 at 16:10
  • \$\begingroup\$ @Shaggy Sure, that's fine, even if the presentation's not perfect it's still getting the job done. \$\endgroup\$ Commented Nov 11 at 16:38
  • \$\begingroup\$ Since you mentioned "You may use any value for the elements of the grid but every element should have that same value. The value doesn't need to be consistent for different inputs." I assume we're allowed to output a matrix consisting of the input as cell-items? \$\endgroup\$ Commented Nov 12 at 9:19
  • \$\begingroup\$ @KevinCruijssen Yes, and in fact some solutions are already doing it :) \$\endgroup\$ Commented Nov 12 at 12:19

21 Answers 21

4
\$\begingroup\$

R, 43 bytes

\(n,i=1:n^.5)matrix(0,k<-max(i[!n%%i]),n/k)

Attempt This Online!

Returns a 2D matrix of 0s.


R, 48 bytes

\(n,i=1:n^.5)write(rep(0,n),1,max(i[!n%%i]),,"")

Attempt This Online!

First version when I didn't read that printing output is optional not required.

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

Japt, 7 bytes

Uses q, outputs an array of lines

ç¬òUâ Ì

Try it

ç¬òUâ Ì     :Implicit input of integer U
ç           :Repeat U times
 ¬          :  "q"
  ò         :Partitions of length
   Uâ       :  (Paired) Divisors of U
      Ì     :  Last element

Japt -h, 7 bytes

Uses l, outputs an array of lines

â £îÊòX

Try it

â £îÊòX     :Implicit input of integer U
â           :Divisors
  £         :Map each X
   î        :  Mold to length U
    Ê       :    "l"
     òX     :  Partitions of length X
            :Implicit output of last element
\$\endgroup\$
3
\$\begingroup\$

APL+WIN, 36 34 bytes

Prompts for n

((n÷v),v←↑⌽(0=m|n)/m←⍳⌊(n←⎕)*.5)⍴0

Try it online! Thanks to Dyalog Classic

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

Wolfram Language (Mathematica), 47 46 40 bytes

Table[,If[i∣#,d=i]~Do~{i,√#};d,#/d]&

Try it online!

Returns an array of Nulls.

                  ~Do~{i,√#}        for i=1... i*i<=N:
       If[i∣#,d=i]                    i divides N: update shape
Table[,                      d,#/d] Nulls of that shape
\$\endgroup\$
3
\$\begingroup\$

Python 2, 74 bytes

def f(b):a=[x+1for x in range(b)if-1<b%~x<b>x*x][-1];print(b/a*'0'+'\n')*a

Try it online!

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

Perl 5 -pa, 45 bytes

$;=0|sqrt;$;++while$_%$;;$_=(1x$;.$/)x($_/$;)

Try it online!

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

JavaScript (Node.js), 52 bytes

f=(n,q=r=`
`)=>q*q<n|n%q?f(n,++q,r+=0):r.repeat(n/q)

Try it online!

From Arnauld's

Python 3, 50 bytes

f=lambda n,q=1:q*[n//q*[0]][n%q:q*q>=n]or f(n,q+1)

Try it online!

-3 bytes from xnor and Albert.Lang

Same idea

\$\endgroup\$
2
  • \$\begingroup\$ n//q*[[0]*q] saves 1. Or transpose with [n//q*[0]]*q to save 2 \$\endgroup\$
    – xnor
    Commented Nov 12 at 11:31
  • 1
    \$\begingroup\$ f=lambda n,q=1:q*[n//q*[0]][n%-q|q*q<n:]or f(n,q+1) saves another I believe.. \$\endgroup\$ Commented Nov 12 at 12:01
3
\$\begingroup\$

Google Sheets, 78 bytes

=let(i,sequence(A1^0.5),y,max(filter(i,0=mod(A1,i))),rept(rept(0,A1/y)&"
",y))

Put \$N\$ in cell A1 and the formula in cell B1. The formula uses a hard-coded newline in quotes — you can enter that with Control + Enter while editing the formula.

The result is a text string with newlines. To get a 2D array instead, use this (85 bytes):

=let(i,sequence(A1^0.5),y,max(filter(i,0=mod(A1,i))),makearray(y,A1/y,lambda(r,c,y)))

This formula uses the number of rows as the value to show in the grid.

screenshot

Ungolfed:

=let( 
  candidates, sequence(A1 ^ 0.5), 
  height, max(filter(candidates, not(mod(A1, candidates)))), 
  width, A1 / height, 
  makearray(height, width, lambda(row, column, height)) 
)

(-5 bytes thanks to jdt)

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Suggests: ..not(mod(A1,i)).. \$\endgroup\$
    – jdt
    Commented Nov 12 at 18:15
  • 1
    \$\begingroup\$ @jdt thanks! That unlocks another squeeze for -5 bytes. \$\endgroup\$ Commented Nov 12 at 18:41
3
\$\begingroup\$

C (gcc), 60 bytes

j,k;f(n){for(j=k=n;j--;)j*j>n|n%k?k--:printf("%0*d\n",n/k);}

Try it online!

Standard math library (i.e. sqrt) not used. Instead, candidate integers are iterated over in descending order, starting from the input number. Integers are tested for whether they are a divisor of the input number and whether they are near or below the square root. Once such a number is found, the rectangle is printed.

Similar approach is used above for JS and Python. This one was derived from the other C solution posted by jdt.

By some stroke of luck, it appears that there is a zero in the third argument on TIO, which saves two bytes in the call to printf. Consequently the function may randomly fail for different callers.

Ternary conditional results in a 1-4 byte reduction from other golfy approaches. I suppose that I could test whether the iterator is at the square root exactly, but where's the fun in that.

\$\endgroup\$
1
  • \$\begingroup\$ I think that with GCC, the modulus result of a division may be stored in a register or on the stack, and could then be used as the third argument in the printf call. TIO. Fortunately, in your function, the modulus is always zero. \$\endgroup\$
    – jdt
    Commented Nov 14 at 15:20
2
\$\begingroup\$

Jelly,  8  7 bytes

sⱮ½¬EƇṪ

A monadic Link that accepts a positive integer, \$N\$, and yields a rectangular list of lists of zeros as near to square as possible (more rows than columns if non-square \$N\$). (Won't work for huge inputs due to floating point inaccuracies creeping in.)

Try it online!

How?

sⱮ½¬EƇṪ - Link: positive integer, N
  ½     - square root {N}
 Ɱ      - map across {x in [1 .. floor(root(N))]} with:
s       -   split {[1..N]} into chunks of length {x} (trailing shorter if need be)
   ¬    - logical NOT (converts all values to zeros)
     Ƈ  - keep those for which:
    E   -   all equal?
      Ṫ - tail

8 bytes

(With no floating point inaccuracy)

Either change ½ to ƽ in the above or...

sÆDŒHḢṪ¬

Try it online!

How?

sÆDŒHḢṪ¬ - Link: positive integer, N
 ÆD      - divisors of {N}
s        - {[1..N]} split into chunks of {those}
   ŒH    - split into two (with first half one longer when N is square)
     Ḣ   - head of {that} -> all ways to make a rectangle with rows <= root(N)
      Ṫ  - tail of {that} -> the one with the most rows
       ¬ - logical NOT (convert all the values to zeros)
\$\endgroup\$
4
  • \$\begingroup\$ Thanks for pointing out my mistake @noodleperson (hopefully I'd have written a test suite and noticed my idiocy shortly :D); now fixed up, but can't help but think there is a better way than this... \$\endgroup\$ Commented Nov 11 at 18:05
  • 1
    \$\begingroup\$ I refuse to accept that Jelly can't beat Japt on this one! Would porting my solution work out any shorter? Repeat a character/digit input times and then split it into chunks of the size of the highest proper divisor. \$\endgroup\$
    – Shaggy
    Commented Nov 11 at 23:32
  • 1
    \$\begingroup\$ @Shaggy the highest proper divisor won't work - e.g. 15 is the highest proper divisor of 30, but we need a 5 by 6. Your Japt is working because of the order the divisors are created in Japt I believe. It does feel like there must be shorter ...somehow, but nothing yet. \$\endgroup\$ Commented Nov 12 at 2:09
  • \$\begingroup\$ @Shaggy OK, got a seven now at least. \$\endgroup\$ Commented Nov 12 at 2:33
2
+100
\$\begingroup\$

Uiua, 18 14 bytes

2 away... birdie! -2 bytes thanks to noodle person

↯⊟◡÷⊣⍖⊸◿⇡+1⌊√.

Try it!

↯⊟◡÷⊣⍖⊸◿⇡+1⌊√.
          ⇡+1⌊√   # get the range from 0-flr(sqrt(n))+1
         ◿     . # mod n by each
    ⊣⍖          # find the index (i) of the last 0
↯⊟◡÷  ⊸         # reshape n into a i x (n/i) array

⊣ last ⍖ fall gets the index of the smallest element, breaking ties toward the end. Here, 0 is always the smallest because at least one number in the range divides n.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Nice solutions! I will say that you are correct, one of your tries is quite close. As a hint, I'd recommend looking at what you might be able to do with ◡ below. Something it seems you missed in the rules which can save a byte here is that you don't have to use the same value for the matrix between calls, so you can use the input as the value to reshape by duplicating before you start and removing :0. (Note you can't just use unshape, because the values should still be equal within a single call) \$\endgroup\$ Commented Nov 12 at 1:28
  • 1
    \$\begingroup\$ Awesome that you beat my solution! Going to give this a small bounty :) For reference, I had: ↯⊟◡÷⊣▽=0◡◿⇡¯⌊⊸√. Using the zero-based range to n+1 rather than the one-based range to n in order to just get the right answer from fall is smart, wish I thought of it \$\endgroup\$ Commented Nov 12 at 3:57
2
\$\begingroup\$

JavaScript (ES6), 50 bytes

Returns a single string made of 0's and newlines.

f=(n,r=q=`0
`)=>++q*q<n|n%q?f(n,0+r):r.repeat(n/q)

Try it online!

Commented

f = (             // f is a recursive function taking:
  n,              //   n = input
  r =             //   r = string holding the the almost-square row,
                  //       initially set to "0" + newline
  q = `0\n`       //   q = divisor, initially zero'ish
) =>              //
++q * q < n |     // increment q; if q² is less than n
n % q ?           // or q is not a divisor of n:
  f(              //   do a recursive call:
    n,            //     pass n unchanged
    0 + r         //     insert a "0" at the beginning of r
  )               //   end of recursive call
:                 // else:
  r.repeat(n / q) //   return r repeated n/q times
\$\endgroup\$
2
\$\begingroup\$

Vyxal, 7 bytes

K:Y∆ṁÞm

Try it Online!

Explanation:

K gives the increasing list of all of the factors of the input.

:Y interleaves this list with itself, giving two of each factor.

∆ṁ gives the median of the list. The list is always of even length because we doubled the number of elements previously.

In most cases we wouldn't need to do the interleaving step, as the two middle elements would be the factor pair. In the case of the input already being a perfect square, however, that number is the middle of the list but it's only present once. By having two of each factor, we fix this case, and the normal case is unaffected because the two middle elements are still the factor pair.

Finally, Þm turns the list of dimensions into an array with that shape filled with zeroes.

\$\endgroup\$
3
  • \$\begingroup\$ You don't actually need to use Y, J will work fine for this. \$\endgroup\$
    – Neil
    Commented Nov 14 at 1:38
  • \$\begingroup\$ @Neil Assuming you mean :J: True, since taking the median sorts the array, doesn't just take the two middle-most items. I like this better because it would work even if it didn't do that sort, and it's the same length \$\endgroup\$ Commented Nov 14 at 2:02
  • \$\begingroup\$ Well, :J instead of :Y if you insist... \$\endgroup\$
    – Neil
    Commented Nov 14 at 6:08
1
\$\begingroup\$

Retina 0.8.2, 46 bytes

.+
$*
^((.)+?)((?<-2>\1))*$
$1$#3$*0
+1`0
¶$%`

Try it online! Link includes test cases. Outputs a rectangle of 1s (this can be changed without affecting the byte count) where the height is no more than 1 greater than the width. Explanation:

.+
$*

Convert to unary.

^((.)+?)((?<-2>\1))*$
$1$#3$*0

Factorise the input into two almost-square-roots. $#3 is actually 1 less than the second factor, which is why it might equal $.1 and therefore the second factor would be 1 greater, although they are still both almost square roots in this scenario. The first factor is represented in unary as a string of 1s while the second factor can use any other printable ASCII character as it will be replaced with newlines below. Alternatively, the first character could have been any ASCII character other than 1 in which case the second factor would need to be represented by 1s to keep the same byte count.

+1`0
¶$%`

Repeat the first factor the second factor of times.

38 bytes in Retina 1:

.+
*
^((.)+?)((?<-2>\1))*$
$1$#3*$(¶$1

Try it online! Link includes test cases. Outputs a rectangle of _s where the height is no more than 1 greater than the width. Explanation: As above but $( is used to generate the output rectangle directly.

35 bytes in Retina 1 with a trailing newline:

.+
*
(?<-2>(^(_)+?|\1))+$
$#1*$($1¶

Try it online! Outputs a rectangle of _s where the height is not greater than the width. Explanation: Based on my answer to Closest to a square which factorises the input into $#1 and $.1 but outputs the rectangle instead of its dimensions.

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

Charcoal, 16 bytes

Nθ⪪×0θ⊕⌈Φ₂θ¬﹪θ⊕ι

Try it online! Link is to verbose version of code. Only works up to 2¹⁰⁶ due to floating-point inaccuracy but but would be stupidly slow well before then anyway. Outputs a rectangle of 0s where the width is no greater than the height. Explanation:

Nθ                  Input `N` as a number
    0               Literal string `0`
   ×                Repeated
     θ              `N` times
  ⪪                 Split into substrings of length
          θ         Input `N`
         ₂          Square root
        Φ           Filtered over implicit range where
             θ      Input `N`
           ¬﹪       Is divisible by
               ι    Current value
              ⊕     Incremented
       ⌈            Take the maximum
      ⊕             Incremented
                    Implicitly print
\$\endgroup\$
1
\$\begingroup\$

C (gcc), 66 bytes

j;f(n){for(j=sqrt(n);n%j;j--);for(n/=j;j--;)printf("%0*d\n",n,0);}

Try it online!

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

APL(Dyalog Unicode), 29 24 18 bytes SBCS

Find the middle factor pair, then reshape the number into the rectangle.

18 bytes

0⍴⍨∘⊃⊢⍸⍤=⍳∘.(××≥)⍳
0⍴⍨∘⊃              ⍝ 0 in the shape of the first of
     ⊢⍸⍤=⍳∘.(××≥)⍳ ⍝ the factor pairs that its left is not less than its right.
                   ⍝ More precisely,
     ⊢⍸⍤=          ⍝ indices of N in
         ⍳∘. ×   ⍳ ⍝   the mulultiplication table of [1, N]
            ( ×≥)  ⍝     with its upper-right triangle being set to 0s

Try it on APLgolf!

24 bytes

{⍵⍴⍨i⊃⍨⌈2÷⍨⍴i←⍸⍵=∘.×⍨⍳⍵}
                 ∘.×⍨⍳⍵  ⍝ Multiplication table of [1,⍵]
            i←⍸⍵=        ⍝ Factor pairs with product being ⍵
    i⊃⍨⌈2÷⍨⍴             ⍝ The pair in the middle
 ⍵⍴⍨                     ⍝ ⍵ in the shape of the pair   

Try it on APLgolf!

29 bytes

(⊣⍴⍨⊢,÷)∘((⍸⊃⍨2⌈⍤÷⍨+⌿)0=⍳|⊢)⍨

It's the tacit version of {⍵⍴⍨j,⍵÷j←(⍸i)⊃⍨2⌈⍤÷⍨+⌿i←0=⍵|⍨⍳⍵}. The following snippet explains what it does more clearly.

{
    i ← 0=(⍳⍵)|⍵      ⍝ Bit mask for factor of N in [1,N]
    j ← (⌈(+⌿i)÷2)⊃⍸i ⍝ The factor in the middle
                      ⍝ (Take the larger one for odd N)
    k ← j,⍵÷j         ⍝ The desired shape
    k ⍴ ⍵             ⍝ Reshape of N in the desired shape
}

Try it on APLgolf!

25 byets with sqare root

Another one using square root in 25 bytes, but I like the other ones without it more.

{⍵(⊣⍴⍨⊢,÷)0⊥⍸0=⍵|⍨⍳⌈⍵*.5}

Try it on APLgolf!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Nice solutions, I will try to figure out how they work soon since I'm trying to learn Dyalog :) I'm also going to attempt a port of my TinyAPL solution because I have a feeling it may be shorter than this. It's based on nyxbird's Uiua, if you want to try it yourself. \$\endgroup\$ Commented Nov 12 at 20:56
  • \$\begingroup\$ @noodleperson I've added some explanations, hope it would help! \$\endgroup\$
    – akamayu
    Commented Nov 13 at 4:07
1
\$\begingroup\$

05AB1E, 11 10 9 bytes

ÑÅsD‚˜`ии

Outputs as a matrix of either the input (for squares) or one of the two side-lengths (for non-squares).

Try it online or verify all test cases.

Explanation:

          #  Example input 1: 12
          #  Example input 2: 16
Ñ         # Get the divisors of the (implicit) input-integer
          #  STACK 1: [1,2,3,4,6,12]
          #  STACK 2: [1,2,4,8,16]
 Ås       # Get the middle value (for squares) or middle pair (for non-squares)
          #  STACK 1: [3,4]
          #  STACK 2: 4
   D‚     # Pair it with a copy of itself
          #  STACK 1: [[3,4],[3,4]]
          #  STACK 2: [4,4]
     ˜    # Flatten, so we now have a pair or quartet
          #  STACK 1: [3,4,3,4]
          #  STACK 2: [4,4]
      `   # Pop and push both or all four values to the stack
          #  STACK 1: 3,4,3,4
          #  STACK 2: 4,4
       и  # Repeat the second-last item the last item amount of times as list
          #  STACK 1: 3,4,[3,3,3,3]
          #  STACK 2: [4,4,4,4]
        и # Map each inner value to a list of that many time the top value (for
          # non-squares), or the implicit input (for squares)
          #  STACK 1: [[4,4,4],[4,4,4],[4,4,4],[4,4,4]]
          #  STACK 2: [[16,16,16,16],[16,16,16,16],[16,16,16,16],[16,16,16,16]]
          # (after which the matrix is output implicitly as result)

NOTE: I can't remove the ¸˜, since the ` would incorrectly push the loose digits of multi-digit squares (e.g. input=\$100\$ with middle divisor \$10\$ would push 1,0 instead of 10,10 without the ¸˜).

\$\endgroup\$
0
\$\begingroup\$

Javascript (ES6), 83 bytes

f=x=>(h=x**.5|0,w=x/h|0,w*h!=x?"0".repeat(x):Array(h).fill("0".repeat(w)).join`
`)

This function returns a string of zeros delimited by newlines.

\$\endgroup\$
5
  • \$\begingroup\$ Welcome to Code Golf and Coding Challenges. Nice first solution! You can shorten this in a few ways: Math.sqrt(x) can be written as x**.5. You can use a literal newline character inside the .join string, rather than writing \n. Since this is not a recursive function definition and the name f is not referenced, you can omit the f= part. \$\endgroup\$ Commented Nov 12 at 3:43
  • 1
    \$\begingroup\$ Incorrect solution, return count doesn't always correct \$\endgroup\$
    – l4m2
    Commented Nov 12 at 3:55
  • \$\begingroup\$ Ah, sorry, l4m2 is correct. The input is not guaranteed to be a square number, so you can't say the sides will both have the same length. Instead, you have to find the factor pair (that is, two integers which multiply to N) with the least difference, so as to get an almost-square. Take another look at the examples in the challenge description. (You should edit your post to remove the incorrect solution and add a correct one. If you can't or don't want to replace it with a correct solution, you should delete your post.) \$\endgroup\$ Commented Nov 12 at 4:02
  • \$\begingroup\$ I updated my post \$\endgroup\$
    – ninjamar
    Commented Nov 12 at 5:12
  • \$\begingroup\$ It's still not correct, it does not work for any number where the closest factor pair is not made of the square root and another number, for example 40 should be 5x8 not 40x1. \$\endgroup\$ Commented Nov 12 at 5:53
0
\$\begingroup\$

TinyAPL, 18 bytes

÷⇾⍪⟜{⊇⍒⍵|⍨⍳⧺⌊√⍵}⊸⍴

Try it

The method this uses comes from nyxbird's Uiua solution.

I did some experimentation to find the shortest way to arrange all the pieces here, and I ended up with having the middle section written as an explicit function because writing it tacitly required a lot of ⍤ Atops and ⍛ Befores:

÷⇾⍪⟜(⍳⍤⧺⍤⌊⍤√⊸|⍛⍒⍛⊇)⊸⍴
\$\endgroup\$
0
\$\begingroup\$

CASIO BASIC (CASIO fx-9750GIII), 84 bytes

?→A~D
For Int √A→J To .5A
A÷J=A Int÷ J And J-A˼J<D-A˼D
DNot Ans+JAns→D
Next
For 1→Q To D
For 1→R To A÷D
PxlOn R,Q
Next
Next

I apologize for the wait.

it draws the almost-square in graph mode

\$\endgroup\$
2
  • \$\begingroup\$ Hi, this seems cool, but the note that it's not accurate worries me. Is this solution valid for all positive integer inputs? If not it should be deleted or edited to a working solution. \$\endgroup\$ Commented Nov 15 at 21:42
  • \$\begingroup\$ It doesnt seem to be. I have a much more accurate solution that i will replace that one with as soon as i can, but that may be a while (no longer than a few hours, though) \$\endgroup\$ Commented Nov 15 at 22:59

Your Answer

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

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