20
\$\begingroup\$

When making a Dungeons & Dragons character, an alternative to rolling ability scores is to assign them within a power budget called point buy. Higher ability scores cost more points, especially towards the upper end: a score of 8 is free, and raising a score by 1 costs 1 point, except raising to 15 or 16 costs 2 points, and raising to 17 or 18 costs 3 points.

+-------+------+
| Score | Cost |
+-------+------+
|     8 |    0 |
|     9 |    1 |
|    10 |    2 |
|    11 |    3 |
|    12 |    4 |
|    13 |    5 |
|    14 |    6 |
|    15 |    8 |
|    16 |   10 |
|    17 |   13 |
|    18 |   16 |
+-------+------+

In list form:

[(8, 0), (9, 1), (10, 2), (11, 3), (12, 4), (13, 5), (14, 6), (15, 8), (16, 10), (17, 13), (18, 16)]

The point buy cost is summed for all six ability scores.

Ability scores: 16   17   8  13   8  12
Point buy cost: 10 + 13 + 0 + 5 + 0 + 4  = 32

Given six ability scores, each 8 through 18, output the total point buy cost. Fewest bytes wins.

    var QUESTION_ID=67472,OVERRIDE_USER=20260;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/67472/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
    body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

**Leaderboard:**

\$\endgroup\$
3
  • 2
    \$\begingroup\$ Ähm is it just me or is the given challange missing? 0o \$\endgroup\$
    – Zaibis
    Commented Dec 23, 2015 at 14:19
  • 1
    \$\begingroup\$ @Zaibis Not sure what you mean. I put in "fewest bytes wins" -- did you mean that? \$\endgroup\$
    – xnor
    Commented Dec 23, 2015 at 19:39
  • \$\begingroup\$ tmp blah blah to say: yep \$\endgroup\$
    – Zaibis
    Commented Dec 23, 2015 at 19:41

6 Answers 6

11
\$\begingroup\$

JavaScript (ES7), 44 42 40 bytes

Crossed out 44 is still regular 44 :(

a=>a.map(s=>t+=s-9-~((s-14)**1.3),t=0)|t

Thanks to @apsillers for saving 2 bytes!

Explanation

The interesting part is -1-~((s-14)**1.3). (s-14)**1.3 produces 1, 2, 4 and 6 for the values 15 - 18. Any number that is less than 15 causes an error because the JavaScript implementation of exponential cannot operate on negative values with a fractional exponent. Basically, any value for s < 15 causes it to return NaN, so the -1-~ is there to cast it to a number (0).

a=>                       // a = input scores as an array of numbers
  a.map(s=>               // for each passed score
    t+=                   // add to the total
      s-9                 // point value = s - 8 (-1 used for next line)
      -~((s-14)**1.3),    // add extra points for scores 15 - 18
    t=0                   // t = total points (this happens BEFORE the map call)
  )
  |t                      // return the total points

ES6 Solution (42 bytes)

a=>a.map(s=>t+=s-9-~[1,2,4,6][s-15],t=0)|t

Test

This test uses Math.pow instead the exponential operator (**) so that it can run in any standard browser.

var solution = a=>a.map(s=>t+=s-9-~Math.pow(s-14,1.3),t=0)|t
Scores separated by spaces = <input type="text" id="input" value="16 17 8 13 8 12" />
<button onclick="result.textContent=solution(input.value.split(' '))">Go</button>
<pre id="result"></pre>

\$\endgroup\$
2
  • \$\begingroup\$ One more byte: use |t instead of &&t. The ECMAScript operation ToInt32 will always coerce the result of map here to 0, because multi-element arrays will always ToNumber-ify to NaN. (This would be a problem if the spec allowed single-element arrays as input, but it requires 6 elements.) \$\endgroup\$
    – apsillers
    Commented Dec 23, 2015 at 14:53
  • \$\begingroup\$ @apsillers Ooh, that's a nice tip! Thanks \$\endgroup\$
    – user81655
    Commented Dec 23, 2015 at 15:15
8
\$\begingroup\$

CJam, 18 bytes

l~[8EG]ff-:~0fe>:+

or

l~[8EG]m*::m0fe>:+

Test it here.

Explanation

The idea is decompose the point cost into three components:

 Score: 8  9 10 11 12 13 14 15 16 17 18
        0  1  2  3  4  5  6  7  8  9 10
        0  0  0  0  0  0  0  1  2  3  4
        0  0  0  0  0  0  0  0  0  1  2
       --------------------------------
 Cost:  0  1  2  3  4  5  6  8 10 13 16

All three components can be computed via a single subtraction and restricting the result to non-negative values.

l~    e# Read and evaluate input.
[8EG] e# Push [8 14 16].
ff-   e# For each pair from the two lists, subtract one from the other. 
:~    e# Flatten the result.
0fe>  e# Clamp each difference to non-negative values.
:+    e# Sum them all up.
\$\endgroup\$
8
\$\begingroup\$

Pyth, 14 bytes

s>#0-M*Q+14yB8

Test suite

This uses the same fundamental means of calculation as Martin Büttner, namely:

max(n-8, 0) + max(n-14, 0) + max(n-16, 0)

That being said, the means of calculation are very different. To generate the list of numbers to subtract, I use the expression +14yB8. yB8 means "Bifurcate 8 on the function y". y doubles numbers, so this gives [8, 16]. Then, we add on 14, giving the list [14, 8, 16].

Next, we take the Cartesian product with the input and subtract every pair of values.

Next, perform the maximization operation, we simply filter for positive values only, and sum the remainder.

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

Samau, 19 bytes

Not sure if the question is posted after the last commit of my new language. They are both 2 hours ago. But all the features used here was added before that.

▐[8 14 16]`-o;0>*ΣΣ

Samau uses CP737 as its default character encoding.

▐[8 14 16]`-o;0>*ΣΣ
▐                      read a list of numbers
 [8 14 16]             push [8 14 16]
          `-           push the function [-]
            o          outer product
             ;         duplicate
              0>       for each element, test if it's larger than 0
                *      times
                 ΣΣ    take the sum twice because it's a 2d array
\$\endgroup\$
0
\$\begingroup\$

PowerShell, 48 Bytes

$args|%{$t+=$_-8+@{15=1;16=2;17=4;18=10}[$_]};$t

(Pretty sure this isn't optimal.)

Takes input command-line arguments and pipes them into a loop |%{...}. Each iteration, we increment our total $t+= with the current number minus 8 $_-8 plus the result of indexing into a hashtable for the more-expensive values @{...}[$_]. Then we simply output $t at the end.

\$\endgroup\$
0
\$\begingroup\$

(🐂👍) Ox++, 248 bytes (62 characters)

🐀👉🌑👺🐁👉🌑👺😂🐀🐟🌗😂🐂👉😷😺😺😷👺🐁👉🐁👏🐂🙌🌙👏🌜🐂🐳🌒🌕🌛👥🌜🐂🙌🌒🌕🌛👏🌜🐂🐳🌒🌗🌛👥🌜🐂🙌🌒🌗🌛👺🐀👍😂👄🐁👄

Language I'm working on. Paste in the code here.

\$\endgroup\$
1
  • \$\begingroup\$ My browser can only display 7 of these characters. \$\endgroup\$
    – isaacg
    Commented Dec 23, 2015 at 20:39

Your Answer

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

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