Create a solar system

39

7

Intro

This is based on an actual problem I recently faced while making a computer game and I thought it would make for a nice round of .

There are seven main spectral classes of star which put out varying amounts of heat. The geology of planets around a star are greatly influenced by the amount of heat received from the star, which is a factor of spectral class and distance from the star. Hence Mercury is practically molten, Neptune frozen.

The galaxy in my game is procedurally generated and randomly selecting planet types for given stars turned out to be a real 'if statement hell'!

The challenge

Your method should select one planet from a list of planet types appropriate for the class of star, based on a minimum heat threshold, a maximum heat threshold and a random number. For simplicity this challenge will only use a class G star, just like our sun.

Inputs

An integer heat in the range 4 to 11 representing the amount of heat received by the planet from the star.

Variables

This table shows the possible planets based on heat. Your method should first narrow the available choices based on the heat min and heat max, heat should fall on or between the two. E.g. with a heat of 10 passed in the only choices would be Desert, Iron and Lava.

Planet type    Heat min   Heat max   Random Chance
Gas Giant         4          9            15
Ice               4          6            10
Ice Giant         4          6            10
Gaia class        5          7            10
Dense Atmosphere  7          9            10
Desert            7          10           25
Iron              7          10           14
Lava             10          11           6

Next, the probability of a planet (in the remaining choices) being chosen is its random chances divided by the sum of the random chances of all the choices.

In the above example, the probability of Iron being chosen is 14/(25+14+6).

Output

Return the planet type as a string.

Do the best you can to avoid logic arrowheads. Shortest code wins, points all round for creativity. Happy golfing!

Absinthe

Posted 2018-02-24T13:27:12.983

Reputation: 499

Should the "class" of "Gaia class" be capitalised like everything else? – Jonathan Allan – 2018-02-24T14:43:33.810

@JonathanAllan it's lower case as it's not a proper noun – Absinthe – 2018-02-24T15:06:19.293

1@Absinthe Then why is Dense Atmosphere uppercase? – Erik the Outgolfer – 2018-02-24T15:08:06.110

@EriktheOutgolfer Because [Dense Atmosphere] is the name of the class of planet and as such both words form the proper noun, like [Erik Outgolfer]. Also, it's in a computer game, so add a sprinkle of artistic licence :) – Absinthe – 2018-02-24T15:14:49.893

17... have anyone said that? | Welcome to PPCG, and nice first challenge! – user202729 – 2018-02-24T15:24:36.290

Thanks :) Been reading the challenges for a while, thought I'd give it a go. – Absinthe – 2018-02-24T16:05:39.837

What are "logic arrowheads"? – Eric Duminil – 2018-02-25T12:23:43.447

3

@EricDuminil aka an arrowhead anti-pattern, aka nested-if-statement-hell! http://wiki.c2.com/?ArrowAntiPattern

– Absinthe – 2018-02-25T13:44:39.873

TIL the formal names for this anti-pattern and guard clauses. – Jeremy Weirich – 2018-02-26T14:59:45.870

Answers

12

Jelly, 78 bytes

“'ĖøÆḳƙ’ḃ7ṣ6+\+3r/ċ€×“½½½½©ÐÇı‘
“ŀỊẋ8ƒ³ẈRɼƈñqẋẏȧɱḌ<ṄỴḳ⁾ÆʋeẒĊ'@ƬØƓƝ}ḟ¬»ỴW€ẋ"ÇẎX

A monadic link accepting an integer (in [4,11]) which returns a list of characters.

Try it online!

How?

Creates the heat ranges of the planets as a list of lists and counts the occurrences of the input heat in those lists to get a list of zeros and ones representing which planet types are possible, then multiplies by the likelihood numbers of the eight planet types to get the distribution. The distribution is used to repeat the planet type names, and finally a uniform random choice is made.

“'ĖøÆḳƙ’ḃ7ṣ6+\+3r/ċ€×“½½½½©ÐÇı‘ - Link 1, getDistribution: integer
“'ĖøÆḳƙ’                        - base 250 integer = 39824688429662
        ḃ7                      - to bijective-base 7 = [1,1,2,4,7,1,4,4,6,2,2,2,2,1,5,3,3]
          ṣ6                    - split at sixes = [[1,1,2,4,7,1,4,4][2,2,2,2,1,5,3,3]]
             \                  - cumulative reduce with:
            +                   -   addition = [[1,1,2,4,7,1,4,4][3,3,4,6,8,6,7,7]]
              +3                - add three = [[4,4,5,7,10,4,7,7],[6,6,7,9,11,9,10,10]]
                 /              - reduce with:
                r               -   inclusive range = [[4,5,6],[4,5,6],[5,6,7],[7,8,9],[10,11],[4,5,6,7,8,9],[7,8,9,10],[7,8,9,10]]
                  ċ€            - count (input) in €ach e.g. for 5: [1, 1, 1, 0,0, 1, 0, 0]
                     “½½½½©ÐÇı‘ - list of code-page indices        [10,10,10,10,6,15,14,25]
                    ×           - multiply                         [10,10,10, 0,0,15, 0, 0]

“ ... »ỴW€ẋ"ÇẎX - Main link: integer
“ ... »         - compressed string = "Ice\nIce Giant\nGaia class\nDense Atmosphere\nLava\nGas Giant\nIron\nDesert"
       Ỵ        - split at new lines = ["Ice","Ice Giant","Gaia class","Dense Atmosphere","Lava","Gas Giant","Iron","Desert"]
        W€      - wrap €ach in a list
            Ç   - call last link (1) as a monad e.g. for 5: [10,10,10,0,0,15,0,0]
           "    - zip with:
          ẋ     -   repeat e.g. for 5:  [["Ice","Ice","Ice","Ice","Ice","Ice","Ice","Ice","Ice","Ice"],["Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant"],["Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class"],["Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant"]]
             Ẏ  - tighten               ["Ice","Ice","Ice","Ice","Ice","Ice","Ice","Ice","Ice","Ice","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Ice Giant","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gaia class","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant","Gas Giant"]
              X - a random choice from that list

Jonathan Allan

Posted 2018-02-24T13:27:12.983

Reputation: 67 804

Crazy! Well done. – Absinthe – 2018-02-24T15:11:03.663

@Absinthe You can simply upvote. Side note: On Code Golf we typically don't accept answers. – user202729 – 2018-02-24T15:12:58.300

2@user202729 I'll add votes in a day or two. I was looking over the GitHub page for Jelly trying to unravel this code. I believe Crazy! is most appropriate :) – Absinthe – 2018-02-24T15:18:27.930

Thanks for the 'How' section, interesting to see how you did it for people like me who don't know the language. – Absinthe – 2018-02-24T15:20:27.803

2@Absinthe yes, I believe a descriptive section is often a good thing to have even for non-esoteric language submissions :) – Jonathan Allan – 2018-02-24T17:29:30.213

3You people are truly insane. – Selvek – 2018-02-25T05:20:15.777

That has to be the longest Jelly script I've seen in a while; which is not good news for the rest. Well done. – seshoumara – 2018-02-25T16:28:39.473

@seshoumara 22 bytes of code, 56 bytes of constants :p – Jonathan Allan – 2018-02-25T16:35:45.113

@Selvek Welcome to the site! – Luis Mendo – 2018-02-26T23:27:32.590

7

R, 225 223 183 bytes

Thanks to Giuseppe for clever refactoring to take it down to 188 bytes; the remaining five were shaved off by using less redundant number representations.

i=scan()-4
sample(c("Gas Giant","Ice","Ice Giant","Gaia class","Dense Atmosphere","Desert","Iron","Lava")[l<-c(0,0,0,1,3,3,3,6)<=i&c(5,2,2,3,5,6,6,7)>=i],1,,c(3,2,2,2,2,5,2.8,1.2)[l])

Try it online!

rturnbull

Posted 2018-02-24T13:27:12.983

Reputation: 3 689

That's a nice approach, I may have to think about removing my if statement maze if favour of this in C# :) – Absinthe – 2018-02-24T18:23:31.763

I suspect saving the logical index rather than using with,data.frame, and subset will be shorter. – Giuseppe – 2018-02-26T13:51:15.720

2188 bytes – Giuseppe – 2018-02-26T15:13:05.693

@Giuseppe, you can probably gain a few more bytes by using some of my tricks with planet data, but I think I'll also improve mine using your idea of separating the probabilities vector from the rest of the data.

– Kirill L. – 2018-02-26T15:38:05.390

4

JavaScript 212

Edit 6 bytes save thx Jonathan Allan

h=>[963,640,640,649,667,1628,924,437].map((z,i)=>(z/8&7)+4>h|z%8+6<h?0:t=r.push(...Array(z>>6).fill(i)),r=[])&&"Gas Giant,Ice,Ice Giant,Gaia class,Dense Atmosphere,Desert,Iron,Lava".split`,`[r[t*Math.random()|0]]

less golfed

h=>( 
   r = [],
   // heat min,max and chance encoded in base 8 with offsets
   // min range 4 to 10, with offset 4, 0 to 6
   // max range 6 to 11, with offset 6, 0 to 5
   [(4-4)*8 + 9-6 + 15*64,
    (4-4)*8 + 6-6 + 10*64,
    (4-4)*8 + 6-6 + 10*64,
    (5-4)*8 + 7-6 + 10*64,
    (7-4)*8 + 9-6 + 10*64,
    (7-4)*8 + 10-6+ 25*64,
    (7-4)*8 + 10-6+ 14*64,
    (10-4)*8+ 11-6+  6*64]
   .forEach( (z,i) => (
      min = (z / 8 & 7) + 4, 
      max = z % 8 + 6,
      chance = z >> 6,
      min > h || max < h 
      ? 0 // out of range
      // add current position i repeated 'chance' times
      // array size in t
      : t = r.push(...Array(chance).fill(i))
   ),
   pos = r[t * Math.random() | 0],
   ["Gas Giant", "Ice", "Ice Giant", "Gaia class", "Dense Atmosphere", "Desert", "Iron", "Lava"][pos]
)

Test

var F=
h=>[963,640,640,649,667,1628,924,437].map((z,i)=>(z/8&7)+4>h|z%8+6<h?0:t=r.push(...Array(z>>6).fill(i)),r=[])&&"Gas Giant,Ice,Ice Giant,Gaia class,Dense Atmosphere,Desert,Iron,Lava".split`,`[r[t*Math.random()|0]]

function test()
{
   var heat=+H.value
   var i,result,hashtable={},rep=1e5
   for (i=0;i<rep;i++)
     result = F(heat),
     hashtable[result] = -~hashtable[result]
 
   console.log('Input',heat)
   for (i in hashtable)
   {
     console.log(i,(hashtable[i]/rep*100).toFixed(2),'%')
   }
}
<input id=H type=number min=1 max =15 value=10>
<button onclick='test()'>Test</button>

edc65

Posted 2018-02-24T13:27:12.983

Reputation: 31 086

A couple of your base 16 numbers are 1 off (should be [3913, 2630, 2630, 2647, 2681, 6522, 3706, 1707]) – Jonathan Allan – 2018-02-24T18:55:28.973

I think (but am not 100%) you can save 2 by replacing (z/16&15) with z/16&15. Regardless, you can save 6 bytes using a base 8 compression with offsets of three and six... use [971,648,648,657,675,1636,932,445] with z/8&7+3, z%8+6 and z>>6 :) – Jonathan Allan – 2018-02-24T19:13:33.323

@JonathanAllan offsets! Great idea, thx – edc65 – 2018-02-24T19:51:37.777

@JonathanAllan i need brackets for (z/8&7)+4 because & has lower priority - it would be 7/8&(7+4) – edc65 – 2018-02-24T20:09:04.400

Could you replace (z/8&7)+4>h with z/8&7>h-4? – Shaggy – 2018-02-26T10:47:20.040

1@Shaggy did you see the comment right above yours? (long story short: no) – edc65 – 2018-02-26T16:15:28.743

4

Charcoal, 115 111 bytes

≔I⁻N³θF⁸«≔§⪪”↷&∧⬤.YLφκ¦(⁼;σ≕]✂↙ζC” ιη¿›θη¿‹θ§η¹FI✂η²⊞υ黧⪪”↓(″1↨▷]U,&ζ^iI″RSY≡´⍘'#﹪υVw5Vu>D<U5r6⁰Q▷Z◨⌕⁸ΣεCZ”¶‽υ

Try it online! Link is to verbose version of code. Edit: Saved 4 bytes thanks to @ASCII-only. Explanation:

≔I⁻N³θ

Subtract 3 from the input so that it can be compared against single digits.

F⁸«≔§⪪”↷&∧⬤.YLφκ¦(⁼;σ≕]✂↙ζC” ιη

Split the string 0715 0410 0410 1510 3710 3825 3814 696 on spaces (spaces seem to compress better than commas but I didn't try any other characters) and loop over each portion.

¿›θη¿‹θ§η¹FI✂η²⊞υι»

Compare the input against the first and second digits and if it's between then push the loop index the given number of times to the predefined empty list, thus populating it.

§⪪”↓(″1↨▷]U,&ζ^iI″RSY≡´⍘'#﹪υVw5Vu>D<U5r6⁰Q▷Z◨⌕⁸ΣεCZ”¶‽υ

Split the list of planets on newlines (again, better than commas for some reason) and select the element corresponding to a index chosen randomly from the list.

Neil

Posted 2018-02-24T13:27:12.983

Reputation: 95 035

Nice one. How does the Random(u) factor in the different probabilities for each planet? (I know nothing about Charcoal). – Absinthe – 2018-02-24T18:21:59.667

It is choosing an index from a list with the correct distribution of planetType indices due to the "push the loop index the given number of times to the predefined empty list, thus populating it." then using the chosen index to get the planetType name. – Jonathan Allan – 2018-02-24T19:20:01.610

@JonathanAllan Got it, thanks – Absinthe – 2018-02-24T21:18:23.287

111 bytes, I think? In general just try using characters earlier in the character class, see compression#11. Default order saves another byte, but that's basically only if you only have symbols – ASCII-only – 2018-02-25T02:04:46.353

@ASCII-only Clear as mud... why are newlines better there but spaces for the other string? – Neil – 2018-02-25T10:15:14.577

@Neil Ooops >_> turns out there was an character in the codepage that wasn't supposed to be there, they're both 111 bytes – ASCII-only – 2018-02-25T10:51:35.173

@Neil Or rather, I added it a while back for no apparent reason, along with two other characters

– ASCII-only – 2018-02-25T11:03:30.220

also it seems that you've forgotten a code block – ASCII-only – 2018-04-06T10:39:03.403

4

Coconut, 214 195 bytes

t->choice..sum([[n]*g(p)*(g(a)<t<g(b))for*n,a,b,p in'Gas Giant3AF_Ice37A_Ice Giant37A_Gaia class48A_Dense Atmosphere6AA_Desert6BP_Iron6BE_Lava9C6'.split('_')],[])
from random import*
g=int$(?,36)

Try it online!

A Python port would be 203 200 bytes long:

lambda t:choice(sum([[n]*int(p,36)*(int(a)<t<int(b,36))for*n,a,b,p in'Gas Giant3AF_Ice37A_Ice Giant37A_Gaia class48A_Dense Atmosphere6AA_Desert6BP_Iron6BE_Lava9C6'.split('_')],[]))
from random import*

Try it online!

ovs

Posted 2018-02-24T13:27:12.983

Reputation: 21 408

1Interestingly, at the time of writing, your Python port beats all other Python solutions! – Kirill L. – 2018-02-26T14:29:58.317

3

Python, 282 Bytes, 261 Bytes:

from random import*
i,p,l=input(),[('Gas Giant',3,11,15),("Ice",3,7,10),("Ice Giant",3,7,10),("Gaia Class",4,8,10),("Dense Atmosphere",6,10,10),("Desert",6,11,25),("Iron",6,11,14),("Lava",9,12,6)],[]
for x in p:exec"l+=x[0],;"*(x[1]<i<x[2])*x[3]
print choice(l)

Pretty simple - fairly sure it could be golfed more - Still looking for a better way to represent the planet range and probability data. If i is in range of the planet type, appends it to the list according to the probability, then randomly prints one.

EDIT: With credit to Jonathan Frech - redid the for loop to knock a few bytes off. Better way of appending items to the list

Chromane

Posted 2018-02-24T13:27:12.983

Reputation: 161

3Welcome to PPCG! Not sure how you counted bytes, but I'm getting only 283. Less if that indent is a tab instead of 4 bytes. – Martin Ender – 2018-02-24T23:35:52.640

Thanks! I just did a char count, guess I used the wrong tool. Updated! – Chromane – 2018-02-25T00:05:39.907

1Doesn't the i in range(x[1], x[2]) exclude the upper edge of the heat, unlike in the specification? – Graipher – 2018-02-25T08:50:07.010

Ahh yep, damn. I updated the code and shuffled it around a bit - managed to keep the byte count. Changed it to take user input - removes need for indenting. – Chromane – 2018-02-25T18:11:12.067

1270 bytes. – Jonathan Frech – 2018-02-26T15:33:27.297

1Could this be any help? p,d="Gas Giant,Ice,Ice Giant,Gaia class,Dense Atmosphere,Desert,Iron,Lava".split(","),[ord(i)-10 for i in"#"] d=[[p[x//3]]+d[x:x+3]for x in range(0,len(d),3)] – MustacheMoses – 2018-02-28T19:13:21.810

@JonathFrech - thanks! redid answer, also managed to shave a few bytes by removing "in range" statement – Chromane – 2018-03-01T23:26:08.990

@MustacheMoses - I'm afraid I don't understand your code, going to keep looking at it though – Chromane – 2018-03-01T23:34:39.693

1@Chromane Apologies it seems that the comments stripped some characters. – MustacheMoses – 2018-03-02T00:17:41.343

3

R, 196 193 190 175 171 bytes

sample(readLines(,8),1,,c(3,2,2,2,2,5,2.8,1.2)*((x=scan()-3)>c(0,0,0,1,3,3,3,6)&x<c(7,4,4,5,7,8,8,9)))
Gas Giant
Ice
Ice Giant
Gaia class
Dense Atmosphere
Desert
Iron
Lava

Try it online!

Initially inspired by this solution by @rturnbull, however as both submissions have significantly evolved, this is now essentially a mix of ideas of the original author, @Giuseppe who has been very helpful in comments, and mine. Here is a summary of key points that helped to bring the byte count down:

  • Encoding planet data as CSV Collecting names with readLines to avoid the large number of quotation characters around strings.

  • Tweaking the heat params so that we could use < and > signs instead of <= and >=.

  • Changing the heat data format from Heat min, Heat max to Heat min, Heat Delta to get rid of double digit numbers.
    Replaced by shifting all numbers by -3

  • Dividing all planet probabilities by 5 which also results in a few less digits.

  • Multiplying the vector of planet probabilities with the vector of Booleans (indicating whether our input satisfies the heat requirements) to nullify the probabilities of unsuitable planets.

Probably, a few more bytes could be gained by applying some sort of data compression.
I think, not anymore.

Kirill L.

Posted 2018-02-24T13:27:12.983

Reputation: 6 693

1t= instead of text= will save 3 bytes as well. – Giuseppe – 2018-02-26T15:52:36.817

1169 bytes – Giuseppe – 2018-02-27T15:39:36.707

solid answer, though, using read.csv for a single column suggested readLines to get rid of the quotes entirely, although you do have to explicitly set n – Giuseppe – 2018-02-27T15:40:45.297

@Giuseppe, it's 171 bytes though, as you also removed the parentheses that were necessary to maintain operator precedence, and your version gives wrong probabilities. Still, a brilliant suggestion! – Kirill L. – 2018-02-27T16:10:01.947

Oh I wondered where those parentheses had come from.... – Giuseppe – 2018-02-27T16:16:56.423

2

Octave with Statistics Package, 178 176 174 158 bytes

@(h)randsample(strsplit('Gas Giant,Ice,Ice Giant,Gaia class,Dense Atmosphere,Desert,Iron,Lava',','),1,1,('UPPPP_TL'-70).*(h>'IIIJLLLO'-70&h<'PMMNPQQR'-70)){1}

The code defines an anonymous function that inputs a number and outputs a string.

Try it online!

Explanation

The code

@(h)

defines an anonymous function with input h.

The string

'Gas Giant,Ice,Ice Giant,Gaia class,Dense Atmosphere,Desert,Iron,Lava'

is split at commas using

strsplit(...,',')

The result is a cell array of strings, where each string is a planet class.

The code

'IIIJLLLO'-70

defines the shown string and subtracts 70 from the code points of its chars. This gives the array of minimum heat values minus 1, that is, [3 3 3 4 6 6 6 9].

Similarly,

'PMMNPQQR'-70

produces the array of maximum heat values plus 1, that is, [10 7 7 8 10 11 11 12].

The comparisons

h>...&h<...

give an array containing true or false indicating which planet classes are possible.

On the other hand,

'UPPPP_TL'-70

defines the array of random chance values, [15 10 10 10 10 25 14 6].

The operation

(...).*(...)

is the element-wise multiplication of the latter two arrays (true and false behave like 0 and 1 respectively). This gives an array where each planet class has either its random chance, or 0 if that class is not possible based on the input. This array will be used as weights in the random sampling

The function call

randsample(...,1,1,...)

selects one of the cells from the cell array of strings (first input argument), using the computed array of weights (fourth input argument). Specifically, the function randsample automatically normalizes the weights to probabilities, and then does the random selection with those probabilities. The result is a cell array containing a string. The code

{1}

is used to extract that string, which constitutes the function output.

Luis Mendo

Posted 2018-02-24T13:27:12.983

Reputation: 87 464

2Great explanation, thanks. Great score too. – Absinthe – 2018-02-25T07:25:43.777

2

Python 3, 263 bytes

from random import*
P=lambda h:"Gas Giant|Ice|Ice Giant|Gaia class|Dense Atmosphere|Desert|Iron|Lava".split("|")[choices(*list(zip(*filter(lambda x:h in range(*x[2:]),zip(*[[int(x,32)for x in"0f4a1a472a473a584a7a5p7b6e7b76ac"][a::4]for a in(0,1,2,3)]))))[:2])[0]]

Try it online!

MooseOnTheRocks

Posted 2018-02-24T13:27:12.983

Reputation: 191

1

Ruby, 214 193 189 bytes

->h{'Gas Giant,Desert,Iron,Lava,Ice,Ice Giant,Gaia class,Dense Atmosphere'.split(?,).zip(31006330.digits,75449887.digits,[15,25,14,6]).flat_map{|n,m,x,r|m<h-3&&x>h-3?[n]*(r||10):[]}.sample}

Try it online!

Asone Tuhid

Posted 2018-02-24T13:27:12.983

Reputation: 1 944

Sorry, I don't get the output, would it be the first item in the list? – Absinthe – 2018-02-24T21:16:14.483

@Absinthe I added some headings, check again. It's all the heat levels from 4 to 11 and a randomly generated planet for each – Asone Tuhid – 2018-02-24T21:32:54.117

Ah I get it thanks, though ideally there should only be one string output – Absinthe – 2018-02-24T21:38:52.870

@Absinthe You're right, that was just my own test code, now you can input the heat value you want and it returns 1 result – Asone Tuhid – 2018-02-24T22:18:20.167

1

Perl 5 (-p), 230 bytes

@a=(['Gas Giant',4,9,15],[Ice,4,6,10],['Ice Giant',4,6,10],['Gaia class',5,7,10],['Dense Atmosphere',7,9,10],[Desert,7,10,25],[Iron,7,10,14],[Lava,10,11,6]);//;map{push@b,($$_[0])x($$_[3]*($$_[1]<=$'&&$'<=$$_[2]))}@a;$_=$b[rand@b]

Try it online!

Xcali

Posted 2018-02-24T13:27:12.983

Reputation: 7 671

If you remove one to the min heats and add one to the max heats (that would give [Ice,4,5,11] instead of [Ice,4,6,10], etc) then you'll be able to use < instead of <= and > instead of >=, thus saving 2 bytes. (yea, that's not a lot...) – Dada – 2018-02-25T09:26:57.167

1

Nim, 314 298 294 bytes

import random,sequtils
proc c(h:int)=
 var a= @[""]
 a.del 0
 for n in[("Gas Giant",4,9,15),("Ice",4,6,10),("Ice Giant",4,6,10),("Gaia Class",5,7,10),("Dense Atmosphere",7,9,10),("Desert",7,10,25),("Iron",7,10,14),("Lava",10,11,6)]:(if h>=n[1]and h<=n[2]:a.add repeat(n[0],n[3]))
 echo random a

For loop now in one line, no return, less bytes to implicit type

4 spaces removed (thanks Kevin)

Try it online!

Panda0nEarth

Posted 2018-02-24T13:27:12.983

Reputation: 111

I've never programmed in Nim, but I think you can golf four spaces: one at for n in[(; and three at if h>=n[1]and h<=n[2]. – Kevin Cruijssen – 2018-02-26T09:57:37.310

1

05AB1E, 78 76 bytes

”Œï²°™Ä²° Gaia classêη•™Äµ‰Ÿ± Lava”#8äðýā<•ŒEŽuS,•2ôו9èÁnÇ∞Λ•SÌ2ôεŸIå}ÏSΩè

Try it online!

Explanation

”Œï²°™Ä²° Gaia classêη•™Äµ‰Ÿ± Lava”
pushes the string Gas Giant Ice Giant Gaia class Dense Atmosphere Ice Desert Iron Lava

#                                          # split on spaces
 8ä                                        # divide into 8 parts
   ðý                                      # join each by spaces
     ā<                                    # push the range [0 ... 7]
       •ŒEŽuS,•                            # push 151010101025146
               2ô                          # split into pieces of 2
                                           # results in [15, 10, 10, 10, 10, 25, 14, 6]
                 ×                         # repeat each number in the range by these amounts
                                           # results in ['000000000000000', '1111111111', '2222222222', '3333333333', '4444444444', '5555555555555555555555555', '66666666666666', '777777']
                  •9èÁnÇ∞Λ•                # push 2724355724585889
                           S               # split to list of digits
                            Ì              # decrement each twice
                                           # results in [4,9,4,6,5,7,7,9,4,6,7,10,7,10,10,11]
                             2ô            # split into pieces of 2
                                           # results in [[4, 9], [4, 6], [5, 7], [7, 9], [4, 6], [7, 10], [7, 10], [10, 11]]
                               εŸIå}       # apply to each pair
                                Ÿ          # range [a ... b]
                                 Iå        # check if input is contained in the range
                                           # ex, for input 10: [0, 0, 0, 0, 0, 1, 1, 1]
                                    Ï      # keep only the indices which are true
                                           # ex, for input 10: ['5555555555555555555555555', '66666666666666', '777777']
                                     S     # split to list of digits
                                      Ω    # pick one at random
                                       è   # index into the list of strings with this

Emigna

Posted 2018-02-24T13:27:12.983

Reputation: 50 798

1

Haskell, 377 364 358 318 312 270 265 262 256 251 bytes

import System.Random
f h|x<-[n|(n,(a,b,c))<-zip(lines"Gas Giant\nIce\nIce Giant\nGaia class\nDense Atmosphere\n
Desert\nIron\nLava")$zip3[4,4,4,5,7,7,7,10][9,6,6,7,9,10,10,11][15,10,10,10,10,25,14,6],h<=
b,h>=a,_<-[1..c]]=(x!!)<$>randomRIO(0,length x-1)

(I've added linebreaks for nicer printout). The task says "return", not "print", so f is a function which returns the randomly selected planet name into the IO monad, f :: Int -> IO String.

The main is main = do {f 10 >>= print} (Haskell golfing tips says it doesn't count). Prints

"Iron"     -- or "Desert", or "Lava"

(edits: removed &'s base case; moved main out; changed to quadruples and unzip, and switched to pattern guards and >>= following suggestions from Laikoni, thanks!; implemented the approach from the Jelly solution instead, repeating the names; explicit type is no longer needed; another advice by Laikoni saves 3 more bytes; made it an IO function; implemented advice from the chat room).

Try it online!

Will Ness

Posted 2018-02-24T13:27:12.983

Reputation: 352

Nice! To avoid flooding the comments, you could join the Haskell chat room Of Monads and Men to further discuss your answer.

– Laikoni – 2018-02-27T22:56:57.980

1

Python 3, 199 194 bytes

from random import*
lambda n:choices("Ice|Ice Giant|Gas Giant|Gaia class|Dense Atmosphere|Desert|Iron|Lava".split('|'),[(0x33b2a53d4a>>5*i&31)*(0xc07878380e3f0707>>8*i+n-4&1)for i in range(8)])

Splitting h into separate bit masks and random chance values (see explanation) saves a few bytes by eliminating an assignment to h and simplifying the range() in the list comprehension.

Previous solution

from random import*
h=0xc033c39e3270a0e51fbc1d40ea
lambda n:choices("Ice|Ice Giant|Gas Giant|Gaia class|Dense Atmosphere|Desert|Iron|Lava".split('|'),[(h>>i&31)*(h>>i+n+1&1)for i in range(0,104,13)])

Defines an anonymous function that takes an int and returns the planet type.

For each planet type, a 13-bit value was calculated. The top 8 bits define a bit mask of valid heat values for that planet type. The bottom 5 bits are the random chance for that planet type. For example, "Gaia class" is a valid type for heat values 4 to 7, so it has a mask of 0b00001111. It has a random chance of 10, or 0b01010. Combining them results it the 13-bit value 0b0000111101010 for the "Gaia class" type. The 13-bit values for each planet type are concatenated to get the value for h (the lowest 13 bits are for the "Ice" planet type). (The newer answer doesn't combine these values).

The list comprehension iterates over the 13-bit values to create a list of weights, where the weight is the random chance if the planet type is a valid choice for the given heat value, and zero otherwise. For each planet type, (h>>i&31) extracts the random chance for that planet type. (h>>i+n+1&1) evaluates to 1 if the planet type is a valid choice for the heat value n and evaluates to 0 otherwise.

The library function random.choices(choices, weights) selects an item from the list of choices based on the list of weights.

RootTwo

Posted 2018-02-24T13:27:12.983

Reputation: 1 749

i+n+1 can be i-~n. TIO – ovs – 2018-02-27T06:53:08.397

0

Min, 280 277 bytes

:a ' =b (("Gas Giant" 4 9 15) ("Ice" 4 6 10) ("Ice Giant" 4 6 10) ("Gaia Class" 5 7 10) ("Dense Atmosphere" 7 9 10) ("Desert" 7 10 25) ("Iron" 7 10 14) ("Lava" 10 11 6)) (=n (a n 1 get >= a n 2 get <= and) ((n 0 get b append #b) n 3 get times) when) foreach b b size random get

Starts with heat on the stack, leaves a string on the stack. Same general process as Python 2 answer.

Explanation

Note that min is concatenative

:a ' =b                               ;Set the value on the stack (heat) to a, set empty quot to b
(("Gas Giant" 4 9 15) ("Ice" 4 6 10) ("Ice Giant" 4 6 10) ("Gaia Class" 5 7 10) ("Dense Atmosphere" 7 9 10) ("Desert" 7 10 25) ("Iron" 7 10 14) ("Lava" 10 11 6)) ;Data to be iterated over
(=n                                   ;  set n to current item
 (a n 1 get >= a n 2 get <= and)      ;    check if n is between the min (2nd elment of n) and max (3rd element of n) heat
 (
  (n 0 get b append #b) n 3 get times ;      insert the name(1st element of n) into the quot of names (b) a number of times corresponding to the 4th element of n
 ) when                               ;    when the previous check is true
) foreach                             ;  for every quot in previous data
b b size random get                   ;choose a random element from the list of names

Panda0nEarth

Posted 2018-02-24T13:27:12.983

Reputation: 111

0

Java 8, 398 384 bytes

n->{String r="",a[];for(String x:"456789~Gas Giant~15;456~Ice~10;456~Ice Giant~10;567~Gaia class~10;789~Dense Atmosphere~10;78910~Desert~25;78910~Iron~14;1011~Lava~6".split(";"))if(x.split("~")[0].contains(n))r+=x+";";long t=0,u=0;for(String x:(a=r.split(";")))t+=new Long(x.split("~")[2]);t*=Math.random();for(String x:a)if((u+=new Long((a=x.split("~"))[2]))>t)return a[1];return"";}

It can definitely be golfed some more, but the probability in combination with the Strings isn't very easy in Java.

Explanation:

Try it online.

n->{                // Method with String as both parameter and return-type
  String r="",      //  Temp-String, starting empty
         a[];       //  Temp String-array
  for(String x:"456789~Gas Giant~15;456~Ice~10;456~Ice Giant~10;567~Gaia class~10;789~Dense Atmosphere~10;78910~Desert~25;78910~Iron~14;1011~Lava~6".split(";"))
                    //  Loop over the String-parts in the format "heats~type~probability"
    if(x.split("~")[0].contains(n))
                    //   If the heats contains the input
      r+=x+";";     //    Append this entire String-part to the temp-String `r`
  long t=0,u=0;     //  Temp numbers, both starting empty
  for(String x:(a=r.split(";")))
                    //  Loop over the temp-String parts:
    t+=new Long(x.split("~")[2]);
                    //   Sum their probabilities
  t*=Math.random(); //  Get a random number in the range [0,sum_of_probabilities)
  for(String x:a)   //  Loop over the temp-String parts again
    if((u+=new Long((a=x.split("~"))[2]))>t)
                    //   The moment the current probability-sum is > the random number
      return a[1];  //    Return the Type of planet
  return"";}        //  Mandatory return we won't encounter (which returns nothing)

Kevin Cruijssen

Posted 2018-02-24T13:27:12.983

Reputation: 67 575

0

PowerShell, 56 + 135 (CSV file) + 1 (file name) = 192 bytes

param($z)ipcsv a|?{$z-in$_.m..$_.x}|%{,$_.p*$_.r}|Random

Try it online! (this is a slightly modified version that creates the temporary CSV file described below)

Imports a CSV file using ipcsv (short for Import-CSV) named a in the local directory that contains the following:

P,m,x,r
Gas Giant,4,9,15
Ice,4,6,10
Ice Giant,4,6,10
Gaia class,5,7,10
Dense Atmosphere,7,9,10
Desert,7,10,25
Iron,7,10,14
Lava,10,11,6

That automatically creates an iterable hashtable of things like the following:

@{P=Gas Giant; m=4; x=9; r=15}
@{P=Ice; m=4; x=6; r=10}
...

We then use Where-Object (?) to pull out those entries where our input integer $z is -in the range $_.m to $_.x (i.e., it's in the heat range). We then pump those into a Foreach-Object loop (%) that creates an array of strings of names based on the random chance of those names. For example, this will create an array of 15 "Gas Giant" strings if that heat matches. We then put those into Get-Random which will pull out the appropriate string with the appropriate weighting.

AdmBorkBork

Posted 2018-02-24T13:27:12.983

Reputation: 41 581

-1

PHP, 1236 bytes

<?php
$heat = (int)fgets(STDIN);
$planets =
    [
        'Gas Giant' =>        ['heat_min' => 4, 'heat_max' => 9, 'selection_chance' => 15],
        'Ice' =>              ['heat_min' => 4, 'heat_max' => 6, 'selection_chance' => 10],
        'Ice Giant' =>        ['heat_min' => 4, 'heat_max' => 6, 'selection_chance' => 10],
        'Gaia class' =>       ['heat_min' => 5, 'heat_max' => 7, 'selection_chance' => 10],
        'Dense Atmosphere' => ['heat_min' => 7, 'heat_max' => 9, 'selection_chance' => 10],
        'Desert' =>           ['heat_min' => 7, 'heat_max' => 10, 'selection_chance' => 25],
        'Iron' =>             ['heat_min' => 7, 'heat_max' => 10, 'selection_chance' => 14],
        'Lava' =>             ['heat_min' => 10, 'heat_max' => 11, 'selection_chance' => 6],
    ];
foreach ($planets as $planet) {
    $chance_sum += ($heat >= $planet['heat_min'] && $heat <= $planet['heat_max']) * $planet['selection_chance'];
}
while (true) {
    foreach ($planets as $name => $planet) {
        $prob = 100 * ($heat >= $planet['heat_min'] && $heat <= $planet['heat_max']) * $planet['selection_chance'] / $chance_sum;
        if (rand(0, 100) < $prob) {
            echo $name."\n";
            exit;
        }
    }
}
?>

Try it online!

Agnius Vasiliauskas

Posted 2018-02-24T13:27:12.983

Reputation: 125

5

Answers to code-golf question need to show effort in golfing them. You can get this a lot shorter just by removing whitespace. The next step would be to shorten variable names to single character names.

– ovs – 2018-02-25T20:56:37.790