Determine Beckett Grading Service (BGS) Final Grade
Charcoal, 73 71 bytes
≦⊗θ≔⌊θη≔⁻⌊Φθ⁻κ⌕θηηζI⊘⁺η∧ζ⎇⌕θη∨⎇⊖⌕θη∨›²ζ∨∧⁼²ζ‹¹⁶η∧⁼³⁻⌈θη›²⁰⌈θ›⁶ζ²⊕⌊⟦²÷ζ⁴
Try it online! Link is to verbose version of code. Takes input as an array of 4 values [Centring, Corners, Edges, Surface]. Explanation:
≦⊗θ
Double all the values so we're dealing in grade points rather than grades.
≔⌊θη
Find the worst grade.
≔⁻⌊Φθ⁻κ⌕θηηζ
Find the worst of the other grades, i.e. the second worst, and subtract the worst grade.
I⊘
Halve the final value and cast to string for display.
⁺η
Add the bonus to the minimum grade.
∧ζ
No bonus if the worst two grades are the same.
⎇⌕θη
Check whether the worst grade was for Centring.
∨⎇⊖⌕θη∨›²ζ∨∧⁼²ζ‹¹⁶η∧⁼³⁻⌈θη›²⁰⌈θ›⁶ζ²
If not then check whether only one bonus point should be awarded otherwise award two bonus points. (If the worst grade was for Corners then add a bonus point if the difference was less than 6 grade points or 2 if it was 6 or more. The calculation for Edges and Surface is longer but still only adds one or two bonus points.)
⊕⌊⟦²÷ζ⁴
If the worst grade was for Centring then add a bonus point for every 4 grade points between the worst two grades up to 2, plus a further bonus point.
Perl 5 (-ap
), 157 154 bytes
minor improvements !$d?0:...
inverted to $d?...:0
, >=9.5
changed to >9.4
and !=10
to <10
($w,$x,$y,$z)=sort{$b<=>$a}@F;$d=$y-$z;$_=$z+=$d?$z==$F[2]|$z==$F[3]?$d<1?.5:$d==1&$z+1>9.4|$w-$z==1.5&$w<10?.5:1:$z==$F[0]?$d<2?.5:$d<4?1:1.5:$d<3?.5:1:0
TIO
first answer was
($w,$x,$y,$z)=sort{$b<=>$a}@F;$d=$y-$z;$_=$z+=!$d?0:$z==$F[2]|$z==$F[3]?$d<1?.5:$d==1&$z+1>=9.5|$w-$z==1.5&$w!=10?.5:1:$z==$F[0]?$d<2?.5:$d<4?1:1.5:$d<3?.5:1
straight forward, ungolfed
!$d?0
:$z==$F[2]|$z==$F[3]?
$d<1?.5
:$d==1&$z+1>=9.5|$w-$z==1.5&$w!=10?.5
:1
:$z==$F[0]?
$d<2?.5
:$d<4?1
:1.5
:$d<3?.5
:1
TIO
JavaScript (V8), 160 159 154 151 bytes
s=>{[C,O,E,S]=[...s];[a,b,c,d]=s.sort((a,b)=>b-a);e=c-d;return(e?d==E|d==S?e<1?.5:(e==1&d>8.4)|(a-d==1.5&a<10)?.5:1:d-C?e<3?.5:1:e<2?.5:e<4?1:1.5:0)+d}
Try it online!
A bit ungolfed:
function calculateScore(score) {
[center,corner,edge,surface] = [...score]; // makes a copy because sort is in-place
[first,second,third,fourth] = score.sort((a,b)=>b-a); // standard sort is alphabetically, this will sort by value
diff = third - fourth;
return fourth + (// Every final score is fourth + something else
diff != 0
? fourth == edge || fourth == surface
? diff < 1
? 0.5
: (diff == 1 && fourth >= 8.5) || (first-fourth == 1.5 && a < 10)
? 0.5
: 1
: fourth != corner
? diff < 3
? 0.5
: 1
: diff < 2
? 0.5
: diff < 4
? 1
: 1.5
: 0 // diff == 0
);
}
- -1:
>=8.5
->>8.4
- -5 thanks to @Kevin Cruijssen
- -3 for ES6 copying with
[...s]