10
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ 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? \$\endgroup\$ – MtnViewMark Jan 8 '14 at 7:38
  • \$\begingroup\$ Related: Balance chemical equations \$\endgroup\$ – Peter Taylor Jan 8 '14 at 8:29
  • \$\begingroup\$ @MtnViewMark It is supposed to be a program. It should take one equation per run. \$\endgroup\$ – gthacoder Jan 8 '14 at 19:16
  • \$\begingroup\$ Your second and third examples are wrong. I think you meant to type 2O2 instead of 202 (two hundred and two). \$\endgroup\$ – r3mainer Jan 12 '14 at 0:14
  • \$\begingroup\$ @squeamishossifrage Oh, yeah. Sure. Thank you. Question is updated. \$\endgroup\$ – gthacoder Jan 12 '14 at 0:19
2
\$\begingroup\$

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.

enter image description here

Then I just count the coefficients.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ How does that work? In your example, the coefficients of each "variable" doesn't simplify to zero. \$\endgroup\$ – MtnViewMark Jan 10 '14 at 16:02
  • \$\begingroup\$ @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. \$\endgroup\$ – ybeltukov Jan 10 '14 at 17:21
2
\$\begingroup\$

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.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Haskell, 400 351 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)
| 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.