39
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ Should the "class" of "Gaia class" be capitalised like everything else? \$\endgroup\$ – Jonathan Allan Feb 24 '18 at 14:43
  • \$\begingroup\$ @JonathanAllan it's lower case as it's not a proper noun \$\endgroup\$ – Absinthe Feb 24 '18 at 15:06
  • 1
    \$\begingroup\$ @Absinthe Then why is Dense Atmosphere uppercase? \$\endgroup\$ – Erik the Outgolfer Feb 24 '18 at 15:08
  • 17
    \$\begingroup\$ ... have anyone said that? | Welcome to PPCG, and nice first challenge! \$\endgroup\$ – user202729 Feb 24 '18 at 15:24
  • 3
    \$\begingroup\$ @EricDuminil aka an arrowhead anti-pattern, aka nested-if-statement-hell! wiki.c2.com/?ArrowAntiPattern \$\endgroup\$ – Absinthe Feb 25 '18 at 13:44

19 Answers 19

12
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ Crazy! Well done. \$\endgroup\$ – Absinthe Feb 24 '18 at 15:11
  • \$\begingroup\$ @Absinthe You can simply upvote. Side note: On Code Golf we typically don't accept answers. \$\endgroup\$ – user202729 Feb 24 '18 at 15:12
  • 2
    \$\begingroup\$ @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 :) \$\endgroup\$ – Absinthe Feb 24 '18 at 15:18
  • 2
    \$\begingroup\$ @Absinthe yes, I believe a descriptive section is often a good thing to have even for non-esoteric language submissions :) \$\endgroup\$ – Jonathan Allan Feb 24 '18 at 17:29
  • 3
    \$\begingroup\$ You people are truly insane. \$\endgroup\$ – Selvek Feb 25 '18 at 5:20
7
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ That's a nice approach, I may have to think about removing my if statement maze if favour of this in C# :) \$\endgroup\$ – Absinthe Feb 24 '18 at 18:23
  • \$\begingroup\$ I suspect saving the logical index rather than using with,data.frame, and subset will be shorter. \$\endgroup\$ – Giuseppe Feb 26 '18 at 13:51
  • 2
    \$\begingroup\$ 188 bytes \$\endgroup\$ – Giuseppe Feb 26 '18 at 15:13
  • \$\begingroup\$ @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. \$\endgroup\$ – Kirill L. Feb 26 '18 at 15:38
4
\$\begingroup\$

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>

\$\endgroup\$
  • \$\begingroup\$ A couple of your base 16 numbers are 1 off (should be [3913, 2630, 2630, 2647, 2681, 6522, 3706, 1707]) \$\endgroup\$ – Jonathan Allan Feb 24 '18 at 18:55
  • \$\begingroup\$ 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 :) \$\endgroup\$ – Jonathan Allan Feb 24 '18 at 19:13
  • \$\begingroup\$ @JonathanAllan offsets! Great idea, thx \$\endgroup\$ – edc65 Feb 24 '18 at 19:51
  • \$\begingroup\$ @JonathanAllan i need brackets for (z/8&7)+4 because & has lower priority - it would be 7/8&(7+4) \$\endgroup\$ – edc65 Feb 24 '18 at 20:09
  • 1
    \$\begingroup\$ @Shaggy did you see the comment right above yours? (long story short: no) \$\endgroup\$ – edc65 Feb 26 '18 at 16:15
4
\$\begingroup\$

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!

\$\endgroup\$
  • 1
    \$\begingroup\$ Interestingly, at the time of writing, your Python port beats all other Python solutions! \$\endgroup\$ – Kirill L. Feb 26 '18 at 14:29
4
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ Nice one. How does the Random(u) factor in the different probabilities for each planet? (I know nothing about Charcoal). \$\endgroup\$ – Absinthe Feb 24 '18 at 18:21
  • \$\begingroup\$ 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. \$\endgroup\$ – Jonathan Allan Feb 24 '18 at 19:20
  • \$\begingroup\$ @JonathanAllan Got it, thanks \$\endgroup\$ – Absinthe Feb 24 '18 at 21:18
  • \$\begingroup\$ 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 \$\endgroup\$ – ASCII-only Feb 25 '18 at 2:04
  • \$\begingroup\$ @ASCII-only Clear as mud... why are newlines better there but spaces for the other string? \$\endgroup\$ – Neil Feb 25 '18 at 10:15
3
\$\begingroup\$

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.

\$\endgroup\$
  • 1
    \$\begingroup\$ t= instead of text= will save 3 bytes as well. \$\endgroup\$ – Giuseppe Feb 26 '18 at 15:52
  • 1
    \$\begingroup\$ 169 bytes \$\endgroup\$ – Giuseppe Feb 27 '18 at 15:39
  • \$\begingroup\$ 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 \$\endgroup\$ – Giuseppe Feb 27 '18 at 15:40
  • \$\begingroup\$ @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! \$\endgroup\$ – Kirill L. Feb 27 '18 at 16:10
  • \$\begingroup\$ Oh I wondered where those parentheses had come from.... \$\endgroup\$ – Giuseppe Feb 27 '18 at 16:16
3
\$\begingroup\$

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

\$\endgroup\$
  • 3
    \$\begingroup\$ Welcome 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. \$\endgroup\$ – Martin Ender Feb 24 '18 at 23:35
  • 1
    \$\begingroup\$ Doesn't the i in range(x[1], x[2]) exclude the upper edge of the heat, unlike in the specification? \$\endgroup\$ – Graipher Feb 25 '18 at 8:50
  • 1
    \$\begingroup\$ 270 bytes. \$\endgroup\$ – Jonathan Frech Feb 26 '18 at 15:33
  • 1
    \$\begingroup\$ Could 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)] \$\endgroup\$ – MustacheMoses Feb 28 '18 at 19:13
  • 1
    \$\begingroup\$ @Chromane Apologies it seems that the comments stripped some characters. \$\endgroup\$ – MustacheMoses Mar 2 '18 at 0:17
2
\$\begingroup\$

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.

\$\endgroup\$
  • 2
    \$\begingroup\$ Great explanation, thanks. Great score too. \$\endgroup\$ – Absinthe Feb 25 '18 at 7:25
2
\$\begingroup\$

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!

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

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!

\$\endgroup\$
  • \$\begingroup\$ 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...) \$\endgroup\$ – Dada Feb 25 '18 at 9:26
1
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ 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]. \$\endgroup\$ – Kevin Cruijssen Feb 26 '18 at 9:57
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ i+n+1 can be i-~n. TIO \$\endgroup\$ – ovs Feb 27 '18 at 6:53
1
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ Sorry, I don't get the output, would it be the first item in the list? \$\endgroup\$ – Absinthe Feb 24 '18 at 21:16
  • \$\begingroup\$ @Absinthe I added some headings, check again. It's all the heat levels from 4 to 11 and a randomly generated planet for each \$\endgroup\$ – Asone Tuhid Feb 24 '18 at 21:32
  • \$\begingroup\$ Ah I get it thanks, though ideally there should only be one string output \$\endgroup\$ – Absinthe Feb 24 '18 at 21:38
  • \$\begingroup\$ @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 \$\endgroup\$ – Asone Tuhid Feb 24 '18 at 22:18
1
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ Nice! To avoid flooding the comments, you could join the Haskell chat room Of Monads and Men to further discuss your answer. \$\endgroup\$ – Laikoni Feb 27 '18 at 22:56
0
\$\begingroup\$

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)
\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
0
\$\begingroup\$

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.

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

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!

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