9
\$\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\$
5
  • \$\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\$ Jan 8, 2014 at 7:38
  • \$\begingroup\$ Related: Balance chemical equations \$\endgroup\$ Jan 8, 2014 at 8:29
  • \$\begingroup\$ @MtnViewMark It is supposed to be a program. It should take one equation per run. \$\endgroup\$
    – gthacoder
    Jan 8, 2014 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, 2014 at 0:14
  • \$\begingroup\$ @squeamishossifrage Oh, yeah. Sure. Thank you. Question is updated. \$\endgroup\$
    – gthacoder
    Jan 12, 2014 at 0:19

3 Answers 3

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.

\$\endgroup\$
2
  • \$\begingroup\$ How does that work? In your example, the coefficients of each "variable" doesn't simplify to zero. \$\endgroup\$ Jan 10, 2014 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, 2014 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.

\$\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)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.