Codegolf Rainbow : Fun with Integer-Arrays

12

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 a list of integers of exactly size 7, where each value indicates the color-particles available to form rainbows (where the largest index indicates red and the smallest index indicated violet), output the amount of rainbows that can be formed.

A single integer-rainbow has to have at least 3x violet, 4x indigo, 5x blue, 6x green, 7x yellow, 8x orange, 9x red. A second rainbow on top of it will be even bigger than the red ring of the first rainbow (including one space between them), so it will need at least 11x violet, 12x indigo, 13x blue, 14x green, 15x yellow, 16x orange, 17x red in addition to what the first rainbow uses. The third rainbow will start at 19x violet again.

Example:

Input-list: [15,20,18,33,24,29,41]
Output: 2

Why? We have 15x violet, and we need at least 3+11=14 for two rainbows. We have 20 indigo and we need at least 4+12=16 for two rainbows. Etc. We have enough colors for two rainbows, but not enough to form three rainbows, so the output is 2.

Challenge rules:

  • The integers in the input-array are guaranteed to be non-negative (>= 0).
  • The input-list is guaranteed to be of size 7 exactly.
  • When no rainbows can be formed we output 0.
  • Input and output format is flexible. Can be a list or array of integers of decimals, can be taken from STDIN. Output can be a return from a function in any reasonable output-type, or printed directly to STDOUT.

Minimum amount of colors required for n amount of rainbows:

Amount of Rainbows    Minimum amount per color
0                     [0,0,0,0,0,0,0]
1                     [3,4,5,6,7,8,9]
2                     [14,16,18,20,22,24,26]
3                     [33,36,39,42,45,48,51]
4                     [60,64,68,72,76,80,84]
5                     [95,100,105,110,115,120,125]
etc...

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:

Input:  [15,20,18,33,24,29,41]
Output: 2

Input:  [3,4,5,6,7,8,9]
Output: 1

Input:  [9,8,7,6,5,4,3]
Output: 0

Input:  [100,100,100,100,100,100,100]
Output: 4

Input:  [53,58,90,42,111,57,66]
Output: 3

Input:  [0,0,0,0,0,0,0]
Output: 0

Input:  [95,100,105,110,115,120,125]
Output: 5

Input:  [39525,41278,39333,44444,39502,39599,39699]
Output: 98

Kevin Cruijssen

Posted 2018-08-14T11:16:50.993

Reputation: 67 575

The 0,0,0,0,0,0,0 edge-case though :( (it does not fit with the 1-gap logic) – Jonathan Allan – 2018-08-14T17:32:00.383

Answers

8

Pyth, 14 bytes

thS.ef<b*+tkyy

Test suite!

How?

Algortihm

First off, let's derive the formula this answer is based off. Let's call the function that gives the necessary amount of colour particles \$C(n, i)\$, where \$n\$ is the number of layers and \$i\$ is the index of the colour, 0-based. First, we note that for the \$n^\text{th}\$ layer alone (where \$n\$ is 1-indexed, in this case), we need \$L(n, i)=i+3+8(n-1)\$ colour particles. Keeping this in mind, we sum the results of each \$L(k, i)\$ for each layer \$k\$:

$$C(n, i)=\color{red}{\underbrace{(i+3)}_{1^\text{st} \text{ layer}}} + \color{blue}{\underbrace{(i+3+8)}_{2^\text{nd} \text{ layer}}}+\cdots + \color{green}{\underbrace{[i+3+8(n-1)]}_{n^\text{th} \text{ layer}}}$$ $$C(n, i)=(i+3)n+8\left(0+1+\cdots +n-1\right)$$ $$C(n, i) = (i+3)n+8\cdot\frac{(n-1)n}{2}=(i+3)n+4n(n-1)$$ $$C(n, i)=n(i+3+4n-4)\implies \boxed{C(n,i)=n(4n+i-1)}$$

Therefore, we now know that the maximum number of possible layers, call it \$k\$, must satisfy the inequality \$C(k, i) \le I_i\$, where \$I_i\$ is the \$i^\text{th}\$ element of the input list.

Implementation

This implements the function \$C\$, and iterates (.e) over the input list, with \$k\$ being the index (0-based) and \$b\$ being the element. For each value, the program searches the first positive integer \$T\$ for which \$b<C(T, i)\$ (the logical negation of \$C(T, i)\le b\$, the condition we deduced earlier), then finds the minimum result and decrements it. This way, instead of searching for the highest integer that does satisfy a condition, we search for the lowest that does not and subtract one from it to make up for the offset of 1.

Mr. Xcoder

Posted 2018-08-14T11:16:50.993

Reputation: 39 774

3

Python 2, 64 61 bytes

lambda l:min(((16*v+i*i)**.5-i)//8for i,v in enumerate(l,-1))

Try it online!


Each colour of the rainbow uses (3+i)+n*8 for layer n and color i(0=violet, etc.)

The total for x layers is therefore: (3*i)*x + 8*x*(x+1).

We simply solve for n, and take the minimum value.


Saved:

  • -3 bytes, thanks to ovs

TFeld

Posted 2018-08-14T11:16:50.993

Reputation: 19 246

2Ah, now I get that response ... – Jonathan Frech – 2018-08-14T12:08:42.940

161 bytes – ovs – 2018-08-14T12:12:20.223

@ovs ,Thanks :) – TFeld – 2018-08-14T12:13:11.437

3

05AB1E, 18 17 16 bytes

-1 byte thanks to Magic Octopus Urn

[ND4*6Ý<+*¹›1å#N

Try it online!

The amount of colour needed for n rainbows is n(4n + [-1, 0, 1, 2, 3, 4, 5]).

Okx

Posted 2018-08-14T11:16:50.993

Reputation: 15 025

[ND4*6Ý<+*¹›1å#N works but I don't know why. -1 byte though. – Magic Octopus Urn – 2018-08-14T15:36:48.750

@MagicOctopusUrn Thanks! That just uses the loop index instead of the counter variable. – Okx – 2018-08-14T17:06:09.417

Seems weird I don't have to do N> though-- because you had ¾> before. – Magic Octopus Urn – 2018-08-14T18:42:04.503

@MagicOctopusUrn The command to increase the counter variable doesn't push the counter variable. – Okx – 2018-08-14T19:03:25.343

2

JavaScript (ES6), 49 bytes

f=(a,n)=>a.some((v,k)=>v<4*n*n-~-k*n)?~n:f(a,~-n)

Try it online!

How?

The number \$P_{(n,k)}\$ of color particles required to generate \$n\$ times the \$k\$-th color is:

$$P_{(n,k)}=n(4n+(k-1))=4n^2+(k-1)n$$

We recursively try all values of \$n\$ until at least one entry \$v_k\$ in the input array is lower than \$P_{(n,k)}\$.

But for golfing purposes, we start with n === undefined and use negative values of n afterwards. The first iteration is always successful because the right side of the inequality evaluates to NaN. Therefore, the first meaningful test is the 2nd one with n == -1.

Arnauld

Posted 2018-08-14T11:16:50.993

Reputation: 111 334

1

Jelly, 18 bytes

Ṁµ×4+-r5¤×)⁸<Ẹ€¬TṪ

Try it online!

Uses the explanation in Okx's 05AB1E answer.

Erik the Outgolfer

Posted 2018-08-14T11:16:50.993

Reputation: 38 134

1

Excel VBA, 78 bytes

Anonymous function that takes input from the range of [A1:G1] and outputs to the VBE immediate window.

[A2:G999]="=A1-(COLUMN()+8*ROW()-14)":[H:H]="=-(MIN(A1:G1)<0)":?998+[Sum(H:H)]

Taylor Scott

Posted 2018-08-14T11:16:50.993

Reputation: 6 709

1

Charcoal, 21 bytes

I⌊EA÷⁻X⁺X⊖κ²×¹⁶ι·⁵⊖κ⁸

Try it online! Link is to verbose version of code. Explanation: Directly calculates the number of rainbows possible with each colour with a formula I derived independently but turns out to be the same as @TField's formula.

   A                   Input array
  E                     Map over values
          κ             Current index
         ⊖              Decrement
        X  ²            Square
               ι        Current index
            ×¹⁶         Multiply by 16
       ⁺                Add
      X         ·⁵      Square root
                   κ    Current index
                  ⊖     Decrement
     ⁻                  Subtract
    ÷               ⁸   Integer divide by 8
 ⌊                      Take the maximum
I                       Cast to string
                        Implicitly print

Neil

Posted 2018-08-14T11:16:50.993

Reputation: 95 035

1

JavaScript (Node.js), 54 bytes

Port of @TFeld answer

_=>Math.min(..._.map((a,i)=>((16*a+--i*i)**.5-i)/8))|0

Try it online!

Luis felipe De jesus Munoz

Posted 2018-08-14T11:16:50.993

Reputation: 9 639

1

Jelly, 14 bytes

This was hard!

Ṃ+9s8Ṗ‘+\>Ż§ỊS

A monadic Link accepting a list of seven integers which yields an integer, the number of rainbows possible.

Try it online! Or see the test-suite.

How?

Unfortunately any naive method seems to take 16 bytes, one such method is Ṃɓ_J×¥H÷‘H<¬Ȧð€S, however it turns out the method used here is much more efficient as well as shorter!

This method builds more than enough rainbow stacks as particle counts, including ultra-violet bands, and adds up 1 for each stack which is possible.

The test for it being possible is to check that there is only a single band NOT possible given we need some ultra-violet band particles but were provided zero.

Ṃ+9s8Ṗ‘+\>Ż§ỊS - Link list of integers    e.g. [0,0,0,0,0,0,0]        or [17,20,18,33,24,29,41]
Ṃ              - minimum                       0                         17
 +9            - add nine                      9                         26
   s8          - split into eights             [[1,2,3,4,5,6,7,8],[9]]   [[1,2,3,4,5,6,7,8],[9,10,11,12,13,14,15,16],[17,18,19,20,21,22,23,24],[25,26]]
     Ṗ         - discard the rightmost         [[1,2,3,4,5,6,7,8]]       [[1,2,3,4,5,6,7,8],[9,10,11,12,13,14,15,16],[17,18,19,20,21,22,23,24]]
      ‘        - increment (vectorises)        [[2,3,4,5,6,7,8,9]]       [[2,3,4,5,6,7,8,9],[10,11,12,13,14,15,16,17],[18,19,20,21,22,23,24,25]]
               -   (single rainbow counts, including ultra-violet bands, ready to stack)
       +\      - cumulative addition           [[2,3,4,5,6,7,8,9]]       [[2,3,4,5,6,7,8,9],[12,14,16,18,20,22,24,26],[30,33,36,39,42,45,48,51]]
               -   (stacked rainbow counts, including ultra-violet bands)
          Ż    - zero concatenate              [0,0,0,0,0,0,0,0]         [0,17,20,18,33,24,29,41]
               -   (we got given zero ultra-violet band particles!)
         >     - greater than? (vectorises)    [[1,1,1,1,1,1,1,1]]       [[1,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1]]
               -   (always a leading 1 - never enough particles for the ultra-violet band)
           §   - sum each                      [8]                       [1,1,8]
               -   (how many bands we failed to build for each sacked rainbow?)
            Ị  - insignificant? (abs(X)<=1?)   [0]                       [1,1,0]
               -   (1 if we only failed to build an ultra-violet band for each sacked rainbow, 0 otherwise)
             S - sum                           0                         2
               -   (the number of rainbows we can stack, given we don't see ultra-violet!)

Jonathan Allan

Posted 2018-08-14T11:16:50.993

Reputation: 67 804

I feel you, it definitely was too hard for me to squeeze Okx's algorithm in 18 bytes... – Erik the Outgolfer – 2018-08-14T18:31:55.993

Also, clever idea with the §ỊS! – Erik the Outgolfer – 2018-08-14T18:33:14.450

1

05AB1E, 14 bytes

žv*āÍn+tā-Ì8÷ß

Try it online!

A closed-form solution which does not require additional looping rather than the map. This works by adapting my Pyth's answer's formula to match 05AB1E's indexing convention, then solving for \$n\$, which happens to match TFeld's algorithm.

Pyth algorithm ⟶ 05AB1E Algorithm

There are many methods one can try for solving this challenge in 05AB1E, so I tried a couple of them and this turned out to be the shortest. Adapting the aforementioned formula from my Pyth answer, keeping in mind that 05AB1E used 1-indexing, we can construct our function as follows:

$$C(n,i)=n(i+2)+4n(n-1)$$

Setting it equal to the element of the input (\$I\$) at index \$i\$ and writing it in standard (quadratic) polynomial notation, we have:

$$4n^2+n(i-2)-I_i=0$$

Note that this equality is not precise (but I currently don't know of a way to state this more formally) and that the solutions to this equation will yield floating-point numbers, but we fix this by using floor division rather than precise division later on. Anyway, to continue on with our argument, most of you are probably very familiar with the solutions of such an equation, so here we have it:

$$n_{1, 2}=\frac{2-i\pm\sqrt{(i-2)^2+16I_i}}{8}$$

As \$I_i\$ is always positive, \$\sqrt{(i-2)^2+16I_i}\ge i-2\$, so the "\$-\$" case doesn't make much sense, because that would be either \$2-i-i+2=4-2i\$, which is negative for \$i\ge 2\$ or \$2-i-2+i=4\$, which is constant. Therefore, we can conclude that \$n\$ is given by:

$$n=\left \lfloor\frac{2+\sqrt{(i-2)^2+16I_i}-i}{8}\right \rfloor$$

Which is exactly the relation that this answer implements.

Mr. Xcoder

Posted 2018-08-14T11:16:50.993

Reputation: 39 774

1

C++, 127 125 bytes

Shaved off 2 bytes thanks to Kevin Cruijssen.

#include<cmath>
int f(int x[7]){size_t o=-1;for(int c=0,q;c<7;c++,o=o>q?q:o)q=(std::sqrt(--c*c-c+16*x[++c])-c+1)/8;return o;}

Try it online!

The function takes a C-style array of seven ints and returns an int.

The algorithm is pretty straightforward (and have already been described a number of times previously, so here is one more description, mostly for my own viewing pleasure). Let \$c\$ be the color index (\$0\le c\le6\$), so the required number of particles to form \$n\$-th \$(n\ge1)\$ rainbow part of that color is \$y_c(n)=(c+3)+8(n-1)\$, and the total amount of particles to form \$n\$ rainbow parts of the color is then \$Y_c(n)=\sum_{k=1}^{n}y_c(k)=n(c+3)+\frac{8n(n-1)}{2}\$. Now we have a system of inequalities \$x_c\ge Y_c(n)\$ (where \$x_c\$ is the elements of input array), which gives us a set of upper bounds on \$n:\$ $$n\le\frac{-(c-1) + \sqrt{(c-1)^2 + 16x_c}}{8}$$.

What is left is just iterate over \$x_c\$ and find the minimum.

Explanation:

#include <cmath> // for sqrt

int f (int x[7])
{
     // Note that o is unsigned so it will initially compare greater than any int
     size_t o = -1;
     // Iterate over the array
     for (int c = 0; c < 7; c++)
     {
         // calculate the bound
         int q = c - 1;
         q = (std::sqrt (q * q + 16 * x[c]) - q) / 8;

         // if it is less than previously found - store it
         o = o > q ? q : o;
     }
     return o;
 }

Max Yekhlakov

Posted 2018-08-14T11:16:50.993

Reputation: 601

Hi there, welcome to PPCG! I don't know C++ too well, but I'm pretty sure you can golf this part: for(int c=0;c<7;c++){int q=c-1;q=(std::sqrt(q*q+16*x[c])-q)/8;o=o>q?q:o;} to this: for(int c=0,q;c<7;c++,o=o>q?q:o)q=(std::sqrt(--c*c-c+16*x[++c]))/8;. Also, could you perhaps provide a TIO-link with test code?

– Kevin Cruijssen – 2018-08-15T07:01:26.033

@KevinCruijssen Thank you! – Max Yekhlakov – 2018-08-17T11:47:00.457