Codegolf Rainbow : Draw in Black-and-White

12

1

Introduction:

enter image description here (Source: Wikipedia)
When we look at a rainbow it will always have the colors from top to bottom:
Red; orange; yellow; green; blue; indigo; violet

If we look at these individual rings, the red ring is of course bigger than the violet ring.
In addition, it's also possible to have two or even three rainbow at the same time.

All this above combined will be used in this challenge:

Challenge:

Given an integer n, output that many rings of the (possibly more than one) 'rainbows', where we'll use the letters vibgyor for the colors.

See the test cases below to see how they are built upwards from n=1, and how the spacing should be handled (at n=8). As you can see, one space is added between two rainbows, including spacing at the top, before we add the ring of the next rainbow in line.

Challenge rules:

  • You are allowed to use capital VIBGYOR instead of lowercase
  • There should be a space between the individual rainbows
  • Any amount of leading and/or trailing spaces/new-lines are allowed, as long as the actual rainbow (wherever it is placed on the screen) is correct
  • The input will always be a positive integer (>= 1). The behavior when n=0 is therefore undefined, and the program/function can do whatever it wants (outputting nothing; outputting the rainbow of n=1; random output; fail with an error; etc.)
  • You are allowed to output a list/array of strings or 2D array/list of characters if you want (you could add the actual pretty-printing code in the TIO footer).
  • Ignore the fact that the outputs looks more like Mayan temples than rainbows.. xD

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, 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.
  • Also, adding an explanation for your answer is highly recommended.

Test cases (first n=1 through n=10, and n=25):

1:
 vvv
v   v

2:
  iii
 ivvvi
iv   vi

3:
   bbb
  biiib
 bivvvib
biv   vib

4:
    ggg
   gbbbg
  gbiiibg
 gbivvvibg
gbiv   vibg

5:
     yyy
    ygggy
   ygbbbgy
  ygbiiibgy
 ygbivvvibgy
ygbiv   vibgy

6:
      ooo
     oyyyo
    oygggyo
   oygbbbgyo
  oygbiiibgyo
 oygbivvvibgyo
oygbiv   vibgyo

7:
       rrr
      rooor
     royyyor
    roygggyor
   roygbbbgyor
  roygbiiibgyor
 roygbivvvibgyor
roygbiv   vibgyor

8:
         vvv
        v   v
       v rrr v
      v rooor v
     v royyyor v
    v roygggyor v
   v roygbbbgyor v
  v roygbiiibgyor v
 v roygbivvvibgyor v
v roygbiv   vibgyor v

9:
          iii
         ivvvi
        iv   vi
       iv rrr vi
      iv rooor vi
     iv royyyor vi
    iv roygggyor vi
   iv roygbbbgyor vi
  iv roygbiiibgyor vi
 iv roygbivvvibgyor vi
iv roygbiv   vibgyor vi

10:
           bbb
          biiib
         bivvvib
        biv   vib
       biv rrr vib
      biv rooor vib
     biv royyyor vib
    biv roygggyor vib
   biv roygbbbgyor vib
  biv roygbiiibgyor vib
 biv roygbivvvibgyor vib
biv roygbiv   vibgyor vib

25:
                            ggg
                           gbbbg
                          gbiiibg
                         gbivvvibg
                        gbiv   vibg
                       gbiv rrr vibg
                      gbiv rooor vibg
                     gbiv royyyor vibg
                    gbiv roygggyor vibg
                   gbiv roygbbbgyor vibg
                  gbiv roygbiiibgyor vibg
                 gbiv roygbivvvibgyor vibg
                gbiv roygbiv   vibgyor vibg
               gbiv roygbiv rrr vibgyor vibg
              gbiv roygbiv rooor vibgyor vibg
             gbiv roygbiv royyyor vibgyor vibg
            gbiv roygbiv roygggyor vibgyor vibg
           gbiv roygbiv roygbbbgyor vibgyor vibg
          gbiv roygbiv roygbiiibgyor vibgyor vibg
         gbiv roygbiv roygbivvvibgyor vibgyor vibg
        gbiv roygbiv roygbiv   vibgyor vibgyor vibg
       gbiv roygbiv roygbiv rrr vibgyor vibgyor vibg
      gbiv roygbiv roygbiv rooor vibgyor vibgyor vibg
     gbiv roygbiv roygbiv royyyor vibgyor vibgyor vibg
    gbiv roygbiv roygbiv roygggyor vibgyor vibgyor vibg
   gbiv roygbiv roygbiv roygbbbgyor vibgyor vibgyor vibg
  gbiv roygbiv roygbiv roygbiiibgyor vibgyor vibgyor vibg
 gbiv roygbiv roygbiv roygbivvvibgyor vibgyor vibgyor vibg
gbiv roygbiv roygbiv roygbiv   vibgyor vibgyor vibgyor vibg

Kevin Cruijssen

Posted 2018-08-14T11:20:28.623

Reputation: 67 575

3Maybe you know this and it's by design (I know that rainbows are not rhombuses or ascii, too, and higher orders' positions get more complicated), but aren't the colours reversed in the 2nd rainbow? – Chris M – 2018-08-14T12:42:07.993

1

@ChrisM Ah, you're indeed right. With two rainbows the second is indeed reversed, but with three only the outer is reversed, and with four both outer are reversed. Ah well, bit too late to change it now. Maybe I'll think of a third related challenges with this later on. :)

– Kevin Cruijssen – 2018-08-14T12:51:01.813

1

@ChrisM Added a third related challenge implementing your comment to the Sandbox.

– Kevin Cruijssen – 2018-08-16T15:09:45.833

Oh cool, nice one :¬) – Chris M – 2018-08-16T16:04:40.923

Answers

5

Python 2, 84 82 81 bytes

-2 bytes thanks to ElPedro.

n=input();n+=n/7;w=''
while-~n:w+=" vibgyor"[n%8];print' '*n+w+w[-1]+w[::-1];n-=1

Try it online!

ovs

Posted 2018-08-14T11:20:28.623

Reputation: 21 408

3

Canvas, 29 28 26 bytes

7÷U+{ <ibgyor@¹×/n}⇵K2*∔─↶

Try it here!

Explanation:

7÷U+                          ceil(input/7) + input
    {             }         for n in 1..the above
      <ibgyor@                in the string " <ibgyor", pick the nth character
              ¹×              repeat n times
                /             create a diagonal of that
                 n            and overlap the top 2 stack items (the 1st time around this does nothing, leaving an item for the next iterations)
                   ⇵        reverse the result vertically
                    K       take off the last line (e.g. " <ibgyor <ib")
                     2*     repeat that vertically twice
                       ∔    and append that back to the diagonals
                        ─   palindromize vertically
                         ↶  and rotate 90° anti-clockwise. This rotates "<" to "v"

25 24 22 bytes after fixing that mold should cycle if the wanted length is bigger than the inputs length and fixing for like the 10th time

dzaima

Posted 2018-08-14T11:20:28.623

Reputation: 19 048

Out of curiosity, why is the v sideways (<)? Is v already a reserved keyword in Canvas, if so, why not use < as that reversed keyword instead? – Kevin Cruijssen – 2018-08-14T12:11:53.003

1the characters are used vertically and then rotated, and Canvas is smart enough to figure out that < rotated 90° anticlockwise equals v :P All ASCII are part of strings in Canvas btw – dzaima – 2018-08-14T12:13:00.683

Ah ok, so if you would have used v here, and you then rotate it 90 degrees counterclockwise, it becomes > instead. I see. :D – Kevin Cruijssen – 2018-08-14T12:15:02.260

@KevinCruijssen That'd have other consequences too

– dzaima – 2018-08-14T12:15:55.973

Ah, you also have a mirror there somewhere? I can't read Canvas tbh, so I'm looking forward to the explanation of the code. ;) – Kevin Cruijssen – 2018-08-14T12:17:57.290

3

JavaScript (ES6), 100 bytes

Returns an array of strings.

f=(n,a=[i='   '])=>++i<n+n/7?f(n,[c=' vibgyor'[i&7],...a].map(s=>c+s+c)):a.map(s=>' '.repeat(--i)+s)

Try it online!

Arnauld

Posted 2018-08-14T11:20:28.623

Reputation: 111 334

3

05AB1E, 32 31 23 bytes

.•VvÈ©•¹∍¬„ v:Rηε¬ý}.c

Try it online!

-1 thanks to Kevin Cruijssen and -8 thanks to Adnan


Explanation (Stack example w/ input of 3):

.•VvÈ©•                  # Push 'aibgyor'           | ['aibgyor']
       ¹∍                # Extend to input length.  | ['aib']
         ¬               # Push head.               | ['aib','a']
          „ v:           # Replace with ' v'.       | [' vib']
              R          # Reverse.                 | ['biv ']
               η         # Prefixes.                | ['b', 'bi', 'biv', 'biv ']
                ε   }    # For each....             | []
                 ¬ý     # Bifurcate, join by head. | ['b','b']       ->    ['bbb']
                                                    | ['bi','ib']     ->   ['biiib']
                                                    | ['biv','vib']   ->  ['bivvvib']
                                                    | ['biv ',' vib'] -> ['biv   vib']
                     .c # Center the result.        | Expected output.

Magic Octopus Urn

Posted 2018-08-14T11:20:28.623

Reputation: 19 422

1"vibgyor" can be golfed by 1 byte to .•2Bãθ(•. (Here the explanation for it at the "How to compress strings not part of the dictionary?" section.) In addition, „vr…v r:ð« can be golfed to 'v„v .:. So 28 bytes. Nice answer though, +1 from me. – Kevin Cruijssen – 2018-08-14T14:51:29.283

2@KevinCruijssen oh I know all about string compression-- I just figured (as is usually the case with super small strings) that the 3-byte bloat of .•• wouldn't save a byte. Figures the *one time* I don't actually check is the time it would save bytes xD. Good catch – Magic Octopus Urn – 2018-08-14T15:14:11.060

Ah yes, you made the tip about the ASCII art compression with transliteral. Nice tip with code-generation btw, I used it recently in an answer of mine. I was also doubting it would work considering the three bytes of .••, but I figured I'd try anyway since "" is also already 2 bytes, and it indeed saved a byte. :) EDIT: Your tip doesn't use String compression though, only number compression. Ah well. xD

– Kevin Cruijssen – 2018-08-14T15:17:59.443

@KevinCruijssen string compression came out ~5 months after I wrote that tip :P. – Magic Octopus Urn – 2018-08-14T15:22:15.073

Ah lol. I have no idea what came out when. Sometimes I see very old answers from mid 2016 however which didn't even had implicit input yet, then I know it's an old version. ;p PS: In my first comment I mentioned something else to golf 3 more bytes. – Kevin Cruijssen – 2018-08-14T16:21:58.587

@KevinCruijssen Didn't see that the first time. Bad habit of skimming comments/summaries. Unfortunately, that doesn't work for multiples of 7; you have to make sure we need the space due to the v AND the r existing. String compression was spot on though :). Could maybe do 'r„ r though if preceeding newlines are fine. – Magic Octopus Urn – 2018-08-14T16:24:33.383

3

For 23 bytes: .•VvÈ©•¹∍¬„ v:Rηε¬ý}.c

– Adnan – 2018-08-14T16:30:40.980

@adnan wellp, yeah, but doing it that way would be smart, and that's just not my style ahaha. You want to post it instead? That's a significant improvement over mine to be honest-- barely even looks the same. – Magic Octopus Urn – 2018-08-14T16:34:21.457

The idea is almost exactly the same as your submission, so I don't think I can post this as my own answer. It was the „vr…v r: part that brought up an idea that saves ~6 bytes. – Adnan – 2018-08-14T16:46:08.193

1@Adnan fair enough, the lack of the mirror makes it a significant refactor in my eyes though (that and I doubt I'd've got there on my own :P). – Magic Octopus Urn – 2018-08-14T16:47:08.470

1@Adnan also ¬ý is genius... Jeez... You think so differently and it's awesome. – Magic Octopus Urn – 2018-08-15T14:53:25.000

3

Haskell, 114 110 101 bytes

Thanks to [nimi][1] for -4 13 bytes!

f n=""#(n+1+div n 7)
w#0=[]
w#n|x<-cycle"r vibgyo"!!n=((' '<$[2..n])++reverse w++x:x:x:w):(x:w)#(n-1)

Try it online!

ovs

Posted 2018-08-14T11:20:28.623

Reputation: 21 408

3

Dyalog APL, 41 39 38 bytes

↑{⌽(⌽,⊃,A↑⊢)⍵↑A⍴' vibgyor'}¨-⍳A←⌈⎕×8÷7

Try it online!

A similar approach to others: A←⌈⎕×8÷7 finds the height of the rainbow (also the width of the longest 'half row' to the left/right of the centre) and assigns it to A for later use, while ¨-⍳ iterates through the values 1..A, negating them to select on the correct side when used with .

A⍴' vibgyor' generates a 'half row' and ⍵↑ selects the correct length substring. (⌽,⊃,A↑⊢) generates the full row in reverse (which takes fewer characters to do), starting with a reversed half row (), then the centre character taken from the beginning of the half row string () and finally a right padded version of the half row (A↑⊢). The final reverses the row into the correct orientation and turns the vector of rows into a 2D array.

Edit: -2 thanks to dzaima

Edit: -1 thanks to ngn

mousetrapper

Posted 2018-08-14T11:20:28.623

Reputation: 91

You can replace ⍕⍪ with - outputting a 2D array of characters is allowed – dzaima – 2018-08-16T03:47:42.347

39 bytes – dzaima – 2018-08-16T04:14:28.513

1+÷7 -> 8÷7 – ngn – 2018-08-25T15:04:15.347

2

Python 2, 108 bytes

n=input()-1
n+=n/7+2
o=[]
for s in(' vibgyor'*n)[:n]:o=[s+l+s for l in[s]+o]
for l in o:print l.center(n-~n)

Try it online!

Rod

Posted 2018-08-14T11:20:28.623

Reputation: 17 588

2

R, 130 bytes

function(n,k=n%/%7*8+1+n%%7,a=el(strsplit(' vibgyor'/k,'')))for(i in k:1)cat(d<-' '/(i-1),a[c(k:i,i,i:k)],d,sep='','
')
"/"=strrep

Try it online!

  • -6 bytes thanks to @JayCe

digEmAll

Posted 2018-08-14T11:20:28.623

Reputation: 4 599

You can save 6 bytes. Also make you to upvote R's nomination for language of the month :)

– JayCe – 2018-08-16T19:41:52.397

@JayCe: thanks ! updated and upvoted ! – digEmAll – 2018-08-16T20:32:32.780

2

Jelly, 31 bytes

:7+‘µ“ vibgyor”ṁṚ,Ṛjṛ/ƲƤṭ"ḶṚ⁶ẋƲ

Try it online!

Check out a test suite!

ಠ_ಠ This is overly complicated because Jelly doesn't have a centralize function...

Mr. Xcoder

Posted 2018-08-14T11:20:28.623

Reputation: 39 774

2

Charcoal, 30 bytes

↶≔… vibgyor⁺²÷×⁸⊖N⁷θθ⸿Eθ✂θκ‖O←

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

Change the drawing direction to upwards.

≔… vibgyor⁺²÷×⁸⊖N⁷θ

Calculate the height of the rainbow and repeat the literal string to that length.

θ⸿

Print the central line of the rainbow.

Eθ✂θκ

Print the right half of the rainbow by taking successive slices and printing each on its own "line".

‖O←

Reflect to complete the rainbow.

Neil

Posted 2018-08-14T11:20:28.623

Reputation: 95 035

2

Jelly, 28 bytes

:7+‘“ vibgyor”ṁµṫJZz⁶U;"⁸ŒBṚ

A monadic link accepting an integer which yields a list of lists of characters.

Try it online! (footer joins with newline characters)

Or see the test-suite.

How?

:7+‘“ vibgyor”ṁµṫJZz⁶U;"⁸ŒBṚ - Link: integer
:7                           - integer divide by seven (number of full rainbows)
   ‘                         - increment (the input integer)
  +                          - add (gets the number bands)
    “ vibgyor”               - list of characters = " vibgyor"
              ṁ              - mould like the result above (as a range)
               µ             - start a new monadic chain
                 J           - range of length
                ṫ            - tail (vectorises) (gets the suffixes)
                  Z          - transpose
                   z⁶        - transpose with filler space character
                             -   (together these pad with spaces to the right)
                     U       - reverse each
                             -   (now we have the left side of the rainbow upside down)
                        ⁸    - chain's left argument, as right argument of...
                       "     -   zip with:
                      ;      -     concatenation
                             -   (adds the central character)
                         ŒB  - bounce (vectorises at depth 1)
                             -   (reflects each row like [1,2,3,4] -> [1,2,3,4,3,2,1])
                           Ṛ - reverse (turn the rainbow up the right way)

Jonathan Allan

Posted 2018-08-14T11:20:28.623

Reputation: 67 804

2

PowerShell, 108 98 89 85 bytes

param($x)($x+=$x/7-replace'\..*')..0|%{' '*$_+-join(" vibgyor"*$x)[$x..$_+$_+$_..$x]}

Try it online!

This one feels pretty alright now. Banker's rounding is still the devil and I figured out how to make a non-dumb join. I tried monkeying with $ofs to not much success. Speaking of, the results without joins look pretty good, a bit melty:

         vvv
        v     v
       v   rrr   v
      v   r ooo r   v
     v   r o yyy o r   v
    v   r o y ggg y o r   v
   v   r o y g bbb g y o r   v
  v   r o y g b iii b g y o r   v
 v   r o y g b i vvv i b g y o r   v
v   r o y g b i v     v i b g y o r   v

Veskah

Posted 2018-08-14T11:20:28.623

Reputation: 3 580

[int]$x+=$x/7 ? – mazzy – 2018-08-17T04:21:43.220

@mazzy That fails for x=25. You have to truncate but casting to int rounds – Veskah – 2018-08-17T20:05:25.290

Yes. And truncate is works – mazzy – 2018-08-18T05:37:16.843

1@mazzy I know, the only ways I know to truncate is either [math]::truncate() or the regex trick used above. [int]$x rounds the number. If you know a better way, I'm all ears. – Veskah – 2018-08-20T20:01:57.370

2

Haskell, 106 113 bytes

I can't yet comment other posts (namely this) so I have to post the solution as a separate answer.

Golfed away 7 bytes by ovs

p x=reverse x++x!!0:x
u m|n<-m+div(m-1)7=[(' '<$[z..n])++p(drop(n-z)$take(n+1)$cycle" vibgyor")|z<-[0..n]]

Try it online!

(Old version, 113 bytes)

Max Yekhlakov

Posted 2018-08-14T11:20:28.623

Reputation: 601

Nice answer. I don't know Haskell, but the code seems rather different from the other Haskell answer. PS: That other Haskell answer is actually 110 bytes after the golf-tips in @nimi's comment. Regardless, this is a nice alternative Haskell answer, so +1 from me.

– Kevin Cruijssen – 2018-08-17T13:51:21.540

1

It seems like list comprehensions were the better tool for this challenge. I was able to golf your solution to 106 bytes by reducing the total number of functions. Feel free to adapt these changes.

– ovs – 2018-08-17T15:35:46.730

1

Python 2, 132 131 bytes

def f(n):
 t=n+n/7;s=('vibgyor '*n)[:t];r=[s[~i:]+t*' 'for i in range(t)]
 for l in zip(*r+3*[' '+s]+r[::-1])[::-1]:print''.join(l)

Try it online!


Saved:

  • -1 byte, thanks to Jonathan Frech

TFeld

Posted 2018-08-14T11:20:28.623

Reputation: 19 246

Why // in Python 2? – Jonathan Frech – 2018-08-14T12:03:52.440

@JonathanFrech Because I'm dumb :P – TFeld – 2018-08-14T12:06:01.597

@dzaima, Yeah. Should be fixed now – TFeld – 2018-08-14T12:22:04.593

1

Red, 153 bytes

func[n][r: take/last/part append/dup copy"""roygbiv "n l: 9 * n + 8 / 8
repeat i l[print rejoin[t: pad/left take/part copy r i l last t reverse copy t]]]

Try it online!

Slightly more readable:

f: func[ n ] [
    r: copy ""
    append/dup r "roygbiv " n
    r: take/last/part r l: 9 * n + 8 / 8
    repeat i l [
        print rejoin [ t: pad/left take/part copy r i l
                       last t 
                       reverse copy t ]
    ]
]

Galen Ivanov

Posted 2018-08-14T11:20:28.623

Reputation: 13 815

1

Java (JDK 10), 184 bytes

n->{int h=n+n/7,i=h+1,w=i*2+1,j,k=0;var o=new char[i][w];for(;i-->0;o[i][w/2]=o[i][w/2+1])for(j=w/2;j-->0;)o[i][j]=o[i][w+~j]=i<h?j<1?32:o[i+1][j-1]:" vibgyor".charAt(k++%8);return o;}

Try it online!

Prints an extra leading and trailing space for each multiple of 7.

Explanation

n->{                             // IntFunction
 int h=n+n/7,                    //  Declare that height = n + n/7
     i=h+1,                      //          that index  = h + 1
     w=i*2+1,                    //          that width  = (h+1)*2+1
     j,                          //          j
     k=0;                        //          that k      = 0
 var o=new char[i][w];           //  Declare a 2D char array
 for(;                           //  Loop
   i-->0;                        //    Until i is 0
   o[i][w/2]=o[i][w/2+1]         //    After each run, copy the middle letter.
 )
  for(j=w/2;                     //   Loop on j = w/2
   j-->0;                        //     Until j = 0
  )                              //
   o[i][j]                       //    copy letters to the left side,
    =o[i][w+~j]                  //      and the right side
    =i<h                         //      if it's not the last line
     ?j<1                        //        if it's the first (and last) character
      ?32                        //          set it to a space.
      :o[i+1][j-1]               //          else set it to the previous character on the next line.
     :" vibgyor".charAt(k++%8);  //      else assign the next letter.
 return o;                       //  return everything
}

Credits

Olivier Grégoire

Posted 2018-08-14T11:20:28.623

Reputation: 10 647

You can save 2 bytes by changing ,w=-~h*2+1,i=h+1 to ,i=h+1,w=i*2+1 – Kevin Cruijssen – 2018-08-16T06:29:21.093

Wow, I should really not golf passed midnight! Thanks for this, @KevinCruijssen! :) – Olivier Grégoire – 2018-08-16T07:27:41.353

Suggest i-~i instead of i*2+1 – ceilingcat – 2019-09-25T20:28:30.113

1

Stax, 23 bytes

⌡G'5h!M╩EV[Ez ▼>≈<S⌡⌡0`

Run and debug it

Unpacked, ungolfed, and commented, it looks like this.

" vibgyor"  string literal
,8*7/^      input * 8 / 7 + 1
:m          repeat literal to that length
|]          get all prefixes
Mr          rectangularize, transpose array of arrays, then reverse
            this is the same as rotating counter-clockwise
m           map over each row with the rest of the program, then implicitly output
            the stack starts with just the row itself
  _h        push the first character of the row
  _r        push the reversed row
  L         wrap the entire stack in a single array

Run this one

recursive

Posted 2018-08-14T11:20:28.623

Reputation: 8 616