29
\$\begingroup\$

How many atoms in the hydrocarbon?

A hydrocarbon is a chemical compound which consists of only hydrogen and carbon atoms. For this challenge, we will only consider the three simplest kinds of hydrocarbons: alkanes, alkenes, and alkynes with no branches.

An alkane with \$n\$ carbon atoms contains \2ドルn+2\$ hydrogen atoms. An alkene with \$n\$ carbon atoms contains \2ドルn\$ hydrogen atoms. An alkyne with \$n\$ carbon atoms contains \2ドルn-2\$ hydrogen atoms.

Each kind of hydrocarbon is named with a prefix indicating the number of carbon atoms it contains, followed by the suffix ane, ene, or yne if it is an alkane, alkene, or alkyne respectively. The numerical prefixes are as follows:

1 <-> meth
2 <-> eth
3 <-> prop
4 <-> but
5 <-> pent
6 <-> hex
7 <-> hept
8 <-> oct
9 <-> non
10 <-> dec

For example, we can see propane has 3 carbon and 8 hydrogen atoms, and heptyne has 7 carbon and 12 hydrogen atoms.

Challenge

Your task is to write a function or program that receives a string or list of characters representing the name of a hydrocarbon, and produces or outputs the number of carbon and hydrogen atoms in a molecule of that hydrocarbon.

For each of the 30 hydrocarbon names, the code must accept at least one possible capitalization of that name. For example, it is fine if your code works for mEthane but not methane, and ETHAnE but not ETHANE, and Propane but not propane. The inputs methene and methyne may give undefined output since those are not real chemicals.

The input and output can be in any convenient format. You don't need to label which number represents carbon and which represents hydrogen, just keep the order of the numbers consistent.

You may assume the input will correspond to a valid hydrocarbon, and there are at most 10 carbon atoms.

Examples

Possible Input -> Possible Output
Methane -> 1 4
propane -> 3 8
Heptyne -> 7 12
Decene -> 10 20

Rules

  • No standard loopholes.
  • Shortest code in bytes wins.
asked Dec 5, 2019 at 20:31
\$\endgroup\$
10
  • 3
    \$\begingroup\$ @Grimmy Yes, if it works for hexANe that is good enough. And it is reasonable to allow undefined behaviour for methene and methyne since they aren't real chemicals, though I wasn't expecting that to help anyone's solutions. \$\endgroup\$ Commented Dec 6, 2019 at 14:44
  • 2
    \$\begingroup\$ @Skyler As was pointed out in a now-deleted comment, the -yne suffix actually means the molecule has a triple bond between carbon atoms. Obviously a single carbon atom does not have a triple bond in it, so we don't call it methyne. \$\endgroup\$ Commented Dec 6, 2019 at 19:38
  • 1
    \$\begingroup\$ "the code must accept at least one possible capitalization of that name" <-- isn't this a loophole that allows you to just require the invoking user to encode the result in the case bits? Then you can say inputs that produce wrong outputs are just not the supported capitalization. \$\endgroup\$ Commented Dec 7, 2019 at 21:29
  • 1
    \$\begingroup\$ @79037662: Well, it's not clear if it was intentional or not, but I think the problem is very different if that's allowed. \$\endgroup\$ Commented Dec 8, 2019 at 0:46
  • 1
    \$\begingroup\$ @Skyler Now you’re just switching up the meaning of "pure". When you said methyne would just be pure carbon, you obviously meant something with molecular formula C, not something composed entirely of C (that would be graphene). Pure gold is like graphene in that regard. \$\endgroup\$ Commented Dec 12, 2019 at 16:02

13 Answers 13

15
\$\begingroup\$

05AB1E, (削除) 27 26 (削除ここまで) 24 bytes

Saved 1 byte thanks to @KevinCruijssen
Saved 2 bytes thanks to @Grimmy

Note: This code was based on my understanding that only the capitalization of the first letter was customizable. It has since been clarified that it applies to all letters, leading to this significantly shorter answer by Grimmy.

Expects mEpBPhHond for the capitalization of the first letter.

ćC•>·¿*•s÷θD>,2I3(èH÷+·,

Try it online!

How?

We define the following magic constant:

$$M=1902159854$$

The number of carbon atoms is given by:

$$c=\left(\left\lfloor\frac{M}{n}\right\rfloor\bmod 10\right)+1$$

where \$n\$ is the first character of the input turned into an 05AB1E code point (0-9, A-Z, a-z, ...).

 input | n | floor(M/n) | mod 10
-------+-----+------------+--------
 meth- | 48 | 39628330 | 0
 Eth- | 14 | 135868561 | 1
 prop- | 51 | 37297252 | 2
 But- | 11 | 172923623 | 3
 Pent- | 25 | 76086394 | 4
 hex- | 43 | 44236275 | 5
 Hept- | 17 | 111891756 | 6
 oct- | 50 | 38043197 | 7
 non- | 49 | 38819588 | 8
 dec- | 39 | 48773329 | 9

Commented

 # example input: 'Heptyne'
ć # extract the first character -> 'H'
 C # turn it into an integer -> 17
 •>·¿*• # push the magic constant 1902159854
 s÷ # swap + integer division -> 1902159854 / 17 = 111891756
 θ # keep the last digit (therefore a modulo 10) -> 6
 D> # duplicate and increment the copy
 , # print the number of carbon atoms
 2 # push 26
 I # push the input string
 3(è # extract the 3rd to last character -> 'y'
 H # parse it as base-36 -> 34
 ÷ # integer division -> 26 / 34 = 0
 + # add to the number of carbon atoms - 1 -> 6
 · # double
 , # print the number of hydrogen atoms
answered Dec 6, 2019 at 4:16
\$\endgroup\$
3
  • 2
    \$\begingroup\$ I'm sure @Grimmy will come in and golf 5 bytes away, since he usually does that to my 05AB1E answers. ;) But here is a straightforward -1 byte for now: ¹ can be s (since the remainder-list from ć is still on the stack), and then the second Ç can be removed: 26 bytes. \$\endgroup\$ Commented Dec 6, 2019 at 7:47
  • \$\begingroup\$ -2 bytes. Note that there's no need to brute-force the magic constant, you can just use the chinese theorem. \$\endgroup\$ Commented Dec 6, 2019 at 13:42
  • 1
    \$\begingroup\$ My bad, the title of your answer says 05AB1E (legacy), but the 24 I suggested only works on modern 05AB1E due to my use of C and H. Here's a 23 that works on both modern and legacy: Ç•cýºÍ•s÷ćθ>=s3(è6%-Ì·, (expects MEpbPhHond capitalization). \$\endgroup\$ Commented Dec 6, 2019 at 16:54
6
\$\begingroup\$

05AB1E, (削除) 16 (削除ここまで) (削除) 12 (削除ここまで) 11 bytes

.uJ4ôCx<O1ǝ

Try it online!

This takes full advantage of the rule that only one possible capitilization has to be handled for each input. All inputs are at least 6 letters long, so we can store 6 bits of data in the capitilization. 4 of those bits are used to store the carbon count, and the remaining 2 store half of the extra hydrogen count (0 for alkynes, 1 for alkenes, 2 for alkanes).

.u # uppercase? (returns a list of 0s and 1s)
 J # join that list to a string
 4ô # split in chunks of 4 digits
 C # convert each chunk from binary
 x # double each, without popping the original list
 < # -1 from each
 O # sum
 1ǝ # replace the second element of the list with this sum

Alternative 11:

.u2β3‰<.\¦ƶ

Try it online!

answered Dec 6, 2019 at 12:57
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Perfectly acceptable. \$\endgroup\$ Commented Dec 6, 2019 at 14:45
  • 3
    \$\begingroup\$ Stupid rules deserve brilliant answers. ;) \$\endgroup\$ Commented Dec 8, 2019 at 12:13
5
\$\begingroup\$

R, (削除) 96 (削除ここまで) (削除) 86 (削除ここまで) (削除) 82 (削除ここまで) 79 bytes

`!`=utf8ToInt;(5-rev(K<-!scan(,""))[3]%%16)/2*0:1+match(K[1],!"mepbPhHond")*1:2

Try it online!

Accepts the prefixes with capitalization mepbPhHond in order; returns c(Carbon, Hydrogen).

yea for this answer.

Thanks to Robin Ryder for golfing down 4 bytes.

answered Dec 5, 2019 at 20:56
\$\endgroup\$
3
  • \$\begingroup\$ yea this is the kind of answer I was looking forward to with the capitalization rule :) \$\endgroup\$ Commented Dec 5, 2019 at 21:34
  • \$\begingroup\$ 82 bytes \$\endgroup\$ Commented Dec 5, 2019 at 22:31
  • \$\begingroup\$ @RobinRyder aahhh, I was too fixated on the match. I messed with the arithmetic as well to cut down three more bytes. \$\endgroup\$ Commented Dec 5, 2019 at 23:06
5
\$\begingroup\$

JavaScript (ES6), 62 bytes

Similarly to other answers, expects all names in lowercase, except Pent- and Hept-. Returns [carbon, hydrogen].

s=>[n='epbPhHond'.search(s[0])+2,n+/a/.test(s)-/y/.test(s)<<1]

Try it online!


JavaScript (ES6), (削除) 84 (削除ここまで) 79 bytes

A version where the capitalization doesn't matter. Returns [carbon, hydrogen].

s=>[n=-~'519.80.76423'[parseInt(s[0]+s[2],28)%17],n+/a/.test(s)-/y/.test(s)<<1]

Try it online!

How?

Carbon

We can concatenate the first and third characters of each prefix to build a unique string identifier.

Example: methmt

We can convert this string ID to an integer ID in \$[0..11]\$ (still unique) by parsing it as base-28 and applying a modulo \17ドル\$ (these values were found with a brute-force search).

Because the character set of base-28 is '0' to 'r', the parsing stops if a character above 'r' is encountered.

Example: mtm\22ドル \bmod 17=5\$

The results are summarized in the following table:

 input | key | base 28 -> dec. | mod 17
-------+------+-----------------+--------
 meth- | 'm' | 22 | 5
 eth- | 'eh' | 409 | 1
 prop- | 'po' | 724 | 10
 but- | 'b' | 11 | 11
 pent- | 'pn' | 723 | 9
 hex- | 'h' | 17 | 0
 hept- | 'hp' | 501 | 8
 oct- | 'o' | 24 | 7
 non- | 'nn' | 667 | 4
 dec- | 'dc' | 376 | 2

Hydrogen

Neither 'a' nor 'y' appears in any of the prefixes. Therefore, it is safe to test whether the suffix is -ane or -yne by looking for these letters in the entire input string.

The following expression:

/a/.test(s) - /y/.test(s)

evaluates to either \$-1\$ for -yne, \0ドル\$ for -ene or \1ドル\$ for -ane.

Given the number \$n\$ of carbon atoms, the number of hydrogen atoms is:

(n + /a/.test(s) - /y/.test(s)) << 1

(and because << has a higher precedence than + and -, the parentheses can be omitted)

answered Dec 5, 2019 at 20:58
\$\endgroup\$
2
  • \$\begingroup\$ Hi Arnauld - would you mind adding some explanation - especially for the second version? I see that it works, but have no idea how (let alone how did you get there...) \$\endgroup\$ Commented Dec 6, 2019 at 22:06
  • 1
    \$\begingroup\$ @G0BLiN I've added an explanation of my original answer. Please let me know if something is still unclear. \$\endgroup\$ Commented Dec 7, 2019 at 11:55
4
\$\begingroup\$

Pyth, (削除) 33 (削除ここまで) 31 bytes

Kx"mepbPhHond"hQhKy+K/%CePPQ7 3

Try it online!

Uses, as you can see, mepbPhHond capitalization. Probably can be golfed much further. Returns carbon, hydrogen on newlines

How it works

Kx"mepbPhHond"hQhKy+K/%CePPQ7 3
 x hQ - The index of the first letter of the input
 "mepbPhHond" - in "mepnPhHond"
K hK - Assign to K... and then print K+1
 CePPQ - The codepoint of the third last character 
 in the input (Q[:-1][:-1][-1])
 /% 7 3 - Modulo 7 divided by 3 (ane, ene, yne -> 2, 1, 0)
 +K - ... plus K
 y - ... times 2, and print implicitly
answered Dec 5, 2019 at 22:04
\$\endgroup\$
3
\$\begingroup\$

Python 3.8, 60 bytes

As other answers, all the names except for those starting with Prop- or Hept-, must be lowercase.

lambda x:(c:=' mePbphHond'.find(x[0]),c+'ea'.find(x[-3])<<1)

-4 bytes thanks to @Arnauld

Try it online!


Fun fact:

Another interesting fact I observerd is the following one:

  • \$ord(a)=97\to9-7=2\$ which is the number we have to add for alkanes.
  • \$ord(e)=101\to1-0-1=0\$ which is the number we have to add for alkenes.
  • \$ord(y)=121\to1-2-1=-2\$ which is the number we have to add for alkynes.

I don't think that I can modify my answer using this way to be less bytes thank it is right now, but I thought it was worth mentioning and maybe another answer can use it effectively!

An implementation of the above idea is the following one:

lambda x:(c:=' mePbphHond'.find(x[0]),2*c+reduce(lambda i,j:i-j,map(int,str(ord(x[-3])))))
from functools import reduce

which obviously is much more bytes (119).

answered Dec 6, 2019 at 1:41
\$\endgroup\$
2
  • \$\begingroup\$ 60 bytes \$\endgroup\$ Commented Dec 6, 2019 at 2:52
  • \$\begingroup\$ @Arnauld Thanks! That's way more elegant :) \$\endgroup\$ Commented Dec 6, 2019 at 2:55
2
\$\begingroup\$

Python 2, 66 bytes

def f(s):n='mePbpHhond'.find(s[0]);return-~n,2*(n+ord(s[-3])%50%3)

Try it online!

Over thinking it a bit. Accepts only lower case, except for 'Prop' and 'Hept' (which must be capitalized). Returns (carbon, hydrogen).

Python 2, (削除) 84 (削除ここまで) 82 bytes

def f(s):n=int('8702563914'[hash(s[:-3])%876%10]);return n+1,2*(n+ord(s[-3])%50%3)

Try it online!

Only accepts lower case.

answered Dec 5, 2019 at 21:19
\$\endgroup\$
2
  • \$\begingroup\$ -1 with %7/3 \$\endgroup\$ Commented Dec 5, 2019 at 22:23
  • \$\begingroup\$ %11%5 works to give already-doubled values. \$\endgroup\$ Commented Dec 6, 2019 at 8:21
2
\$\begingroup\$

Ruby, (削除) 74 (削除ここまで) 67 bytes

->s{z=" etthroutenexepctonec".index s[1,2];[z/2,z-2*(s[-3]<=>?e)]}

Try it online!

Thanks @Value Ink for (削除) golfing it for me. :-) (削除ここまで) -7 bytes

answered Dec 6, 2019 at 7:16
\$\endgroup\$
2
2
\$\begingroup\$

Wolfram Language (Mathematica), (削除) 26 (削除ここまで) 25 bytes

Tally@*AtomList@*Molecule

Thanks to att for the byte reduction.

enter image description here

answered Jul 14, 2021 at 10:52
\$\endgroup\$
9
  • \$\begingroup\$ Compose the functions Tally@*AtomList@*Molecule for -1 \$\endgroup\$ Commented Jul 14, 2021 at 18:02
  • \$\begingroup\$ @att Thanks! In general, based on your suggestion, it seems when you have a single argument at the end, you don't need the @#&. But why use @* in this case, since you can simply do Tally@AtomList@Molecule for –3? I.e., both f@*g@*h@x andf@g@h@x give f[g[h[x]]]. I can see @* behaves differently from @ in cases when the latter would need to be followed by enclosing brackets, e.g. (adapted from Martin Ender's example in the MMA golfing tips ques.), Last@*Range /@ Range[5] works, but Last@Range /@ Range[5] doesn't.... \$\endgroup\$ Commented Jul 14, 2021 at 21:35
  • \$\begingroup\$ ...But you can do Last[Range /@ Range[5]] for the same no. of bytes as Last@*Range /@ Range[5]. I've not used @* before, so I'd be interested to see an example in which it saves bytes over@. \$\endgroup\$ Commented Jul 14, 2021 at 21:35
  • \$\begingroup\$ f@g@h is f[g[h]], which when applied on an argument x is obviously not what you want (f[g[h]][x]). It only works as intended when used as a snippet, inserting the input into the source code. \$\endgroup\$ Commented Jul 14, 2021 at 22:01
  • 1
    \$\begingroup\$ [] has higher precedence than @*//* - see this page. It's useful for composing operator forms (e.g. Last@*Position[0] finds the last position of a 0). \$\endgroup\$ Commented Jul 18, 2021 at 4:46
1
\$\begingroup\$

Python 3, 83 bytes

x=input();n=list('_mepbPhHond').index(x[0]);print(n,2*n+{'a':2,'e':0,'y':-2}[x[-3]])

Try it online!

-51 bytes thanks to 79037662

answered Dec 5, 2019 at 21:26
\$\endgroup\$
1
1
\$\begingroup\$

Charcoal, 39 bytes

≔⊘+3⌕"↶↓>AkQN!{a6⟧"...θ−Lθ5ηI⟦η⊗−+ηNoθaNoθy

Try it online! Link is to verbose version of code. Takes input in lower case and outputs carbon and hydrogen atoms on separate lines. Explanation:

...θ−Lθ5

Remove the last 5 characters of the input.

⌕"↶↓>AkQN!{a6⟧"...

Search for the resulting prefix within the compressed string e prb peh heo n d. Note that there's a space before the e, so that the the prefixes are found at positions -1 for me(th?ne), 1 for e(th?ne), 3 for pr(op?ne) etc.

≔⊘+3...η

Add 3 to the position, then halve and store the resulting number of carbon atoms.

I⟦η

Output the carbon atoms...

⊗−+ηNoθaNoθy

... and adjust for whether there is an a or y in the input, before doubling to give the number of hydrogen atoms.

answered Dec 5, 2019 at 23:59
\$\endgroup\$
1
\$\begingroup\$

C# (Visual C# Interactive Compiler), 65 bytes

x=>(l=" mepbPhHond".IndexOf(x[0]),~-l+x[x.Count-3]%7/3<<1);int l;

Try it online!

answered Dec 6, 2019 at 2:02
\$\endgroup\$
1
\$\begingroup\$

GolfScript, (削除) 32 (削除ここまで) 30 bytes

Thanks to this user for pointing out that I forgot to account for -ane, -ene, -yne

.0="mepbPhHond"?).@-3=7%3/(+2*

Try it online!

This uses the same concept as in this answer

Explanation:

.0= Make a copy of input and select first letter
 "mepbPhHond"?) Find index of letter and increase by one for number of carbons
 .@ Duplicate for number of hydrogens and bring input to top of stack
 -3= Get the a, e, or y in ane, ene, yne
 7%3/ Ascii value mod 7 integer divide 3
 (+ Decrement and add to number of carbons
 2* Double

Uses mepbPhHond capitalization.

Example Execution: Input: propene

.0= Stack: 'propene' 'p'
 "mepbPhHond"?) Stack: 'propene' 3
 .@ Stack: 3 3 'propene'
 -3= Stack: 3 3 'e'
 7%3/ Stack: 3 3 1
 (+ Stack: 3 3
 2* Stack: 3 6
answered Dec 6, 2019 at 4:08
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.