# Mario Kart Scoring w/ Ties

I ran into this problem while working on another challenge I'm making for this site. In that challenge I utilize "Mario Kart 8 Scoring". The amount of points the player in kth place gets is represented by this 1-indexed array: [15,12,10,9,8,7,6,5,4,3,2,1]. So 1st place gets 15 points, 2nd place gets 12 points, etc.

It's easy enough to assign points like this, however the tricky part comes with how I handle ties. What I do is give each tying player the average of the points given for each tying place. For example, if only 1st and 2nd tied, then both players get (15+12)/2 = 13.5 points. (Note: You're allowed to round to the nearest int, so 13 or 14 are both also acceptable.) Then 3rd - 12th place get the normal amount of points for their position.

## Challenge

Given 12 non-negative integer scores that are decreasingly sorted, output the number of points each player gets. You can also take the points list [15,12,10,9,...] as input. Note that the number of points each player gets does not depend on the actual values of the scores, but how they compare to the other scores.

## Test Cases

• [21,21,15,14,12,9,6,5,4,3,2,1] => [14,14,10,9,8,7,6,5,4,3,2,1]
• [20,15,15,15,10,9,8,7,6,5,4,3] => [15,10,10,10,8,7,6,5,4,3,2,1]
• explanation: (12+10+9)/3 = 10.3333
• [1,1,1,1,1,1,1,1,1,1,1,1] => [7,7,7,7,7,7,7,7,7,7,7,7]
• explanation: (15+12+10+9+8+7+6+5+4+3+2+1)/12 = 6.8333
• [20,20,20,20,10,10,10,9,8,7,6,5] => [12,12,12,12,7,7,7,5,4,3,2,1]
• explanation: (15+12+10+9)/4 = 11.5, (8+7+6)/3 = 7
• [100,99,98,95,95,95,94,93,93,92,91,91] => [15,12,10,8,8,8,6,5,5,3,2,2]
• explanation: (9+8+7)/3 = 8, (5+4)/2 = 4.5, (2+1)/2 = 1.5

# JavaScript (ES6), 57 bytes

Takes input in currying syntax (p)(s), where p is the list of points and s is the list of scores.

p=>s=>s.map(v=>s.reduce((t,x,i)=>x-v?t:t+p[n++,i],n=0)/n)


### Test cases

let f =

p=>s=>s.map(v=>s.reduce((t,x,i)=>x-v?t:t+p[n++,i],n=0)/n)

points = [15,12,10,9,8,7,6,5,4,3,2,1];

console.log(JSON.stringify(f(points)([21,21,15,14,12,9,6,5,4,3,2,1])))
console.log(JSON.stringify(f(points)([20,15,15,15,10,9,8,7,6,5,4,3])))
console.log(JSON.stringify(f(points)([1,1,1,1,1,1,1,1,1,1,1,1])))
console.log(JSON.stringify(f(points)([20,20,20,20,10,10,10,9,8,7,6,5])))
console.log(JSON.stringify(f(points)([100,99,98,95,95,95,94,93,93,92,91,91])))

# R, 3 bytes

Apparently R has a built-in for this. Takes a list of points and scores as input.

ave


Try it online!

Example:

p=c(15,12,10,9,8,7,6,5,4,3,2,1)

> ave(p,c(20,15,15,15,10,9,8,7,6,5,4,3))
[1] 15.00000 10.33333 10.33333 10.33333  8.00000  7.00000  6.00000  5.00000  4.00000  3.00000  2.00000  1.00000
> ave(p,c(1,1,1,1,1,1,1,1,1,1,1,1))
[1] 6.833333 6.833333 6.833333 6.833333 6.833333 6.833333 6.833333 6.833333 6.833333 6.833333 6.833333 6.833333

• Right tool for the job! Aug 23 '17 at 19:55
• This should be 3 bytes (just ave) otherwise it's just a snippet (which isn't allowed). Fortunately, this saves you 5 bytes. Sep 10 '17 at 19:31
• @caird thanks, you're absolutely right.
– BLT
Sep 11 '17 at 14:17

# Perl 5, 109 +1 (-a) = 110 bytes

@p=(1..10,12,15);while(@F){$/=$,=0;do{$,++;$/+=pop@p}while($w=shift@F)==$F[0];push@r,(int.5+$//$,)x$,}say"@r"  Try it online! Includes 17 bytes to hardcode the point values. # MATL, 12 10 bytes 2 bytes off thanks to @geokavel! 7#uti2XQw)  Inputs are a column vector (; as separator) of integer scores and a column vector with the points. The output contains the results separated by newlines. ### Explanation  % Implicitly take first input. % STACK: [21;21;15;14;12;9;6;5;4;3;2;1] 7#u % Unique consecutive integer labels % STACK: [1;1;2;3;4;5;6;7;8;9;10;11] t % Duplicate % STACK: [1;1;2;3;4;5;6;7;8;9;10;11], [1;1;2;3;4;5;6;7;8;9;10;11] i % Take second input % STACK: [1;1;2;3;4;5;6;7;8;9;10;11], [1;1;2;3;4;5;6;7;8;9;10;11], [15;12;10;9;8;7;6;5;4;3;2;1] 2XQ % Average second argument as grouped by the first % STACK: [1;1;2;3;4;5;6;7;8;9;10;11], [13.5;10;9;8;7;6;5;4;3;2;1] w % Swap % STACK: [[13.5;10;9;8;7;6;5;4;3;2;1], [1;1;2;3;4;5;6;7;8;9;10;11] ) % Reference indexing % STACK: [13.5;10;9;8;7;6;5;4;3;2;1] % Implicitly display  • Nics solution! I think you can save some bytes by not rounding to nearest int (it's not required). Aug 18 '17 at 13:31 • @geokavel Oh, you are right! I misread the challenge as requering rounding. Thanks! Aug 18 '17 at 16:36 # 05AB1E, 12 bytes γ€g£vygFyÅAˆ  Try it online! Explanation γ # group the scores into chunks of consecutive equal elements €g # get the length of each chunk £ # split the points list into chunks of these sizes v # for each chunk y in the points list ygF # len(y) times do: yÅA # get the arithmetic mean of y ˆ # add to global list # implicitly output global list  # C# (.NET Core), 154 bytes x=>s=>{for(int i=0;i<12;){int b=0,j=i,a=0,c=0;for(;j<12&&x[i]==x[j];j++,b++){a+=s[j];}a=(int)Math.Round(a/(b+.0));for(;c<b;c++){x[i+c]=a;}i+=b;}return x;}  Try it online! # C# (.NET Core) + using Linq, 170 + 23 bytes x=>s=>x.GroupBy(z=>z).Select(y=>Enumerable.Repeat(Math.Round(s.Skip(Array.IndexOf(x,y.Key)).Take(y.Count()).Average()),y.Count())).Aggregate((a,b)=>a.Concat(b)).ToArray()  Try it online! # J, 15 bytes [:;<@(##+/%#)/.  Try it online! Takes the list of scores (1 2 ... 12 15) as a right-hand argument and the values to score as a left-hand argument. If this isn't a logical input, add 1 byte for a ~-passive to invert the order in which the inputs are taken. There might be a few things to golf, which include • My usage of boxing • The cap at the end # Explanation I'll split this into a couple functions. avg_and_dupe =. # # +/ % # score =. [: ; <@avg_and_dupe/.  • avg_and_dupe takes the average of a list and duplicates it as many times as the list's length • score scores an input (left argument) given a list of scores (right argument). # avg_and_dupe # # +/ % # # Length # Copy as many times as the left argument +/ % # Average +/ Sum % Divided by # Length  This works so nicely because it's treated as two forks. If you're still scratching your head (I know I was at first), ask and I can provide a more in-depth explanation for why this works as it does. ### score [: ; <@avg_and_dupe/. /. Key: using the values given, partition the scores <@avg_and_dupe For each partition: avg_and_dupe Average and duplicate < Then box ; Raze the boxes into a single list  If it's still confusing, I can also add an explanation for /.-key, but I think the wiki page explains it pretty well. • Note that OP added You can also take the points list [15,12,10,9,...] as input. if that saves you any bytes Aug 18 '17 at 1:01 # Python 2, 66 bytes -8 bytes thanks to Leaky Nun. lambda s,p:[sum(p[s.index(i):][:s.count(i)])/s.count(i)for i in s]  Try it online! # Jelly, 11 bytes ṁ⁴Œg¤Æmṁ$€F


Try it online!

-3 bytes thanks to fireflame for noticing new Jelly features :D

• Yeah, it's probably too long looking at how short the solutions on the related challenge are. Aug 18 '17 at 0:46
• @geokavel the annoying thing is that the code to generate the list is longer than the J solution on that one ;_; Aug 18 '17 at 0:49
• I forgot to put that you can take the points list as input too. I'm going to add that. Aug 18 '17 at 0:50
• 11 bytes. Uses the new arithmetic mean monad instead of S÷L and mold instead of xL, which allows \$ instead of two µ. Aug 18 '17 at 2:53
• Sep 10 '17 at 19:25

# Python 3, 67 bytes

lambda s,p:[sum(v for j,v in zip(s,p)if j==i)/s.count(i)for i in s]


Try it online!

# Python 2, 108 70 bytes

lambda s,p:[1.*sum(v for j,v in zip(s,p)if j==i)/s.count(i)for i in s]


Try it online!

# Python 3, 72 bytes

lambda s,p:[sum(p[s.index(i):12-s[::-1].index(i)])/s.count(i)for i in s]


Try it online!

# Proton, 62 bytes

(s,p)=>[sum(p[s.index(i)to][to s.count(i)])/s.count(i)for i:s]


Try it online!

# Proton, 63 bytes

(s,p)=>map(i=>sum(p[s.index(i)to][to s.count(i)])/s.count(i),s)


Try it online!

• ^^ I'm just gonna start with Proton next time lol. Aug 18 '17 at 19:52

# Dyalog APL, 14 bytes

∊{(⊂≢⍴+/÷≢)⍵}⌸


Takes the list of scores as left argument and points list as right argument. Add 2 bytes for wrapping it in () if called directly and not as a named function.

{...}⌸ group right argument by key in left argument and apply function in braces to each group (key operator).

⊂≢⍴+/÷≢ is a fork where:

+/÷≢ is average points for group (sum divided by tally)

≢⍴ tally reshape (replicate the average to match number of items in group)

⊂ boxes the result (this is to counteract the mixing of the result that the key operator applies)

∊ is enlist and flattens the result of the key operator (which is a nested vector of vectors) into a simple list.

TryAPL online

f::[Int]->[Int]
f=concat.g(15:12:[10,9..1])[]
g[q]t _=[q:t]
g(q:r)t(x:z)|x>head z=(replicate(l(q:t))(sum(q:t)divl(q:t))):g r[]z|1<2=g
r(q:t)z
l=length


It's a pain to import groupBy and on, so I had to do my own.

Averaging function will be shortened shortly.

Needing the signature could probably be avoided with compiler flags.