27
\$\begingroup\$

Introduction

In the strategy game Starcraft 2, there are three "races" to choose from: Terran, Zerg, and Protoss. In this challenge we will be focusing on the Protoss and the iconic phrase "You must construct additional pylons!" This message is stated when you run out of supply to build your army. So, to help out the Starcraft community, you must write a program or function that tells players exactly how many pylons they need.

The Challenge

You will be given an input of a string consisting of a single integer N and space-separated list of units. N will always be zero or positive, and the list of units will always have one or more valid units. N represents the amount of pylons the player currently has. Your job is to calculate if the amount of pylons that the player has is enough to build the units. Your program or function must output/return a truthy value if there is enough supply, or if there is not enough supply you must output You must construct ZZZ additional pylons where ZZZ is the amount of pylons needed to build the units. Note that pylon(s) must be plural when needed and unplural when not (...1 additional pylon!, ...2 additional pylons!).

Protoss Units and Supply Cost

Here is a list of all units and their corresponding supply cost. Pylons provide an additional 8 supply.

Unit            Supply Cost

Probe           1
Zealot          2
Sentry          2
Stalker         2
HighTemplar     2
DarkTemplar     2
Immortal        4
Colossus        6
Archon          4
Observer        1
WarpPrism       2
Phoenix         2
MothershipCore  2
VoidRay         4
Oracle          3
Tempest         4
Carrier         6
Mothership      8

Examples WITHOUT Bonuses

Input:
   2 Probe Probe Probe Probe Stalker Zealot Carrier Probe Zealot
Output:
   You must construct 1 additional pylon!
Why?
   Adding up the supply costs for all of the units gives 17. The current 2 pylons provide 16 supply, so one more is needed to provide enough for 17.

Input:
   5 Mothership Carrier Probe Tempest HighTemplar
Output:
   true
Why?
   Adding up the units gets 21. The current 5 pylons provide 40 supply, which is plenty enough.

Input:
  0 Mothership Colossus Zealot
Output:
  You must construct 2 additional pylons!
Why?
  Adding the units gets 16. There is no pylons so 2 need to be built to provide enough supply. 

Bonuses

  1. Any experienced Starcraft 2 player would know that you need a mothership core before to transform it into a mothership. Also, you can only have one mothership at a time (whether it is an actual mothership or a mothership core). If neither of these conditions are true, output any falsy value. If your program can check to see that only one mothership is active at a time, and that a mothership core is built before the actual mothership, take 20% off your byte count.
  2. Little may you know, but nexuses (protoss command centers) actually provide supply too! If your program can add 11 to the maximum supply every time it encounters a nexus in the unit list, take 10% off your byte count. Note that it does not matter where the Nexus is in the build order, so 0 Probe Nexus would still return true.

Examples WITH Bonuses

Input (Bonus 1):
  3 Mothership Zealot
Output:
  false
Why?
  According to the first bonus, a mothership core has to be built before a mothership.

Input (Bonus 1):
  3 MothershipCore Mothership MothershipCore
Output:
  false
Why?
  According to the first bonus, only one mothership can be built and here there is two (MothershipCore -> Mothership and a second MothershipCore).

Input (Bonus 2):
  0 Probe Nexus Probe
Output:
  true
Why?
  According to the second bonus, nexuses add 11 to the maximum supply, allowing both probes to be built.

Input (Both Bonuses):
  0 Nexus MothershipCore Mothership Carrier
Output:
  You must construct 1 additional pylon.
Why?
  There are no pylons, but the nexus provides 11 supply. The motherships take up 2 and 8, respectively and the carrier takes up 6. You need one more pylon to have enough to provide for all 16 supply.

TL;DR

Input a string consisting of an integer and space-separated unit names (from the table above). Output a truthy value if you can build all of the units with the supply provided by the N pylons (the integer in input). Output You must construct ZZZ additional pylon(s) if more pylons are needed, where ZZZ is the amount of pylons needed. Make sure to make pylons plural if necessary.

This is , so shortest code in bytes (or your language's counting method) wins!

Leaderboard

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

# Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the leaderboard snippet:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

var QUESTION_ID=69011,OVERRIDE_USER=36670;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/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>

\$\endgroup\$
  • 1
    \$\begingroup\$ Does it have to be space-separated or can it be 'convenient'? \$\endgroup\$ – Blue Jan 9 '16 at 18:11
  • \$\begingroup\$ @muddyfish If I understand you correctly, yes the input has to be space separated in the form N unit1 unit2 unit3.... \$\endgroup\$ – GamrCorps Jan 9 '16 at 18:12
  • \$\begingroup\$ Will there ever be more than 9 pylons? Do I have to output exactly true or is a truthy value acceptable? \$\endgroup\$ – Dom Hastings Jan 12 '16 at 8:31
  • \$\begingroup\$ @DomHastings there can be more than 9. Any truthy value is acceptable. \$\endgroup\$ – GamrCorps Jan 12 '16 at 13:01
  • 2
    \$\begingroup\$ Oh, come on! Does anyone remember Starcraft: Broodwar or the original Starcraft? They have that phrase, too! \$\endgroup\$ – user47018 Apr 26 '16 at 9:35
4
\$\begingroup\$

Ruby, 263 - 30% = 184 bytes

v=c=k=0
l,a={PeOr:1,ZtSySrHrDrWmPxMe:2,Oe:3,VyIlAnTt:4,CsCr:6,Mp:8,Ns:-11},ARGV.shift
ARGV.map{|u|k+=l[l.keys.grep(/#{q=u[0]+u[-1]}/)[0]];c+=1if q=="Me";v=!0if c!=1&&q=~/M/}
n=k/8.0-a.to_i
p v ?n<0||"You must construct #{n.ceil} additional pylon#{'s'if n>1}!":nil

Usage

ruby sc.rb 0 Probe Nexus

\$\endgroup\$
7
\$\begingroup\$

Python 3, 207*.9 == 186.3 bytes.

Implements the nexus bonus.
Saved 26 bytes thanks to DSM.
Saved 2 bytes thanks to Tim Pederick

x,*l=input().split()
d=-((int(x)*8-sum((('vexuobcl'+2*'clsuie'+4*'Ratahoiesuhihi').count(q[-3:-1])*(1-12*(q[0]>'w'))or 2)for q in l))//8)
print((1,"You must construct %s additional pylon"%d+'s!'[d<2:])[d>0])
\$\endgroup\$
  • \$\begingroup\$ Nice work! Since you need only output a truthy value, not necessarily True, you can save two bytes by replacing 1>0 with just 1. \$\endgroup\$ – Tim Pederick Jan 16 '16 at 14:15
  • \$\begingroup\$ @TimPederick I wasn't sure if that counted as truthy enough. \$\endgroup\$ – Morgan Thrapp Jan 16 '16 at 14:16
  • \$\begingroup\$ It satisfies the most popular definition of "truthy" from meta. \$\endgroup\$ – Tim Pederick Jan 16 '16 at 14:18
  • 3
    \$\begingroup\$ You must construct additional pythons... \$\endgroup\$ – Brian Jan 18 '16 at 16:27
4
\$\begingroup\$

JavaScript, 274 265 bytes (no bonuses) 281 - 10% = 252.9 bytes

s=>(c=eval(s[a="replace"](" ","-(")[a](/ /g,"+")[a](/\w+/g,m=>m[b="match"](/^(Pr|Ob)/g)?1:m[b](/^([ZSHDWP]|M\w+C)/g)?2:m[b](/^O/g)?3:m[b](/^[IAVT]/g)?4:m[b](/^N/g)?-11:m[b](/^C/g)?6:+m!=m?8:m*8)+")"))>0?true:`You must construct ${Math.ceil(-c/8)} additional pylon${c/8<-1?"s":""}!`

This appears to be pretty lengthy...

Demo + explanation:

p = s => (c = eval(
  s[a = "replace"](" ", "-(")         //replace the first space (after the number of pylons) with "-" and open the bracket
   [a](/ /g, "+")                       //replace all the remaining spaces with "+"
   [a](/\w+/g, m =>                     //replace any sequence of characters with...
    m[b = "match"](/^(Pr|Ob)/g) ? 1 :   //with 1, if matches "Probe" or "Observer"
    m[b](/^([ZSHDWP]|M\w+C)/g) ? 2 :    //with 2, if it matches bunch of the units with cost 2. "Probe" didn't match already, so it's safe to catch "Phoenix" by only the first letter.
    m[b](/^O/g) ? 3 :                   //with 3, if match is "Oracle"
    m[b](/^[IAVT]/g) ? 4 :              //with 4, if matches "Immortal", "Archon", "VoidRay" or "Tempest"
    m[b](/^C/g) ? 6 :                   //with 6, if it's "Carrier" or "Colossus"
    m[b](/^N/g) ? -11 :                 //don't forget nexuses!
    +m != m ? 8 : m * 8                 //and if's not a number, then it's "Mothership", so with 8. If it's number, it can only be the number of pylons, replace it with itself multiplied by 8.
  ) + ")"                             //close the opened bracket
)) > 0 ? true : `You must construct ${Math.ceil(-c/8)} additional pylon${c/8<-1?"s":""}!`

document.write(
  p("2 Probe Probe Probe Probe Stalker Zealot Carrier Probe Zealot") + "<br>" +
  p("5 Mothership Carrier Probe Tempest HighTemplar") + "<br>" +
  p("0 Mothership Colossus Zealot") + "<br>" +
  p("0 Probe Nexus Probe")
)

\$\endgroup\$
  • \$\begingroup\$ I have no idea why I didn't look at bonuses, should do it. \$\endgroup\$ – nicael Jan 9 '16 at 21:32
  • \$\begingroup\$ Save 8 bytes by using -(c>>3) instead of Math.ceil(-c/8). Save another 2 bytes by using c<-8 instead of c/8<-1. \$\endgroup\$ – Neil Jan 14 '16 at 10:36
  • \$\begingroup\$ Your inner matches don't need /g do they? That would save another 6 bytes. Also /ob/i looks like it would work for another 5 byte saving. \$\endgroup\$ – Neil Jan 14 '16 at 10:42
  • \$\begingroup\$ Your test seems to be wrong - you're using >0 but if you have an exact match then that's still true. Obviously for golfing purposes you would switch it to <0 and reverse the ?: arms. \$\endgroup\$ – Neil Jan 14 '16 at 10:43
  • 1
    \$\begingroup\$ I think you can save a further 17 bytes by using subtraction throughout. This is what I have so far: s=>(c=eval(s.replace(/ /g,"-").replace(/\w+/g,m=>m[b="match"](/ob/i)?1:m[b](/^([ZSHDWP]|M\w+C)/)?2:m[b](/^O/)?3:m[b](/^[IAVT]/)?4:m[b](/^N/)?-11:m[b](/^C/)?6:+m!=m?8:m*8)))<0?`You must construct ${-(c>>3)} additional pylon${c<-8?"s":""}!`:true \$\endgroup\$ – Neil Jan 14 '16 at 10:48
4
\$\begingroup\$

Python 3, 293 − 30% = 205.1 bytes

Implements both bonuses. Prints 1 as its truthy value, and either 0 or an empty string as its falsey value.

s='5N 8O5P bDbHeM7P6S7S9W6Z 6O 6A8I7T7V . 7C8C . aM'.split()
m=M=n=o=0
p,*u=input().split()
for v in u:
 S=0
 while'%x'%len(v)+v[0]not in s[S]:S+=1
 n+=S or-11;M+=S>7;m+='pC'in v;o+=m>1or M>1or m<1<=M
q=int(p)+n//-8
print([1,'You must construct %d additional pylon'%-q+'s!'[q>-2:]][q<0]*(o<1))

Credit to Dom Hastings' solution for helping me shave off a good few bytes with a "poor man's ceil" of my own, and Morgan Thrapp's for the idea underlying 's!'[q>-2:], which saved me six bytes—not to mention pointing out, in the comments, how to save another byte on that bit.


Explanations

The string in line 1 encodes all of the units and their supply requirements. Each unit is represented as two characters: a hexadecimal digit giving the length of the unit's name, and the first character of the name (e.g. 8O is the Observer; aM is the Mothership). The supply requirement is the index of the encoded unit within the sequence s, formed by splitting the string on the spaces. Full stops mark unused amounts of supply (no unit needs 5 or 7 supply), and as a special case, the Nexus (5N) is at index 0.

Line 2 initialises values: m is the number of mothership cores, M is the number of motherships, n is the total supply cost, and o indicates whether or not the mothership build conditions have been violated. Line 3 takes the input, putting the number of pylons into p and the list of units into u.

Within the loop that starts at line 4, S is an index into s and, thus, also the amount of supply needed for the current unit, v. In line 6, the while statement steps through s until the unit is found. ('%x'%len(v) turns the length of the unit's name into a hex digit.)

Line 7 updates the total supply cost n (note the special case, -11, if S is zero). It then increments the counts of motherships M (identified by the supply cost being over 7) and mothership cores m (identified by the substring pC in the unit's name). Then, if either of these is greater than 1, or if M is at least one while m is still zero, the flag o is set. (Actually, it's incremented, but later on we only care if it's zero or non-zero.)

The pylon deficit q is calculated, a little oddly, in line 8. Naively, it should be n // 8 - int(p) (i.e. one eighth of the supply cost, minus any pylons we already have). But that would round down, when we need to round up. Integer division (//) rounds towards negative infinity, though, so we just work everything in negatives: int(p) - -(n // -8), which simplifies to the form actually used.

Lastly, the output. If we're just one pylon short, q will be -1, hence the test q>-2 (which slices the s out of the string s! if true, and keeps it otherwise). If there's no pylon deficit, q will be zero or positive, hence q<0 to select between the truthy value 1 or the output string. Lastly, if the flag o isn't zero, multiplying either result (1 or a string) by Boolean False (handled as numeric 0) will give a falsey value (0 or the empty string).

\$\endgroup\$
3
\$\begingroup\$

C++11, 732-30% = 512.4 bytes

Uses Dom Hastings's poor man's ceil and Martin Büttner suggestions of shorting the dictionary.

#include <iostream>
#include <map>
#include <string>
#include <cctype>
using namespace std;
map<int,int>a ={{536,1},{655,2},{677,2},{758,2},{1173,2},{1175,2},{869,4},{891,6},{635,4},{872,1},{997,2},{763,2},{1516,2},{766,4},{630,3},{770,4},{744,6},{1091,8},{563,-11}};
int main(){string b,c;int d,e,l,j,k=0,m=0,n=0,v=0;cin>>d;getline(cin,b);
while(b.size()){e=0;auto z=b.find(" ");c=b.substr(0,z);b.erase(0,((z==string::npos)?z:z+1));
for(int i=0;i<c.size();i++){e+=tolower(c[i]);}
if(e==1516){m++;}else if(e==1091){((m>1)?v=1:v=0);}
if((l=k-(d*8)>0)&&(m==n==1)){j=(int)(((float)l/8)+0.99);cout<<"You must construct "<<j<<" additional pylon"<<((j==1)?"!":"s!")<<endl;}
else{cout<<((m==n==1&&!v)?"True":"False")<<endl;}}
\$\endgroup\$
  • \$\begingroup\$ +1 Welcome to Programming Puzzles and Code Golf, and to all of Stack Exchange. This is a very good first answer. If you would like any help, just ask by typing @username at the beginning of a comment, e.g. @wizzwizz4. \$\endgroup\$ – wizzwizz4 Jan 18 '16 at 16:59
2
\$\begingroup\$

Python 2, 442 359 464 332 314 306 - 10% = 275.4

a,*l=input().split(' ');p=int(a)*8;for i in l:p-={"Ne":-11,"Pr":1,"Ze":2,"Se":2,"St":2,"Hi":2,"Da":2,"Im":4,"Co":6,"Ar":4,"Ob":1,"Wa":2,"Ph":2,"MoC":2,"Vo":4,"Or":3,"Te":4,"Ca":6,"Mo":8}[i[:2]+("C"if i[-4:]=="Core")]
e=int(.9+p/8)+1;print[1,"You must construct "+`e`+" additional pylon"+"s!"[e>1:]][p>=0]
\$\endgroup\$
  • \$\begingroup\$ How could I shorten my dictionary? \$\endgroup\$ – NoOneIsHere Jan 10 '16 at 15:50
  • 2
    \$\begingroup\$ There are tons of ways to do that. E.g. the JavaScript answer uses regular expressions instead of checking against individual strings. Maybe you could try finding a hash that maps each string to a unique number (maybe sum of the character codes). Those numbers might be shorter than the strings. \$\endgroup\$ – Martin Ender Jan 10 '16 at 16:27
  • \$\begingroup\$ I'm not sure, but maybe it's long enough get savings with something like dict(x[:2],int(x[2:]) for x in "Ne-11 Pr1 Ze2".split()) \$\endgroup\$ – user16488 Jul 26 '16 at 2:31
1
\$\begingroup\$

Lua, 418 - 10% = 376,2 bytes

function p(i)i=i:gsub("(%w+)",function(w)q=tonumber(w)*8;return""end,1);n=0;i:gsub("(%w+)",function(w)m=w.match;n=n+(m(w,"^Pr.*")and 1 or m(w,"^Ob.*")and 1 or m(w,"^[ZSHDWP]")and 2 or m(w,"^M.*C")and 2 or m(w,"^O")and 3 or m(w,"^[IAVT]")and 4 or m(w,"^C")and 6 or m(w,"^N")and -11 or 8)end)if n>q then a=math.ceil((n-q)/8);print("You must construct "..a.." additional pylon"..(a>1 and"s"or"")..".")else print(1)end end

Implements the Nexus bonus.

First time I've posted something here. Was writing Lua scripts for a game, stumbled across this and felt like contributing, hah.

Note: This Lua function assumes that the base library has been loaded, and that the host application defines an appropriate print function that accepts any non-nil value. I'm exploiting Lua's string.gsub to the best of my ability, as well as its and and or operators.

Here's the pretty version:

function pylons(i)
    -- Replace the first word, the number, with a space, while also storing it as a number * 8
    i = i:gsub("(%w+)", function(w)
        q = tonumber(w) * 8
        return ""
    end, 1)
    n = 0
    -- the function passed to gsub gets every word in the string,  and then I misuse Lua's and/or
    -- operator order to assign supply values to string.match calls that do not return nil
    i:gsub("(%w+)", function(w)
        m = w.match
        n = n + (m(w,"^Pr.*") and 1 or
        m(w,"^Ob.*") and 1 or
        m(w,"^[ZSHDWP]") and 2 or
        m(w,"^M.*C") and 2 or
        m(w,"^O") and 3 or
        m(w,"^[IAVT]") and 4 or
        m(w,"^C") and 6 or
        m(w,"^N") and -11 or 8)
    end)
    if n>q then
        a = math.ceil((n-q)/8)
        print("You must construct "..a.." additional pylon"..(a>1 and"s"or"")..".")
    else
        print(1)
    end
end

pylons("5 Nexus Probe Observer Zealot Sentry Stalker HighTemplar DarkTemplar WarpPrism Phoenix MothershipCore Oracle Immortal Archon VoidRay Tempest Colossus Carrier Mothership")
pylons("2 Probe Probe Probe Probe Stalker Zealot Carrier Probe Zealot")
pylons("5 Mothership Carrier Probe Tempest HighTemplar")
pylons("0 Mothership Colossus Zealot")
\$\endgroup\$
0
\$\begingroup\$

JavaScript (ES6), 228-10% = 206

s=>(s.replace(/\w+/g,x=>t+=~~{Ns:-11,Pe:1,Zt:2,Sy:2,Sr:2,Hr:2,Dr:2,Il:4,Cs:6,An:4,Or:1,Wm:2,Px:2,Me:2,Vy:4,Oe:3,Tt:4,Cr:6,Mp:8}[x[0]+x.slice(-1)]-8*~~x,t=7),t=t/8|0,t<=0||`You must construct ${t} additional pylon${t>1?'s':''}!`)

Test

F=s=>(
  t=7,
  s.replace(/\w+/g,
   x=>t+=~~{Ns:-11,Pe:1,Zt:2,Sy:2,Sr:2,Hr:2,Dr:2,Il:4,Cs:6,An:4,Or:1,Wm:2,Px:2,Me:2,Vy:4,Oe:3,Tt:4,Cr:6,Mp:8}[x[0]+x.slice(-1)]-8*~~x),
  t=t/8|0,
  t<=0||`You must construct ${t} additional pylon${t>1?'s':''}!`
)

console.log=x=>O.textContent+=x+'\n';

;['2 Probe Probe Probe Probe Stalker Zealot Carrier Probe Zealot',
'5 Mothership Carrier Probe Tempest HighTemplar',
'0 Mothership Colossus Zealot','0 Probe Nexus Probe'
].forEach(t=>console.log(t+'\n'+F(t)))
<pre id=O></pre>

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

Perl, 212 bytes code + 3 for -p - 10% = 193.5 bytes

I'm sure I can reduce this some more, not happy about the full for$s(...){...} block but I'm done for now!

$x=$_*8;s/^\d+ //;map{for$s(Pr,Ob,Or,C,V,I,A,T,Z,S,H,D,W,Ph,'.+C',N,'.+p$'){$x-=(1,1,3,6,(4)x4,(2)x7,-11,8)[$i++%17]*/^$s/}}/\w+/g;$x=int$x/-8+.9;$s=1<$x&&'s';$_=$x>0?"You must construct $x additional pylon$s!":1

Interesting snippets

  • Poor mans ceil: int$n+.9 - I tried to use 0| but got what looks like overflow!
  • List duplication: (9)x9 yields (9,9,9,9,9,9,9,9,9,9)

Usage:

perl -p pylons.pl <<< '3 Mothership Zealot'
1

Thanks to Tim Pederick for helping to save an extra byte!

\$\endgroup\$
  • \$\begingroup\$ I believe your "poor man's ceil" only needs to add .9, because the lowest decimal you'll get is 0.125 (1/8). \$\endgroup\$ – Tim Pederick Jan 16 '16 at 13:51
  • \$\begingroup\$ @TimPederick A good point, I need to save a lot more to be competitive! Might be worth looking into the other bonus for me... \$\endgroup\$ – Dom Hastings Jan 18 '16 at 15:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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