11
\$\begingroup\$

The challenge is simple

Write a script that, when given a string input, will hash the string using the MD2 hashing algorithm, and then return either a positive integer or negative integer output based on which character set below is more common in the resulting hash as a hexadecimal string:

01234567 - (positive)
89abcdef - (negative)
  • The input will always be a string, but may be of any length up to 65535
  • The entire input, whitespace and all, must be hashed
  • For the purposes of this challenge, the integer 0 is considered neither positive nor negative (see tie output)
  • The more common set is the one who's characters are more common within the 32 character hexadecimal hash string
  • Your output may contain trailing whitespace of any kind, as long as the only non-whitespace characters are a valid truthy or falsey output
  • In the event of a tie, where the hexadecimal string contains exactly 16 characters from each set, the program should output a 0

I/O Examples

Input: "" (Empty String)
Hash: 8350e5a3e24c153df2275c9f80692773
Output: 1

Input: "The quick brown fox jumps over the lazy cog" (Without quotes)
Hash: 6b890c9292668cdbbfda00a4ebf31f05
Output: -1

Input: "m" (Without quotes)
Hash: f720d455eab8b92f03ddc7868a934417
Output: 0

Winning Criterion

This is , fewest bytes wins!

\$\endgroup\$
  • 1
    \$\begingroup\$ It would be good to link to or ideally explain the MD2 hashing algorithm in the challenge specification to make it self contained. \$\endgroup\$ – Martin Ender Apr 19 '17 at 15:28
  • \$\begingroup\$ @MartinEnder Will do! \$\endgroup\$ – Skidsdev Apr 19 '17 at 15:29
  • \$\begingroup\$ I think it would be fair to simply accept three distinct values for win, lose, and tie \$\endgroup\$ – math junkie Apr 19 '17 at 15:45
  • \$\begingroup\$ @mathjunkie true, probably shouldn't be changing the spec so much, but I guess just having 1, 0 or -1 is the best way \$\endgroup\$ – Skidsdev Apr 19 '17 at 15:47
  • 2
    \$\begingroup\$ This strikes me as a chameleon challenge. Either your language has a build-in or library to do MD2 and the rest is simple character counting, or it doesn't and you have to implement it yourself. \$\endgroup\$ – xnor Apr 20 '17 at 0:20
1
\$\begingroup\$

Octave, 35 bytes

@(s)diff(hist(hash('md2',s),+'78'))

*Requires the latest version of Octave (at least 4.2).

Computes histcounts of the hash string with it's center of bins are 7 and 8 then computes the difference of counts.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Given it's been a few days I'll put yours up as the winning answer, if somebody comes along later with a shorter solution I can always change it. Well done! \$\endgroup\$ – Skidsdev Apr 21 '17 at 13:02
  • \$\begingroup\$ @Mayube Thanks! \$\endgroup\$ – rahnema1 Apr 21 '17 at 16:35
8
\$\begingroup\$

Mathematica, 43 bytes

Tr@Sign[15-2#~Hash~"MD2"~IntegerDigits~16]&

Outputs the number of digits in 01234567 minus the number of digits in 89abcdef.

|improve this answer|||||
\$\endgroup\$
  • 1
    \$\begingroup\$ Too bad that 3E is between 8 and 9 and not between 7 and 8. :| \$\endgroup\$ – Martin Ender Apr 19 '17 at 15:54
8
\$\begingroup\$

JavaScript (ES6), 731 bytes

This monster is implementing the MD2 algorithm, so it's embarrassingly long. Based on js-md2 by Chen Yi-Cyuan.

let f =

m=>{L=x=s=b=0,n=m.length,M=[],X=[],C=[],S=[...atob`KS5DyaLYfAE9NlSh7PAGE2KnBfPAx3OMmJMr2bxMgsoem1c8/dTgFmdCbxiKF+USvk7E1tqe3kmg+/WOuy/ueqloeZEVsgc/lMIQiQsiXyGAf12aWpAyJzU+zOe/95cD/xkws0iltdHXXpIqrFaqxk+4ONKWpH22dvxr4px0BPFFnXBZZHGHIIZbz2XmLagCG2Alra6wufYcRmFpNEB+D1VHoyPdUa86w1z5zrrF6iYsUw1uhSiECdPfzfRBgU1Satw3yGzBq/ok4XsIDL2xSniIlYvjY+ht6cvV/jsAHTny77cOZljQ5KZ3cvjrdUsKMURQtI/tHxrbmY0znxGDFA`].map(c=>c[O='charCodeAt']());for(l=1;l-2;){for(j=19;j--;)M[j]=M[16+j]||0;for(i=s;i<16;x++)L=(x-n||(b+=i-s,s=i-16,l=2),C[i]^=S[(M[i++]=x<n?m[O](x):16-(b&15))^L]);for(i=0;i<l;i++){for(j=16;j--;)X[32+j]=(X[16+j]=(i?C:M)[j])^X[j];for(t=j=0;j<18;t=t+j++&255)for(k=0;k<48;)t=X[k++]^=S[t]}}for(i=16,n=-i;i--;)n+=!(X[i]&8)+!(X[i]&128);return n}

console.log(f(''))
console.log(f('The quick brown fox jumps over the lazy cog'))
console.log(f('m'))

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Beat me to it. Really nice effort. \$\endgroup\$ – Luke Apr 20 '17 at 6:13
  • \$\begingroup\$ Props for, thus far, being the only one to actually implement the full MD2 algorithm rather than using built-in functions. \$\endgroup\$ – Skidsdev Apr 20 '17 at 9:50
  • \$\begingroup\$ Highest byte answer deserving of more points. \$\endgroup\$ – Magic Octopus Urn Apr 20 '17 at 13:51
5
\$\begingroup\$

Python 2 + Crypto, 108 99 93 91 87 78 bytes

Python doesn't have a native builtin for MD2.

from Crypto.Hash import*
lambda s:sum(x<'8'for x in MD2.new(s).hexdigest())-16

Saved 12 bytes thanks to @ovs.
Saved 9 bytes thanks to @FelipeNardiBatista.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ lambda s:cmp(sum((int(x,16)<8)-.5for x in MD2.new(s).hexdigest()),0) should reduce the byte count to 93 \$\endgroup\$ – ovs Apr 19 '17 at 17:45
  • \$\begingroup\$ @ovs Very clever! \$\endgroup\$ – mbomb007 Apr 19 '17 at 20:08
  • \$\begingroup\$ sum(x<'8'for x ...... \$\endgroup\$ – Felipe Nardi Batista Apr 20 '17 at 12:35
  • \$\begingroup\$ lambda s:sum(x<'8'for x in MD2.new(s).hexdigest())-16 for 78. the output can be any number, not just -1,0,1 \$\endgroup\$ – Felipe Nardi Batista Apr 20 '17 at 12:45
4
\$\begingroup\$

Java 8, 173 bytes

-4 thanks to dzaima

-128 thanks to Oliver, this is basically his answer now.

a->{String h="";for(byte b:java.security.MessageDigest.getInstance("MD2").digest(a.ge‌​tBytes()))h+=h.forma‌​t("%02x",b);return h.codePoints().filter(c->c>47&&c<56).count()-16;}

Positive for truthy. Negative for falsy. 0 for 0.

|improve this answer|||||
\$\endgroup\$
  • 1
    \$\begingroup\$ You can save 4 bytes by removing the enclosing brackets of for and if \$\endgroup\$ – dzaima Apr 19 '17 at 16:48
  • 1
    \$\begingroup\$ bytes to hex can be golfed: String s="";for(byte b:bytes)h+=h.format("%02x",b);. Also, you don't need to write a full program, but a lambda suffice: a->{... return x;}. Finally the for loop can be replaced by int x=s.codePoints().filter(c->c>47&&c<56).count();. All in all, I get 173 for your algorithm, golfed: a->{String h="";for(byte b:java.security.MessageDigest.getInstance("MD2").digest(a.getBytes()))h+=h.format("%02x",b);return h.codePoints().filter(c->c>47&&c<56).count()-16;}. More golfing is possible, but this is a net improvement in byte count, isn't it? \$\endgroup\$ – Olivier Grégoire Apr 20 '17 at 8:16
  • \$\begingroup\$ Some things to golf: println -> print and for(char c:s.toCharArray())if("01234567".contains(""+c))x++; -> for(String c:s.split(""))if("01234567".contains(c))x++; \$\endgroup\$ – Kevin Cruijssen Apr 20 '17 at 11:25
  • \$\begingroup\$ @OlivierGrégoire I don't know much about Java 8, I switched to Groovy/Grails around the same time. \$\endgroup\$ – Magic Octopus Urn Apr 20 '17 at 13:50
3
\$\begingroup\$

PHP, 50 Bytes

prints 1 for truthy and -1 for false and 0 for a tie

<?=preg_match_all("#[0-7]#",hash(md2,$argn))<=>16;

PHP, 58 Bytes

prints 1 for truthy and -1 for false and 0 for a tie

<?=16<=>strlen(preg_filter("#[0-7]#","",hash(md2,$argn)));
|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Sorry for all the spec changes, final output requirements are in now. Basically what you currently have but reversed (1 for truthy, -1 for falsey) which should be fairly easy as iirc in PHP -0 === 0 \$\endgroup\$ – Skidsdev Apr 19 '17 at 15:51
  • \$\begingroup\$ @Mayube this is too long 1 Byte more is enough. The best way is to specified the output by the possibilities of the language and not general \$\endgroup\$ – Jörg Hülsermann Apr 19 '17 at 16:09
  • 1
    \$\begingroup\$ echo 16<=>strlen(preg_filter("#[0-7]#","",hash(md2,$argn))); should do the trick without additional byte. \$\endgroup\$ – Christoph Apr 20 '17 at 6:57
  • 1
    \$\begingroup\$ Golfed version: <?=preg_match_all("/[0-7]/",hash(md2,$argn))<=>16; \$\endgroup\$ – Christoph Apr 20 '17 at 7:10
  • \$\begingroup\$ @Christoph I feel like an idiot that I have not think about preg_match_all \$\endgroup\$ – Jörg Hülsermann Apr 20 '17 at 11:47
1
\$\begingroup\$

PHP, 56 bytes

while($i<32)${hash(md2,$argn)[$i++]>'7'}++;echo$$_<=>16;
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Java 137 130 124 123 bytes

a->{int c=32;for(int b:java.security.MessageDigest.getInstance("MD2").digest(a.getBytes()))c-=(b>>6&2)+(b>>2&2);return c;}

Test it online!

Basically, for each byte, we're asked to check against its 4th and 8th least significant bits. I don't go through the hex representation at all. So it seemed only natural to start playing with bits.

Values <0 are falsey, values >0 are truthy, value 0 is neither truthy or falsey. The usual truthy and falsey can't be applied to Java this time (because it can't be true or false or 0 with the rule if(<truthy>)), so I took the liberty to declare as such.

Saves

  1. 137 -> 130 bytes: golfed by using bit operations, removing 2 everytime I get a "falsy" bit.
  2. 130 -> 124 bytes: more bitwise operations
  3. 124 -> 123 bytes: replaced byte by int in the for loop declaration.
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Tcl + Trf package, 79

package require Trf
puts [expr [regexp -all \[0-7\] [hex -m e [md2 $argv]]]-16]

Try it online. (Thanks @Dennis for adding Tcl to TIO.)

|improve this answer|||||
\$\endgroup\$

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.