The Digit Triangles

26

2

Challenge:

Input: A positive integer \$n\$

Output:

Create a list in the range \$[1,n]\$, and join it together to a string (i.e. \$n=13\$ would be the string 12345678910111213).

Now we output a triangle using the prefixes or suffixes of this string, in one of the following four orientations based on the input integer:

  • If \$n\equiv 0\pmod 4\$, output it in the triangle shape ◣
  • If \$n\equiv 1\pmod 4\$, output it in the triangle shape ◤
  • If \$n\equiv 2\pmod 4\$, output it in the triangle shape ◥
  • If \$n\equiv 3\pmod 4\$, output it in the triangle shape ◢

Example:

Input: \$n=13\$

Because \$13\equiv 1\pmod 4\$, the shape will be ◤. Here three possible valid outputs:

12345678910111213    11111111111111111    12345678910111213
1234567891011121     2222222222222222     2345678910111213
123456789101112      333333333333333      345678910111213
12345678910111       44444444444444       45678910111213
1234567891011        5555555555555        5678910111213
123456789101         666666666666         678910111213
12345678910          77777777777          78910111213
1234567891           8888888888           8910111213
123456789            999999999            910111213
12345678             11111111             10111213
1234567              0000000              0111213
123456               111111               111213
12345                11111                11213
1234                 1111                 1213
123                  222                  213
12                   11                   13
1                    3                    3

Challenge rules:

  • As you can see at the three valid outputs above, only the correct shape and using all the digits in the correct order is important. Apart from that you're free to use prefixes or suffixes; reverses/reflects; diagonal printing; etc. etc. Any of the six possible outputs for each shape is allowed (see the test case below to see all valid outputs based on the shape). This allows languages with rotation builtins to use it, but those without can also use an alternative approach of using the prefixes in the correct size from top-to-bottom, or using the prefixes for two of the shapes but suffixes for the other two shapes. Choosing the most appropriate output options for your language is part of the golfing process. :)
  • Input is guaranteed to be a positive integer. For \$n=1\$ we simply output 1.
  • Any amount of leading/trailing newlines/spaces are allowed, as long as it prints the correct triangle (without vertical nor horizontal delimiters!) somewhere on the screen.

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer with default I/O rules, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code (i.e. TIO).
  • Also, adding an explanation for your answer is highly recommended.

Test cases:

Input: \$n=5\$
All possible valid outputs:

12345    54321    12345    54321    11111    55555
1234     5432     2345     4321     2222     4444
123      543      345      321      333      333
12       54       45       21       44       22
1        5        5        1        5        1

Input: \$n=6\$
All possible outputs:

123456    654321    123456    654321    111111    666666
 12345     65432     23456     54321     22222     55555
  1234      6543      3456      4321      3333      4444
   123       654       456       321       444       333
    12        65        56        21        55        22
     1         6         6         1         6         1

Input: \$n=7\$
All possible outputs:

      1          1          7          7          7          1
     12         21         67         76         66         22
    123        321        567        765        555        333
   1234       4321       4567       7654       4444       4444
  12345      54321      34567      76543      33333      55555
 123456     654321     234567     765432     222222     666666
1234567    7654321    1234567    7654321    1111111    7777777

Input: \$n=8\$
All possible outputs:

1           1           8           8           8           1
12          21          78          87          77          22
123         321         678         876         666         333
1234        4321        5678        8765        5555        4444
12345       54321       45678       87654       44444       55555
123456      654321      345678      876543      333333      666666
1234567     7654321     2345678     8765432     2222222     7777777
12345678    87654321    12345678    87654321    11111111    88888888

Input: \$n=1\$
Only possible output:

1

Input: \$n=2\$
All possible outputs:

12    21    12    21    11    22
 1     2     2     1     2     1

Kevin Cruijssen

Posted 2019-03-20T13:17:20.643

Reputation: 67 575

Can we use other values for different triangles, like 1 for ◤, etc? – Embodiment of Ignorance – 2019-03-20T16:44:02.860

@EmbodimentofIgnorance Unfortunate example, since that's what the spec says. I think you wanted to ask if we can change the order of the four arrangements as long as we keep it consistent (I think that would be a no). – Erik the Outgolfer – 2019-03-20T17:04:55.580

1If n==13, can the topmost row be '33333333333333333' (or, equivalently, '31211101987654321')? – Chas Brown – 2019-03-20T19:42:23.253

@EmbodimentofIgnorance Sorry, but I'd say no in this case. The shapes and their corresponding mod 4 are strict pairs for this challenge. So you may not switch the four shapes for the four mod 4 cases. But good question nonetheless. – Kevin Cruijssen – 2019-03-20T21:42:58.210

@ChasBrown Yes, both of those are fine. I only gave three possible examples for the $n=13$, but all six options (like the $n=5$ test case) are valid outputs. – Kevin Cruijssen – 2019-03-20T21:44:30.110

Answers

9

JavaScript (ES6),  93  89 bytes

Returns a matrix of characters.

n=>[...(g=n=>n?g(n-1)+n:'')(n)].map((d,y,a)=>a.map(_=>y-(n&2)*y--<0?' ':d)).sort(_=>-n%2)

Try it online!

Alternate pattern (same size):

n=>[...(g=n=>n?g(n-1)+n:'')(n)].map((_,y,a)=>a.map(d=>y-(n&2)*y--<0?' ':d)).sort(_=>-n%2)

Try it online!

Commented

n =>                 // n = input
  [...               // split the result of ...
    ( g = n =>       //   ... a call to the recursive function g, taking n
      n ?            //     if n is not equal to 0:
        g(n - 1)     //       append the result of a recursive call with n - 1
        + n          //       append n
      :              //     else:
        ''           //       stop recursion and return an empty string
    )(n)             //   initial call to g
  ].map((d, y, a) => // for each digit d at position y in this array a[]:
    a.map(_ =>       //   for each character in a[]:
      y -            //     we test either y < 0 if (n AND 2) is not set
      (n & 2)        //     or -y < 0 (i.e. y > 0) if (n AND 2) is set
      * y-- < 0      //     and we decrement y afterwards
      ?              //     if the above condition is met:
        ' '          //       append a space
      :              //     else:
        d            //       append d
    )                //   end of inner map()
  )                  // end of outer map()
  .sort(_ => -n % 2) // reverse the rows if n is odd

Shape summary

Below is a summary of the base shape (generated by the nested map loops) and the final shape (after the sort) for each \$n\bmod 4\$:

 n mod 4  | 0     | 1     | 2     | 3
----------+-------+-------+-------+-------
 n & 2    | 0     | 0     | 2     | 2
----------+-------+-------+-------+-------
 test     | y < 0 | y < 0 | y > 0 | y > 0
----------+-------+-------+-------+-------
 base     | #.... | #.... | ##### | #####
 shape    | ##... | ##... | .#### | .####
          | ###.. | ###.. | ..### | ..###
          | ####. | ####. | ...## | ...##
          | ##### | ##### | ....# | ....#
----------+-------+-------+-------+-------
 n % 2    | 0     | 1     | 0     | 1
----------+-------+-------+-------+-------
 reverse? | no    | yes   | no    | yes
----------+-------+-------+-------+-------
 final    | #.... | ##### | ##### | ....#
 shape    | ##... | ####. | .#### | ...##
          | ###.. | ###.. | ..### | ..###
          | ####. | ##... | ...## | .####
          | ##### | #.... | ....# | #####

Arnauld

Posted 2019-03-20T13:17:20.643

Reputation: 111 334

1thank you for your detail explaining. – chau giang – 2019-03-22T10:43:37.593

9

Python 2, 94 bytes

n=0;s=''
exec"n+=1;s+=`n`;"*input()
K=k=len(s)
while k:k-=1;print s[k^n/-2%-2:].rjust(n%4/2*K)

Try it online!

xnor

Posted 2019-03-20T13:17:20.643

Reputation: 115 687

7

Japt, 8 bytes

Returns an array of lines.

õ ¬å+ zU

Try it

Saved 2 bytes thanks to Kevin.

õ ¬å+ zU     :Implicit input of integer U
õ            :Range [1,U]
  ¬          :Join to a string
   å+        :Cumulatively reduce by concatenation
      zU     :Rotate clockwise by 90 degrees U times

Shaggy

Posted 2019-03-20T13:17:20.643

Reputation: 24 623

1Is the ú necessary? It seems the rotate does this implicitly? – Kevin Cruijssen – 2019-03-20T14:12:15.417

@KevinCruijssen, hmm ... so it does. I always forget that; rarely get to use z. – Shaggy – 2019-03-20T14:24:37.857

1Well, I don't know Japt at all. Was just curious what the output looked like without the padding for fun, and saw it worked exactly the same.. ;) – Kevin Cruijssen – 2019-03-20T14:30:10.287

4

Canvas, 8 bytes

ŗ]∑[]⁸[↷

Try it here!

dzaima

Posted 2019-03-20T13:17:20.643

Reputation: 19 048

4

Perl 6, 94 bytes

{[o](|(&reverse xx$_/2+.5),|(*>>.flip xx$_/2+1))([\~](my@a=[~](1..$_).comb)>>.fmt("%{+@a}s"))}

Try it online!

Anonymous code block that takes a number and returns a list of lines.

Jo King

Posted 2019-03-20T13:17:20.643

Reputation: 38 234

3

Charcoal, 17 bytes

Nθ≔⭆θ⊕ιηGLLηη⟲⊗θ‖

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

Nθ

Input n.

≔⭆θ⊕ιη

Create a string by concatenating the numbers 1 to n.

GLLηη

Fill a triangle of that length with the string.

⟲⊗θ

Rotate the triangle anticlockwise by n*90 degrees.

Reflect everything, thus ending up with a triangle that is rotated clockwise by n*90 degrees.

Neil

Posted 2019-03-20T13:17:20.643

Reputation: 95 035

3

Ruby, 95 82 79 bytes

->n{r=(0...z=/$/=~s=[*1..n]*'').map{|i|" "*n[1]*i+s[0,z-i]};-n&2>0?r:r.reverse}

Try it online!

3 bytes saved by G B.

Kirill L.

Posted 2019-03-20T13:17:20.643

Reputation: 6 693

3

C# (Visual C# Interactive Compiler), 128 bytes

n=>{var s="";int i=0,j,p;for(;i<n;s+=++i);for(p=j=s.Length;;)Write("{0,"+(n%4>1?p:0)+"}\n",new string(s[--j],-~n%4>1?j+1:p-j));}

Try it online!

Embodiment of Ignorance

Posted 2019-03-20T13:17:20.643

Reputation: 7 014

3

R, 152 139 137 134 bytes

function(n,N=nchar(s<-Reduce(paste0,1:n,'')),A=!n%%4%%3)for(i in 1:N)cat(rep('',(M=c(N-i+1,i))[1+!A]*(n%%4>1)),substr(s,1,M[1+A]),'
')

Unrolled code :

function(n){
  s = Reduce(paste0,1:n,'')      # concat the digits from 1 to n into a string s

  N = nchar(s)                   # store the length of s

  A = !n%%4%%3                   # A = TRUE if n MOD 4 == 1 or 2 

  for(i in 1:N){                 # for 1 to N (length of s)

    M = c(N-i+1,i)               # store N-i+1 and i into a vector

    nSpaces = M[1+!A]*(n%%4>1)   # if n MOD 4 == 1 or 2 then nSpaces = i else nSpaces = N-i+1, 
                                 # but if n MOD 4 == 0 or 1, then force nSpaces = 0

    nDigits = M[1+A]             # if n MOD 4 == 1 or 2 then nDigits = N-i+1 else nDigits = i

    prfx = rep('',)              # create a character vector repeating '' nSpaces times

    sufx = substr(s,1,M[1+A])    # substring s by taking the first nDigits characters

    cat(pr,su,'\n')              # print prfx and sufx using space as separator for the values 
                                 # contatenation (cat function default) and append a newline
  }

Try it online!

digEmAll

Posted 2019-03-20T13:17:20.643

Reputation: 4 599

...it hasn't been my day for golfing, clearly. – Giuseppe – 2019-03-22T21:51:20.430

@Giuseppe: ahah been there...and then you usually outgolfed me :P – digEmAll – 2019-03-23T11:55:42.900

2

APL+WIN, 45 bytes

Prompts for integer

m←⊃(⍳⍴s)↑¨⊂s←(⍕⍳n←⎕)~' '⋄⍎(' ⊖⍉⌽'[1+4|n]),'m'

Try it online! Courtesy of Dyalog Classic

Graham

Posted 2019-03-20T13:17:20.643

Reputation: 3 184

2

05AB1E (legacy), 14 12 10 bytes

Using the legacy verion as the rewrite is extremely slow on this for some reason.

Saved 2 bytes thanks to Kevin Cruijssen

LSηsFRζ}J»

Try it online!

Explanation

L           # push range [1 ... input]
 S          # split to list of individual digits
  η         # calculate prefixes
   sF  }    # input times do:
     R      # reverse list
      ζ     # and transpose it
        J   # join to list of strings
         »  # and join on newlines

Emigna

Posted 2019-03-20T13:17:20.643

Reputation: 50 798

You can save 2 bytes changing LJη€S to LSη, since S implicitly flattens. – Kevin Cruijssen – 2019-03-20T14:22:07.197

@KevinCruijssen: Oh yeah, thanks! I'd forgotten about that. I tried €S which didn't work out very well ;) – Emigna – 2019-03-20T14:24:28.180

2

PowerShell, 108 bytes

param($n)0..($y=($x=-join(1..$n)).length-1)|%{' '*(0,0,$_,($z=$y-$_))[$n%4]+-join$x[0..($_,$z,$z,$_)[$n%4]]}

Try it online!

A bit rough around the edges but works. Joins the digits 1 to n into a string then iterates from 0 to the length of that string-1. Each time, it uses list indexing to swap to the correct spacing method and number range used to slice our new string.

Veskah

Posted 2019-03-20T13:17:20.643

Reputation: 3 580

2

Jelly, 12 bytes

D€Ẏ;\z⁶U$⁸¡Y

Try it online!

Erik the Outgolfer

Posted 2019-03-20T13:17:20.643

Reputation: 38 134

2

Stax, 10 bytes

Ç√çZ╟84Γó║

Run and debug it

recursive

Posted 2019-03-20T13:17:20.643

Reputation: 8 616

2

PowerShell, 105 101 95 bytes

-4 bytes thanks Arnauld for the trick with Sort.

param($n)($x=1..$n-join'')|% t*y|%{($s+="$_")}|sort -d:($n%4-in1,2)|% *ft($x.Length*($n%4-ge2))

Try it online!

Less golfed:

param($n)
$x=1..$n-join''
$x|% toCharArray |% {
    ($s+="$_")
} | sort -Descending:($n%4-in1,2) |% PadLeft ($x.Length*($n%4-ge2))

mazzy

Posted 2019-03-20T13:17:20.643

Reputation: 4 832

2

R, 175 172 154 bytes

function(n)write(c(" ",0:9)[1+(x=utf8ToInt(Reduce(paste0,1:n,""))-47)*!upper.tri(diag(y<-sum(x|1)))["if"(n%%4>1,1:y,y:1),"if"(!n%%4%%3,y:1,1:y)]],1,y,,"")

Try it online!

A horrible in-line mess!

-3 bytes by changing the rotation condition

-17 bytes thanks to digEmAll's suggestion, and another byte after golfing that further

Giuseppe

Posted 2019-03-20T13:17:20.643

Reputation: 21 077

I like this upper.triangle approach and can be shortened to 155 bytes... maybe even more, I'm sure I'm missing something obvious...

– digEmAll – 2019-03-23T13:35:00.707

@digEmAll ah, much improved, but still long :-( – Giuseppe – 2019-03-24T00:46:36.043

1

Wolfram Language (Mathematica), 137 bytes

(t=Table[Table[" ",If[(m=#~Mod~4)>1,Tr[1^s]-k,0]]<>ToString/@s[[;;k]],{k,Length[s=Join@@IntegerDigits/@Range@#]}];If[0<m<3,Reverse@t,t])&

Try it online!

J42161217

Posted 2019-03-20T13:17:20.643

Reputation: 15 931

1

Python 2, 116 bytes

n=input()
s=''.join(map(str,range(1,n+1)));L=len(s)
p=-~n/2%2;i=~-L*p+1
exec'print s[:i].rjust(n/2%2*L);i+=1-2*p;'*L

Try it online!

Chas Brown

Posted 2019-03-20T13:17:20.643

Reputation: 8 959

1

Red, 155 bytes

func[n][b: copy""repeat i n[append b i]repeat i l:
length? b[t:[l - i + 1]set[k m]pick[i t[l t][l i]]n % 4 + 1
print pad/left copy/part b do do m do do k]]

Try it online!

Galen Ivanov

Posted 2019-03-20T13:17:20.643

Reputation: 13 815

1

perl 5, 117 bytes

$p=$_++&2?'/ ':'$/';$s='(.*\d.\n)';$r=$_--&2?$s.'\K$':"^(?=$s)";$_=(join"",1..$_).$/;1while s,$r,'$1=~s/\d'."$p/r",ee

TIO

Nahuel Fouilleul

Posted 2019-03-20T13:17:20.643

Reputation: 5 582

1

PHP, 116 111 109 bytes

for($m=$l=strlen($s=join(range(1,$n=$argn)));$l--;)printf('%'.($n&2?$m:-$l).'.'.($n-1&2?$m-$l:$l+1)."s
",$s);

Try it online!

Run with php -nF input from STDIN.

$ echo 6|php -nF t.php

123456
 12345
  1234
   123
    12
     1

640KB

Posted 2019-03-20T13:17:20.643

Reputation: 7 149

1

Java (JDK), 247 209 188 186 160 148 bytes

i->{String s="";int l=0,w;for(;l<i;s+=++l);for(w=s.length(),l=0;l<w;)System.out.printf("%"+(1>i%4/2?1:w)+"s\n",s.substring(0,1>~-i%4/2?w-l++:++l));}

Try it online!

-38 bytes thanks to @KevinCruijssen
-21 bytes by letting printf handle the padding.
-2 bytes by doing substring before replace, allowing us to increment l in one location rather than two.
-26 bytes - with printf doing the padding, the string full of spaces was no longer necessary, and the digit strings could be generated in a shorter way apparently.
-12 bytes by not messing about with single digits instead of printing substrings of the perfectly servicable digit string we already have.

Ungolfed

input->{
    // Lambda expression with target type of IntConsumer
    String allDigits = "";
    int lineLength, line = 0;

    // Collect a list of all digits in order.
    for (;line < input; allDigits += ++line) {}

    // Save the max length of a line, and create a string of that many spaces.
    for (lineLength=allDigits.length(), line=0; line < lineLength;) {
        System.out.printf(   "%" // construct a format string to handle the padding
                           + (   1 > input%4/2
                               ? 1 // No padding
                               : w // Yes padding
                             )
                           + "s\n"
                         , allDigits.substring( 0
                                              ,   1 > (i-1)%4/2
                                                ? w - l++
                                                : ++l
                                              ) // A string containing only the digit we want.
                         );
    }
}

Sara J

Posted 2019-03-20T13:17:20.643

Reputation: 2 576

1

Nice answer. There are a bunch of things to golf more, though: The spaces after the for( can be removed. new String(new char[w=s.length()]).replace('\0',' ') can be " ".repeat(w=s.length()) using Java 11+. You can remove the parenthesis around the ternary-checks. 1>(i-1)%4/2 can be 1>~-i%4/2. w-1-l++ can be w+~l++. And you don't have to count the trailing semicolon in the byte-count. Which all combined becomes 209 bytes.

– Kevin Cruijssen – 2019-03-24T16:56:41.210