Back to the chemistry class

Introduction

One of the first things I learned in chemistry, was giving the formula for the combustion of alkanes. The most basic example was: 2CH4 + 4O2 -> 4H2O + 2CO2. Note that the equation could have been simplified by dividing every coefficient by 2, we would get CH4 + 2O2 -> 2H2O + CO2. To make things easier, we are going to ignore this to not complicate things.

You can see that with the combustion of any alkane, oxygen is used. After the reaction, only CO2 and H2O are made.

The input will always be in the form C(n)H(2n+2), with n>0. These are some example inputs:

CH4
C2H6
C3H8
C4H10
C5H12
C6H14


Useful tip:

Every alkane has a standard pattern in the combustion reaction:

2C(n)H(2n+2) + (3n+1)O2 -> (2n+2)H2O + (2n)CO2


e.g.

C4H10 gives the following equation: 2C(4)H(2*4+2) + (3*4+1)O2 -> (2*4+2)H2O + (2*4)CO2. After calculating everything, we get this final equation 2C4H10 + 13O2 -> 10H2O + 8CO2

Testcases

CH4
2CH4 + 4O2 -> 4H2O + 2CO2

C3H8
2C3H8 + 10O2 -> 8H2O + 6CO2

C4H10
2C4H10 + 13O2 -> 10H2O + 8CO2

C12H26
2C12H26 + 37O2 -> 26H2O + 24CO2


Rules

• Note that I used spaces for the examples to increase readability, these are not necessary. 2CH4 + 4O2 -> 4H2O + 2CO2 and 2CH4+4O2->4H2O+2CO2 are both valid outputs. However, if you consistently use spaces for the output, you get a -10% bonus
• This is , so the program with the least amount of bytes wins!
• totally different but related: Drawing Lewis Structures of Alkanes Commented Nov 20, 2015 at 20:18
• So we can assume that the input will be correct formulas? Commented Nov 20, 2015 at 20:26
• @TanMath, yes, you don't have to worry about invalid formulas Commented Nov 20, 2015 at 20:28
• "consistently use spaces" - would consistently using 0 spaces count?
– user45941
Commented Nov 20, 2015 at 22:59
• @Mego, no. Using 0 spaces is not using spaces at all, so the rule doesn't apply Commented Nov 20, 2015 at 23:07

Python 3, 86 * 0.9 = 77.4 bytes

s=input()
N=int(s.split('H')[1])
print("2%s + %dO2 > %dH20 + %dCO2"%(s,N*1.5-2,N,N-2))


Try it online!

Extracts the number of H's rather than the number of C's from the input. This avoid special-casing CH4 and simplifies the output expressions in terms of N=2n+2.

The output has parameters plugged in via string formatting. The first summand is just the input string, and the rest have calculated numbers plugged in. Note that N*1.5-2 (same as N*3/2-2) gives a float, but the string formatting converts it to an int.

Java, 202 * 0.9 = 181.8 bytes

Sometimes, I wonder if I'm just hurting myself with Java.

Thanks to @TNT and @TFeld for shaving off a good 20 bytes!

class A{public static void main(String[]a){String s=a[0].substring(1,a[0].indexOf("H"));long n=Long.parseLong((s.length()>0)?s:"1");System.out.printf("2%s + %dO2 > %dH2O + %dCO2",a[0],3*n+1,2*n+2,2*n);}}


Pretty simple. Basically, I cut the input from C to H, and get that substring. If it's nothing, I set n to one. Otherwise, I set it to the number between C and H. The code following just prints it out and puts it into proper notation.

Ungolfed

class A{
public static void main(String[]a) {
String s=a[0].substring(1,a[0].indexOf("H"));
long n=Long.parseLong((s.length()>0)?s:"1");
System.out.printf("2%s + %dO2 > %dH2O + %dCO2",a[0],3*n+1,2*n+2,2*n);
}
}

• Good answer, but you must use STDIN and not command line args. Though you could shorten it by using printf instead of + (-11 from your raw score if I counted correctly).
– TNT
Commented Nov 20, 2015 at 21:38
• I've been told that using command line arguments is an acceptable alternative to STDIN. Also, could you clarify how you mean for me to use printf? (A little finicky on that, haven't used it before. :D) Commented Nov 20, 2015 at 21:43
• printf uses mechanics from java.util.Formatter. You can have a string to print such as "%d" in your print statement and after it some value or variable that will be printed instead. It can be useful in situations where you have a lot of variables to print, for example.
– TNT
Commented Nov 20, 2015 at 21:53
• And the fact that command line arguments is acceptable in place of STDIN is new (and rather helpful) news to me. :)
– TNT
Commented Nov 20, 2015 at 21:55
• @VoteToClose Yes, you are hurting yourself with Java. Commented Nov 21, 2015 at 6:07

Python 2, 122 91 * 0.9 = 81.9 bytes

i=input()
n=2*int(i[1:i.find('H')]or 1)
print'2%s + %dO2 > %dH2O + %dCO2'%(i,n*3/2+1,n+2,n)


Try it online!

JavaScript ES6, 63 * 0.9 = 56.7 bytes

_=>2${_} +${$=_.splitH[1],$*1.5-2}O2 > ${$}H2O + ${$-2}CO2


Pyth, 53*0.9 = 48 bytes

Previous byte count:

• 69 * 0.9 = 62

• 63 * 0.9 = 57

• 56 * 0.9 = 50

Js>z+xz\H1s[\2z%" + %dO2 > %dH2O + %dCO2"[-*1.5J2J-J2


It is just like xnor's answer, where I use the H values. A variable J is used to store the amount of H's in the molecular formula of the molecule.

Try it here

• You spend six bytes on spacing, but gain only five bytes from the bonus, so it's not worth it. Commented Nov 26, 2015 at 2:58

f=s=>2C${(n=(s.match(/\d+(?!.*\d)/)[0]-2))>2?n/2:''}H${n+2} + ${1.5*n+1}O2 >${n+2}H2O + ${n}CO2  CJam, 45 44 bytes 2r_'H/1=[i_((_2/1$+)@@]"+%dO2>%dH2O+%dCO2"e%


Try it online

To avoid special casing CH4, I don't use the first number at all, and only extract the number after the H. This gives the value of 2n+2. The remaining values are then calculated based on that, and formatted.

Explanation:

2       Push leading 2 for output.
r       Get input.
_'H/    Copy and split at 'H.
1=      Take second part after split, this is 2n+2.
[       Start list.
i       Convert string value to integer.
_((     Copy and decrement twice, giving 2n.
_2/     Copy and divide by 2, giving n.
1$Copy the 2n to the top. + Add, to get 3n. ) Increment, giving 3n+1. We now have 2n+2, 2n, 3n+1 on stack. @@ Rotate top 3 entries twice, to get 3n+1, 2n+2, 2n. ] Close list. "+%dO2>%dH2O+%dCO2" Format string for output. e% "printf" operator.  • 2r_[[~]W=_2/(3*)\_2-]"+%dO2>%dH2O+%dCO2"e% saves a byte. Commented Nov 21, 2015 at 5:10 Perl, (84 + 1) * 0.9 = 76.5 (+1 char for running with the -n flag) My first Perl golf! @x=(1,m/C(\d)/g);$n=$x[$#x];say"2$_ + ".(3*$n+1)."O2 > ".(($n*=2)+2)."H20 +${n}CO2"


It's important that STDIN not contain a trailing newline. Example usage:

llama@llama:...code/perl/ppcg64412chemistry$printf CH4 | perl -n chemistry.pl 2CH4 + 4O2 > 4H20 + 2CO2  Ungolfed-ish: #!/usr/bin/perl use 5.10.0;$_ = 'C3H8';
my @x = (1, m/C(\d)/g);
my $n =$x[$#x]; say "2$_ + ".(3*$n+1)."O2 > ".(($n*=2)+2)."H20 + ${n}CO2";  The lines my @x = (1, m/C(\d)/g); my$n = $x[$#x];


are fairly interesting here. $#x represents the "last populated index" of @x (and SE's syntax highlighting thinks it's a comment because it's dumb), so $x[\$#x] will select the captured part of the C(\d) regex if it exists, or 1 otherwise. (Perl doesn't care that it'll be a string in all other cases except 1; you can use numerical operators on strings just fine in Perl.)

Python, 148 * 0.9 = 133 bytes

Prev byte counts

• 0.9*195 = 175
• 0.9*190 = 171
i=raw_input()
O=3*int(i[1:i.find('H')]or 1)+1;C=2*int(i[1:i.find('H')]or 1);print"2"+i+" + "+O+"O2"+" > "+i[i.find('H')+1:]+"H2O"+ " + "+C+"CO2"


Try it online!

• You don't need a space between print and a " character, and the CO2 variable could be named something shorter :) Commented Nov 20, 2015 at 20:54
• @undergroundmonorail thanks Commented Nov 20, 2015 at 20:56
• Since i[1] is guaranteed to be either "H" or a digit, you can save another byte with if i[1]>"9" (or replace "9" with any other character with an ascii value from 58 to 71) Commented Nov 20, 2015 at 21:14

𝔼𝕊𝕄𝕚𝕟, 64 * 0.9 = 57.6 bytes

a=ïČH”[1],2⦃ï} + ⦃a*1.5-2}O2 > ⦃a}H2O + ⦃a-2}CO2


Try it here (Firefox only)

Explanation

a=ïČH”[1],      // split input along H to get 2n+2
  2⦃ï}          // 2C(n)H(2n+2) – this is the same as 2[input alkane's formula]
+ ⦃a*1.5-2}O2 // + 2(3n+1)O2
> ⦃a}H2O      // > (2n+2)H2O
+ ⦃a-2}CO2    // + (2n)O2
// implicitly output the template string above


Pyth, 40 bytes

s[2z\+h*3Jv|hctz\H\1"O2>"yhJ"H2O+"yJ"CO2


JS, 118 (106) bytes

x=prompt();y=x.replace("CH","C1H").match(/\d{1,}/g)[0];alert(2+x+" + "+(3*y+1)+"O2 > "+(2*y+2)+"H2O + "+(2*y)+"CO2");


MATLAB, 96 * 0.9 = 86.4 bytes

s=input('');i=[sscanf(s,'C%dH'),1];n=i(1);fprintf('%s + %dO2 > %dH2O + %dCO2',s,3*n+1,2*n+2,2*n)


Fairly self explanatory. Takes an input string (need to wrap it in quote marks so MATLAB doesn't try to execute it!). Then converts the number between the C and the H in the input to decimal. The value 1 is appended as an array to the output of sscanf so that in the case CH4 when we extract the first index in the array into n we get a 1 if there was no number between the C and H. Then just prints out with the spaces following the formula in the question.

This should also work with Octave using the online interpreter here.

Clojure/ClojureScript, 98*0.9 = 88.2 bytes

#(let[n(max 1(int((re-find #"C(.*)H"%)1)))m(* 2 n)](str "2"%" + "(inc(* 3 n))"O2 > "(+ 2 m)"H2O + "m"CO2"))


Creates an anonymous function. Try it by going here and entering (def f #(let...)), then (f "C3H8").

Excel, 123 * 0.9 = 110.7 bytes

=="2"&A1&" + "&(3*MID(A1,FIND("H",A1)+1,9)/2-2)&"O2 > "&MID(A1,FIND("H",A1)+1,9)&"H2O + "&(MID(A1,FIND("H",A1)+1,9)-2)&"CO2"


If we could take CH4 input as C1H4, can be reduced to 122 * 0.9 = 109.8 bytes

="2"&A1&" + "&3*MID(A1,2,FIND("H",A1)-2)+1&"O2"&" > "&MID(A1,FIND("H",A1)+1,9)&"H2O + "&(MID(A1,FIND("H",A1)+1,9)-2)&"CO2"


Jelly, 33 bytes

ṣ”HṪVµ2³”+2⁸_©+H“O2>”⁸“H2O+”®“CO2


Try it online!

The bonus doesn't help here.

C++ (clang), 160 bytes

#include<iostream>
int main(){int n=1,t;std::cin.get();std::cin>>n;t=2*n;printf("2C");n-1&&printf("%i",n);printf("H%i + %iO2 > %iH2O + %iCO2",t+2,t+n+1,t+2,t);}


Try it online!

A bit more that I expected. Reads first char and discards it, then reads int and outputs the result. Problem is with n being 1. I can't think of shorter way to output it.

Ungolfed

#include <iostream>
int main()
{
int n = 1, t;
std::cin.get();
std::cin >> n;
t = 2 * n;
printf("2C");
n - 1 && printf("%i", n);
printf("H%i + %iO2 > %iH2O + %iCO2", t + 2, t + n + 1, t + 2, t);
}

• Now works for CH4 152 bytes Commented Feb 5, 2023 at 5:55

F# (.NET Core), 113 bytes

let s=stdin.ReadLine()
float s.[1+s.IndexOf 'H'..]|>fun f->printf"2%s + %gO2 > %gH2O + %gCO2"s<|f*1.5-2.<|f<|f-2.


Try it online!