My Word can beat up your Word

26

4

PROBLEM

Given two words, find the winner in a digital root battle.

Define the digital root of a word this way:

  1. Each letter of the alphabet is assigned a number: A = 1, B = 2, C = 3, ..., Z = 26
  2. Add the values for each letter to total the word. Take "CAT", for example. C+A+T = 3+1+20 = 24
  3. Add all the single digits that make up that result: 24 => 2 + 4 = 6
  4. Repeat step #3 until you reach a single digit. That single digit is the digital root of the word.

Rules:

  1. A winner is declared if its digital root is larger than the other.
  2. If the digital root values are equal, shorten the words by removing every instance of the highest value letter from both words and recalculating.
  3. Repeat steps #1 and #2 until there is a winner or one of the words has only a single letter (or no letters) remaining.
  4. If the digital root values are equal after going through the shortening process, the longer word is declared the winner.
  5. If the words are of equal length and no winner is found after going through the shortening process, no winner is declared.

Special rules:

  1. No use of modulus is allowed in the calculation of the digital root itself. It can be used anywhere else.
  2. Assume words will consist only of uppercase letters - no punctuation, no spaces, etc.

INPUT

Pull the words in through stdin (comma-separated). method parameters, or however you want. Make it clear in your solution or the code how the words are parsed or prepared.

OUTPUT

Display the winning word. If there is no winner, display "STALEMATE".

Examples:

intput: CAN,BAT

CAN = 18 = 9
BAT = 23 = 5 

output: CAN

intput: ZOO,NO

ZOO = 56 = 11 = 2
NO = 29 = 11 = 2

OO = 30 = 3
N = 14 = 5

output: NO

UPDATE: Input must be read using stdin with the words as a comma-separated string.

UPDATE: Added a couple examples to test against.

UPDATE: clarified the removal of the highest valued letter in the case of a tie - this also alters slightly the stop condition as well - if a word is one letter or zero letters long, the shortening process is stopped

Steve

Posted 2011-02-22T03:13:40.517

Reputation: 671

I couldn't be bothered to put this on EVERY entry, so here's a tip for anyone who sees this: if you have "-64" anywhere in your code to convert ascii codes, you can save yourself a character and make it "-1", since that's what it will work out to anyway! – Johno – 2012-08-24T15:38:53.607

You should decide on the input, not leave it to choice, as it makes a huge difference in the programs. By picking an input method, and specing it, you remove "creative interpretations", and make a challenge that is equal for all. – MtnViewMark – 2011-02-22T03:17:47.017

@MtnViewMark - Understood, but effectively I'm trying to remove the reading of the input from the character count. I'm not interested in the most clever or shortest way to read in the two words. Requiring a specific method also handicaps certain languages - I guess I'm just trying to get at the meat of the problem. – Steve – 2011-02-22T04:16:26.687

1@Steve - Then you shouldn't specify the output as "display" either, yes? However, I think you are perhaps eliminating too much from the problem. A clever and short golf often stems from combining different aspects of the problem in tricky ways, for example folding some of the processing into the input or output. As for handicapping languages -- pretty much all of them can read stdin and write stdout. – MtnViewMark – 2011-02-22T04:22:22.060

@MtnViewMark - Fair point. I'll make a simple update and clear it up. My language of choice just has a lengthy way of reading from stdin, so I get biased. :) – Steve – 2011-02-22T04:27:37.697

Does taking the input an argument to main count as being from stdin? Oh, and generally, if you want to keep the requirements down on stray stuff like reading from stdin and having to import or include other modules or files, making the puzzle require a function rather than a whole program would probbaly be the best way to go. – Jonathan M Davis – 2011-02-22T05:50:47.357

It would probably be a good idea to add some examples too, so that there are values to test against. – Jonathan M Davis – 2011-02-22T06:20:27.373

@Jonathan - That was my intent without explicitly stating it (requiring a function/method) - my fault. I'll be clearer next time. For now, assume a full program is required. I also added some simple examples to test against. – Steve – 2011-02-22T13:29:47.167

Oh. floccinaucinihilipilification – Martin York – 2011-02-22T21:05:14.913

@Steve: If the word BANANA ties another word, does it become BAANA or BAAA? – Eelvex – 2011-02-22T21:45:08.423

@Eelvex - my intent was that it becomes "BAAA" - post should have read "by removing every instance of the highest value letter". – Steve – 2011-02-22T22:32:53.363

It would really help to see a more comprehensive set of test vectors. In particular, it would be good to have test vectors that prove that code is correctly shortening BANANA to BAAA, not BAANA (as I thought you meant prior to your clarification). I wonder how many submitted solutions get that right - since it complicates things significantly (which is fine, just subtle). – MtnViewMark – 2011-02-23T03:11:13.350

The problem never states that only two words will be supplied; is this given? Oh, and Rules #2/#3 are the suck :) – Phrogz – 2011-02-26T06:57:27.137

Would subtracting nine from the total value until it's less than ten be considered "using a modulus"? – supercat – 2014-02-14T03:21:37.227

Answers

9

J, 100

z=:"."0@":@(+/)^:9@(64-~a.i.])@(#~' '&i.)"1
f=:*@-/"2@(z@((]#~]i.~{.@\:~)"1^:([:=/z))){'STALEMATE'&,

runs like this:

f 'NO',:'ZOO'
NO       
f 'CAN',:'BAT'
CAN      
f 'FAT',:'BANANA'
FAT      
f 'ONE',:'ONE'
STALEMATE

it doesn't yet accept input exactly as asked.

Eelvex

Posted 2011-02-22T03:13:40.517

Reputation: 5 204

9

APL (Dyalog) (91 86)

⎕ML←3⋄{Z≡∪Z←{2>⍴⍕⍵:⍵⋄∇+/⍎¨⍕⍵}¨+/¨⎕A∘⍳¨⍵:G[↑⍒Z]⋄1∊↑¨⍴¨⍵:'STALEMATE'⋄∇1∘↓¨⍵}G←Z⊂⍨','≠Z←⍞

Explanation (in order of execution):

  • ⎕ML←3: set ML to 3 (this makes mean partition, among other things).
  • G←Z⊂⍨','≠Z←⍞: read input, separate by commas, store in G and pass to the function.
  • +/¨⎕A∘⍳¨⍵: calculate the score for each word. (⎕A is a list containing the alphabet.)
  • Z←{2>⍴⍕⍵:⍵⋄∇+/⍎¨⍕⍵}¨: calculate the digital root for each score (by summing all digits as long as there is still more than one digit) and store them in Z.
  • Z≡∪Z: if all scores are unique...
  • :G[↑⍒Z]: ...then output the word with the highest score (from the original list).
  • ⋄1∊↑¨⍴¨⍵:'STALEMATE': otherwise (if there's a tie), if one of the words is of length 1, output STALEMATE.
  • ⋄∇1∘↓¨⍵: otherwise, take the first letter off each word and run the function again.

marinus

Posted 2011-02-22T03:13:40.517

Reputation: 30 224

5

Ruby - 210

d,e=(a,b=$<.read.chop.split(/,/)).map{|w|w.bytes.sort}
r=->w,o=65{n=0;w.map{|c|n+=c-o};n>9?r[n.to_s.bytes,48]:n}
d.pop&e.pop while r[d]==r[e]&&d[1]&&e[1]
$><<[[:STALEMATE,a,b][a.size<=>b.size],a,b][r[d]<=>r[e]]

Tests:

$ ruby1.9 1128.rb <<< CAN,BAT
CAN

$ ruby1.9 1128.rb <<< ZOO,NO
NO

$ ruby1.9 1128.rb <<< ZOO,ZOO
STALEMATE

Arnaud Le Blanc

Posted 2011-02-22T03:13:40.517

Reputation: 2 286

Why not shorten this further by using some other word to denote a tie? i.e. "TIE" vs. "STALEMATE" – Gaffi – 2012-08-23T17:46:16.267

@Gaffi because the spec requires that the word "STALEMATE" be used. – Paul Prestidge – 2012-08-23T21:51:50.000

@chron Shame on me, I stopped reading at "If the words are of equal length and no winner is found after going through the shortening process, no winner is declared." – Gaffi – 2012-08-23T22:11:51.777

First line can be shortened to d,e=(a,b=gets.split ?,).map{|w|w.bytes.sort}. – Ventero – 2011-02-23T00:08:55.217

5

Haskell, 205 characters

import List
s b=d.sum.map((-b+).fromEnum)
d q|q<10=q|1<3=s 48$show q
f=map(s 64.concat).tails.group.reverse.sort
w(a,_:b)=f a#f b where x#y|x<y=b|x>y=a|1<3="STALEMATE"
main=getLine>>=putStrLn.w.span(/=',')

Sample runs:

> ghc --make WordVsWord.hs 
[1 of 1] Compiling Main             ( WordVsWord.hs, WordVsWord.o )
Linking WordVsWord ...

> ./WordVsWord <<< CAN,BAT
CAN

> ./WordVsWord <<< ZOO,NO
NO

> ./WordVsWord <<< FAT,BANANA
FAT

> ./WordVsWord <<< ONE,ONE
STALEMATE

  • Edit: (227 -> 219) better picking of winner, shortened pattern match in w, imported older, shorter module
  • Edit: (219 -> 208) Incorporate JB's suggestions
  • Edit: (208 -> 205) handle negative numbers, exploiting odd rules in Haskell about hyphen

MtnViewMark

Posted 2011-02-22T03:13:40.517

Reputation: 4 779

1Using straight list comparison is a very nice touch. A few suggested "at-a-glance" improvements: ',':b_:b (-2), if you're not too attached to multiline processing interact$unlines.map([...]).linesputStr.[...]=<<getLine (-11), if you allow yourself to lax output putStrprint (-1). I hate those negation operation taking so many chars, but can't find a way around it. – J B – 2011-02-23T09:15:19.747

Thanks, JB! I incorporated most of suggestions. I felt the output should follow the spec, in particular end with a newline. But I'd be willing to save those two characters if it got close! :-) – MtnViewMark – 2011-02-24T03:30:49.127

Good job with the subtractions! – J B – 2011-02-24T07:31:45.190

3

Perl, 224 225 229

Basic golfing (nothing smart yet):

split",",<>;$_=[sort map-64+ord,/./g]for@a=@_;{for(@b=@a
){while($#$_){$s=0;$s+=$_ for@$_;$_=[$s=~/./g]}}($a,$b)=
map$$_[0],@b;if($a==$b){pop@$_ for@a;@{$a[1]}*@{$a[0]}&&
redo}}say+("STALEMATE",@_)[$a<=>$b||@{$a[0]}<=>@{$a[1]}]

Perl 5.10 and above, run with perl -M5.010 <file> or perl -E '<code here>'

$ perl -M5.010 word.pl <<<CAN,BAT
CAN
$ perl -M5.010 word.pl <<<ZOO,NO
NO

$ perl -M5.010 word.pl <<<NO,ON
STALEMATE

J B

Posted 2011-02-22T03:13:40.517

Reputation: 9 638

2

This really took my fancy and is my first post. Although it is old I noticed no one had done a php version so here is mine.

<?php $f='CAN,CBN';$w=explode(',',$f);$a=$ao=$w[0];$b=$bo=$w[1];$c='';
function splice($a,$t){$s=$h=0;$y=array();$x=str_split($a);
foreach($x as $k=>$v){$s=$s+ord($v)-64;if($v>$h){$h=$k;}}
$y[0]=$s;if($t==1){unset($x[$h1]);$y[1]=$x;}return $y;}
while($c==''){$y1=splice($a,0);$y2=splice($b,0);$y3=splice($y1[0],1);
$y4=splice($y2[0],1);if($y3[0]>$y4[0]){$c=$ao;}else if($y3[0]<$y4[0]){$c=$bo;
}else if((strlen($a)<1)OR(strlen($b)<1)){if(strlen($a)<strlen($b)){$c=$ao;}
else if(strlen($b)<strlen($a)){$c=$bo;}else{$c='STALEMATE';}}}
echo $c;
?>

534 Characters.

Now I am unsure as to the rules for starting off so I started with $f='CAN,CBN' as my input. I hope that was right. I have run all the tests and it passes all of them although it is not particularly elegant. I really must get some sleep now but I had great fun working this out - thank you for a great puzzle.

Coded on http://codepad.org/ZSDuCdin

Paul Drewett

Posted 2011-02-22T03:13:40.517

Reputation: 181

You can use $f=trim(fgets(fopen('php://stdin'))); for taking the input. – Élektra – 2017-07-16T20:26:19.117

Scratch that, $w=fgetcsv(STDIN); works better. – Élektra – 2017-07-23T02:27:46.413

2

VBA (242 462)

Function s(q,Optional l=0)
s=-1:t=Split(q,","):r=t:m=t
For j=0 To 1
m(j)=0:w=t(j)
While Len(w)>1 Or Not IsNumeric(w)
b=0
For i=1 To Len(w)
a=Mid(w,i,1):a=IIf(IsNumeric(a),a,Asc(a)-64):b=b+a
If m(j)+0<a+0 Then m(j)=a
Next
w=b
Wend
r(j)=b
Next
s=IIf(r(0)>r(1),0,IIf(r(0)<r(1),1,s))
For j=0 To 1
r(j)=Replace(t(j),Chr(m(j)+64),"",,1)
Next
If s<0 And Len(t(0))+Len(t(1))>2 Then s=s(r(0) & "," & r(1),1)
If l=0 Then If s>=0 Then s=t(s) Else s="STALEMATE"
End Function

Turns out the below code didn't match the spec, so I had to re-work, adding much length (see above). :-/ This may be able to be golfed further, but it's already pretty compact and I doubt I'll be able to bring it back down to a competitive score.

The original (below) did not remove the highest-valued letter from the words when there was a tie.

Sub s(q)
t=Split(q,",")
r=t
For j=0 To 1
w=t(j):b=0
For i=1 To Len(w)
b=b+Asc(Mid(w,i,1))-64
Next
While Len(b)>1
d=0
For i=1 To Len(b)
d=d+Mid(b,i,1)
Next
b=d
Wend
r(j)=b
Next
MsgBox IIf(r(0)>r(1),t(0),IIf(r(0)<r(1),t(1),"STALEMATE"))
End Sub

Gaffi

Posted 2011-02-22T03:13:40.517

Reputation: 3 411

2

K, 106

{a::x;@[{$[(>). m:{+/"I"$'$+/@[;x].Q.A!1+!26}'x;a 0;(<). m;a 1;.z.s 1_'x@'>:'x]};x;"STALEMATE"]}[","\:0:0]

Uses exception handling to catch stack errors, which result in cases of stalemate.

tmartin

Posted 2011-02-22T03:13:40.517

Reputation: 3 917

1

D: 326 Characters

import std.algorithm,std.array,std.conv,std.stdio;void main(string[]a){alias reduce r;auto b=array(splitter(a[1],","));auto s=map!((a){int n=r!"a+b"(map!"cast(int)(a-'A')+1"(a));while(n>9)n=r!"a+b"(map!"cast(int)(a-'0')"(to!string(n)));return n;})(b);int v=r!"a>b?a:b"(s);writeln(count(s,v)>1?"STALEMATE":b[countUntil(s,v)]);}

More Legibly:

import std.algorithm, std.array, std.conv, std.stdio;

void main(string[] a)
{
    alias reduce r;

    auto b = array(splitter(a[1], ","));
    auto s = map!((a){int n = r!"a + b"(map!"cast(int)(a - 'A') + 1"(a));

                      while(n > 9)
                          n = r!"a+b"(map!"cast(int)(a - '0')"(to!string(n)));

                      return n;
                     })(b);
    int v = r!"a > b ? a : b"(s);

    writeln(count(s, v) > 1 ? "STALEMATE" : b[countUntil(s, v)]);
}

Jonathan M Davis

Posted 2011-02-22T03:13:40.517

Reputation: 705

1

Mathematica

Some details still missing

a = {"ZOO"}; b = {"NO"}
f = FixedPoint[IntegerDigits@Total@# &, #] &

If[(s = f /@ 
        NestWhile[(# /. Max@# -> 0 &) /@ # &, (ToCharacterCode @@ # - 64) & /@ #, 
        f[#[[1]]] == f[#[[2]]] &, 1, 5] &@{a, b})[[1, 1]] > s[[2, 1]], 
   a, b, "STALMATE"]  

{"NO"}

Dr. belisarius

Posted 2011-02-22T03:13:40.517

Reputation: 5 345

1

PHP, 339 (not to spec), 410 382 359 339 337 Bytes

$b=$w=fgetcsv(STDIN);function a($c){for(;a&$g=$c[$p++];)$f+=ord($g)-64;$f=trim($f);for(;$f[1]&a;$f=$h)for($h=0;a&$r=$f[$q++];$h=bcadd($h,$r));return$f;}function d($f){return strtr($f,[max(str_split($f))=>'']);}for(;$c==$d;$b=[$e,$f]){$x=$z++?d:trim;$e=$x($b[0]);$f=$x($b[1]);$c=a($e);$d=a($f);$e||die(STALEMATE);$c!=$d&&die($w[$c<=$d]);}

EDIT 1: +71 bytes. Using STDIN instead of fopen('php://stdin','r'); and short tags. Also, full conformance to the spec.

EDIT 2: -28 bytes. Using fgetcsv(STDIN) instead of explode(',',trim(fgets(STDIN))), and used for loop instead of while loop.

EDIT 3: -23 bytes. Merged functions a and b, merged for loops.

EDIT 4: -20 bytes. Turned c from a recursive into a loop. Then, removed function c and put its code into the global namespace.

EDIT 5: -2 bytes. Thanks to @Titus for the -r flag.

Élektra

Posted 2011-02-22T03:13:40.517

Reputation: 284

1

no need for a PHP tag with -r flag

– Titus – 2018-09-03T15:23:14.617

1

Mathematica 220 207

After writing this, I noticed that this follows the same reasoning that Belisarius used,

h@u_ := ToCharacterCode@u - 64;
m@w_ := FromCharacterCode[Most@Sort@h@w + 64];
f@v_ := FixedPoint[Tr@IntegerDigits@# &, Tr@h@v];
x_~g~y_ := If[f@x == f@y, g[m@x, m@y], If[f@x > f@y, 1, 2]];
x_~z~x_ := "STALEMATE";
x_~z~y_ := {x, y}[[x~g~y]] 

Usage

z["ZOO", "NO"]
z["CAN", "BAT"]
z["FAT", "BANANA"]
z["ONE", "ONE"]

results

Because the response is not competitive (being so long-winded), I decided to use an input format more congenial to Mathematica.

DavidC

Posted 2011-02-22T03:13:40.517

Reputation: 24 524

1

CoffeeScript - 335

z=(a,b,g=a,h=b)->c=y a;d=y b;e=a.length;f=b.length;return g if(c>d);return h if(d>c);return g if(e<2&&f>1);return h if(f<2&&e>1);return "STALEMATE" if(f==e&&f<2);z(x(a),x(b),a,b)
y=(a)->t=0;t+=c.charCodeAt(0)-1 for c in a;t-=9 while 9<t;t
x=(a)->for i in[90..65]
 b=new RegExp(String.fromCharCode(i));return a.replace b, "" if b.test a

Not as happy with this one as I might have been, but I'll put it up anyway. The actual scoring is very concise (y function), but the ifs to compare results (in z) get pretty long.

To use it call z with your two words (e.g. z 'FOO','BAR'). It will score both words and return the higher scoring word. If it's a tie, it will recurse with the modified words (keeping the originals to return eventually, hence the extra two parameters) which it gets from the x function.

The equivalent (expanded) javascript for those interested:

var x, y, z;

z = function(a, b, g, h) {
  var c, d, e, f;
  if (g == null) {
    g = a;
  }
  if (h == null) {
    h = b;
  }
  c = y(a);
  d = y(b);
  e = a.length;
  f = b.length;
  if (c > d) {
    return g;
  }
  if (d > c) {
    return h;
  }
  if (e < 2 && f > 1) {
    return g;
  }
  if (f < 2 && e > 1) {
    return h;
  }
  if (f === e && f < 2) {
    return "STALEMATE";
  }
  return z(x(a), x(b), a, b);
};

y = function(a) {
  var c, t, _i, _len;
  t = 0;
  for (_i = 0, _len = a.length; _i < _len; _i++) {
    c = a[_i];
    t += c.charCodeAt(0) - 1;
  }
  while (9 < t) {
    t -= 9;
  }
  return t;
};

x = function(a) {
  var b, i, _i;
  for (i = _i = 90; _i >= 65; i = --_i) {
    b = new RegExp(String.fromCharCode(i));
    if (b.test(a)) {
      return a.replace(b, "");
    }
  }
};

Johno

Posted 2011-02-22T03:13:40.517

Reputation: 301

1

Racket 479 bytes

(define(dl n)(let p((ol '())(n n))(let-values(((q r)(quotient/remainder n 10)))(if(= q 0)(cons r ol)(p(cons r ol)q)))))
(define(dr N)(let p2((n N))(define s(apply +(dl n)))(if(< s 10)s(p2 s))))
(let p3((l(for/list((i(string->list s)))(-(char->integer i)64)))(k(for/list((i(string->list t)))(-(char->integer i)64))))
(let((a(dr(apply + l)))(b(dr(apply + k))))(cond[(> a b)s][(< a b)t][(equal? l k)"STALEMATE"][else(p3(remove*(list(apply max l))l)(remove*(list(apply max k))k))])))

Ungolfed:

(define (f s t)

  (define (getDigitList n)                     ; sub-fn  to get digit list
    (let loop ((ol '())
               (n n))
      (let-values (((q r) (quotient/remainder n 10)))
        (if (= q 0) (cons r ol)
            (loop (cons r ol) q)))))

  (define (digit_root N)                       ; sub-fn to get digital root of a number
    (let loop2 ((n N))                        
      (define s (apply + (getDigitList n)))    
      (if (< s 10)
          s
          (loop2 s))))

  (let loop3 ((l (for/list ((i (string->list s)))  ; actual fn to compare 2 strings
                   (- (char->integer i) 64)))
              (k (for/list ((i (string->list t)))
                   (- (char->integer i) 64))))
    (let ((a (digit_root (apply + l)))
          (b (digit_root (apply + k))))
      (cond
        [(> a b) s]
        [(< a b) t]
        [(equal? l k) "STALEMATE"]
        [else (loop3 (remove* (list (apply max l)) l)
                     (remove* (list (apply max k)) k)
                     )]
        ))))

Testing:

(f "CAN" "BAT")
(f "ZOO" "NO")

Output:

"CAN"
"NO"

rnso

Posted 2011-02-22T03:13:40.517

Reputation: 1 635

0

JAVA

    public static void main(String args[]) throws Exception{
        String input=(new BufferedReader(new InputStreamReader(System.in)).readLine());
        StringTokenizer st = new StringTokenizer(input, ",");
        String w1 = st.nextToken();String w2 = st.nextToken();int s1=0;int s2=0;
        String flag="";
        do{ Integer sum1=0;Integer sum2=0;
        for (int i=0;i<w1.length();i++)
            sum1+=((int)w1.charAt(i) - 64);
        for (int i=0;i<w2.length();i++)
            sum2+=((int)w2.charAt(i) - 64);
        while (sum1.toString().length()>1){
            s1=0;
            for (int i=0;i<sum1.toString().length();i++)
                s1+=((int)sum1.toString().charAt(i)-48);
            sum1=s1;
        }
        while (sum2.toString().length()>1){
            s2=0;
            for (int i=0;i<sum2.toString().length();i++)
                s2+=((int)sum2.toString().charAt(i)-48);
            sum2 =s2;
        }
        flag=(s1>s2)?w1:(s1!=s2)?w2:"";
        if (flag!="")
            {st = new StringTokenizer(input,",");
                if (s1>s2)
                    System.out.println(st.nextToken());  
                else{
                    st.nextToken();
                    System.out.println(st.nextToken());
                }
            }
        int max=0;
        for (int i=0;i<w1.length();i++){
            max=((int)w1.charAt(i)>max)?(int)w1.charAt(i):max;
        }
        w1 = w1.replace((char)max, (char)64);
        max=0;
        for (int i=0;i<w2.length();i++){
            max=((int)w2.charAt(i)>max)?(int)w2.charAt(i):max;
        }
        w2 = w2.replace((char)max, (char)64);
            }while(flag=="" && !w1.equals(w2)); 
    if (flag.length()<1)
        System.out.println("STALEMATE");
        }

Aman ZeeK Verma

Posted 2011-02-22T03:13:40.517

Reputation: 609

The code above replaces all max character in case of tie.. is that required? – Aman ZeeK Verma – 2011-02-22T14:39:17.327

0

F#, 559 533 530 bytes

Not competitive as of yet. I'm sure c can be made shorter as well as the last few lines. Not having easier access to command line args is also hurting here.

open System
let m=Seq.map
let a s=s="";s.ToUpper()|>m(fun c->int c-64)
let rec c i=if i>9 then string i|>m(int>>(-))|>m(fun x->x 48)|>Seq.sum|>c else i
let b i=Seq.fold(fun(r,a)j->(Seq.sum i-a)::r,a+j)([],0)(Seq.sortBy(~-)i)|>fst|>m c
[<EntryPoint>]
let x z=
 let y=z.[0].Split(',')
 let u,v=y.[0].Length,y.[1].Length
 printf"%s"(Seq.fold2(fun s l r->if l=r then 3::s else if l>r then 0::s else 1::s)[](b<|a y.[0])(b<|a y.[1])|>Seq.tryFind((>)3)|>function|None when u>v->y.[0]|None when u<v->y.[1]|Some x->y.[x]|_->"STALEMATE")
 0

Try it online!

  • Saved 3 bytes by constraining s to string by comparing it with string

Ungolfed version

open System
let m=Seq.map // this is just to save some characters and I'll use Seq.map for this version

let toIntList s =
    s = "" // constrain s to type string
    s.ToUpper()
    |>Seq.map (fun c -> int c - 64) // converts char value to int and offsets it so that A=1

let rec digitSumUntilSingle i =
    if i > 9 then
        string i                // convert number to string
        |>Seq.map ( int>>(-) )  // convert individual char to int and partially apply substraction
                                // this returns a function
        |>Seq.map (fun x -> x 48) // provide last parameter for substraction, this is equivalent to
                                  // charValue - 48
        |>Seq.sum                 // sum over all digits
        |>digitSumUntilSingle     // recursively call this function again in case we are >9
    else
        i

let calculateDigitalRoot input =
    Seq.fold(fun (result, acc) current ->       // calculate digital root for all possible iterations
                (Seq.sum input - acc)::result,  // basically, this calculates Rule 3 until the end for a given word
                acc + current
            ) ([], 0) (Seq.sortBy (~-) input) // sort input by value descending
    |>fst   // only interested in the lits, not the final accumulator
    |>Seq.map digitSumUntilSingle

[<EntryPoint>]
let main (args) =
    let y = args.[0].Split(',')
    let leftLength = y.[0].Length
    let rightLength = y.[1].Length

    Seq.fold2 (fun state left right ->
                if left = right then
                    3::state
                else if left > right then
                    0::state                // 0 is chosen because this represents y[0] index
                else
                    1::state
               ) [] (calculateDigitalRoot (toIntList y.[0])) (calculateDigitalRoot (toIntList y.[1]))
    |> Seq.tryFind ((>) 3)                  // try to find first variation where left and right digital root isn't equal
    |> function
        | None when leftLength > rightLength -> y.[0]
        | None when leftLength < rightLength -> y.[1]
        | Some x -> y.[x]
        | _ ->"STALEMATE"
    |>printf "%s" 
    0

Brunner

Posted 2011-02-22T03:13:40.517

Reputation: 331

0

PHP, 296 281 267 bytes

function f(&$s){for(;$c=$s[$i++];$m>$c||$m=$c)$p+=ord($c)&31;for($s=str_replace($m,'',$s);9<$p=array_sum(str_split($p)););return$p;}for(list($a,$b)=$x=fgetcsv(STDIN);$s==$t&&$a&$b;$t=f($b))$s=f($a);echo($s-=$t)||($s=strlen($x[0])-strlen($x[1]))?$x[+($s<0)]:STALEMATE;

run with -n or try it online (TiO includes breakdown).

Back in Feb 2011, the current PHP version was 5.3.5; so I could not

  • use shorthand list assignment ([$a,$b]=fgetcsv(...) and such)
  • alias count_chars inline
  • index function results directly
  • use negative string indexes instead of substr

But neither would have saved a lot; so it doesn´t matter much.

Most costly things were the loops (of course) and rule #4 (40 36 bytes).

Titus

Posted 2011-02-22T03:13:40.517

Reputation: 13 814

0

C++, 473 (I'm borrowing a course iron)

#include<iostream>
#define $ string
#define _ return
using namespace std;$ S($&s){int i=-1,m=i,x=0;while(++i<s.length())if(s[i]-'@'>x)m=i,x=s[i];s.erase(m,1);_ s;}int M($ w){int i,v=0;for(i=0;i<w.length();++i)v+=w[i]-'@';while(v>9){i=0;while(v)i+=v-v/10*10,v/=10;v=i;}_ v;}$ B($ x, $ y){while(!(M(x)-M(y)))S(x),S(y);if(M(x)>M(y))_ x;if(M(x)<M(y))_ y;_"STALEMATE";}int main(int c,char**v){$ s;cin>>s;$ x=s.substr(0,s.find(',')),y=s.substr(s.find(',')+1);cout<<B(x,y)<<endl;_ 0;}

I'm sure I could shorten it up somehow, but I'm tired.

Edit: originally took command line argument, modified to use cin. It's probably a few characters longer now but I'm too tired to recount it.

Wug

Posted 2011-02-22T03:13:40.517

Reputation: 1 607

0

Python :383 chars

run the function c('CAN','BAT'):

def k(j):
 l=list(j);l.remove(max(j));return''.join(l)
def f(x):
 x=str(x)
 if len(x)==1 and x.isdigit():return int(x)
 return f(sum('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.index(y)+1 for y in x)) if x.isalpha() else f(sum(map(int,x)))
def c(a,b):
 v=f(a);u=f(b);
 if v>u:return a
 if v<u:return b
 return'STALEMATE' if v==u and (len(a)==1 or len(b)==1)else c(k(a),k(b))

Ashwini Chaudhary

Posted 2011-02-22T03:13:40.517

Reputation: 169