16
\$\begingroup\$

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

Related: Rank a list of scores with "skips"

\$\endgroup\$
0

14 Answers 14

5
\$\begingroup\$

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])))

\$\endgroup\$
5
\$\begingroup\$

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
\$\endgroup\$
3
  • \$\begingroup\$ Right tool for the job! \$\endgroup\$
    – geokavel
    Aug 23, 2017 at 19:55
  • 5
    \$\begingroup\$ This should be 3 bytes (just ave) otherwise it's just a snippet (which isn't allowed). Fortunately, this saves you 5 bytes. \$\endgroup\$ Sep 10, 2017 at 19:31
  • \$\begingroup\$ @caird thanks, you're absolutely right. \$\endgroup\$
    – BLT
    Sep 11, 2017 at 14:17
4
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

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.

Try it online! Or verify all test cases.

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
\$\endgroup\$
2
  • \$\begingroup\$ Nics solution! I think you can save some bytes by not rounding to nearest int (it's not required). \$\endgroup\$
    – geokavel
    Aug 18, 2017 at 13:31
  • \$\begingroup\$ @geokavel Oh, you are right! I misread the challenge as requering rounding. Thanks! \$\endgroup\$
    – Luis Mendo
    Aug 18, 2017 at 16:36
3
\$\begingroup\$

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
\$\endgroup\$
0
2
\$\begingroup\$

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!

\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ Note that OP added You can also take the points list [15,12,10,9,...] as input. if that saves you any bytes \$\endgroup\$
    – Stephen
    Aug 18, 2017 at 1:01
2
\$\begingroup\$

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!

\$\endgroup\$
2
\$\begingroup\$

Jelly, 11 bytes

ṁ⁴Œg¤Æmṁ$€F

Try it online!

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

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

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!

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
  • \$\begingroup\$ ^^ I'm just gonna start with Proton next time lol. \$\endgroup\$ Aug 18, 2017 at 19:52
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

Haskell, 152 bytes

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)`div`l(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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.