25
\$\begingroup\$

Using the following table (source) write some code that takes the names of two planets and returns the distance between them:

+-------------------+---------------+
|      Planets      | Distance (km) |
+-------------------+---------------+
| Mercury -> Venus  |      50290000 |
| Venus -> Earth    |      41400000 |
| Earth -> Mars     |      78340000 |
| Mars -> Jupiter   |     550390000 |
| Jupiter -> Saturn |     646270000 |
| Saturn -> Uranus  |    1448950000 |
| Uranus -> Neptune |    1627450000 |
| Neptune -> Pluto  |    1405380000 |
+-------------------+---------------+

Examples, input then output:

Mercury, Mars
170030000
Neptune, Jupiter
-3722670000
Earth, Earth
0

Note the negative sign there, as Jupiter comes before Neptune. They are also all integers.

Pluto doesn't have to be included (mostly because of a weird orbit which makes it hard to work out the distance - that distance given is my own calculation, but as Pluto is all famous now...).

By distances between planets I'm meaning orbits - I don't expect a date and working out where they are.

This is code golf, shortest code wins.

\$\endgroup\$
  • 10
    \$\begingroup\$ +1 for not "coz Pluto ain't a planet" \$\endgroup\$ – Optimizer Jul 15 '15 at 16:04
  • \$\begingroup\$ @Optimizer I'm doing a project which needs the distances and nobody can agree! I resorted to using it's orbital period and orbital speed... \$\endgroup\$ – Tim Jul 15 '15 at 16:04
  • \$\begingroup\$ Can our function/program return a float? i.e. Mercury, Mars -> 170030000.0? \$\endgroup\$ – Kade Jul 15 '15 at 16:06
  • 8
    \$\begingroup\$ It's implied, but are we assuming the holy moment in time where the planets are all in a straight line and the distance between any two non-adjacent planets is the sum of distances in between? \$\endgroup\$ – Sp3000 Jul 15 '15 at 16:10
  • 3
    \$\begingroup\$ Is there a penalty for including Pluto (besides the bytes)? I feel kinda bad for it, it just had it's big day and all... \$\endgroup\$ – DeadChex Jul 15 '15 at 16:23

16 Answers 16

24
\$\begingroup\$

CJam, 54 51 44 bytes

2{"X84VT:Z/3KD'Y->>6\ Ta "3/r26b93%=70be4}*-

Try it online in the CJam interpreter.

Idea

We use a simple hashing function to identify all eight planets. By considering each name as the array of its code points, converting them from base 26 to integer and taking the result modulo 93 then modulo 8, Mercury, Venus, Earth, etc. map to 2, 4, 0, 1, 3, 5, 6 and 7.

Now, we choose a point that lies 320,000 km behind Neptune and calculate the distances of all eight planets to that point. After dropping four trailing zeroes and reordering the planets so that they fit the 8 indexes from above, we obtain the array

[435172 427338 444341 372299 439312 307672 162777 32]

which, if we encode each integer in base 70, yields the following:

[
   [1 18 56 52] [1 17 14 58] [1 20 47 51] [1 5 68 39]
   [1 19 45 62] [  62 55 22] [  33 15 27] [       32]
]

Remembering that two adjacent digits (A B) can be replaced with ((A-1) (B+70)), we can modify the array from above so that all integers can be encoded as printable ASCII characters:

["X84" "VT:" "Z/3" "KD'" "Y->" ">6\\" " Ta" " "]

Code

2{                         e# Do twice:   
  "X84VT:Z/3KD'Y->>6\ Ta " e#   Push that string.
  3/                       e#   Chop it into chunks of length 3.
  r                        e#   Read a token from STDIN.
  26b                      e#   Convert from base 26 to integer.
  93%                      e#   Take the result modulo 93.
  =                        e#   Retrieve the chunk at that index.
  70b                      e#   Convert from base 70 to integer.
  e4                       e#   Multiply by 10,000.
}*                         e#
-                          e# Subtract the two results.
\$\endgroup\$
10
\$\begingroup\$

Python 2, 149 147 142 138 128 123 119 Bytes

Just uses a simple lookup to figure out which distances to use :) This defines an anonymous function, so to use it you'll need to give it a name.

Thanks to Sp3000 for ideas that saved a bunch of bytes!

lambda*x:int.__sub__(*[[0,5029,9169,17003,72042,136669,281564,444309]['MeVeEaMaJuSaUr'.find(k[:2])/2]for k in x])*~9999

Indented properly and ungolfed slightly for readability:

def f(*x):
 d=0,5029,9169,17003,72042,136669,281564,444309
 a,b=[d['MeVeEaMaJuSaUr'.find(k[:2])/2]for k in x]
 print(b-a)*10000

Call like so:

f("Mercury","Mars")    -> 170030000
f("Neptune","Jupiter") -> -3722670000L
\$\endgroup\$
  • \$\begingroup\$ Your output is missing a 0, but you seem to be multiplying by the right amount. \$\endgroup\$ – Tim Jul 15 '15 at 16:31
  • \$\begingroup\$ @Tim I messed up in the example call, it does have a fourth 0 at the end :P \$\endgroup\$ – Kade Jul 15 '15 at 16:32
  • \$\begingroup\$ You are forgetting pluto? \$\endgroup\$ – Will Jul 15 '15 at 20:08
  • \$\begingroup\$ @Will Pluto doesn't have to be included... \$\endgroup\$ – Kade Jul 15 '15 at 20:09
  • \$\begingroup\$ (You'll save at least two bytes if you copy that find returning -1 trick from my entry, and then you'll pull ahead of me :) \$\endgroup\$ – Will Jul 15 '15 at 20:28
8
\$\begingroup\$

Prolog, 190 174 151 bytes

Thanks to Fatalize for guidance.

g(A,X):-sub_atom(A,2,2,_,B),member(B:X,[rc:0,nu:5029,rt:9169,rs:17003,pi:72042,tu:136669,an:281564,pt:444309]).
s(A,B,R):-g(A,X),g(B,Y),R is(Y-X)*10^4.

$ gprolog --consult-file src.pro 
| ?- s('Mercury','Mars',R).   
R = 170030000 ? 
yes
| ?- s('Neptune','Jupiter',R).
R = -3722670000 ? 
yes
| ?- s('Earth','Earth',R).    
R = 0 ? 
yes
\$\endgroup\$
  • \$\begingroup\$ Why don't you return this result directly like this s(A, B, R) instead of writingR? Nothing is specified for outputs so a predicate return should be fine. \$\endgroup\$ – Fatalize Jul 15 '15 at 19:42
  • \$\begingroup\$ You can also shave off 22 bytes by modifying predicate g to g(A,X):-sub_atom(A,2,2,_,B),member(B:X,[rc:0,nu:5029,rt:9169,rs:17003,pi:72042,tu:136669,an:281564,pt:444309]). and removing all facts for planets. It's less cool than =.. but it's shorter to get a key-value mapping \$\endgroup\$ – Fatalize Jul 15 '15 at 19:48
7
\$\begingroup\$

JavaScript (ES6), 115 110 bytes

(x,y,g=k=>"Me0Ve5029Ea9169Ma17003Ju72042Sa136669Ur281564Ne444309".match(k[0]+k[1]+"(\\d*)")[1]*1e4)=>g(y)-g(x)

This is an anonymous function, so you will need to store it in a variable (f=...; f("Earth", "Mercury")) or use it as a parenthesised expression ((...)("Earth", "Mercury").

That messy string is the first two letters of each planet, followed by that planet's distance from Mercury (divided by 10000, to save space). The inner function g does the following:

  1. takes a name (k),
  2. reduces it to the first two letters (k[0]+k[1]),
  3. uses a regex match to find the corresponding distance from Mercury, divided by 10000 (e.g., the "Earth" regex looks like Ea(\d*)),
  4. multiplies the value by 10000 (1e4) and returns the result.

By subtracting one Mercury-distance from the other, we get the distance between the planets.

\$\endgroup\$
  • \$\begingroup\$ @vihan1086 Aha, I have made the classic blunder of confusing code-point-value with actual byte representation :( \$\endgroup\$ – apsillers Jul 15 '15 at 19:55
  • 1
    \$\begingroup\$ UTF-8 is just the wrong encoding for this trick. All characters returned by btoa have code points below 256, so ISO 8859-1 will encode each character using a single byte. \$\endgroup\$ – Dennis Jul 16 '15 at 2:35
7
\$\begingroup\$

Java, 274 272 264 bytes (includes Pluto!)

  void p(String p,String l){String q="MeVeEaMaJuSaUrNePl";int w=q.indexOf(p.substring(0,2))/2,e=q.indexOf(l.substring(0,2))/2,m=1,t=e,d[]={5029,4140,7834,55039,64627,144895,162745,140538};long h=0;if(w>e){e=w;w=t;m=-1;}for(;e-->w;)h+=d[e]*1e4;System.out.print(h*m);}

Input/Output:

p("Mercury","Mars") --> 170030000
p("Mars","Mercury") --> -170030000
p("Earth","Earth")  --> 0

Spaced and tabbed:

void p(String p,String l){
    String q="MeVeEaMaJuSaUrNePl";
    int w=q.indexOf(p.substring(0,2))/2,
      e=q.indexOf(l.substring(0,2))/2,
      m=1,
      t=e,
      d[]={5029,4140,7834,55039,64627,144895,162745,140538};
    long h=0;
    if(w>e){
        e=w;
        w=t;
        m=-1;
    }
    for(;e-->w;)
        h+=d[e]*1e4;
    System.out.print(h*m);
}
\$\endgroup\$
  • 1
    \$\begingroup\$ You could cut off a lot by dividing all numbers by 1000 \$\endgroup\$ – Tim Jul 15 '15 at 16:31
  • \$\begingroup\$ Just about to do that! \$\endgroup\$ – DeadChex Jul 15 '15 at 16:31
  • 1
    \$\begingroup\$ You can also put both the int and int[] declarations on one line if the array comes last: Like int i=0,j=1,k[]={}; \$\endgroup\$ – Geobits Jul 15 '15 at 16:55
  • 1
    \$\begingroup\$ You can shave off two bytes by replacing 10000 with 1e4. \$\endgroup\$ – Anubian Noob Jul 16 '15 at 17:59
  • 1
    \$\begingroup\$ since we know e > w you can trim a character using the goes to operator: while(e-->w) which is 12 characters, instead of for(;e--!=w;) which is 13. \$\endgroup\$ – corsiKa Jul 16 '15 at 21:11
6
\$\begingroup\$

Python, 118 bytes

n=lambda x:(5029,9169,17003,72042,136669,281564,444309,0)["VeEaMaJuSaUrNe".find(x[:2])/2]*10000
f=lambda a,b:n(b)-n(a)

n is a function that returns distance from Mercury.

The string "VeEaMaJuSaUrNe" is the first two characters of all planet names except Mercury. find cannot find Mercury so will return -1. -1/2 is still -1 so this is the last element in the tuple, which is 0.

Simple test code:

test = (
    ("Mercury","Venus",50290000),
    ("Venus","Earth",41400000),
    ("Earth","Mars",78340000),
    ("Mars","Jupiter",550390000),
    ("Jupiter","Saturn",646270000),
    ("Saturn","Uranus",1448950000),
    ("Uranus","Neptune",1627450000),
    #("Neptune","Pluto",1405380000),
    ("Mercury","Mars",170030000),
    ("Neptune","Jupiter",-3722670000),
    ("Earth","Earth",0))

for a, b, expect in test:
    print a, "->", b, "=", expect
    assert f(a, b) == expect, f(a, b)
\$\endgroup\$
  • \$\begingroup\$ Nice trick there. \$\endgroup\$ – Anubian Noob Jul 16 '15 at 18:01
6
\$\begingroup\$

APL, 97 95 85 bytes

{1E4×-/(0 5029 9169 17003 72042 136669 281564 444309[{⍵≡'Mars':4⋄'MVEmJSUN'⍳⊃⍵}¨⍵⍺])}

This creates an unnamed dyadic function that takes the origin planet as the left argument and the destination planet as the right.

You can try it online!

\$\endgroup\$
4
\$\begingroup\$

J--, 226 bytes

main{str q="MeVeEaMaJuSaUrNePl";int w=q.indexOf(a[0].subs(0,2))/2,e=q.indexOf(a[1].subs(0,2))/2,m=1,t=e,d[]={5029,4140,7834,55039,64627,144895,162745,140538};lg h = 0;@i(w>e){e=w;w=t;m=-1;}@f(;e--^^w;)h+=d[e]*10000;echo(h*m);}

I don't think this counts as I was making the language while the question was out, but it was mostly a test of how small I could compress Java code. This is totally and completely based off DeadChex's answer.

Here's how to use it:

$ j-- planets.j-- Mercury Mars
170030000
\$\endgroup\$
4
\$\begingroup\$

Pyth - 59 53 bytes

Encodes the distance in unicode codepoints.

-Fm*^T4s<CM"Ꭵာẚ훿ﱳ𣗿𧮹"x"MshrJtaN"@d14_Q

The name lookup is kinda cool because it loops around. Thanks to @Dennis for suggesting index 14 as a collision free lookup!

Try it here online.

\$\endgroup\$
  • \$\begingroup\$ I used index 14 in my first revision. It is collision-free. \$\endgroup\$ – Dennis Jul 16 '15 at 2:37
3
\$\begingroup\$

Bash, 140 bytes

bc<<<"(-`sed -e 's/,/+/;s/[abd-z]//g;s/Mc/0/g;s/V/5029/g;s/E/9169/g;s/M/17003/g;s/J/72042/g;s/S/136669/g;s/U/281564/g;s/N/444309/g'`)*10^4"

$ bash script.sh 
Mercury, Mars
170030000
$ bash script.sh 
Neptune, Jupiter
-3722670000
$ bash script.sh 
Earth, Earth
0
\$\endgroup\$
3
\$\begingroup\$

CoffeeScript, 183 180 bytes

f=(a,b)->t=[d=0,5029,4140,7834,55039,64627,144895,162745];n='MeVeEaMaJuSaUrNe';t=(x=n[q='indexOf'](a[..1])/2)<(y=n[q](b[..1])/2)&&t[x+1..y]||t[y+1..x];d+=c*1e4for c in t;x>y&&-d||d

Unminified:

f = (a,b) ->
 t = [d = 0, 5029, 4140, 7834, 55039, 64627, 144895, 162745]
 n = 'MeVeEaMaJuSaUrNe'
 t = if (x = n[q='indexOf'](a[..1]) / 2) < (y = n[q](b[..1]) / 2) then t[x+1..y] else t[y+1..x];
 d += c * 1e4 for c in t
 if x > y then -d else d
\$\endgroup\$
3
\$\begingroup\$

Ruby, 168 bytes

a=ARGV.map{|e|e=='Mars'?3:%w(M V E m J S U N P).index(e[0])}
p 10000*(a[1]<=>a[0])*[5029,4140,7834,55039,64627,144895,162745,140538][a.min..a.max-1].inject(0){|r,e|r+e}

It's designed as a script to be run from command line, thus uses ARGV. Run as

$ ruby planets.rb Mercury Mars
170030000
$ ruby planets.rb Neptune Jupiter
-3722670000
$ ruby planets.rb Earth Earth
0
$ ruby planets.rb Mercury Venus
50290000
$ ruby planets.rb Venus Earth
41400000
$ ruby planets.rb Mercury Mercury
0
$ ruby planets.rb Pluto Pluto
0
$ ruby planets.rb Mercury Pluto
5848470000
$ ruby planets.rb Pluto Mercury
-5848470000
\$\endgroup\$
3
\$\begingroup\$

Haskell, 160 158 157 bytes

data P=Mercury|Venus|Earth|Mars|Jupiter|Saturn|Uranus|Neptune deriving Enum
d x=[0,5029,9169,17003,72042,136669,281564,444309]!!fromEnum x
x#y=(d y-d x)*10^4

Usage example:

*Main> Neptune # Jupiter
-3722670000

*Main> Mercury # Mars
170030000

How it works: I define a new data type P where the constructor names are the names of the planets. I also put it in the Enum class, i.e. I get a mapping to integers via fromEnum (in order of definition, starting with Mercury -> 0). This integer can be used as a index for the distance list.

Edit: @Kritzefitz found two bytes to save and @Alchymist another one. Thanks!

\$\endgroup\$
  • \$\begingroup\$ You can remove the parentheses around fromEnum x and save two bytes. \$\endgroup\$ – Kritzefitz Jul 15 '15 at 21:26
  • \$\begingroup\$ Can you use 10^4 instead of 10000 or will that affect the output? \$\endgroup\$ – Alchymist Jul 16 '15 at 14:54
  • \$\begingroup\$ @Alchymist: yes, it's possible. Thanks! \$\endgroup\$ – nimi Jul 16 '15 at 18:01
2
\$\begingroup\$

Julia, 206 203 190 bytes

(f,t)->t==f?0:(M(p)=p=="Mars"?4:findin("MVEmJSUN",p[1])[1];T=M(t);F=M(f);(T>F?1:-1)*sum([get(Dict(zip(1:8,[5029,4140,7834,55039,64627,144895,162745,0])),i,0)for i=T>F?(F:T-1):(T:F+1)])*1000)

This creates an unnamed function that accepts two strings and returns an integer. To call it, give it a name.

Ungolfed + explanation:

function planet_distance(p_from, p_to)
    if p_from == p_to
        # Return 0 right away if we aren't going anywhere
        0
    else
        # Define a function to get the planet's order in the solar system
        M(p) = p == "Mars" ? 4 : findin("MVEmJSUN", p[1])[1]

        # Get indices for origin and destination
        ind_from = M(p_from)
        ind_to = M(p_to)

        # Define a dictionary to look up distances by index
        D = Dict(zip(1:8,[5029,4140,7834,55039,64627,144895,162745,0])

        # Determine whether the distance will be positive or negative
        # and the range over which we'll sum distances
        if ind_to > ind_from
            coef = 1
            range = ind_from:ind_to-1
        else
            coef = -1
            range = ind_to:ind_from+1
        end

        # Sum the distances between points
        coef * sum([get(D, i, 0) for i in range]) * 1000
    end
end
\$\endgroup\$
2
\$\begingroup\$

Java, 257 228 bytes

enum Z{Mercury(0),Venus(5029),Earth(9169),Mars(17003),Jupiter(72042),Saturn(136669),Uranus(281564),Neptune(444309),Pluto(584847);long r;Z(long x){r=x*10000;}static long d(String...s){return Z.valueOf(s[1]).r-Z.valueOf(s[0]).r;}}

static long d(String...s){...} solves the challenge. Input requires names of planets to match the enum's constants' names exactly. I love how java provides a string to enum conversion method for me <3

Usage:

Z.d("Mercury","Pluto") returns 5848470000

Z.d("Pluto","Mercury") returns -5848470000

Z.d("Uranus","Neptune") returns 1627450000

Z.d("Mars","Pluto") returns 5678440000

\$\endgroup\$
1
\$\begingroup\$

C (gcc) pre-processor macro, 146 bytes

char*p="(3$,?2'+";D[]={0,5029,9169,17003,72042,136669,281564,444309,584847};	
#define E(x)D[strchr(p,*x^x[1])-p]
#define f(s,t)(E(t)-E(s))*10000LL

Try it online!

\$\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.