Given the names of two planets, give the distance

25

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.

Tim

Posted 2015-07-15T15:55:48.390

Reputation: 2 789

10+1 for not "coz Pluto ain't a planet" – Optimizer – 2015-07-15T16:04:19.190

@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... – Tim – 2015-07-15T16:04:58.230

Can our function/program return a float? i.e. Mercury, Mars -> 170030000.0? – Kade – 2015-07-15T16:06:24.413

@Vioz- I'm gonna say no, they're all integer distances. – Tim – 2015-07-15T16:06:51.890

8It'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? – Sp3000 – 2015-07-15T16:10:02.080

@Sp3000 yes. will clarify – Tim – 2015-07-15T16:10:30.513

3Is there a penalty for including Pluto (besides the bytes)? I feel kinda bad for it, it just had it's big day and all... – DeadChex – 2015-07-15T16:23:26.613

@DeadChex no penalty :) I'll add it onto the table – Tim – 2015-07-15T16:26:15.533

@Sp3000 It doesn't have to be a holy moment as the distances are pairwise. – Optimizer – 2015-07-15T16:39:57.473

I'm testing something right now, since Python will attach an L to a value that's too large, is it OK if I return something like -3722670000L? – Kade – 2015-07-15T17:31:05.497

@Vioz- yeah that's fine. – Tim – 2015-07-15T18:00:08.467

do you care about the orbits' eccentricity? or assume circular orbits? edit nvm i read the link to the data source – Plato – 2015-07-15T20:14:58.593

@Plato use the distances provided. They're circular orbits here. – Tim – 2015-07-15T20:15:27.723

Is the input guaranteed to be a valid planet? – kirbyfan64sos – 2015-07-17T17:03:04.303

@kirbyfan64sos yes – Tim – 2015-07-17T21:37:20.673

Answers

24

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.

Dennis

Posted 2015-07-15T15:55:48.390

Reputation: 196 637

10

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

Kade

Posted 2015-07-15T15:55:48.390

Reputation: 7 463

Your output is missing a 0, but you seem to be multiplying by the right amount. – Tim – 2015-07-15T16:31:47.883

@Tim I messed up in the example call, it does have a fourth 0 at the end :P – Kade – 2015-07-15T16:32:11.657

You are forgetting pluto? – Will – 2015-07-15T20:08:23.107

@Will Pluto doesn't have to be included... – Kade – 2015-07-15T20:09:17.797

(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 :) – Will – 2015-07-15T20:28:46.823

@Will If you look at the golfed code, you'll notice that Neptune is actually missing from the .find string. For some reason it's in the ungolfed code though. – Sp3000 – 2015-07-16T07:37:28.210

I'm not doing so well with my attention to small details :) – Will – 2015-07-16T07:41:46.227

8

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

SteelRaven

Posted 2015-07-15T15:55:48.390

Reputation: 741

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. – Fatalize – 2015-07-15T19:42:21.397

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 – Fatalize – 2015-07-15T19:48:45.700

7

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);
}

DeadChex

Posted 2015-07-15T15:55:48.390

Reputation: 508

1You could cut off a lot by dividing all numbers by 1000 – Tim – 2015-07-15T16:31:00.213

Just about to do that! – DeadChex – 2015-07-15T16:31:16.660

Fixed the Overflow and Neptune being missing – DeadChex – 2015-07-15T16:38:31.130

1You can also put both the int and int[] declarations on one line if the array comes last: Like int i=0,j=1,k[]={}; – Geobits – 2015-07-15T16:55:17.217

1You can shave off two bytes by replacing 10000 with 1e4. – Anubian Noob – 2015-07-16T17:59:23.243

1since 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. – corsiKa – 2015-07-16T21:11:09.230

@corsiKa Having m=1e4 is a type error. 1e4 is a double whereas m is an int Thanks for the other suggestions though! – DeadChex – 2015-07-16T21:16:23.750

@corsiKa Sorry, but I don't see where I can drop the /2s. From what I understand, I need both w and e to be halved before the start of the For loop, otherwise I'll have too many iterations. – DeadChex – 2015-07-16T21:31:12.540

Ah, correct you are. – corsiKa – 2015-07-16T21:36:12.173

since you're only using String p and String l once each, you can actually save 1 byte by using varargs String...p and using s[0].substring(0,2) and s[1].substring(0,2). – Jack Ammo – 2015-07-17T05:03:51.860

7

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.

apsillers

Posted 2015-07-15T15:55:48.390

Reputation: 3 632

@vihan1086 Aha, I have made the classic blunder of confusing code-point-value with actual byte representation :( – apsillers – 2015-07-15T19:55:46.243

1UTF-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. – Dennis – 2015-07-16T02:35:34.483

6

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!

Alex A.

Posted 2015-07-15T15:55:48.390

Reputation: 23 761

6

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)

Will

Posted 2015-07-15T15:55:48.390

Reputation: 1 143

Nice trick there. – Anubian Noob – 2015-07-16T18:01:33.687

4

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

phase

Posted 2015-07-15T15:55:48.390

Reputation: 2 540

4

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.

Maltysen

Posted 2015-07-15T15:55:48.390

Reputation: 25 023

I used index 14 in my first revision. It is collision-free. – Dennis – 2015-07-16T02:37:48.913

3

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

rink.attendant.6

Posted 2015-07-15T15:55:48.390

Reputation: 2 776

3

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!

nimi

Posted 2015-07-15T15:55:48.390

Reputation: 34 639

You can remove the parentheses around fromEnum x and save two bytes. – Kritzefitz – 2015-07-15T21:26:56.807

Can you use 10^4 instead of 10000 or will that affect the output? – Alchymist – 2015-07-16T14:54:46.143

@Alchymist: yes, it's possible. Thanks! – nimi – 2015-07-16T18:01:37.383

3

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

SteelRaven

Posted 2015-07-15T15:55:48.390

Reputation: 741

3

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

Karsten S.

Posted 2015-07-15T15:55:48.390

Reputation: 131

2

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

Alex A.

Posted 2015-07-15T15:55:48.390

Reputation: 23 761

2

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

Jack Ammo

Posted 2015-07-15T15:55:48.390

Reputation: 430

1

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!

gastropner

Posted 2015-07-15T15:55:48.390

Reputation: 3 264