33
\$\begingroup\$

This challenge was posted on the DailyProgrammer subreddit, and I figured it would be a great candidate for a code golf challenge. Determining if a letter balances is based on its distance from the point of balance, and the letter's value. The value of a letter can be determined by either taking its one-indexed position in the alphabet, or by subtracting 64 from its ASCII value. Furthermore, the value of a letter is multiplied by its distance from the balance point. Let's take a look at an example, STEAD:

STEAD   -> 19, 20, 5, 1, 4 ASCII values
           This balances at T, and I'll show you why!
S T EAD -> 1*19 = 1*5 + 2*1 + 3*4
           Each set of letters on either side sums to the same value, so
           T is the anchor.

However, it should be noted that not all words balance. For example, the word WRONG does not balance in any configuration. Also, words must balance on a letter, not between two letters. For example, SAAS would balance if there was a letter in the middle of the two As, but since there is none it does not balance.

The Task

You should create a program or function that takes in an uppercase word as input or function arguments, and then produces one of two outputs:

  1. If the word balances, then the word should be printed with the left side, a space, the anchor letter, another space, and the right side.

    function (STEAD) -> S T EAD

  2. If the word does not balance, you should print out the word, followed by DOES NOT BALANCE

    function (WRONG) -> WRONG DOES NOT BALANCE

You may assume that all input will be uppercase and there will only be alpha characters.

Example I/O

function (CONSUBSTANTIATION) -> CONSUBST A NTIATION
function (WRONGHEADED)       -> WRO N GHEADED
function (UNINTELLIGIBILITY) -> UNINTELL I GIBILITY
function (SUPERGLUE)         -> SUPERGLUE DOES NOT BALANCE

This is , so the shortest answer in bytes wins.

\$\endgroup\$
  • \$\begingroup\$ Can we omit the spaces in the output of single letter words, e.g. function (A) -> A instead of -> ` A `? \$\endgroup\$ – nimi Jul 7 '15 at 21:03
  • 1
    \$\begingroup\$ @nimi Yes, you may omit spaces. \$\endgroup\$ – Kade Jul 7 '15 at 21:18
  • \$\begingroup\$ Should single character input be considered balanced at all? \$\endgroup\$ – some user Jul 7 '15 at 21:38
  • 1
    \$\begingroup\$ @someuser Yes, because the "weight" on either side is 0. \$\endgroup\$ – Kade Jul 7 '15 at 21:53
  • 14
    \$\begingroup\$ BALANCE DOES NOT BALANCE \$\endgroup\$ – Optimizer Jul 8 '15 at 14:29

15 Answers 15

6
\$\begingroup\$

Pyth, 49 bytes

jd.xcz,Jhf!s*Vm-Cd64zr_TlzUzhJ,z"DOES NOT BALANCE

Demonstration.

Explanation:

jd.xcz,Jhf!s*Vm-Cd64zr_TlzUzhJ,z"DOES NOT BALANCE

                                    Implicit: z = input(), d = ' '
         f                Uz        Filter T over range(len(z)).
              m     z               Map the characters in z to
               -Cd64                their ASCII values - 64.
            *V                      Vectorized multiplication by
                     r_Tlz          range(-T, len(z)).
                                    This is equivalent to putting the fulcrum at T.
           s                        Sum the weights.
          !                         Logical not - filter on sum = 0.
        h                           Take the first result.
                                    This throws an error if there were no results.
       J                            Save it to J.
      ,J                    hJ      Form the list [J, J+1].
    cz                              Chop z at those indices, 
                                    before and after the fulcrum.
  .x                                If no error was thrown, return the above.
                              ,z".. If an error was thrown, return [z, "DOES N..."]
jd                                  Join the result on spaces and print.
\$\endgroup\$
12
\$\begingroup\$

Pure bash (no coreutils or other utilities), 125

Standard center of mass calculation using moments about the origin:

for((;i<${#1};w=36#${1:i:1}-9,m+=w,M+=w*++i)){ :;}
((M%m))&&echo $1 DOES NOT BALANCE||echo ${1:0:M/m-1} ${1:M/m-1:1} ${1:M/m}

Test output:

$ for t in \
> STEAD \
> CONSUBSTANTIATION \
> WRONGHEADED \
> UNINTELLIGIBILITY \
> SUPERGLUE
> do ./wordbal.sh $t; done
S T EAD
CONSUBST A NTIATION
WRO N GHEADED
UNINTELL I GIBILITY
SUPERGLUE DOES NOT BALANCE
$ 
\$\endgroup\$
10
\$\begingroup\$

Python 3, 124

w=input()
i=a=b=0
for c in w:n=ord(c)-64;a+=n;b+=n*i;i+=1
m=b//a
print(*[w[:m],w,w[m],"DOES NOT BALANCE",w[m+1:]][b%a>0::2])

This code doesn't test potential fulcrums, but rather finds the "center of mass" and checks if it's an integer. It does so by summing the total mass a and the position-weighted mass b, to find the center of mass m=b/a. It then prints either the string split at position m, or the string plus "DOES NOT BALANCE", chosen by the [_::2] list-slicing trick.

\$\endgroup\$
8
\$\begingroup\$

CJam, 57 bytes

l_,,_f{f-W$'@fm.*:+}0#:I){ISIW$=S++t}" DOES NOT BALANCE"?

This can still be golfed a bit.

Try it online here

\$\endgroup\$
  • \$\begingroup\$ That fixes it. '@fm is shorter than 64f-:i. \$\endgroup\$ – Dennis Jul 7 '15 at 20:45
  • \$\begingroup\$ Yeah.. forgot that CJam acts weird in case of char subtractions.. \$\endgroup\$ – Optimizer Jul 7 '15 at 20:46
7
\$\begingroup\$

JavaScript (ES6), 211 200 160 bytes

f=w=>{for(j=-w.length;j++;)if(![...w].reduce((p,v,i)=>p+(parseInt(v,36)-9)*(j+i),0))return w.slice(0,-j)+` ${w[-j]} `+w.slice(1-j);return w+` DOES NOT BALANCE`}

Previous attempt, 200 bytes

Thanks to edc56 and nderscore for helping me golf this

f=w=>{for(j=0,r=(a,z)=>[...a][z||`reverse`]().reduce((p,v,i)=>p+(parseInt(v,36)-9)*++i,0);j++<w.length;)if(r(a=w[s=`slice`](0,j))==r(b=w[s](j+1),s))return a+` ${w[j]} `+b;return w+` DOES NOT BALANCE`}

Demo

Firefox and Edge only for now, as it is ES6

f=w=>{for(j=1-w.length;j++;)if(!([...w].reduce((p,v,i)=>p+(parseInt(v,36)-9)*(j+i),0)))return w.slice(0,-j)+` ${w[-j]} `+w.slice(1-j);return w+` DOES NOT BALANCE`}

// DEMO
console.log = function(a) {
  document.body.innerHTML += a + "<br>";
}

console.log(f('STEAD'));
console.log(f('CONSUBSTANTIATION'));
console.log(f('WRONGHEADED'));
console.log(f('UNINTELLIGIBILITY'));
console.log(f('SUPERGLUE'));

\$\endgroup\$
  • 3
    \$\begingroup\$ Try array comprehension [for(v of w)v.charCode....], it's usually 1 byte shorter than .map for strings \$\endgroup\$ – edc65 Jul 7 '15 at 20:44
  • \$\begingroup\$ @edc65 Thanks! Learn something new every day \$\endgroup\$ – rink.attendant.6 Jul 7 '15 at 20:48
  • 1
    \$\begingroup\$ @edc65 array comprehension is technically pushed to the ES7 draft now :( \$\endgroup\$ – nderscore Jul 7 '15 at 20:53
  • 1
    \$\begingroup\$ -1 byte: move j=0 inside the call to charCodeAt :) \$\endgroup\$ – nderscore Jul 7 '15 at 21:00
6
\$\begingroup\$

C, 236 198 192 188 180 173 bytes

a,i,j,k,L;f(char*s){L=strlen(s);for(;i<L;i++){for(a=j=0;j<L;j++)a+=(s[j]-64)*(i-j);if(!a)break;}for(;k<L;k++)printf(k-i?"%c":" %c ",s[k]);if(a)printf(" DOES NOT BALANCE");}

Expanded with main():

#define p printf    
a,i,j,k,L;
f(char*s)
{
    L=strlen(s);
    for(;i<L;i++){
        for(a=j=0;j<L;j++)
            a+=(s[j]-64)*(i-j);
        if(!a)
            break;
    }
    for(;k<L;k++)
        printf(k-i?"%c":" %c ",s[k]);
    if(a)
        printf(" DOES NOT BALANCE");
}
// 83 bytes below
int main(int argc, char **argv)
{
    f(argv[1]);
    printf("\n");
}

Verification:

$ ./a.out CONSUBSTANTIATION
CONSUBST A NTIATION
$ ./a.out WRONGHEADED
WRO N GHEADED
$ ./a.out A
 A 
$ ./a.out WRONG
WRONG DOES NOT BALANCE
$ ./a.out SUPERGLUE
SUPERGLUE DOES NOT BALANCE
\$\endgroup\$
  • 1
    \$\begingroup\$ My solution was too similar to yours to post an answer, but I was able to get down to 146 chars: i,l=1,j;g(char*v){for(;v[i]&&l;++i)for(j=l=0;v[j];++j)l+=(i-j)*(v[j]-64);l?printf("%s DOES NOT BALANCE",v):printf("%.*s %c %s",--i,v,v[i],v+i+1);} Note: uses undefined behavior :) \$\endgroup\$ – Cole Cameron Jul 8 '15 at 15:46
  • \$\begingroup\$ I think you should post it anyway. I also realized that I should have get rid of my #define as it is wasting bytes. \$\endgroup\$ – some user Jul 8 '15 at 17:12
  • \$\begingroup\$ I'm trying really hard to beat C with PHP but I'm still a byte off \$\endgroup\$ – rink.attendant.6 Jul 8 '15 at 18:34
6
\$\begingroup\$

CJam, 50 bytes

r_'@f-_ee::*:+\:+md"X DOES NOT BALANCEX"@?)/()@]S*

Using the Java interpreter, this exits with an error to STDERR for non-balancing words.

If you try the code in the CJam interpreter, just ignore everything but the last line of output.

Idea

My "original idea" turned out to be the same approach @xnor posted several hours before me. Nevertheless, here it goes:

Given a list of values (v0, … vn), we have that v_t is the anchor of the list if and only if any of the following, equivalent conditions holds:

  • tv0 + … + 1vt-1 == 1vt+1 + … tvn

  • (0 - t)v0 + … + (n - t)vn == 0

  • 0v0 + … + nvn == t(v0 + … + vn)

  • t := (0v0 + … + nvn)/(v0 + … + vn) is an integer.

Code

r     e# Read a whitespace separated token from STDIN.
_'@f- e# Push a copy and subtract '@' from each char (pushes code point - 64). 
_ee   e# Push a copy of the array of values and enumerate them.
::*   e# Multiply each value by its index.
:+    e# Add all results.
\:+   e# Add the unmodified values.
md    e# Perform modular division. Pushes quotient and residue.

"X DOES NOT BALANCEX"

@     e# Rotate the quotient on top of the string.
?     e# If the residue is 0, select the quotient. Otherwise, select the string.

At this part, we start having a little fun with overloaded operators.

For the quotient, this happens:

)     e# Add 1 to the quotient.
/     e# Split the input string into chunks of that length.
(     e# Shift out the first chunk.
)     e# Pop the last character of the first chunk.
@     e# Rotate the rest of the string on top of the stack.
]S*   e# Wrap all three parts in an array and join them, separating by spaces.

For the string, this happens:

)     e# Pop out the last char: "X DOES NOT BALANCE" 'X'
/     e# Split the remainder at X's: ["" " DOES NOT BALANCE"]
(     e# Shift out the first chunk: [" DOES NOT BALANCE"] ""
)     e# Pop out the last char.

At this point, a runtime error happens, since "" does not have a last char. The stack gets printed and executing is aborted immediately.

\$\endgroup\$
  • \$\begingroup\$ The code you linked seems different (and better?) \$\endgroup\$ – aditsu Jul 9 '15 at 12:54
  • \$\begingroup\$ @aditsu: Oh, wrong link. It's shorter and cleaner, yes, but it has trailing spaces... \$\endgroup\$ – Dennis Jul 9 '15 at 14:16
5
\$\begingroup\$

Julia, 122 bytes

s->(v=[int(i)-64for i=s];m=dot(v,1:length(s))/sum(v);m==int(m)?join([s[1:m-1],s[m],s[m+1:end]]," "):s*" DOES NOT BALANCE")

This creates an unnamed function that accepts a string as input and returns a string. To call it, give it a name, e.g. f=s->....

We treat the word like a one-dimensional system for which we need to find the center of mass. The center of mass is computed as the dot product of the masses with their locations, divided by the total mass of the system. If the computed center is an integer, it corresponds to one of the letters in the word. Otherwise the word doesn't balance.

Ungolfed + explanation:

function f(s)
    # Create a vector of ASCII code points -- these are the "masses"
    v = [int(i)-64 for i in s]

    # Compute the center of mass, taking the locations to be the indices
    m = dot(v, 1:length(s)) / sum(v)

    # Check whether the center corresponds to a letter's position
    if m == int(m)
        join([s[1:m-1], s[m], s[m+1:end]], " ")
    else
        m * " DOES NOT BALANCE"
    end
end

Examples:

julia> f("WRONG")
"WRONG DOES NOT BALANCE"

julia> f("STEAD")
"S T EAD"

julia> f("CONSUBSTANTIATION")
"CONSUBST A NTIATION"
\$\endgroup\$
5
\$\begingroup\$

PHP, 249 174 bytes

Takes one command-line argument.

<?for($i=-$l=strlen($w=$argv[1]);$i++;){for($k=$q=0;$l>$k;)$q+=($i+$k)*(ord($w[$k++])-64);$q?:exit(substr($w,0,-$i)." {$w[-$i]} ".substr($w,1-$i));}echo"$w DOES NOT BALANCE";

Initial attempt:

<?function r($a){for($i=$q=0;strlen($a)>$i;){$q+=(ord($a[$i])-64)*++$i;}return$q;}for($i=0;$i++<strlen($w=$argv[1]);)(strlen($w)<2?exit($w):(r(strrev($a=substr($w,0,$i)))==r($b=substr($w,$i+1)))?exit("$a {$w[$i++]} $b"):0);echo"$w DOES NOT BALANCE";
\$\endgroup\$
4
\$\begingroup\$

Haskell, 161 135 bytes

a#b=a*(fromEnum b-64)
v=sum.zipWith(#)[1..]
h![]=h++" DOES NOT BALANCE"
h!(x:y)|v(reverse h)==v y=h++' ':x:' ':y|1<2=(h++[x])!y
f=([]!)

Usage example:

*Main> putStr $ unlines $ map f ["CONSUBSTANTIATION","WRONGHEADED","UNINTELLIGIBILITY","SUPERGLUE"]
CONSUBST A NTIATION
WRO N GHEADED
UNINTELL I GIBILITY
SUPERGLUE DOES NOT BALANCE

How it works: f calls the helper function ! which takes two parameters, the left and right part of the word at a given position. It stops if both parts have equal weight (function v) or calls itself recursively with the first letter of the right part moved to the left. It ends with the DOES NOT BALANCE message if the right part is empty.

\$\endgroup\$
4
\$\begingroup\$

C, 183 134 bytes

h,i,a=1;c(char*s){for(;s[i++]&&a;)for(a=h=0;s[h];)a+=(s[h]-64)*(h++-i);printf(a?"%.*s DOES NOT BALANCE":"%.*s %c %s",i,s,s[--i],s+i);}

New Version Explained:

Like the other two entries, it makes use of constant addition on one side and subtraction on the other to hopefully reach zero which is the indication of balance. My original output is reused from the first answer, albeit slightly modified.

l,h,i,a,b;c(char*s){for(l=strlen(s);h++<l&&(a^b|!a);)for(i=a=b=0;i<l;i++)i==h?a=b,b=0:(b+=(s[i]-64)*abs(i-h));printf(a==b?"%.*s %c %s":"%.*s DOES NOT BALANCE",a==b?h:l,s,s[--h],s+h);}

Old Version Explained:

The first loop (h) is the main iterator for the length of the string. The second loop (i) accumulates (b) until h==i. Once that happens, (b) is stored in (a), reset to 0, and then continues until the end of the string is reached where (a) is compared to (b). If there's a match, the main iterator's loop is broken and the output is printed.

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

Ruby 175

F=->s{v=->s{(0...s.size).map{|i|(i+1)*(s[i].ord-64)}.inject :+}
r="#{s} DOES NOT BALANCE"
(0...s.size).map{|i|b,a=s[0...i],s[i+1..-1]
v[b.reverse]==v[a]&&r=b+" #{s[i]} "+a}
r}

Test it online: http://ideone.com/G403Fv

This is a pretty straightforward Ruby implementation. Here's the readable program:

F=-> word {
  string_value = -> str {
    (0...str.size).map{|i|(i+1) * (str[i].ord - 64)}.inject :+
  }

  result = "#{word} DOES NOT BALANCE"

  (0...word.size).map {|i|
    prefix, suffix = word[0...i], word[i+1..-1]
    if string_value[prefix.reverse] == string_value[suffix]
      result = prefix + " #{word[i]} " + suffix
    end
  }

  result
}
\$\endgroup\$
3
\$\begingroup\$

R, 190 bytes

As an unnamed function. I think I can get a few more, but that'll have to wait.

function(A){D=colSums(B<-(as.integer(charToRaw(A))-64)*outer(1:(C=nchar(A)),1:C,'-'));if(!length(E<-which(B[,D==0]==0)))cat(A,'DOES NOT BALANCE')else cat(substring(A,c(1,E,E+1),c(E-1,E,C)))}

Ungolfed a bit with brief explanation

function(A){
D=colSums(  #column sums of the outer function * character values
    B<-(
       as.integer(charToRaw(A))-64)    # character values
       * outer(1:(C=nchar(A)),1:C,'-') # matrix of ranges eg -3:2, -1:4, etc
       )
if(!length(
    E<-which(B[,D==0]==0) # where the colsum = 0, get the index of the zero
    ))
    cat(A,'DOES NOT BALANCE')
else 
    cat(substring(A,c(1,E,E+1),c(E-1,E,C)))  #cat the substrings
}

It doesn't put a newline at the end.

Test run

> f=
+ function(A){D=colSums(B<-(as.integer(charToRaw(A))-64)*outer(1:(C=nchar(A)),1:C,'-'));if(!length(E<-which(B[,D==0]==0)))cat(A,'DOES NOT BALANCE')else cat(substring(A,c(1,E,E+1),c(E-1,E,C)))}
> 
> f('CONSUBSTANTIATION')
CONSUBST A NTIATION
> f('WRONGHEADED')
WRO N GHEADED
> f('UNINTELLIGIBILITY')
UNINTELL I GIBILITY
> f('SUPERGLUE')
SUPERGLUE DOES NOT BALANCE
> 
\$\endgroup\$
2
\$\begingroup\$

C, 142 bytes

Credit to some user for beating me to it :)

i,l=1,j;g(char*v){for(;v[i]&&l;++i)for(j=l=0;v[j];++j)l+=(i-j)*(v[j]-64);printf(l?"%.*s DOES NOT BALANCE":"%.*s %c %s",l?i:--i,v,v[i],v+i+1);}
\$\endgroup\$
1
\$\begingroup\$

Java, 240 bytes

String b(String s){for(int i=-1,a=s.length(),l=0,r,m;++i<a;){for(r=i;--r>=0;l+=(s.charAt(r)-64));for(m=r=0;++m+i<a;r+=(s.charAt(m+i)-64)*m);if(l==r)return s.substring(0,i)+" "+s.charAt(i)+" "+s.substring(i+1);}return s+" DOES NOT BALANCE";}
\$\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.