102
\$\begingroup\$

You've just been hired by a German car manufacturing company. Your first task, as an engineer, is to write a program that computes the ecological footprint of ASCII strings.

The ecological footprint of character is computed as follows:

Write the character's ASCII code in binary, and count the number of 1's.

For example, A has a footprint of 2, but O is dirtier with a footprint of 5.

The global footprint of a string is the sum of the footprints of its characters. An empty string has a footprint of zero.

Your program must accept an ASCII string as parameter (through command line or input), compute its ecological footprint, and output it. The program itself must be ASCII encoded.

There is a hiccup though. As your company wishes to enter a new market with stricter environmental rules, you need to tune your program so that it behaves differently in "test mode". Thus:

The program should output 0 when it receives the string test as parameter.

Scoring

The source code with the smallest ecological footprint wins (and yes, the answer test is forbidden!)

\$\endgroup\$
  • 36
    \$\begingroup\$ I'm sorry, I haven't been keeping up with the news, but I've just read it. Can we assume the German car company is definitely NOT called Volkswagen? \$\endgroup\$ – Level River St Sep 25 '15 at 11:18
  • 7
    \$\begingroup\$ For reference, most costly to less costly characters: \x7F}~_?{ow7yvu/s\x1F;=znm>k|OW[]^gc\x1Ex\x1D\eef\\'ZY+-VU.St\x173iNM5K6r\x0FG9:q<ljQ\x15\x13pC\aEF8IJL4\x0E21\x16RTh,X*)\x19\v&%\x1A#d\x1C\rab`!\"$(\x180\x05A\x14B\x12\x11DHP\x03\f\x06\n\t\x80\x10\x01@\x04\b\x02 \x00 \$\endgroup\$ – Caridorc Sep 25 '15 at 11:59
  • 19
    \$\begingroup\$ @steveverrill It is a fictional company, but its name indeed starts with V and has a W somewhere in the middle. But any similarities with reality is mere coincidence, least someone sues us. \$\endgroup\$ – Mindwin Sep 25 '15 at 12:40
  • 1
    \$\begingroup\$ Functions allowed (instead of programs)? \$\endgroup\$ – Luis Mendo Sep 25 '15 at 20:58
  • 12
    \$\begingroup\$ They're lying to you! 1's are much more ecologically friendly than 0's. Want proof? Print out your source code in binary. 0's use nearly twice as much ink as 1's. And if you code with a dark background, they also waste more electricity to display on your screen. (If you code with a white background, you're already wasting electrons rendering all that white, so clearly any environmentally conscious programmer should be using a black background in their editor.) To be extra eco-friendly, we should all be writing in Whitespace... \$\endgroup\$ – Darrel Hoffman Sep 27 '15 at 18:03

37 Answers 37

45
\$\begingroup\$

CJam, 33 31

"",AA#b:c~

There are 11300000000950000000034000000011600000001010000000115000000011600000000340000000061000000003300000000420000000058000000010500000000500000000102000000009800000000490000000102000000009800000000490000000098 null bytes between the double quotes.

The code is equivalent to

11300000000950000000034000000011600000001010000000115000000011600000000340000000061000000003300000000420000000058000000010500000000500000000102000000009800000000490000000102000000009800000000490000000098
AA#b:c~

which can be tested online.

How this works

"",  e# Push the length of the string.
AA#  e# Push 10000000000.
b    e# Turn the length into the array of its base-10000000000 digits.
:c   e# Cast each digit to character. This pushes the following:
     e# q_"test"=!*:i2fb1fb1b
~    e# Evaluate the string.

How that works

q_     e# Read all input and push a copy.
"test" e# Push the string "test".
=!*    e# Check for inequality and repeat the string 0 or 1 times.
       e# This replaces input "test" with the empty string.
:i     e# Cast each character to integer
2fb    e# Replace each integer by the array of its base-2 digits.
1fb    e# Replace each array of base-2 digits by the sum of its digits.
1b     e# Add the sums of digits.

This source code has an ecological footprint of 75.

\$\endgroup\$
  • 3
    \$\begingroup\$ Wow, that's clever. I guess the caveat is that you could never run it, since all the memory in the world couldn't hold the entire code. \$\endgroup\$ – Reto Koradi Sep 25 '15 at 15:33
  • 51
    \$\begingroup\$ That's a minor inconvenience. You can't put a price on nature. \$\endgroup\$ – Dennis Sep 25 '15 at 15:56
  • \$\begingroup\$ That's a nice trick, but it is invalid if can't be run \$\endgroup\$ – edc65 Sep 25 '15 at 18:02
  • 5
    \$\begingroup\$ @PyRulez : Not by anything unless it will be built out of something other than matter and occupy something other than space. \$\endgroup\$ – vsz Sep 25 '15 at 21:00
  • 5
    \$\begingroup\$ Why not just to use Lenguage? \$\endgroup\$ – jimmy23013 Sep 25 '15 at 22:08
40
\$\begingroup\$

Lenguage, 0


Output is in unary, since Lenguage/Brainfuck has no sane way of printing integers in base 10.

The actual source code contains

22360559967824444567791709913713659826044558304969374451791514225490473373040212332757409553558758107085015797320276213515502796255082717802632399123502087743818475438512153373406931103005017157351410347278489842099128517039634739852783737052963203448945756470632484148121769939122103257063633371522287190530269279693540898545359211009781370158317748609540216376596783541124510013448091325488601732964773653391702083563797082990404753843419895799343996435988722965711513708742853668363743953430527328863418281733901770990932025503662188187254784985474815936854540100376410040743052620419372327997519047616042603909398552951490180076364164838561112002025592431155898041427468731461614504254168899805662501979953318388813759833797929243626668399650485310047043700001093878284174322463350892654886806075148010832042248607926124030339950499631072150856939786062937034833055717723216663269161130154002679878012158315587925933383341827053312086716181702533743607685576475754259877651521989944802973721727159955208722180232955193930065862370838526521351991966172723976565264862909528310162816593997640732796289501819499741414526385058421824690665542546821941125191276568479078107133076037506211133628962099403163812267452274532219562823184225236020523509355625620557197876838014050964240952738109101849512504021041103516630358995290177306585560988278630098667702211916671663291473843258785929522017507744814910480115446168939335008597569919072874897148594826036210511162928991890818427747059833051607455121463371211282760364668765311589329918870071117807132901910082663054895226456039171170783440772764031568108965851688162729239711772886386306884508520204834432674839183166053019421652064937613583258148354531835035461504442885024563141848164279928769795684221364984104923764359842286827870778678989243517189772102669283996930513577004801536579491093711362942690905779844535371088542020595945700544234301668098553671685123172583259206072965508639556627967633275762621813851479909708616154198658896714629908456913467267354690109885368211752176196164620615081464122410029328694509842558492529684841818953632659248840216891072110853731776562597900145806210691868173380612838327841104919352821441230296200143603175486627682007399030356592930049570084097858148122367

null bytes and is equivalent to the following Brainfuck program:

,[<<+++++++++++++++++++++++++++++++++++++++++++++++++>>>>>>,]
>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<
<<<++++++++++++++++++++++++++++
[-<----<<<<----<<<<----<<<<---->>>>>>>>>>>>>]
<----<<<<---<<<<+++++++++++<<<<----
<<<<
[>>>>>>>>>>>>>>>>>>>>>>>>]
>>>>
[>>>>>>>>>>>>>>>>>>>>>>>>]
>>>>
[>>>>>>>>>>>>>>>>>>>>>>>>]
>>>>
[>>>>>>>>>>>>>>>>>>>>>>>>]
>>>>
[>>>>>>>>>>>>>>>>>>>>>>>>]
>>>>
[
 <<<<<<<<<<<<<<<<<<<<<<<<
 <<<++++++++++++++++++++++++++++
 [-<++++<<<<++++<<<<++++<<<<++++>>>>>>>>>>>>>]
 <++++<<<<+++<<<<-----------<<<<++++
 >>>>>>>>>>>>
 [
  -[<]<<[.<]
  >>>
  -[<]<<[.<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[.<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[.<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[.<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[......<]
  >>>
  -[<]<<[.<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[......<]
  >>>
  -[<]<<[..<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[......<]
  >>>
  -[<]<<[...<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[......<]
  >>>
  -[<]<<[....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[......<]
  >>>
  -[<]<<[.....<]
  >>>
  -[<]<<[......<]
  >>>
  -[<]<<[......<]
  >>>
  -[<]<<[.......<]
  <
 ]
]

Try it online on brainfuck.tk.

The length of the Brainfuck code is highly suboptimal – for starters, I've hardcoded the footprints of all ASCII characters – but score 0 is score 0...

\$\endgroup\$
  • \$\begingroup\$ No way, Lenguage actually supports null bytes?! \$\endgroup\$ – Beta Decay Sep 26 '15 at 6:07
  • 20
    \$\begingroup\$ I feel that answer like this one show no respect of the public: it's cheating, and gaming the system ... But this is the whole point of this challenge after all. +1 \$\endgroup\$ – edc65 Sep 26 '15 at 9:12
  • 1
    \$\begingroup\$ "Output is in unary, since Lenguage/Brainfuck has no sane way of printing integers in base 10.". I thought part of the point of Lenguage/Brainfuck was that it didn't have a sane way of doing anything :) \$\endgroup\$ – Adam Sep 28 '15 at 14:57
  • 9
    \$\begingroup\$ This didn't quite work for me when I tried to recreate your program from the definition you gave. Could you please post the full Lenguage source so that I can see where your program differs from my attempt at recreating it? ;-) \$\endgroup\$ – Cort Ammon Sep 29 '15 at 0:08
  • 1
    \$\begingroup\$ What amazes me isn't that Lenguage supports nulls, but that you managed to make such a program in BF. Haunting... \$\endgroup\$ – Erik the Outgolfer Jan 13 '17 at 13:59
12
\$\begingroup\$

PowerShell, 337 344 304 points

PARAM([CHAR[]]$A)$A|%{$B+=([CONVERT]::TOSTRING(+$_,2)-REPLACE0).LENGTH};($B,0)[-JOIN$A-CEQ"test"]

I'M SHOUTING AT YOU BECAUSE IT'S CHEAPER!

Takes input as $A, then casts as a char-array, then iterates over a for-loop on each character, uses the ridiculously wordy [convert]::ToString() to convert the character at that position to binary, replaces all the 0's with nothing, then counts the length, and adds that to $B. At the end, uses an equivalence to index into a dynamic array (i.e., if $A is test, then -CEQ is $TRUE, so it indexes to the second element, 0).

Edit1 -- Corrected test case "TEST"
Edit2 -- Golfed a couple points by iterating over the characters themselves rather than their indices, and by remembering that -replace doesn't need a second parameter if you're replacing it with nothing.

\$\endgroup\$
  • \$\begingroup\$ Double quote " 00100010 is more environmentally friendly than single quote ' 00100111. \$\endgroup\$ – Jacob Krall Sep 25 '15 at 17:23
  • \$\begingroup\$ Returns incorrect value 0 for input "TEST" \$\endgroup\$ – Jacob Krall Sep 25 '15 at 17:27
  • 1
    \$\begingroup\$ @JacobKrall Good catch on the double-quote ". Also corrected with -CEQ for case-sensitivity. It upped the points a little bit, because I was incorrectly scoring the ' ' as I didn't delimit it correctly on my tests. \$\endgroup\$ – AdmBorkBork Sep 25 '15 at 18:23
9
\$\begingroup\$

Pyth - 52 49

Three points save thanks to @orlp.

*/.BQ`1nQ"test

Takes input in quotes to save footprint.

Test Suite.

\$\endgroup\$
  • \$\begingroup\$ Ugh, I almost got the same as you, but my answer is too similar and you posted first. Replace @,0 with * to save 3 :) \$\endgroup\$ – orlp Sep 25 '15 at 13:19
  • 1
    \$\begingroup\$ @Maltysen You say that you found three points but the source still says @,0, did you just forget to change? \$\endgroup\$ – clap Sep 26 '15 at 4:55
  • \$\begingroup\$ @ConfusedMr_C yep. I just changed the permalink and forgot the actual answer. \$\endgroup\$ – Maltysen Sep 27 '15 at 15:01
7
\$\begingroup\$

Common Lisp, 294 281 235

In order to reduce the score, I used @ (cost 1) and ! (cost 2) as variable names (edit: and it is even better if I use @ for the variable occuring the most in the function). I AM SHOUTING TOO because it is cheaper.

(LAMBDA(@)(IF(STRING="test"@)0(LOOP FOR ! ACROSS @ SUM(LOGCOUNT(CHAR-CODE !)))))

Pretty-printed

(LAMBDA (@)
  (IF (STRING= "test" @) 0
      (LOOP FOR ! ACROSS @ SUM (LOGCOUNT (CHAR-CODE !)))))
\$\endgroup\$
  • \$\begingroup\$ Well the score is more like 294 ;) \$\endgroup\$ – Cabbie407 Sep 25 '15 at 12:39
  • \$\begingroup\$ @Cabbie407 I missed the part about scoring, sorry :-) \$\endgroup\$ – coredump Sep 25 '15 at 12:40
  • 1
    \$\begingroup\$ @Cabbie407 I had the strange feeling of having a very low score for a couple of minutes... \$\endgroup\$ – coredump Sep 25 '15 at 12:42
  • 1
    \$\begingroup\$ Just wanted to let you know, because knowing about the scoring method you'd probably look at your code from a different angle. And I see you changed something already. \$\endgroup\$ – Cabbie407 Sep 25 '15 at 13:05
  • 1
    \$\begingroup\$ @Cabbie407 I forgot to thank you, btw. Thanks. \$\endgroup\$ – coredump Sep 25 '15 at 13:12
6
\$\begingroup\$

JavaScript, 279

Edit Bug fix (did not count bit 1 of each char)

A complete program, with input and output via popup. Tested in Firefox, should work in any modern browser.

B=(P=prompt)(H=D=0)
while(B!="test"&&(A=B.charCodeAt(H++)))while(A)D+=A&1,A>>=1
P(D)

Some tools (Tested with Firefox)

w=c=>c.toString(2).split('').reduce(function(a,b){return a- -b})

t=[[],[],[],[],[],[],[],[],[]]
u=[[],[],[],[],[],[],[],[],[]]
for(c=1;c<256;c++)
  c<33|c>126&c<161 ? t[w(c)].push('\\'+c) : u[w(c)].push('&#'+c+';')
for(i=0; i++<8;)       
  T.innerHTML+=i+': '+u[i].concat(t[i]).join(' ')+'\n'

function Calc()
{
  var r='', t=0, b
  I.value.split('').forEach(function(c) {
    c = c.charCodeAt(), r += '\n&#'+c+' '+((256+c).toString(2).slice(1))+' : '
    for(b=0;c;c>>=1) b += c&1
    r += b, t += b
  })
  R.innerHTML='Total '+t+'\nDetail'+r
}
#I { width: 400px }
<b>Weight table</b><pre id=T></pre><br>
<b>Counter</b><br><textarea id=I></textarea><button onclick="Calc()">-></button> <pre id=R></pre>

\$\endgroup\$
  • 1
    \$\begingroup\$ This answer is invalid - it outputs 17 for test instead of 0. \$\endgroup\$ – ASCIIThenANSI Sep 25 '15 at 15:57
  • \$\begingroup\$ @ASCIIThenANSI not it doesn't in my browser. But I'm going to check again \$\endgroup\$ – edc65 Sep 25 '15 at 16:56
  • \$\begingroup\$ That's funny... Testing it with your counter, I get 279, and testing it with itself, I get 277. I wonder which is correct; could it have something to do with the newlines? \$\endgroup\$ – ETHproductions Sep 25 '15 at 20:57
  • \$\begingroup\$ @ETHproductions I double checked and the right count is 279. But it does not work with a string containing a newline - it's a problem related to the prompt function. In Firefox, prompt translates the newlines (2bit) in spaces (1bit), so we get 277 instead of 279 \$\endgroup\$ – edc65 Sep 26 '15 at 1:45
  • \$\begingroup\$ @ETHproductions ... in Chrome (on Windows) the newline becomes a CR LF pair (3bit + 2bit) and the count is wrong again \$\endgroup\$ – edc65 Sep 26 '15 at 1:49
6
\$\begingroup\$

Julia, 254 246 232

P=readline()
print(P=="test"?0:sum([count_ones(1*A)for A=P]))

The count_ones function counts the number of ones in the binary representation of its input.

Reduced my ecological footprint thanks to FryAmTheEggman!

\$\endgroup\$
  • 1
    \$\begingroup\$ No problem, I just really care about the environment ;) \$\endgroup\$ – FryAmTheEggman Sep 25 '15 at 16:28
6
\$\begingroup\$

Python 3, 271

z=input();print([sum([bin(ord(i)).count("1")for i in z]),0][z=="test"])
\$\endgroup\$
  • 3
    \$\begingroup\$ A lot of little changes gives me 228 \$\endgroup\$ – FryAmTheEggman Sep 25 '15 at 13:40
  • 2
    \$\begingroup\$ Why not take advantage that bools are ints? z=input();print(sum(bin(ord(i)).count("1")for i in z)*(z!="test")) ....@FryAmTheEggman jinx? \$\endgroup\$ – NightShadeQueen Sep 25 '15 at 13:40
  • 1
    \$\begingroup\$ @NightShadeQueen Haha, does that mean I can't post for a day? :X Anyway that's a very nice catch for a new user to this site, nice job! Anyway, welcome to PPCG! :) Also, more on-topic, the semicolon could be removed as it costs slightly more than a newline. \$\endgroup\$ – FryAmTheEggman Sep 25 '15 at 16:32
5
\$\begingroup\$

Perl, 136 118 73

$_=unpack"B*";$_=y@1@@

Replace all @ with \0

Usage example:

perl -p entry.pl entry.pl
\$\endgroup\$
5
\$\begingroup\$

MATLAB, 198 194 bytes

A=input('','s');~strcmp('test',A)*nnz(dec2bin(A)-48)

First, the string is read in from STDIN via the input function. Once this happens, we compare the input string to the string test. If the result isn't test, we convert each character to its ASCII code and then its binary representation via dec2bin. A beautiful consequence of this function is that if you submit a string, the binary representation of its ASCII code is delimited as one character per line.

As an example:

>> dec2bin('ABCD')

ans =

1000001
1000010
1000011
1000100

dec2bin outputs a character array. Once this happens, subtract by 48, which is the ASCII code for 0 so that the matrix gets converted to double consisting of 0s and 1s. Once that happens, a call to nnz counts up the total number of non-zero elements in this matrix. Take note that this result is multiplied by the opposite of the string compare with test. Should the string not be test, we get the footprint calculation. If it's equal, then the multiplication results in 0.

Some examples:

>> A=input('','s');~strcmp('test',A)*nnz(dec2bin(A)-48)
A

ans =

     2

>> A=input('','s');~strcmp('test',A)*nnz(dec2bin(A)-48)
O

ans =

     5

>> A=input('','s');~strcmp('test',A)*nnz(dec2bin(A)-48)
test

ans =

     0


>> A=input('','s');~strcmp('test',A)*nnz(dec2bin(A)-48)
  %// Note - no characters were added here.  Simply pushed Enter

ans =

     0
\$\endgroup\$
  • \$\begingroup\$ If you're allowed to use Communications Toolbox, you can use de2bi instead and avoid the -48 to cast it to a numeric type (as well as the 2 extra characters in the function name). \$\endgroup\$ – beaker Sep 25 '15 at 21:15
5
\$\begingroup\$

Bash 440 430 412 405 403

A=0
[ test != "$1" ]&&for((D=0;D<${#1};D++)){
A=$((A+`bc<<<$(printf "obase=2;%d" "'${1:$D:1}")|tr -d "0
"|wc -m`))
}
echo $A

Pretty straightforward. Loops characters in the input converting first to ascii (with printf %d and the leading ' on the number then to binary (with bc), strips out the zeros and counts the number of characters.

Not a great answer but hadn't seen a bash attempt yet.

Modified since my first answer allowed the input string to be given simply on the command line (i.e. it became multiple input params if multipe words) but after reading some other answers I think I can assume it is quoted, so the whole string comes as $1

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to Programming Puzzles & Code Golf! 1. You can replace do with { and done with }. 2. You also don't need the spaces around <<<. 3. You can replace \n with a literal linefeed. \$\endgroup\$ – Dennis Sep 27 '15 at 15:37
  • \$\begingroup\$ THanks @Dennis. One of the challenges on this site is unlearning a bunch of "good habits" :). \$\endgroup\$ – Adam Sep 27 '15 at 15:42
  • 3
    \$\begingroup\$ It sure is. If you haven't already, I recommend checking out Tips for golfing in Bash. It's a great resource. \$\endgroup\$ – Dennis Sep 27 '15 at 15:44
  • 3
    \$\begingroup\$ This challenge is weird even by golf standards! Extra characters can still save points. Using = and || costs 15 whereas using != and && is only 13! An extra character but saves two points... \$\endgroup\$ – Adam Sep 27 '15 at 18:30
5
\$\begingroup\$

Ceylon, 1431, 764, 697, 571, 547, 538, 501, 493, 467, 451

shared void p(){print(sum{0,if(exists a=process.arguments[0])if(a!="test")for(c in a)for(b in 0..7)if(c.hash.get(b))1});}

This was the original, ungolfed:

Integer footprintCharacter(Integer b) {
    return sum({0, for(i in 0..7) if(b.get(i)) 1 });
}
Integer footPrintString(String s) {
    if(s == "test") {return 0;}
    return sum({0, for(c in s) footprintCharacter(c.integer)});
}
shared void footprint() {
     if(exists s = process.arguments[0]) {
         print(footPrintString(s));
     } else {
         print("This program needs at least one parameter!");
     }
}

This takes the argument from a command line parameter ... process.arguments is an (possibly empty) sequence of strings, so before using one of them, we need to check if it actually exists. In the other case we output an error message (this is not required by the question and will be thrown away in the next versions).

Ceylon's sum function takes a non-empty Iterable of elements of some type which needs to satisfy Summable, i.e. has a plus method, like Integer. (It doesn't work with empty sequences because each Summable type will have its own zero, and the runtime has no chance to know which one is meant.)

The elements of a string, or the one bits of an integer, are not a non-empty iterable. Therefore we are using here the feature to build an iterable by specifying some elements, then a "comprehension" (which will get evaluated to zero or more elements). So in the character case we are adding ones (but only when the corresponding bit is set), in the string case we are adding the result of the characters. (The comprehension will only be evaluated when the receiving function actually iterates over it, not when building the Iterable.)

Let's see how we can shrink this down. First, each of the functions is only called at one place, so we can inline them. Also, as mentioned above, get rid of the error message. (764 footprint points.)

shared void footprint() {
    if (exists s = process.arguments[0]) {
        if (s == "test") {
            print(0);
        } else {
            print(sum({ 0, for (c in s) sum({ 0, for (i in 0..7) if (c.integer.get(i)) 1 }) }));
        }
    }
}

We don't actually need the inner nested sum, we can make this one big comprehension. (This saves us 37 footprint points for sum({0,}), and some more for whitespace, which will be eliminated at the end anyways.) This is 697:

shared void footprint() {
    if (exists s = process.arguments[0]) {
        if (s == "test") {
            print(0);
        } else {
            print(sum({ 0, for (c in s) for (i in 0..7) if (c.integer.get(i)) 1 }));
        }
    }
}

We can apply a similar principle to the special cased "test" string: as in that case the result is 0 (i.e. nothing is contributed to the sum), we can just do this as a part of the summation (but we have to invert the condition). This mainly saves us the print(0);, some braces and a bunch of indentation spaces, coming down to a footprint of 571:

shared void footprint() {
    if (exists s = process.arguments[0]) {
        print(sum({ 0, if (s != "test") for (c in s) for (i in 0..7) if (c.integer.get(i)) 1 }));
    }
}

We do the same for the first if, with the side effect that now giving no argument also outputs 0 instead of doing nothing. (At least I thought that would happen here, instead it seems to hang with an eternal loop? Strange.)

shared void footprint() {
    print(sum({ 0, if (exists s = process.arguments[0]) if (s != "test") for (c in s) for (i in 0..7) if (c.integer.get(i)) 1 }));
}

We can actually omit the () for the sum function here, using an alternative function call syntax, which uses {...} instead of (), and will fill in comprehensions into iterable arguments. This has footprint 538:

shared void footprint() {
    print(sum{ 0, if (exists s = process.arguments[0]) if (s != "test") for (c in s) for (i in 0..7) if (c.integer.get(i)) 1 });
}

Replacing the function name footprint (40) by p (3) saves another 37 points, bringing us to 501. (Ceylon function names have to start with lower case characters, so we can't get less than 3 points here.)

shared void p() {
    print(sum{ 0, if (exists s = process.arguments[0]) if (s != "test") for (c in s) for (i in 0..7) if (c.integer.get(i)) 1 });
}

The variable names s (5) and c (4), i (4) are also not optimal. Let's replace them by a (argument), d (digit?) and b (bit-index). Footprint 493:

shared void p() {
    print(sum{ 0, if (exists a = process.arguments[0]) if (a != "test") for (c in a) for (b in 0..7) if (c.integer.get(b)) 1 });
}

I don't see any remaining non-whitespace optimization, so let's remove the non-needed whitespace (1 point for each space, two for each of the two line breaks):

shared void p(){print(sum{0,if(exists a=process.arguments[0])if(a!="test")for(c in a)for(b in 0..7)if(c.integer.get(b))1});}

When browsing the API, I found that Character.hash actually returns the same value as its integer attribute. But it has just 14 points instead of 30, so we come down to 451!

shared void p(){print(sum{0,if(exists a=process.arguments[0])if(a!="test")for(c in a)for(b in 0..7)if(c.hash.get(b))1});}
\$\endgroup\$
4
\$\begingroup\$

PowerShell, 273 336 328 324 293 288 295

PARAM($A)[CHAR[]]$A|%{$D=[INT]$_;WHILE($D){$B+=$D-BAND0X1;$D=$D-SHR1}};($B,0)[$A-CEQ"test"]

edit - forgot the 'test' case ... so much expensive.

editedit - missed an UPPERCASE opportunity.

editeditedit - incorporated the comment suggestions (Thanks TimmyD).

edit 4 - D is a cheaper varable than C (2 vs. 3)

edit 5 - Back to 295 due to the case-sensitivity check.

Loops over the string and counts the 1s which get shifted off the characters ASCII value.

Hat-tip to TimmyD for giving me the foresight to use uppercase characters AND to use the array index at the end.

\$\endgroup\$
  • 1
    \$\begingroup\$ Nice approach! A couple of golfs (removed the $B initialization, as it will default to zero, removed a couple parens, removed some semicolons), brings it down to 293 PARAM($A)[CHAR[]]$A|%{$C=[INT]$_;WHILE($C){$B+=$C-BAND0X1;$C=$C-SHR1}};($B,0)[$A-EQ"TEST"] \$\endgroup\$ – AdmBorkBork Sep 25 '15 at 16:52
  • \$\begingroup\$ What does it mean when I read "Nice approach!" and heard the voice from Wii Golf? Thanks for the pointers! The initialization was tripping me up when testing it in the PowerShell console and I left it in. Good to know otherwise. \$\endgroup\$ – Forty3 Sep 25 '15 at 16:55
  • \$\begingroup\$ Yeah - if you're using the console, it's pretty much a REPL environment, in that variables assigned remain from one line to the next. If you save it as a .ps1, then the $B (and every other variable) is re-initialized, even if you press up-arrow-enter from the same shell. E.g., PS C:\scripts> .\ecological-footprint.ps1 \$\endgroup\$ – AdmBorkBork Sep 25 '15 at 17:01
  • \$\begingroup\$ Returns incorrect value 0 for input "TEST" \$\endgroup\$ – Jacob Krall Sep 25 '15 at 17:29
  • 1
    \$\begingroup\$ 281 PARAM($A)(([CHAR[]]$A|%{$B=$_;0..9|?{[INT]$B-SHR$_-BAND1}}).LENGTH,0)[("TEST"-EQ$A)] \$\endgroup\$ – tomkandy Sep 25 '15 at 17:46
4
\$\begingroup\$

Matlab, 320

A=(input('','s'));nnz(floor(rem(bsxfun(@times,[A 0],2.^(-7:0)'),2)))*~strcmp(A,'test')
\$\endgroup\$
4
\$\begingroup\$

C,374

Newlines (not included in score) added for clarity. Could be improved to 360 just by changing variable names to uppercase, but I'll try to think of something better.

Input is via commandline, which means it segfaults on absent input. I expect a worse score for input through stdin.

i,t;
main(int c,char**v){
for(;c=v[i][i/8];i++)t+=(c>>i%8)&1;
printf("%d",strcmp(v[1],"test")?t:0);
}
\$\endgroup\$
4
\$\begingroup\$

PHP, 377 337 299 Ecological Footprint (still a lot), 102 91 Bytes

Seems that PHP is environment friendly in test-mode only. ;)

WHILE($D<STRLEN($A=$argv[1]))$B+=SUBSTR_COUNT(DECBIN(ORD($A[$D++])),1);ECHO"test"!=$A?$B:0;

Runs from command line like:

php footprint.php hello
php footprint.php test

while is more environment friendly than for even though they share the same character count. Also uppercase variable names have a better footprint than their lowercase counterparts.

Edit

  • saved 40 points by using uppercase function names.
  • saved 38 points by using decbin instead of base_convert
\$\endgroup\$
4
\$\begingroup\$

VBA, 475 418

Thanks Jacob for 57 points off

  • Converts String to Byte Array (128 is vba shortcut for "Converts the string from Unicode to the default code page of the system" So won't work on Mac....)

  • Loops though byte array converting to Binary and Concatenating everything together.

  • checks for test
  • Prints length of string with all the 0's replaced with nothing

VBA why are you so bad at golfing... :(

SUB A(D)
DIM B() AS BYTE
B=STRCONV(D,128)
FOR P=0 TO UBOUND(B)
H=H+APPLICATION.DEC2BIN(B(P))
NEXT
IF D="test" THEN H=0
MSGBOX LEN(REPLACE(H,0,""))
ENDSUB
\$\endgroup\$
  • 4
    \$\begingroup\$ VBA is case-insensitive, so you should use use uppercase everywhere to save a point per lowercase character! (except "test" of course) \$\endgroup\$ – Jacob Krall Sep 25 '15 at 16:40
4
\$\begingroup\$

JavaScript, 418 410

A=prompt();B=0;!A||A=="test"?0:A.split("").forEach(D=>B+=D.charCodeAt().toString(2).match(/1/g).length);alert(B)
\$\endgroup\$
  • \$\begingroup\$ Double quote " 00100010 is more environmentally friendly than single quote ' 00100111. \$\endgroup\$ – Jacob Krall Sep 25 '15 at 17:21
3
\$\begingroup\$

Pyth, 64

?qz"test"0l`sS.Bz

Checks if the input is test and if not, counts the number of 1's in the binary representation of the input.

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

Haskell, 292

a 0=0
a b=rem b 2+a(div b 2)
b"test"=0
b d=sum$map(a.fromEnum)d
main=interact$show.b

Nothing much to say here: turn every character into ascii value (fromEnum) and calculate the 1s (via a). Sum all the results.

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

JavaScript (ES6), 521 478 458 449 473 465

alert(((A=prompt(),A!="test")&&(A!=""))?(A.split``.map(H=>(H.charCodeAt().toString(2).match(/1/g)||[]).length)).reduce((A,B)=>A+B):0)

This is my first attempt at a JavaScript golf, so it's probably very ungolfed.

\$\endgroup\$
  • \$\begingroup\$ It's generally agreed on that JavaScript golf needs some form of output other than implicit. This can be an alert, document.write, or even a function return. \$\endgroup\$ – Mwr247 Sep 25 '15 at 14:11
  • \$\begingroup\$ You can move your prompt assignment into the first 's' in the if statement, surrounded by parenthesis, to save a couple bytes. You can also remove the '0' in charCodeAt. Also, a big savings you can make is using the ternary operator instead of the if/else statements =) \$\endgroup\$ – Mwr247 Sep 25 '15 at 14:12
  • \$\begingroup\$ Thanks a lot! I ended up using a comma instead of parenthese for the prompt assignment, though; it saves another byte. (: @Mwr247 \$\endgroup\$ – Zach Gates Sep 25 '15 at 14:33
  • \$\begingroup\$ s.split('') can instead be s.split``, saving 2 bytes \$\endgroup\$ – Dendrobium Sep 25 '15 at 15:58
  • 1
    \$\begingroup\$ Per Dendrobium's comment above @JacobKrall \$\endgroup\$ – Zach Gates Sep 25 '15 at 16:26
3
\$\begingroup\$

Ruby, 316 313

Very straightforward, looking for some more golfing possibilities:

b=gets.chomp;b=='test'?0:b.chars.map{|i|i.ord.to_s(2).count('1')}.inject(:+)
  • Used b instead of x to save 3 points.
\$\endgroup\$
  • \$\begingroup\$ You can use $*[0] instead of gets.chomp (takes input as a command line argument) \$\endgroup\$ – Mhmd Sep 25 '15 at 15:01
  • \$\begingroup\$ Double quote " 00100010 is more environmentally friendly than single quote ' 00100111. \$\endgroup\$ – Jacob Krall Sep 25 '15 at 17:21
  • \$\begingroup\$ Uppercase variable names are also more environmentally friendly than the equivalent lowercase. H is better than I for the same reason. \$\endgroup\$ – Jacob Krall Sep 25 '15 at 17:22
3
\$\begingroup\$

Python 2, 294 281 269 266

A=input()
print sum(format(ord(H),"b").count("1")for H in A)if A!="test"else 0

A port of my Pyth answer, above.

Input is received as a string (with quotes):

"ABC"
\$\endgroup\$
  • 1
    \$\begingroup\$ Double quote " 00100010 is more environmentally friendly than single quote ' 00100111. \$\endgroup\$ – Jacob Krall Sep 25 '15 at 17:20
  • \$\begingroup\$ A couple basic modifications get this down to A=input();print[sum(bin(ord(H)).count("1")for H in A),0][A=="test"] with a score of 243. \$\endgroup\$ – Kade Sep 25 '15 at 20:49
2
\$\begingroup\$

CJam, 123

q_"test"={;0}{{s2b2b~}%1e=}?
\$\endgroup\$
2
\$\begingroup\$

Pyth, 96

Iqz"test"0.q)/j""m.BdmCdz\1

A port of my CJam answer, above/below.

\$\endgroup\$
  • \$\begingroup\$ Just some Pyth general notes: instead of I try to use the ternary ?, but in this case since it is a bool you can just use * (after switching to n instead of q), k is automatically "" and s on strings is the same a jk. Hope you have fun learning pyth! :) \$\endgroup\$ – FryAmTheEggman Sep 25 '15 at 16:35
  • \$\begingroup\$ This was my first Pyth answer :P It was hard enough to get this, haha, fun though. Thanks for the tips! @FryAmTheEggman \$\endgroup\$ – Zach Gates Sep 25 '15 at 16:36
2
\$\begingroup\$

CJam, 83 81 79 77

Best so far after trying a number of variations:

l0$"test"=!\:i2fbe_1b*

Try it online

Explanation:

l       Get input. Other options like q and r are the same number of bits.
0$      Copy input for comparison. This saves 2 bits over _.
"test"  Push special case string.
=       Compare.
!       Negate so that we have 0 for special case, 1 for normal case.
\       Swap input string to top.
:i      Convert characters to integers.
2fb     Apply conversion to base 2 to all values.
e_      Flatten array.
1b      Sum up the bits. This is 2 bits shorter than :+.
*       Multiply with result from special case test.
\$\endgroup\$
2
\$\begingroup\$

Ruby, 247

Straightforward approach looping through all bytes of the input and all bits in each byte, summing to variable d.

d is initialized to -2 because h contains the terminating newline from the input (worth 2 bits) and we do not want to count that.

Similarly h will contain test with a trailing newline, so a newline must included in the comparison value.

d=-2
h=gets
h.bytes{|a|8.times{|b|d+=a>>b&1}}
p h=='test
'?0:d
\$\endgroup\$
2
\$\begingroup\$

R, 279

sum(as.integer(rawToBits(charToRaw(if((s=readline())=='test')''else s))))

Pretty self explanatory.
Tests:

> sum(as.integer(rawToBits(charToRaw(if((s=readline())=='test')''else s))))
sum(as.integer(rawToBits(charToRaw(if((s=readline())=='test')''else s))))
[1] 279
> sum(as.integer(rawToBits(charToRaw(if((s=readline())=='test')''else s))))
A
[1] 2
> sum(as.integer(rawToBits(charToRaw(if((s=readline())=='test')''else s))))
O
[1] 5
> sum(as.integer(rawToBits(charToRaw(if((s=readline())=='test')''else s))))
test
[1] 0
> sum(as.integer(rawToBits(charToRaw(if((s=readline())=='test')''else s))))
OAO
[1] 12
\$\endgroup\$
2
\$\begingroup\$

C, 378 footprint, 98 bytes

Another C solution:

s;main(c,a)char**a;{for(s=-17*!strcmp(a[1],"test");c=*a[1]++;)for(;c;s+=c&1,c/=2);printf("%d",s);}

The way this works is that s is initialized to 0 usually, but becomes -17 if the command-line argument is "test" (strcmp returns 0 on equal strings, and non-zero on distinct strings, so inverting it gives 1 if string is "test"). The number -17 was chosen to compensate for the footprint of 17 that will be calculated for "test". The computation of the footprint is easy with bitwise operators.

Snap! I initially missed the "shortest footprint wins" so I was aiming for shortest code... I'll see if I can make the "footprint" smaller.

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

Java, 594

class A{public static void main(String[]P){Integer D,H;for(D=H=0;D<P[0].length();)H+=D.bitCount(P[0].charAt(D++));System.out.print(P[0].equals("test")?0:H);}}

Java is not very green.

Ungolfed version:

class A {
    public static void main(String[]P) {
        Integer D,H;
        for(D=H=0;D<P[0].length();)
            H+=D.bitCount(P[0].charAt(D++));
        System.out.print(P[0].equals("test")?0:H);
    }
}

D is declared as an Integer so we can access Integer's static bitCount method in an environmentally conscientious manner. The bitCount method treats the chars as integers and returns the number of set bits.

\$\endgroup\$
  • 1
    \$\begingroup\$ Interesting comparing Java with Ceylon ... Java has some overhead due to the boilerplate, and a longer print statement. The bitCount does help, though, Ceylon doesn't have this. Ceylon has a longer way to access to the command line parameters, and also needs to check if they are actually given (where your program would simply throw an ArrayIndexOutOfBoundsException). Ceylon's sum function is certainly shorter than adding it manually in Ceylon (but Java has no comprehensions, so adding manually is better than building an Iterable yourself). \$\endgroup\$ – Paŭlo Ebermann Sep 28 '15 at 11:20

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.