# Crazy chemical equations

You should get string of chemical equation (no spaces, only letters (upper-case and lower-case), numbers, brackets and math signs) from user and print the answer if equation is balanced or not (any pair of positive/negative answers: Yes/No, true/false, 1/0). To make code shorter you can assume that input strings can contain only these elements: Al, Ar, B, Be, C, Cl, Cr, Cu, Fe, H, He, K, N, O, S. And one more thing: there could be - signs. It's all about math: + means addition, - means subtraction.

Examples:

Input:

C6H5COOH-O2=7CO2+3H2O


Output:

No


Input:

2Fe(CN)6+2SO2+202=Fe2(SO4)2+6C2N2


Output:

Yes


Input:

2SO2=2SO4-2O2


Output:

Yes


The shortest code wins.

• Are you looking for a function? Or a program that takes text input and gives text output? If the later, should it take and process multiple lines? Or just one equation per run? – MtnViewMark Jan 8 '14 at 7:38
• Related: Balance chemical equations – Peter Taylor Jan 8 '14 at 8:29
• @MtnViewMark It is supposed to be a program. It should take one equation per run. – gthacoder Jan 8 '14 at 19:16
• Your second and third examples are wrong. I think you meant to type 2O2 instead of 202 (two hundred and two). – r3mainer Jan 12 '14 at 0:14
• @squeamishossifrage Oh, yeah. Sure. Thank you. Question is updated. – gthacoder Jan 12 '14 at 0:19

# Mathematica 152

f=Times@@@Tr@CoefficientRules@ToExpression@(r=StringReplace)[r[
#<>")",{"="->"-(",x:_?LetterQ|")"~~y_?DigitQ:>x<>"^"<>y}],x_?UpperCaseQ:>" "<>x]⋃{}=={0}&


Result:

f@"C6H5COOH-O2=7CO2+3H2O"
f@"2Fe(CN)6+2SO2+2O2=Fe2(SO4)2+6C2N2"
f@"2SO2=2SO4-2O2"


False

True

True

I treat the chemical formula as a polynomial, e.g.

Then I just count the coefficients.

• How does that work? In your example, the coefficients of each "variable" doesn't simplify to zero. – MtnViewMark Jan 10 '14 at 16:02
• @MtnViewMark More precisely, I count powers with Tr@CoefficientRules and then multiply they by coefficients with Times@@@. For O: 2*2+2*2=4*2, for C: 2*6 = 6*2, etc. – ybeltukov Jan 10 '14 at 17:21

## Python 2.7, 316 276 chars

import re
r=re.sub
x='(^|[=+-])'
y=r'\1+\2'
z='(\w)([A-Z(])'
t=r('=','==',r(z,y,r(z,y,r('([A-Za-z)])(\d)',r'\1*\2',r('([=+-]|$)',r')\1',r(x+'(\d+)',r'\1\2*(',r(x+'([A-Z])',r'\1(\2',raw_input()))))))) E=re.findall('[A-Za-z]+',t) print all(eval(t,{f:f==e for f in E})for e in E)  It does a lot of regex-rewriting to convert the input equation into something evalable. Then it checks the equation for each element individually. For instance, the example equations rewrite to (the t variable): (C*6+H*5+C+O+O+H)-(O*2)==7*(C+O*2)+3*(H*2+O) 2*(Fe+(C+N)*6)+2*(S+O*2)+2*(O*2)==(Fe*2+(S+O*4)*2)+6*(C*2+N*2) 2*(S+O*2)==2*(S+O*4)-2*(O*2)  I'm sure there's more golf to be had on the regex part. ## Haskell, 400351 308 characters import Data.List import Text.Parsec (&)=fmap r=return s=string l f b=(>>=(&b).f) x=(=<<).replicate m=sort&chainl1(l x(concat&many1(l(flip x)n i))n)((s"+">>r(++))<|>(s"-">>r(\\))) i=between(s"(")(s")")m<|>(:[])&(l(:)(many lower)upper) n=option 1$read&many1 digit
main=getContents>>=parseTest(l(==)(s"=">>m)m)


This just might have all the golf squeezed out of it. I don't know if there is another 100 51 8 characters to be saved!

& echo 'C6H5COOH-O2=7CO2+3H2O' | runhaskell Chemical.hs
False

& echo '2Fe(CN)6+2SO2+2O2=Fe2(SO4)2+6C2N2' | runhaskell Chemical.hs
True

& echo '2SO2=2SO4-2O2' | runhaskell Chemical.hs
True


Here's the ungolf'd version, in case anyone want to follow along. It is a simple Parsec based parser:

import Control.Applicative ((<$>), (<*>)) import Data.List import Text.Parsec import Text.Parsec.String (Parser) type Atom = String {- golf'd as x -} multiple :: Int -> [Atom] -> [Atom] multiple n = concat . replicate n {- golf'd as m -} chemicals :: Parser [Atom] chemicals = sort <$> chainl1 molecules op
where
op :: Eq a => Parser ([a] -> [a] -> [a])
op = (char '+' >> return (++))
<|> (char '-' >> return (\\))

molecules :: Parser [Atom]
molecules = multiple <$> number <*> terms terms :: Parser [Atom] terms = concat <$> many1 term

term :: Parser [Atom]
term = flip multiple <$> item <*> number {- gofl'd as i -} item :: Parser [Atom] item = between (char '(') (char ')') chemicals <|> (:[]) <$> atom
where
atom :: Parser Atom
atom = (:) <$> upper <*> many lower {- gofl'd as n -} number :: Parser Int number = option 1$ read <$> many1 digit {- gofl'd as main -} main :: IO () main = getContents >>= parseTest chemEquality where chemEquality :: Parser Bool chemEquality = (==) <$> chemicals <*> (char '=' >> chemicals)