Words from periodic table of elements

9

1

Back when I was a freshman in highschool taking chemistry, I'd look at the periodic table of elements and spell dirty words out with the number of the elements (HeCK would be 2619, 2-6-19).

I was thinking about this the other day when I saw an amazing shirt that spelled out BeEr (4-68)

So my codegolf challenge is shortest program to output a list of words you can spell with the periodic table of elements AND the number code that would represent that word.

/usr/share/dict/words or whatever dictionary you want to use for the word list. If you're using a "non-standard" word list, let us know what it is!

Rob

Posted 2012-06-09T04:22:33.697

Reputation: 299

Question was closed 2017-03-11T18:01:35.597

'The' number code? What about cases where there's more than one? E.g. CO vs Co. – Peter Taylor – 2012-06-09T07:13:11.540

I guess it depends on your code. Both are valid. – beary605 – 2012-06-09T07:33:32.163

3As I'm reading the responses below, I noticed one place that everybody could cut out a few characters. They might remove Co, Si, Sc, Os, Hs, Po, Pb, Np, No, Yb, Cs, and maybe others from their list of elements, since they can all be constructed from other elements. – PhiNotPi – 2012-06-09T12:35:29.947

@PhiNotPi, I considered dropping elements which aren't used, but that one's arguable because someone might want to use a different word list (or even one from a different language). I think I could get away with reducing the elements you suggest to one character each. – Peter Taylor – 2012-06-09T12:51:31.073

1Not Ytterbium, that's my favorite element! – Rob – 2012-06-09T15:22:28.493

2Just to clarify, the elements that I listed can always be safely removed. For example, Ytterbium can always be replaced with a Yttrium and a Boron, no matter what language the word list is in. – PhiNotPi – 2012-06-09T21:00:33.807

1I'm not quite sure whether I understand the task completely: Shall we find matching words for the elements until every element was printed, or shall we print every word from the dict, which can be combined from the element table? Or something else? – user unknown – 2012-06-10T03:50:59.390

Every word that can made from the elements that is in the dictionary. Elements can and will have to repeat. – Rob – 2012-06-10T06:22:21.383

@Rob: I would have received a notification about your comment, if you had tagged it with an @ sign, and my name. While typing the first characters of a name, you get a suggestion to complete it with TAB. The original writer of a Q or A doesn't need to be tagged - he gets informed automatically. – user unknown – 2012-06-12T15:01:45.440

Answers

6

GolfScript (339 303 302 301 294 chars)

n/{{{32|}%}:L~['']{{`{\+}+'HHeLiBeBCNOFNeNaMgAl
PSClArKCa TiVCrMnFe


ZnGaGeAsSeBrKrRbSrYZr
MoTcRuRhPdAgCd


TeIXe
BaLaCePrNdPmSmEuGdTbDy
ErTm
Lu
TaWRe
IrPtAuHgTl


AtRnFrRaAcThPaU

AmCm

EsFmMd
LrRfDbSg

MtDsRg
UutFl
Lv'{[1/{.0=96>{+}*}/]}:S~:^/}%.{L}%2$?.){=S{^?}%`+p 0}{;{L.,2$<=},.}if}do}%;

With credit to PhiNotPi whose observation on unnecessary elements allowed me to save 33 chars.

This is IMO much more idiomatic GolfScript than the previous recursive approach.

Note that I allow words in the dictionary to be mixed case (L is a function to lower-case text on the assumption that it doesn't matter if non-alpha characters get broken) but reject any with apostrophes or accents.

Since this is code golf, I've optimised for code length rather than speed. This is horrendously slow. It expects the word list to be supplied at stdin and outputs to stdout in the format:

"ac[89]"
"accra[89 6 88]"
"achebe[89 2 4]"
...

(lower-casing any mixed-case input words for which it finds a match).

If you're more interested in the elements than the numbers per se, for the low low price of 261 253 chars you can use

n/{{{32|}%}:L~['']{{`{\+}+'HHeLiBeBCNOFNeNaMgAlPSClArKCaTiVCrMnFeZnGaGeAsSeBrKrRbSrYZrMoTcRuRhPdAgCdTeIXeBaLaCePrNdPmSmEuGdTbDyErTmLuTaWReIrPtAuHgTlAtRnFrRaAcThPaUAmCmEsFmMdLrRfDbSgMtDsRgUutFlLv'[1/{.0=96>{+}*}/]/}%.{L}%2$?.){=p 0}{;{L.,2$<=},.}if}do}%;

which gives output like

"Ac"
"AcCRa"
"AcHeBe"
...

Peter Taylor

Posted 2012-06-09T04:22:33.697

Reputation: 41 901

Take the extra character out, " doesn't bother me at all. And of course peter taylor comes in and blows everyone away with golfscript. – Rob – 2012-06-09T15:23:34.683

3

Ruby - 547 393

New version, thanks for the suggestions:

e='HHeLiBeBCNOFNeNaMgAlSiPSClArKaCaScTiVCrMnFeCoNiCuZnGaGeAsSeBrKrRbSrYZrNbMoTcRuRhPdAgCdInSnSbTeIXeCsBaLaCePrNdPmSmEuGdTbDyHoErTmYbLuHfTaWReOsIrPtAuHgTlPbBiPoAtRnFrRaAcThPaUNpPuAmCmBkCfEsFmMdNoLrRfDbSgBhHsMtDsRgCnUutFlUupLvUusUuo'.scan(/[A-Z][a-z]*/).map &:upcase
r="(#{e.join ?|})"
$<.each{|w|(i=0;i+=1 until w=~/^#{r*i}$/i
$><<w;p$~.to_a[1..-1].map{|m|e.index(m.upcase)+1})if w=~/^#{r}+$/i}

e=%w{h he li be b c n o f ne na mg al si p s cl ar ka ca sc ti v cr mn fe co ni cu zn ga ge as se br kr rb sr y zr nb mo tc ru rh pd ag cd in sn sb te i xe cs ba la ce pr nd pm sm eu gd tb dy ho er tm yb lu hf ta w re os ir pt au hg tl pb bi po at rn fr ra ac th pa u np pu am cm bk cf es fm md no lr rf db sg bh hs mt ds rg cn uut fl uup lv uus uuo}
x = "(#{e.join(?|)})"
regex = /^#{x}+$/i
File.foreach('/usr/share/dict/words'){|w|
if w=~/^#{x}+$/i
puts w
i=1
i+=1 until w=~/^#{x*i}$/i 
puts $~[1..-1].map{|m|e.index(m.downcase)+1}.join ?-
end
}

uses regexes. slow, and much room for improvement but i must go now :-)

Patrick Oscity

Posted 2012-06-09T04:22:33.697

Reputation: 765

1>

  • You can spare storage by using Peter Taylor's trick (as in his original code): e='HHeLiBe...LvUusUuo'.scan(/[A-Z][a-z]*/).map &:downcase. 2) Variable regex is never used. 3) Read the words from standard input: $<.each{|w|.... With these modification the code got reduced to 410 characters.
  • < – manatwork – 2012-06-15T06:40:20.927

    I think that you can apply the same space-saving approach for unnecessary elements too, at the cost of adding two characters to the scan regex. Use space if you don't like newlines - I'm using newlines mainly so that it's not necessary to scroll to see the main loop. – Peter Taylor – 2012-06-15T13:54:43.030

    2

    Python 710 (357 + 261 + 92)

    e=". h he li be b c n o f ne na mg al si p s cl ar k ca sc ti v cr mn fe co ni cu zn ga ge as se br kr rb sr y zr nb mo tc ru rh pd ag cd in sn sb te i xe cs ba la ce pr nd pm sm eu gd tb dy ho er tm yb lu hf ta w re os ir pt au hg tl pb bi po at rn fr ra ac th pa u np pu am cm bk cf es fm md no lr rf db sg bh hs mt ds rg cn uut fl uup lv uus uuo".split()
    
    i=e.index
    def m(w,p=("",[])):
     if not w:return p
     x,y,z=w[0],w[:2],w[:3]
     if x!=y and y in e:
        a=m(w[2:],(p[0]+y,p[1]+[i(y)]))
        if a:return a
     if x in e:
        b=m(w[1:],(p[0]+x,p[1]+[i(x)]))
        if b:return b
     if z in e:
        c=m(w[3:],(p[0]+z,p[1]+[i(z)]))
        if c:return c
    
    f=open('/usr/share/dict/words','r')
    for l in f:
     x=m(l[:-1])
     if x:print x[0],x[1]
    f.close()
    

    There's sure to be room for improvement in there somewhere. It's also worth noting that the second level of indentation uses the tab character.

    It takes just over 5 seconds (on my computer) to go through the whole dictionary, producing output like this:

    acaciin [89, 89, 53, 49]
    acacin [89, 89, 49]
    acalycal [89, 13, 39, 6, 13]
    ...
    

    By adding another 18 characters, you can get output with the right capitalization:

    e=". H He Li Be B C N O F Ne Na Mg Al Si P S Cl Ar K Ca Sc Ti V Cr Mn Fe Co Ni Cu Zn Ga Ge As Se Br Kr Rb Sr Y Zr Nb Mo Tc Ru Rh Pd Ag Cd In Sn Sb Te I Xe Cs Ba La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu Hf Ta W Re Os Ir Pt Au Hg Tl Pb Bi Po At Rn Fr Ra Ac Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr Rf Db Sg Bh Hs Mt Ds Rg Cn Uut Fl Uup Lv Uus Uuo".split()
    
    i=e.index
    def m(w,p=("",[])):
     if not w:return p
     w=w.capitalize()
     x,y,z=w[0],w[:2],w[:3]
     if x!=y and y in e:
        a=m(w[2:],(p[0]+y,p[1]+[i(y)]))
        if a:return a
     if x in e:
        b=m(w[1:],(p[0]+x,p[1]+[i(x)]))
        if b:return b
     if z in e:
        c=m(w[3:],(p[0]+z,p[1]+[i(z)]))
        if c:return c
    
    OUTPUT:
    
    AcAcIIn [89, 89, 53, 49]
    AcAcIn [89, 89, 49]
    AcAlYCAl [89, 13, 39, 6, 13]
    ...
    

    You can also check individual words:

    >>> m("beer")
    ('beer', [4, 68])
    

    grc

    Posted 2012-06-09T04:22:33.697

    Reputation: 18 565

    Can you add the one that outputs proper capitalization? I think that's pretty neat and I'm pretty new to python. – Rob – 2012-06-09T15:26:13.247

    0

    Python - 1328 (975 + 285 chars of code + 68 dictionary code)

    t1={'c':6,'b':5,'f':9,'i':53,'h':1,'k':19,'o':8,'n':7,'p':15,
    's':16,'u':92,'w':74,'v':23,'y':39}
    t2={'ru':44,'re':75,'rf':104,'rg':111,'ra':88,'rb':37,
    'rn':86,'rh':45,'be':4,'ba':56,'bh':107,'bi':83,
    'bk':97,'br':35,'os':76,'ge':32,'gd':64,'ga':31,
    'pr':59,'pt':78,'pu':94,'pb':82,'pa':91,'pd':46,
    'cd':48,'po':84,'pm':61,'hs':108,'ho':67,'hf':72,
    'hg':80,'he':2,'md':101,'mg':12,'mo':42,'mn':25,
    'mt':109,'zn':30,'eu':63,'es':99,'er':68,'ni':28,
    'no':102,'na':11,'nb':41,'nd':60,'ne':10,'np':93,
    'fr':87,'fe':26,'fl':114,'fm':100,'sr':38,'kr':36,
    'si':14,'sn':50,'sm':62,'sc':21,'sb':51,'sg':106,
    'se':34,'co':27,'cn':112,'cm':96,'cl':17,'ca':20,
    'cf':98,'ce':58,'xe':54,'lu':71,'cs':55,'cr':24,
    'cu':29,'la':57,'li':3,'lv':116,'tl':81,'tm':69,
    'lr':103,'th':90,'ti':22,'te':52,'tb':65,'tc':43,
    'ta':73,'yb':70,'db':105,'dy':66,'ds':110,'at':85,
    'ac':89,'ag':47,'ir':77,'am':95,'al':13,'as':33,
    'ar':18,'au':79,'zr':40,'in':49}
    t3={'uut':113,'uuo':118,'uup':115,'uus':117}
    def p(s):
     o=0;b=0;a=[];S=str;l=S.lower;h=dict.has_key;L=len
     while o<L(s):
      D=0
      for i in 1,2,3:exec('if h(t%d,l(s[o:o+%d])) and b<%d:a+=[S(t%d[s[o:o+%d]])];o+=%d;b=0;D=1'%(i,i,i,i,i,i))
      if D==0:
       if b==3 or L(a)==0:return
       else:b=L(S(a[-1]));o-=b;a.pop()
     return '-'.join(a)
    

    For the dictionary part:

    f=open(input(),'r')
    for i in f.readlines():print p(i[:-1])
    f.close()
    

    beary605

    Posted 2012-06-09T04:22:33.697

    Reputation: 3 904

    It is really shorter to use an explicit hash initialisation than to use an explicit array initialisation and turn it into an index-of hash? – Peter Taylor – 2012-06-09T09:31:18.770

    I just used a dictionary for ease of use. Having an array of tuples would be a little more character costly. Although ordering the elements would be a good idea... – beary605 – 2012-06-09T14:02:03.160

    0

    C, 775 771 chars

    char*e[]={"h","he","li","be","b","c","n","o","f","ne","na","mg","al","si","p","s","cl","ar","k","ca","sc","ti","v","cr","mn","fe","co","ni","cu","zn","ga","ge","as","se","br","kr","rb","sr","y","zr","nb","mo","tc","ru","rh","pd","ag","cd","in","sn","sb","te","i","xe","cs","ba","la","ce","pr","nd","pm","sm","eu","gd","tb","dy","ho","er","tm","yb","lu","hf","ta","w","re","os","ir","pt","au","hg","tl","pb","bi","po","at","rn","fr","ra","ac","th","pa","u","np","pu","am","cm","bk","cf","es","fm","md","no","lr","rf","db","sg","bh","hs","mt","ds","rg","cn","uut","fl","uup","lv","uus","uu",0};
    b[99],n;
    c(w,o,l)char*w,*o,**l;{
        return!*w||!strncmp(*l,w,n=strlen(*l))&&c(w+n,o+sprintf(o,",%d",l-e+1),e)||*++l&&c(w,o,l);
    }
    main(){
        while(gets(b))c(b,b+9,e)&&printf("%s%s\n",b,b+9);
    }
    

    Input: Word per line, must be lowercase. usr/share/dict/words is fine.
    Output: Word and numbers, e.g.: acceptances,89,58,15,73,7,6,99

    Logic:
    c(w,o,l) checks the word w, starting with element l.
    Two-way recursion is used - if the first element matches the head of the element list, check the remainer of w against the full element list. If this match fails, check the word against the tail of the list.
    The buffer o accumulates the element numbers along the successful path. After a match, it will contain the list of numbers, and is printed.

    Issues:
    The list isn't encoded efficiently - too much " and ,". But this way it's easy to use. I'm sure it can be much improved, without too much cost in code.

    ugoren

    Posted 2012-06-09T04:22:33.697

    Reputation: 16 527