g | x | w | all
Bytes Lang Time Link
149AWK251014T170228Zxrs
063Wolfram Language Mathematica251011T193739ZGreg Mar
085Ruby251010T133713ZShadowRa
094Python251008T123023ZThemooni
117Rust251010T011306ZShadowRa
109Perl 5 MListUtil=min251009T173720ZXcali
045APLNARS251009T070837ZRosario
052APL+WIN251009T151145ZGraham
075R251009T095352ZGlory2Uk
095JavaScript ES6251008T175925ZArnauld
084R251009T053047Zpajonk
055Charcoal251008T124709ZNeil
032Jelly251008T174326ZJonathan
5752J251008T172000Zm90
04605AB1E251008T131041ZKevin Cr
117Python 3251008T122113ZLucenapo

AWK, 152 149 bytes

{d=2.375
f[1]=5*($2/$1-0.3)
f[2]=0.25*($3/$1-3)
f[3]=20*($4/$1)
for(f[4]=d-25*($5/$1);i++<4;x+=f[i])f[i]=f[i]>d?d:f[i]<0?0:f[i];printf"%.1f",100*x/6}

Attempt This Online!

Feels heavy, but AWK doesn't have many built in math functions.

Wolfram Language (Mathematica), 63 bytes

.1Round[125/6Tr@Clip[{40,2,160,-200}#2/#-{12,6,0,-19},{0,19}]]&

Try all test cases online! Unnamed function taking \$n\$ as the first argument and \$\{c,y,t,i\}\$ as the second argument. Leans on the built-in Clip (Clamp) function. I rediscovered some optimizations already used by earlier answers (multiplying by 8 for example). My truly original one-byte savings: originally I had Round[25/12 ... ,.1] to round the expression to one decimal place. But multiplying 25/12 by 10 yields the equally short 125/6, and that let me change the structure to .1Round[125/6 ... ] which avoided the comma 😄

Ruby, 85 bytes

->{([20*_2/_1-6,_3/_1-3,80*_4/_1,9.5-100*_5/_1].sum{|v|25.*v.clamp 0,9.5}/6).round 1}

Attempt This Online!

The Ruby version of my Rust answer, using the same basic tricks (Ruby also comes with clamp!) which comes out much shorter thanks to unnamed parameters on the method, being able to mix integer literals (no trailing .s) with floating point variables, and round accepting an argument for number of places to keep, so we can multiply by 25, not 250, and needn't divide by 10.

Python, 94 bytes

lambda n,c,y,t,i,k=9.5:"%.1f"%sum(min(v,k)/.24for v in(20*c/n-6,y/n-3,80*t/n,k-100*i/n)if v>0)

-1 byte by Lucenaposition
-2 bytes inspired by Arnaud's js answer
-7 bytes by xnor
-7 bytes by Jonathan Allan
-2 bytes by me using string formatting for rounding

Attempt This Online!

Rust, 117 bytes

|n,c,y,t,i|([20.*c/n-6.,y/n-3.,80.*t/n,9.5-100.*i/n].iter().fold(0.,|a,v:&f64|a+v.clamp(0.,9.5)*250.)/6.).round()/10.

Attempt This Online!

Solution assumes all the inputs are provided as f64 values, even though they are logical integers (because Rust ain't gonna let you mix floating point and integer values!).

This is a rare case where Rust isn't substantially longer than the non-golf scripting languages (e.g. Python, Perl). I avoided looking at any other answers to minimize reusing other's approaches, but oops, all I did was independently reinvent many of the same tricks Arnauld used for JS.

Highlights (Rust specific, Arnauld covered the numeric tricks):

  1. Rust just gives you a clamp function. Saves a lot of headache relative to other languages

  2. But Rust also demands a . in all floating point literals, even if they're whole numbers that are being used with f64 variables, because reasons.

  3. Rust doesn't provide a round function that rounds to a specific number of digits, but multiplying by an extra factor of 10, rounding, then dividing by 10, works fine. The string formatting approach is two bytes longer:

    |n,c,y,t,i|format!("{:.1}",[20.*c/n-6.,y/n-3.,80.*t/n,9.5-100.*i/n].iter().fold(0.,|a,v:&f64|a+v.clamp(0.,9.5)*25.)/6.)
    
  4. fold is basically always better than map+sum in Rust, and often similar even if you don't need a map operation, cause sum is just pathologically terrible at type-inference, and needs the turbofish to specify type, while fold never needs the turbofish, and frequently gets to skip some/all type annotations.

Perl 5 -MList::Util=min,max -n, 109 bytes

printf'%.1f',100/6*(min($p=2.375,max<>*5/$_-1.5,0)+(min$p,max<>/$_/4-.75,0)+(max<>/$_*20,0)+max$p-25*<>/$_,0)

Try it online!

APL(NARS), 45 chars

1⍕50r3×+/19r8⌊0⌈5 .25 20 ¯25×.3 3 0 .095-⍨⎕÷⎕

The program above has as the first input the array "c y t i" the second input "n" and return one float.

I use the relation

 f_4=-25(i/n-19/200) 

'0⌈' it seems means "for each element of input array make the min with 0" and return that.

test:

  1⍕50r3×+/19r8⌊0⌈5 .25 20 ¯25×.3 3 0 .095-⍨⎕÷⎕
⎕:
  2 25 0 1
⎕:
  10
0.0
  1⍕50r3×+/19r8⌊0⌈5 .25 20 ¯25×.3 3 0 .095-⍨⎕÷⎕
⎕:
  12 276 3 0
⎕:
  15
158.3

APL+WIN, 52 bytes

Prompts for n and then a vector of c,y,t,i

1⍕+/(50×0⌈n⌊(¯4↑n←19÷8)+5 .25 20 ¯25×(⎕÷⎕)-4↑.3 3)÷3

Try it online! Thanks to Dyalog APL Classic

R, 76 75 bytes

\(n,A)round(sum(pmin(9.5,pmax(0,A/n*c(20,1,80,-100)-c(6,3,0,-9.5))))/.24,1)

Attempt This Online!

I have used the logic from the existing J answer.

In this sumbission only two arguments are passed (and this is codegolf ;-) ): \$n\$, which corresponds to the first argument \$n\$ of the task and the vector \$A\$ containing \$c, y, t, i\$ arguments.

The test cases are adapted from the pajonk's answer.

JavaScript (ES6), 95 bytes

(n,c,y,t,i)=>(s=q=9.5,[20*c/n-6,y/n-3,80*t/n,q-100*i/n].map(v=>s+=(v<0?0:v>q?q:v)/.024)|s-9)/10

Try it online!

Method

Multiplying each component by \$4\$ leads to shorter expressions:

$$F_1=20c/n-6$$ $$F_2=y/n-3$$ $$F_3=80t/n$$ $$F_4=9.5-100i/n$$

And what we actually compute is:

$$\left\lfloor1000\times\frac{s}{24}+\frac{1}{2}\right\rfloor/10$$

where: $$s=C(F_1)+C(F_2)+C(F_3)+C(F_4)$$

and \$C\$ is the clamp function:

$$n\gets \max\big(0,\min(9.5,n)\big)$$

R, 84 bytes

\(n,a,y,t,i)round(sum(pmax(0,pmin(9.5,c(20*a/n-6,y/n-3,80*t/n,9.5-100*i/n))))/.24,1)

Attempt This Online!

Uses @Arnauld's formulas.

Charcoal, 63 55 bytes

Nθ﹪%.1f∕ΣE⟦⁴⁰¦²¦¹⁶⁰±²⁰⁰⟧⌈⟦⁰⌊⟦¹⁹⁻×ι∕Nθ§⟦¹²¦⁶¦⁰±¹⁹⟧κ⟧⟧·⁴⁸

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

Nθ

Input n as an integer.

E⟦⁴⁰¦²¦¹⁶⁰±²⁰⁰⟧

Loop over the four multipliers, which themselves are premultiplied by 8.

⁻×ι∕Nθ§⟦¹²¦⁶¦⁰±¹⁹⟧κ

Read in the next integer, divide by n, multiply by the current multiplier, then subtract the relevant (doubly premultiplied where necessary) adjustment.

⌈⟦⁰⌊⟦¹⁹...⟧⟧

Clamp the result into the premultiplied desired range.

∕Σ...·⁴⁸

Divide the sum by 0.48, which is equivalent to dividing by 8, multiplying by 100 and dividing by 6.

﹪%.1f...

Output rounded to 1 decimal place.

Jelly, 32 bytes

÷_.3,3ד(£ɦṀ‘_@0¦19«19»0S÷.48ær1

A dyadic Link that accepts [c, y, t, i] on the left and n on the right and yields the rating.

Try it online! Or see the test-suite.

How?

÷_.3,3ד(£ɦṀ‘_@0¦19«19»0S÷.48ær1 - Link: [c, y, t, i], n
÷                                - {[c, y, t, i]} divide {n}
                                     -> [c/n, y/n, t/n, i/n]
 _.3,3                           - subtract [0.3, 3]
                                     -> [c/n-0.3, y/n-3, t/n, i/n]
      ד(£ɦṀ‘                    - multiply [40, 2, 160, 200]
                                     (this is [5×8, 0.5×8, 20×8, 25×8])
                                     -> [40(c/n-0.3), 2(y/n-3), 160t/n, 200i/n]
             _@0¦19              - subtract last from 19  (19=2.375×8)
                                     -> [40(c/n-0.3), 2(y/n-3), 160t/n, 19-200i/n]
                   «19           - min (each) with 19
                      »0         - max (each) with zero
                        S        - sum these four values
                         ÷.48    - divide that by 0.48
                                     (this is 8×6/100)
                             ær1 - round to one decimal place

J, 57 52 bytes

0j1":6%~25*1#.9.5<.0>.6 3 0 _9.5-~20 1 80 _100*}.%{.

Try it online!

05AB1E, 46 bytes

/•1ǝj1•т>в4/*ŽOµS4/-`2.375©s-)ε0M®‚ß}O6/т*1.ò

Two loose inputs \$n\$ and \$[c,y,t,i]\$.

Try it online or verify all test cases.

Explanation:

/          # Divide the second (implicit) input-list by the first (implicit) input
•1ǝj1•     # Push compressed integer 20624401
  т>       # Push 100, and increase it to 101
    в      # Convert the larger integer to a base-101 list: [20,1,80,100]
     4/    # Divide each by 4: [5,0.25,20,25]
       *   # Multiply the values at the same positions
ŽOµ        # Push compressed integer 6300
   S       # Convert it to a list of digits: [6,3,0,0]
    4/     # Divide each by 4 again: [1.5,0.75,0,0]
      -    # Subtract the values at the same positions
`          # Pop and push all four values to the stack
 2.375     # Push 2.375
      ©    # Store it in variable `®`
       s   # Swap so the last value is at the top again
        -  # Subtract it from the 2.375
         ) # Wrap the stack into a list of four values again
ε          # Map over each value:
           #  (implicitly push the current value)
 0         #  Push a 0
  M        #  Push a copy of the largest value on the stack (of these two)
   ®‚      #  Pair it with the 2.375 of variable `®`
     ß     #  Pop and push the minimum
}O         # After the map: sum these clamped values together
  6/       # Divide this sum by 6
    т*     # Multiply it by 100
      1.ò  # Round to 1 decimal
           # (after which the result is output implicitly)

See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand why •1ǝj1• is 20624401; •1ǝj1•т>в is [20,1,80,100]; and ŽOµ is 6300.

Python 3, 119 117 bytes

lambda n,c,y,t,i,Q=2.375:round((max(min(Q,5*c/n-1.5),0)+max(min(Q,(y/n-3)/4),0)+min(Q,20*t/n)+max(0,Q-25*i/n))/.06,1)

Try it online!

The boring answer.