[Question]
  [
## 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*
  
[Answer]
## 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.
[Answer]
## 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.
[Answer]
# 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
```
[Answer]
## 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
[Answer]
## 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
```
[Answer]
# 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.
[Answer]
## 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
```
[Answer]
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>
[Answer]
# 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)]);
}
```
[Answer]
## 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"}
```
[Answer]
# 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](https://i.stack.imgur.com/adw3w.png)
Because the response is not competitive (being so long-winded), I decided to use an input format more congenial to Mathematica.
[Answer]
# 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 `if`s 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, "");
    }
  }
};
```
[Answer]
## 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"
```
[Answer]
**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");
        }
```
[Answer]
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.
[Answer]
**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))
```
[Answer]
# 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!](https://tio.run/nexus/fs-mono#TVDRboIwFH3nK25IFtsMjEyzbEyauMQ9OV2Ce5khC2LRGiiMFieG7NdZC8zsqfece@85PbfJcsrBr4SkqZFQCann069hGuYtCkF4wjPNJzFcZ@95TguEa5KiuOQQ2YRxqZ77CW6HCxpBBMxjMTDyCPKglIUsGN8D00tqmhBk46vC2SZnmDworD1FmdYkApoICqwV3Cox3YmzZKcXUGGF@GgT1I8Ds0Psuoq9PWK0CawR7lpZIZ8r9GNjprRjIZUhRMZmOueyqN4y/ZGgdTjDxTNAV5V3GW5GwdDPEybRwBrgji@tk1e1nQXle3mwFHD@gAG5iidj80aY6O@nd202AQkU6kIxJF7R3WLsuqKPp1jSs6Mr66gKbwK0ndYhtJ74WjtBfyUV4IXxHUIEj3W4kkeSZbxeZpzCtxYsyckm7fp/ctqRTlD7WUr16RU6B/WnTUx/PVvMX2frualCj5qm@VitrOXqFw "F# (Mono) – TIO Nexus")
* 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
```
[Answer]
# 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.
[Answer]
# 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](http://sandbox.onlinephpfunctions.com/code/3566230223fa0542e4edc7dd9ef85cd26fc8a3a9) (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).
]