48
\$\begingroup\$

For any positive integer \$k\$, let \$d(k)\$ denote the number of divisors of \$k\$. For example, \$d(6)\$ is \$4\$, because \$6\$ has \$4\$ divisors (namely \$1, 2, 3, 6\$).

Given a positive integer \$N\$, display a "skyline" in ASCII art using a fixed character, such that the height of the "building" located at horizontal position \$k\$ is \$d(k)\$ for \$k = 1, ..., N\$. See test cases below.

Rules

  • Any non-whitespace character may consistently be used, not necessarily # as shown in the test cases.
  • The algorithm should theoretically work for arbitrarily high \$N\$. In practice, it is acceptable if the program is limited by time, memory, data-type size or screen size.
  • Horizontally or vertically leading or trailing spaces or newlines are allowed.
  • Input and output can be taken by any reasonable means.
  • Programs or functions are allowed, in any programming language. Standard loopholes are forbidden.
  • Shortest code in bytes wins.

Test cases

N = 10:

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

N = 50:

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

N = 200:

                                                                                                                                                                                   #                    
                                                                                                                                                                                   #                    
                                                                                                                       #                                               #           #                    
                                                                                                                       #                       #                       #           #                    
                                                                                                                       #                       #                       #           #           #        
                                                                                                                       #                       #                       #           #           #        
                                                           #           #           #     #     #           #           #     #     #       #   #     #     #   #       #           #           #     # #
                                                           #           #           #     #     #           #           #     #     #       #   #     #     #   #       #           #           #     # #
                                               #           #           #       #   #     #     #           #   #       #     #     #       #   #     #     #   # #     #       #   #           #     # #
                                   #           #           #           #       #   #     #     #   #       #   #       #     #     #       #   #     #     #   # #     #       #   #           #   # # #
                       #     #     #   # #     #     # #   #     #   # #     # #   #   # #     #   # # ##  # # # #     #     # # # #  ## # #   #     # # # #   # #  #  # #   # #   # # # #  ## #  ## # #
                       #     #     #   # #     #     # #   #   # #   # #     # #   #   # #     #   # # ##  # # # #     #     # # # #  ## # #   #     # # # #   # #  #  # #   # #   # # # #  ## #  ## # #
           #     # #   #   # # #   #   # # ##  # # # # #   #  ## # # # #  ## # #   #   # # #   # ### # ##  # # # # ##  #   # # # # #  ## # #   #  ## # ### #   # # ##  # ### ###   # # # # ### #  ## # #
           #   # # #   #   # # #   #   # # ##  # # # # #   #  ## # # # #  ## # ##  #   # # #   # ### # ##  # # # # ##  #   # # # # #  ## # #   #  ## # ### #   # # ##  # ### ###   # # # # ### #  ## # #
     # # # # ### # ### # ### # ##### ### # ### # ### ##### # ##### ### # ##### ### ##### ####### ### # ### # ### ####### ##### ### ##### # ######### # ##### ##### ### # ### ##### # ######### # ### # #
   # # ### # ### # ### ##### # ##### ### # ### ##### ##### # ##### ### # ##### ### ##### ####### ### # ### # ### ############# ### ##### # ######### # ##### ##### ### ##### ##### # ######### # ### # #
 #######################################################################################################################################################################################################
########################################################################################################################################################################################################
\$\endgroup\$
0

32 Answers 32

12
\$\begingroup\$

Jelly, 9 bytes

Uses 0 instead of #.

RÆD0ṁz⁶ṚY

Try it online!

\$\endgroup\$
2
  • 2
    \$\begingroup\$ 5 minutes and 10 seconds :-) \$\endgroup\$
    – Luis Mendo
    May 7, 2017 at 16:37
  • 15
    \$\begingroup\$ I was reading other stuff in the meantime... I'll be faster next time. \$\endgroup\$
    – Leaky Nun
    May 7, 2017 at 16:37
8
\$\begingroup\$

Octave, 41 40 32 bytes

Thanks to @StewieGriffin saved 8 bytes.

@(N)" #"(sort(~mod(k=1:N,k'))+1)

Try it online!

Previous answers:

@(N)" #"(sort(~bsxfun(@mod,k=1:N,k')+1))

Try it online!

@(N)" #"(sort(ismember((k=1:N)./k',k))+1)

Try it online!

Explanation:

N=5;
d = (1:N)./(1:N)'    %divide each of numbers from 1 to N by 1 to N 
                     %a [N by N] matrix created
d =

   1.00   2.00   3.00   4.00   5.00
   0.50   1.00   1.50   2.00   2.50
   0.33   0.66   1.00   1.33   1.66
   0.25   0.50   0.75   1.00   1.25
   0.20   0.40   0.60   0.80   1.00

m = ismember(d,1:N)      %find divisors of each number
m =

  1  1  1  1  1
  0  1  0  1  0
  0  0  1  0  0
  0  0  0  1  0
  0  0  0  0  1

idx = sort(m)                  %sort the matrix

idx =

  0  0  0  0  0
  0  0  0  0  0
  0  0  0  1  0
  0  1  1  1  1
  1  1  1  1  1

" #"(idx+1)     %replace 0 and 1 with ' ' and '#' respectively

                                                                                                          
   #
 ####
#####
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Very nice approach! \$\endgroup\$
    – Luis Mendo
    May 8, 2017 at 10:34
  • 2
    \$\begingroup\$ Octave performs singleton expansion implicitly, so @(N)" #"(sort(~mod(k=1:N,k')+1)) saves you a few bytes :) You get a bunch of leading newlines though, I'm not sure what the rules are in that regard. \$\endgroup\$ May 8, 2017 at 18:22
  • 1
    \$\begingroup\$ Same bytecount (32): @(N)['',35*sort(~mod(k=1:N,k'))]. \$\endgroup\$ May 8, 2017 at 18:33
  • \$\begingroup\$ @StewieGriffin Thanks! I didn't aware of that feature . Is mod(1:N,(1:N).') acceptable in MATLAB? \$\endgroup\$
    – rahnema1
    May 8, 2017 at 18:55
  • 3
    \$\begingroup\$ I think it is possible as of R2016b, but I can't test it myself unfortunately, since I don't have it. \$\endgroup\$ May 8, 2017 at 19:08
7
\$\begingroup\$

C, 99 95 92 91 90 bytes

c,l,i,j;f(n){for(j=n;j--;puts(""))for(i=0;i<n;c=!putchar(32|c>j))for(l=++i;l;c+=i%l--<1);}

See it work here.

\$\endgroup\$
6
\$\begingroup\$

Haskell, 71 bytes

f takes an Int and returns a String.

f m|l<-[1..m]=unlines[[last$' ':drop(m-i)['#'|0<-mod n<$>l]|n<-l]|i<-l]

Try it online!

  • m is the N of the OP (Haskell variables must be lowercase.)
  • The abbreviation l=[1..m] is used in the nested list comprehensions for iterating through all of rows, columns, and potential divisors. This means some extra initial rows filled with whitespace.
  • n is column (also number checked), i is row.
  • ['#'|0<-mod n<$>l] is a list of '#' characters with length the number of divisors of n.
\$\endgroup\$
6
\$\begingroup\$

Python 3, 111 bytes

lambda n:'\n'.join([*map(''.join,zip(*['#'*sum(x%-~i==0for i in range(x))+n*' 'for x in range(1,n+1)]))][::-1])

Try it online!


This produces some leading vertical whitespace

\$\endgroup\$
1
  • \$\begingroup\$ 109 bytes should do :) \$\endgroup\$
    – movatica
    Mar 3, 2021 at 14:28
6
\$\begingroup\$

Octave, 61 bytes

for i=1:input(''),p(1:nnz(~rem(i,1:i)),i)=35;end,[flip(p),'']

Explanation:

for i=1:input('')         % Loop, for i from 1 to the input value
 p(1:nnz(~rem(i,1:i)),i)=35;end,[flip(p),'']   
% Breakdown:
         ~rem(i,1:i)      % Return true if the remainder of i divided by any of the values
                          % in the vector 1 - i
     nnz(~rem(i,1:i))     % Check how many of them are non-zero
 p(1:nnz(~rem(i,1:i)),i)=35;end   % Assign the value 35 (ASCII for #) to rows 1
                                  % to the number of divisors of i, in column i
end,              % End loop
[flip(p),'']      % Flip the matrix, and concatenate it with the empty string

A few things I wish to highlight

  • Takes the input directly into the loop
    • Doesn't assign the input value to any variable
  • Doesn't initialize any array
    • It creates it on the fly, adding columns and rows as necessary
  • Automatically casts ASCII-value 0 to whitespace (ASCII-32)

What happens inside the loop (suppose input 6)

p =  35
p =
   35   35
    0   35
p =
   35   35   35
    0   35   35
p =
   35   35   35   35
    0   35   35   35
    0    0    0   35
p =
   35   35   35   35   35
    0   35   35   35   35
    0    0    0   35    0
p =
   35   35   35   35   35   35
    0   35   35   35   35   35
    0    0    0   35    0   35
    0    0    0    0    0   35

  1. Starts of as a single 35
  2. Expands one column and one row, to make room for the two divisors of 2
  3. Expands one column, to make room for 3 (only two divisors)
  4. Expands one column and one row, to make room for the 3 divisors (1,2,4)
  5. Expands one column, to make room for 5
  6. Expands one column and one row, to make room for the 4 divisors (1,2,3,6)

Finally we flip it, and converts it to a string, implicitly changing the 0 to 32:

warning: implicit conversion from numeric to char
ans =
     #
   # #
 #####
######
\$\endgroup\$
6
\$\begingroup\$

Mathematica, 59 57 bytes

Rotate[Grid@Map[X~Table~#&,0~DivisorSigma~Range@#],Pi/2]&

enter image description here

\$\endgroup\$
5
  • \$\begingroup\$ Welcome to answering on PPCG, fellow Lego minifig :-) \$\endgroup\$
    – Luis Mendo
    May 8, 2017 at 11:01
  • 2
    \$\begingroup\$ Now there's no turning back... \$\endgroup\$
    – Luis Mendo
    May 8, 2017 at 11:06
  • \$\begingroup\$ Welcome! Nice to see another Mathematica golfer. This answer isn't entirely valid though because you've hardcoded the input into the snippet. Answers need to be full programs or callable functions (which may be unnamed though). So this can be fixed at no cost by replacing 50 with # and appending &. You can save some bytes with infix notation as well: X~Table~#& and 0~DivisorSigma~Range@# \$\endgroup\$ May 8, 2017 at 11:14
  • \$\begingroup\$ @MartinEnder Thanks. I forgot that bit when I moved from testing to answering. And thanks for the hint about infixing. Its not something I normally use (as I don't really golf). \$\endgroup\$
    – Ian Miller
    May 8, 2017 at 11:30
  • \$\begingroup\$ 39 bytes: the central part can be done with 0Divisors@Range@#+X and the presentation expression becomes Rotate[Grid[0Divisors@Range@#+X],Pi/2]&. \$\endgroup\$
    – Roman
    Oct 16, 2020 at 18:02
6
\$\begingroup\$

C#, 333 281 Bytes

using System.Linq;using C=System.Console;class P{static void Main(){var n=int.Parse(C.ReadLine());var v=new int[n];for(var k=2;k<=n;k++)for(var i=1;i<k;i++)if(k%i==0)v[k-1]++;for(var i=0;i<v.Length;i++)for(var u=v.Max()-v[i];u<v.Max();u++){C.SetCursorPosition(i,u);C.Write("#");}}}

With line breaks:

using System.Linq;
using C = System.Console;

class P
{
    static void Main()
    {
        var n = int.Parse(C.ReadLine());
        var v = new int[n];
        for (var k = 2; k <= n; k++)
            for (var i = 1; i < k; i++)
                if (k % i == 0)
                    v[k - 1]++;
        for (var i = 0; i < v.Length; i++)
            for (var u = v.Max() - v[i]; u < v.Max(); u++)
            {
                C.SetCursorPosition(i, u);
                C.Write("#");
            }
    }
}

While I'm sure this is possible shorter as well, I hope we'll achieve a shorter solution together ;)

Saved 52 Bytes with the help of raznagul

\$\endgroup\$
4
  • 1
    \$\begingroup\$ If you use an int-array instead of a list, you can save a lot of bytes from the using-statement. \$\endgroup\$
    – raznagul
    May 8, 2017 at 15:06
  • \$\begingroup\$ @raznagul updated it. \$\endgroup\$
    – MetaColon
    May 8, 2017 at 15:16
  • \$\begingroup\$ 222 bytes: using System.Linq;using C=System.Console;n=>{var v=new int[n];for(var k=1,i;++k<=n;)for(i=1;i<k;)if(k%i++==0)v[k-1]++;for(var i=0,u;i<v.Length;i++)for(u=v.Max()-v[i];u<v.Max();){C.SetCursorPosition(i, u++);C.Write("#");}}; Compile to an Action, move the increments around and a couple of other minor tweaks. I haven't tested that but it should work. \$\endgroup\$ May 9, 2017 at 16:21
  • \$\begingroup\$ @TheLethalCoder I'll test it / update my answer tomorrow. \$\endgroup\$
    – MetaColon
    May 9, 2017 at 19:08
6
\$\begingroup\$

Mathematica, 99 bytes

{T=DivisorSigma[0,Range@#];Row[Column/@Table[Join[Table[,Max[T]-T[[i]]],$~Table~T[[i]]],{i,1,#}]]}&

for N=50

enter image description here

\$\endgroup\$
4
  • \$\begingroup\$ Are all those spaces (and newlines) necessary for the code to run? I've never programming Mathematica myself, but in most languages you could remove almost all of those spaces. \$\endgroup\$ May 8, 2017 at 10:40
  • \$\begingroup\$ this is my first golf. thanks for the tips \$\endgroup\$
    – ZaMoC
    May 8, 2017 at 22:47
  • 2
    \$\begingroup\$ No problem, and welcome to PPCG! If you haven't yet, you might find Tips for golfing in <all languages> and Tips for golfing in Mathematica interesting to read through. :) Enjoy your stay. \$\endgroup\$ May 9, 2017 at 7:14
  • \$\begingroup\$ The outer curly braces can be changed to round brackets to prevent them from showing in the output, and you can use some infix/prefix syntax to save 2 bytes: (T=0~DivisorSigma~Range@#;Row[Column/@Table[Join[Table[,Max@T-T[[i]]],$~Table~T[[i]]],{i,1,#}]])& \$\endgroup\$ May 21, 2017 at 2:13
5
\$\begingroup\$

APL (Dyalog), 19 bytes

⊖⍉↑'#'⍴¨⍨+⌿0=∘.|⍨⍳⎕

Try it online!

 get evaluated input (N)

 1...N

∘.|⍨ division remainder table with 1...N both as vertical and as horizontal axis

0= where equal to zero (i.e. it divides)

+⌿ sum the columns (i.e. gives count of divisors for each number)

'#'⍴¨⍨ use each number to reshape the hash character (gives list of strings)

 mix (list of strings into table of rows)

 transpose

 flip upside down

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

Charcoal, 23 22 20 bytes

F…·¹N«Jι⁰Fι¿¬﹪ι⁺κ¹↑#

Try it online! Link is to verbose version of code. Edit: Saved 1 byte by looping k from 0 to i-1 and adding 1 inside the loop. Saved a further two bytes by not storing the input in a variable. Explanation:

F…·¹N       for (i : InclusiveRange(1, InputNumber()))
«           {
 Jι⁰         JumpTo(i, 0);
 Fι          for (k : Range(i))
  ¿¬﹪ι⁺κ¹     if (!(i % (k + 1)))
   ↑#          Print(:Up, "#");
            }

Edit: This 18-byte "one-liner" (link is to verbose version of code) wouldn't have worked with the version of Charcoal at the time the question was submitted: Try it online!

↑E…·¹N⪫Eι⎇﹪ι⁺¹λω#ω
\$\endgroup\$
1
4
\$\begingroup\$

Python 2, 101 bytes

N=input();r=range
for i in r(N,0,-1):print''.join('# '[i>sum(x%-~p<1for p in r(x))]for x in r(1,1+N))

Try it online!

This produces (a lot of) vertically leading whitespace. It prints a total of N lines, the great majority of which will typically be blank.

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

Japt, 34 33 16 14 bytes

Saved 17 bytes thanks to @ETHproductions

õ@'#pXâ l÷z w

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ You can save a lot of bytes by just letting z do the padding: õ_â lã'#pX÷z w \$\endgroup\$ May 8, 2017 at 17:05
  • \$\begingroup\$ Didn't know that padded the strings automatically. Thanks! \$\endgroup\$
    – Luke
    May 8, 2017 at 18:51
4
\$\begingroup\$

SOGL V0.12, 8 bytes

∫Λ⁄╗*}⁰H

Try it here!

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

05AB1E, 12 bytes

Code:

LÑ€g'#×.BøR»

Explanation:

L             # Create the range 1 .. input
 Ñ            # Get the list of divisors of each
  €g          # Get the length of each element
    '#        # Push a hash tag character
      ×       # String multiply
       .B     # Squarify, make them all of equal length by adding spaces
         ø    # Transpose
          R   # Reverse the array
           »  # Join by newlines

Uses the 05AB1E encoding. Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Can't you use ζ instead of .Bø? Also, the character doesn't have to be # \$\endgroup\$
    – Oliver Ni
    Aug 9, 2017 at 13:27
  • \$\begingroup\$ ζ didn't exist back then. \$\endgroup\$ Aug 9, 2017 at 14:37
3
\$\begingroup\$

R, 83 82 bytes

-1 byte thanks to MickyT

N=scan();m=matrix('#',N,N);for(i in 1:N)m[i,1:sum(i%%1:N>0)]=' ';write(m,'',N,,'')

Reads N from stdin.

N=scan()                        # read N
m=matrix('#',N,N)               # make an NxN matrix of '#' characters
for(i in 1:N)                   # for each integer in the range
    m[i,1:sum(i%%1:N!=0)]=' '   # set the first n-d(n) columns of row i to ' '
write(m,'',N,,'')               # print to console with appropriate formatting

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ !=0 can be >0 \$\endgroup\$
    – MickyT
    May 10, 2017 at 22:47
3
\$\begingroup\$

PowerShell, 101 bytes

((($d=1.."$args"|%{($x=$_)-(1..$_|?{$x%$_}).Count})|sort)[-1])..1|%{$l=$_;-join($d|%{' #'[$_-ge$l]})}

Less golfed test script:

$f = {

$d=1.."$args"|%{
    ($x=$_)-(1..$_|?{$x%$_}).Count
}                                     # $d is the Divisor count array
$maxHeight=($d|sort)[-1]
$maxHeight..1|%{
    $l=$_
    -join($d|%{' #'[$_-ge$l]})
}

}

@(
    ,(10, 
    "     # # #",
    "   # # ###",
    " #########",
    "##########")

    ,(50, 
    "                                               #  ",
    "                                   #           #  ",
    "                       #     #     #   # #     #  ",
    "                       #     #     #   # #     #  ",
    "           #     # #   #   # # #   #   # # ##  # #",
    "           #   # # #   #   # # #   #   # # ##  # #",
    "     # # # # ### # ### # ### # ##### ### # ### # #",
    "   # # ### # ### # ### ##### # ##### ### # ### ###",
    " #################################################",
    "##################################################")

    ,(200,
    "                                                                                                                                                                                   #                    ",
    "                                                                                                                                                                                   #                    ",
    "                                                                                                                       #                                               #           #                    ",
    "                                                                                                                       #                       #                       #           #                    ",
    "                                                                                                                       #                       #                       #           #           #        ",
    "                                                                                                                       #                       #                       #           #           #        ",
    "                                                           #           #           #     #     #           #           #     #     #       #   #     #     #   #       #           #           #     # #",
    "                                                           #           #           #     #     #           #           #     #     #       #   #     #     #   #       #           #           #     # #",
    "                                               #           #           #       #   #     #     #           #   #       #     #     #       #   #     #     #   # #     #       #   #           #     # #",
    "                                   #           #           #           #       #   #     #     #   #       #   #       #     #     #       #   #     #     #   # #     #       #   #           #   # # #",
    "                       #     #     #   # #     #     # #   #     #   # #     # #   #   # #     #   # # ##  # # # #     #     # # # #  ## # #   #     # # # #   # #  #  # #   # #   # # # #  ## #  ## # #",
    "                       #     #     #   # #     #     # #   #   # #   # #     # #   #   # #     #   # # ##  # # # #     #     # # # #  ## # #   #     # # # #   # #  #  # #   # #   # # # #  ## #  ## # #",
    "           #     # #   #   # # #   #   # # ##  # # # # #   #  ## # # # #  ## # #   #   # # #   # ### # ##  # # # # ##  #   # # # # #  ## # #   #  ## # ### #   # # ##  # ### ###   # # # # ### #  ## # #",
    "           #   # # #   #   # # #   #   # # ##  # # # # #   #  ## # # # #  ## # ##  #   # # #   # ### # ##  # # # # ##  #   # # # # #  ## # #   #  ## # ### #   # # ##  # ### ###   # # # # ### #  ## # #",
    "     # # # # ### # ### # ### # ##### ### # ### # ### ##### # ##### ### # ##### ### ##### ####### ### # ### # ### ####### ##### ### ##### # ######### # ##### ##### ### # ### ##### # ######### # ### # #",
    "   # # ### # ### # ### ##### # ##### ### # ### ##### ##### # ##### ### # ##### ### ##### ####### ### # ### # ### ############# ### ##### # ######### # ##### ##### ### ##### ##### # ######### # ### # #",
    " #######################################################################################################################################################################################################",
    "########################################################################################################################################################################################################")


) | % {
    $n,$expected = $_
    $result = &$f $n
    "$result"-eq"$expected"
    #$result    # uncomment this to enjoy the view of the Divisor skyline
}

Output:

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

Husk, 13 11 bytes

↔T' †K'#mḊḣ

Try it online!

-2 bytes from Ko King(No, not JoKing).

\$\endgroup\$
4
  • \$\begingroup\$ Don't you mean JoKing? \$\endgroup\$
    – lyxal
    Oct 10, 2020 at 8:20
  • \$\begingroup\$ @Lyxal Absolutely not \$\endgroup\$
    – Razetime
    Oct 10, 2020 at 8:38
  • \$\begingroup\$ Who is this ko king? \$\endgroup\$
    – lyxal
    Oct 10, 2020 at 8:42
  • \$\begingroup\$ Here. \$\endgroup\$
    – Razetime
    Oct 10, 2020 at 9:08
2
\$\begingroup\$

J, 28 bytes

[:|:&.|.[('#',@$~1+_&q:)@-i.

Defines a monadic verb. Try it online!

Explanation

[:|:&.|.[('#',@$~1+_&q:)@-i.  Input is y.
                          i.  Range from 0 to y-1
        [                -    subtracted from y (gives range from y to 1).
         (             )@     For each of the numbers:
                   _&q:         Compute exponents in prime decomposition,
                 1+             add 1 to each,
          '#'  $~               make char matrix of #s with those dimensions,
             ,@                 and flatten into a string.
                              The resulting 2D char matrix is padded with spaces.
[:|:&.|.                      Reverse, transpose, reverse again.
\$\endgroup\$
2
\$\begingroup\$

PHP, 126 Bytes

for(;$n++<$argn;)for($c=$d=0;$d++<$n;)$n%$d?:$r[$n]=++$c;for($h=max($r);$h--;print"
")for($n=0;$n++<$argn;)echo$h<$r[$n]?:" ";

Try it online!

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

Brachylog, 34 bytes

⟦fᵐlᵐgDh⌉⟦↔gᵐ;D↔z{z{>₁∧0ṫ|∧Ṣ}ᵐcẉ}ᵐ

Try it online!

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

Alice, 33 bytes

I.!.t&w?t!aot&wh.Bdt.?-ex' +o&;k@

Try it online!

Input is (unfortunately) in the form of a code point. At least it reads a UTF-8 character, so you can use larger inputs than 255, but they're still limited and it's a pretty painful input format. For three additional bytes, we can read a decimal integer:

/
ki@/.!.t&w?t!aot&wh.Bdt.?-ex' +o&;

Try it online!

The non-whitespace character in the output is !.

Note that the solution also prints a ton of leading whitespace (it always starts with an empty line and then prints an NxN grid so for larger N, there will be many lines of spaces before the first !s.)

Explanation

I've used and explained the &w...k construction before (for example here). It's a neat little idiom that pops an integer n and then runs a piece of code n+1 times (consequently, it's usually used as t&w...k to run a loop n times, with t decrementing the input value). This is done by working with the return address stack (RAS). w pushes the current IP address to the RAS, and if we repeat it with & then the address gets pushed n times. k pops one address from the RAS and jumps back there. If the RAS is empty, it does nothing at all and the loop is exited.

You might notice that it's not trivially possible to nest these loops, because at the end of the inner loop, the stack isn't empty, so the k doesn't become a no-op. Instead, the IP would jump back to the beginning of the outer loop. The general way to fix this involves wrapping the inner loop in its own subroutine. But if we can arrange the nested loop such that the outer loop ends with the inner loop, we can actually make use of this behaviour and even save on one k!

So this construction:

&wX&wYk

Is a working nested loop which runs the XYYYXYYYXYYY... (for some number of Ys in each iteration). It's pretty neat that we can end both loops with a single k, because it will consume an outer address from RAS each time the inner addresses have been depleted.

This idiom is used in the program to run the loop over the output grid.

I         Read a character and push its code point as input N.
.!        Store a copy on the tape.
.         Make another copy.
t&w       Run this outer loop N times. This loops over the lines of the
          output, so the current iteration corresponds to a divisor count
          no more than i (i counting down from N).
  ?t!       Decrement the value on the tape. That means we'll actually have
            i-1 on the tape during the iteration.
  ao        Print a linefeed. Doing this now leads to the weird leading linefeed, 
            but it's necessary for the &w...&w...k pattern.
  t&w       Remember that we still have a copy of N on the stack. We'll also
            ensure that this is the case after each loop iteration. So this
            also runs the inner loop N times. This iterates over the columns
            of the output grid so it's j that goes from 1 to N and corresponds
            to the number whose divisors we want to visualise.
              At this point the stack will always be empty. However, operating
              on an empty stack works with implicit zeros at the bottom of
              the stack. We'll use the top zero to keep track of j.
    h         Increment j.
    .B        Duplicate j and push all of its divisors.
    dt        Push the stack depth minus 1, i.e. the divisor count of j.
    .         Duplicate the divisor count.
    ?-        Retrieve i-1 from the tape and subtract it. So we're computing
              d(j)-i+1. We want to output a non-whitespace character iff this
              value is positive (i.e. if i is no greater than d(j)).
    ex        Extract the most significant bit of this value. This is 1 for
              all positive values and 0 for non-positive ones. It's the shortest
              way (I believe) to determine if a value is positive.
    ' +       Add this to the code point of a space. This gives a 33, or '!',
              if the cell is part of the skyline.
    o         Output the character.
    &;        We still have all the divisors and the divisor count on the stack.
              We pop the divisor count to discard that many values (i.e. to
              get rid of the divisors again).
k         Return to the appropriate loop beginning to run the continue the
          nested loop.
@         Terminate the program.
\$\endgroup\$
3
  • 1
    \$\begingroup\$ First Alice program with a single line ever? :-) \$\endgroup\$
    – Luis Mendo
    May 7, 2017 at 20:19
  • 1
    \$\begingroup\$ @LuisMendo No, I think Leo has written a few Cardinal-only programs (and maybe I have as well... the quine and the Hello, World for example). Probably the most elaborate single-line program though. :) \$\endgroup\$ May 7, 2017 at 20:20
  • \$\begingroup\$ Hmm, my solution could save some bytes with "ton of leading whitespace" trick \$\endgroup\$
    – quintopia
    May 8, 2017 at 16:51
2
\$\begingroup\$

Actually, 25 bytes

R♂÷♂l;M' *╗⌠'#*╜@+⌡M┬♂ΣRi

Try it online!

22-byte version with a lot of leading newlines

;╗R⌠÷l'#*╜' *@+⌡M┬♂ΣRi

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Okay, the Readme on the github should be updated to include ÷l as the standard divisor counting function... \$\endgroup\$
    – quintopia
    May 8, 2017 at 17:03
2
\$\begingroup\$

SpecBAS - 149 bytes

1 INPUT n: DIM h(n)
2 FOR i=1 TO n
3 FOR j=1 TO i
4 h(i)+=(i MOD j=0)
5 NEXT j
6 NEXT i
7 FOR i=1 TO n
8 FOR j=51-h(i) TO 50
9  ?AT j,i;"#"
10 NEXT j
11 NEXT i

An array keeps track of number of divisors, then prints the right number of characters down to screen position 50.

enter image description here

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

PHP, 99 bytes

for(;$d<$k?:$k++<$argn+$d=$n=0;)$k%++$d?:$r[--$n]=str_pad($r[$n],$k).H;ksort($r);echo join("
",$r);

prints one leading space; run as pipe with php -nr '<code>' or try it online.

breakdown

for(;$d<$k?:                    # inner: loop $d from 1 to $k
    $k++<$argn+$d=$n=0;)        # outer: loop $k from 1 to $argn, reset $d and $n
    $k%++$d?:                       # if $d divides $k
        $r[--$n]=str_pad($r[$n],$k).H;  # add one store to building $k
ksort($r);echo join("\n",$r);   # reverse and print resulting array
\$\endgroup\$
2
\$\begingroup\$

Wolfram Language (Mathematica), 46 44 bytes

Grid[PadLeft[0Divisors@Range@#-" "]+" "]&

Try it online! But maybe try it online! with ColumnForm instead of Grid, since Grid doesn't work in TIO. In Mathematica, it looks better:

Mathematica output

A third Mathematica solution... Divisors@Range@# finds all the divisors in the range we want, and then we multiply by 0 and subtract " ", making every divisor equal to -" ".

PadLeft adds zeroes on the left, creating a sideways skyline, whose orientation we fix with =\[Transpose]. Finally, adding " " to everything makes all entries either 0 or " ".

As an alternative, the 59-byte ""<>Riffle[PadLeft["X"-" "+0Divisors@Range@#]+" ","\n"]& produces string output.

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

Add++, 58 bytes

D,g,@,FL1+
D,k,@~,J
L,R€gd"#"€*$dbM€_32C€*z£+bUBcB]bR€kbUn

Try it online!

How it works

Our program consists of two helpers functions, g and k, and the main lambda function. g iterates over each integer, \$x\$, between \$1\$ and \$n\$ and returns \$d(x)\$ as defined in the challenge body, while k takes a list of characters and concatenates them into a single string.

The main lambda function generates \$A = [d(1), d(2), d(3), ..., d(n)]\$, then repeats the # character for each element of \$A\$. We then take \$\max(A)\$, and subtract each element in \$A\$ from this maximum, before yielding this number of spaces for each element and concatenating the spaces to the repeated hashes. Next, we transpose and reverse the rows, before joining each line on newlines. Finally, we output the skyline.

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

05AB1E, 7 bytes

LÑ_ζRJ»

Uses 0 (or 1) instead of #.

Try it online.

Explanation:

L        # Push a list in the range [1, (implicit) input]
 Ñ       # Convert each value to a list of its divisors
  _      # Convert each inner integer to 0
   ζ     # Zip/transpose; swapping rows/columns, with space as default filler
    R    # Reverse the list of lists
     J   # Join each inner list together
      »  # And then join the list of strings by newlines
         # (after which the result is output implicitly)

The _ (==0) has some a few alternatives to get distinct values: a (is_alphabetic); Ā (!=0); d (>=0):
try it online.

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

Vyxal, L, 6 5 bytes

ƛKL×*

Try it Online!

Explained

ƛKL×*
ƛ       # Over the range [1, input] do the following:
 KL     #   Push the length of the list of that number's divisors
   ×    #   Push '*'
    *   #   And multiply the two together, repeating the "*"
        # Automatically close the map and then use the L flag to vertically join that list
\$\endgroup\$
4
  • \$\begingroup\$ ƛ this character been exercising(also this answer is scarily short) \$\endgroup\$
    – Razetime
    Oct 10, 2020 at 8:39
  • \$\begingroup\$ It is spooktober after all lol \$\endgroup\$
    – lyxal
    Oct 10, 2020 at 8:39
  • \$\begingroup\$ It's incredible how many M flags my suggestion has reduced... \$\endgroup\$
    – user100947
    Mar 3, 2021 at 2:09
  • \$\begingroup\$ @2x-1 I know. Thank you! \$\endgroup\$
    – lyxal
    Mar 3, 2021 at 2:12
1
\$\begingroup\$

Pyth, 16 bytes

j_.tm*\#/%LdSQ0S

Try it online!

\$\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.