Introduction:

I think everyone knows what a Lava Lamp is, but in case they do not:

enter image description here
(Image source)

They're basically glass tubes that contain wax in a translucent liquid. The bottom part is heated when the lamp is turned on, causing a change in density and thus the wax floats to the top. When it cools down, it falls down again, causing the effect we see above.

It usually takes about 45-60 minutes for the base of the lamp to rise in temperature high enough to change the solid wax to liquid wax (if the lamp is located in an area at room temperature).

More information on Wikipedia, which is also used as source for some of the text above.

Challenge:

Given a positive integer n indicating the amount of minutes that have passed since we've turned the Lava Lamp on, output a random state of the Lava Lamp based on integers on five levels.

For this challenge we'll say the Lava Lamp contains 1000 units of wax in total, and we have five levels where the wax can be at.

1) If n is below 45, the Lava Lamp is still heating up, so the output will be four empty lines with 1000 at the bottom:





1000

2) If n is in the range [45, 60) the Lava Lamp has increased in temperature enough for wax to move around, but no very high yet. The wax can reach up to and including the third level.
3) If n is 60 or higher, the wax can be at any of the five levels.

So given the positive integer n as input, we'll output a random state with the three rules above in mind.

Here are some example outputs:

Possible outputs for any n that is >= 45:



523
106
371


913

87

Possible outputs for any n that is >= 60:

73
113
312
5
497
284
55
637

24

Constant output for n that is <= 44 (and possible output for any n):





1000

Challenge rules:

  • There can be empty lines, even though the level above it is not empty.
  • Just 0 isn't allowed on any line. Should be empty instead.
  • Output is somewhat flexible. You are allowed to output a list/array of strings/objects instead of a new-line delimited result as above. The reason I say strings/objects is due to the rule above. An empty line should be "", null, [], etc., but cannot be 0 or a negative integer (nor can it be false) (I.e. ["", "", 913, "", 87] for n >= 45). You are also allowed to reverse the output (I.e. 1000\n\n\n\n instead of \n\n\n\n1000 or [87, null, 913, null, null] instead of [null, null, 913, null, 87]).
  • The numbers should all be integers. The can be decimals with 0 as decimal value, but none of the numbers should have any decimal digits, and the integers should always sum to exactly 1000.
  • All possible random outputs based on n should have a non-zero chance of occurring.
  • A trailing new-line (so there are six lines of output) is allowed.

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code.
  • Also, adding an explanation for your answer is highly recommended.

18 Answers 18

up vote 5 down vote accepted

MathGolf, 21 20 bytes

5º*♪{k[K∞╟(]m<Σ∞wΦ}σ

Try it online!

This is my first answer in my new language. Since some features were implemented after the posting of this challenge (but not necessarily related to this challenge), I marked it as non-competing. I based my solution on Emigna's 05AB1E solution, but used some neat features of MathGolf to make it a tiny bit shorter.

Explanation

5º*                   push 5, [0], multiply (yielding [0,0,0,0,0]
   ♪                  push 1000
    {                 start block
     k                push input as integer
      K∞              push 22 and double it, yielding 44
        ╟(            push 60 and decrease, yielding 59
          α           wrap last two elements in array, yielding [44,59]
           m<         map is less than, giving [0,0], [1,0] or [1,1]
             Σ        sum array, giving 0, 1 or 2
              ∞       double, giving 0, 2 or 4
               w      push random integer in range
                Φ     increase array element
                 }    execute for loop (loops 1000 times)
                  σ   convert to string and remove leading zeroes (implicit map)
  • If the features aren't builtins for this challenge in of itself, the non-competing tag won't be necessary. Since mid last year non-competing is no longer a thing. Since it's very new I assume there isn't an online compiler for your language yet? Could you instead perhaps add some screenshots (or links to screenshots if it would clutter the post too much) as verification? And I would contact @Dennis' to ask if your language could be added to TryItOnline. – Kevin Cruijssen Sep 12 at 11:39
  • 2
    @KevinCruijssen Thanks for the feedback! I'll add some screenshots, and I'm working on getting the language to TIO. I'll contact Dennis once I feel that I'm not constantly adding new features. – maxb Sep 12 at 11:44
  • Have you considered creating a room for your language? I'm very interested in learning it! – Jo King Sep 15 at 10:36
  • @JoKing glad to hear you're interested! I'll try to create a room sometime this weekend. I only just got the language on TIO thanks to Dennis, I'm working on making it accessible to everyone! – maxb Sep 15 at 10:55
  • @JoKing I created a room for MathGolf. I'll try to answer any questions as soon as I can, I know the documentation is a bit unfinished. – maxb Sep 17 at 7:14

Python 2, 117 113 108 107 106 105 bytes

from random import*
def f(n):a=['']*5;exec"i=randint(0,(n>44)+(n>59)<<1);a[i]=(a[i]or 0)+1;"*1000;print a

Try it online!

Returns a reversed list (bottom first)


Version inspired by the stackoverflow answer in the comments (edgecases are more likely):

Python 2, 129 bytes

from random import*
def f(n):a=sorted([1000]*5+sample(range(1001)*5,(n>44)+(n>59)<<1));print[y-x or''for x,y in zip([0]+a,a)[:5]]

Try it online!

  • I don't know exactly how your code work, but does every state have a non-zero chance of occurring? All your numbers are hovering near the 333 or 200 for the 3 or 5 parts respectively. I don't see any spikes/outliers towards 0 or 1000. Or are the chances for those just astronomically small (but still non-zero) in comparison to integers near 333 and 200? – Kevin Cruijssen Sep 11 at 8:54
  • 1
    @KevinCruijssen Each of the 1000 lava-units are put into a random bin (0 or 0-2 or 0-4), and counted. The chances of none of then going into either is there, but very small. – TFeld Sep 11 at 8:59
  • Ah ok, that makes sense. Now I also understand your code better already. Thanks! +1 from me. – Kevin Cruijssen Sep 11 at 9:01

JavaScript (ES6), 78 bytes

Returns a reversed array where empty levels are filled with a space.

t=>(a=[...'     '],g=k=>k?g(k-1,a[Math.random()*(t>59?5:t<45||3)|0]++):a)(1e3)

Try it online!

Commented

t => (                      // t = input
  a = [...'     '],         // a[] = output array, initially filled with 5 spaces
  g = k =>                  // g = recursive function taking an iteration counter k
    k ?                     //   if k is not equal to zero:
      g(                    //     do a recursive call:
        k - 1,              //       decrement k
        a[                  //       update a[]:
          Math.random() * ( //         pick a random slot:
            t > 59 ? 5 :    //           among all 5 slots if t > 59
            t < 45          //           force the 1st slot if t < 45
            || 3            //           among the 3 first slots otherwise
          ) | 0             //         round the above result to an integer
        ]++                 //       increment the wax amount on this slot
      )                     //     end of recursive call
    :                       //   else:
      a                     //     stop recursion and return a[]
)(1e3)                      // initial call to g() with k = 1000
  • I actually have the same question as the comment I made for the Python answer: Does every state have a non-zero chance of occurring? – Kevin Cruijssen Sep 11 at 8:55
  • 1
    @KevinCruijssen Each state has a non-zero chance of occurring, but extreme values have a very low probability. If I did my maths correctly, you are ~\$10^{90}\$ times more likely to be hit by a meteorite than to get an intermediate empty slot in there. :p – Arnauld Sep 11 at 9:15
  • Rofl, nice analogy with the meteorite. ;) I now indeed see that your method is similar to the Python answer in that it puts values in one of the 3 or 5 spots in the array, up to a count of 1000. Nice answer, so +1 from me. – Kevin Cruijssen Sep 11 at 9:30

R, 85 84 bytes

function(n)write(ifelse(t<-table(cut(runif(1e3,2*(n<60)+3*(n<45),5),0:5)),t,""),1,1)

-1 byte thanks to @Giuseppe

Try it online!

Explanation (ungolfed):

function(n){
      # Generate 1000 random uniform numbers in [5,5] (if n<45),
      # in [2,5] (if 45<=n<60) and in [0,5] (if n>=60).
    x = runif(1e3,2*(n<60)+3*(n<45),5) 
      # Code each by the number of the interval it falls in (0,1],(1,2]...(4,5]
    cx = cut(x,0:5)
      # Tabulate the intervals. Because cut() returns a factor,
      # zero counts are included 
    t = table(cx)
      # Vector-wise replace zero elements with "" and cat out, 1 per line.
    t1 = ifelse(t,t,"")
    write(t1,1,1)
}
  • If NA is allowed as empty line/element, here's a 77 byte solution (Try it online!) or an 80 byte solution (Try it online!) if the element names are a problem – duckmayr Sep 11 at 23:19

C (gcc), 131, 116, 90, 89, 87 bytes

L(l,a,v,A){for(A=5,v=1e3;A--;v-=a)printf("%d\n"+!a*2,a=l>59|A<3&l>44?rand()%-~v:!A*v);}

Try it online!

Update: Fixed a bug in the original. Fused in the helper function, reducing an additional 15 bytes.

Update 2: -25 bytes thanks to ErikF.

Update 3: -1 byte thanks to ceilingcat.

Degolf

L(l,a,v,A){
    for(A=5,v=1e3;A--;v-=a)
        printf("%d\n"+!a*2, // No clue how this works anymore, but it'll advance the pointer 
                            // to the string constant when a number shouldn't be printed.
        a=l>59|A<3&l>44?rand()%-~v // Random integer to print in [0, v]
        :!A*v); // If bottom layer, return remaining volume
}
  • You can eliminate the puts() by combining the printing into a single printf() and putting the subtraction into the loop end. Also, I think you're allowed to put the srand() initialization into the caller. Try it online! – ErikF Sep 12 at 1:11
  • I realized that I missed the "no zeroes" restriction. Here's the fixed version: Try it online! – ErikF Sep 12 at 1:50
  • Some last tweaks! Try it online! – ErikF Sep 12 at 1:57
  • Great; I golfed it down by an additional byte. – Rogem Sep 12 at 9:43
  • 1
    Also, we did it! We beat Python! – Rogem Sep 12 at 9:53

05AB1E, 27 26 25 bytes

Saved a byte thanks to Adnan.
Saved another byte thanks to Kevin Cruijssen.

5Å0₄FD„,;ÇI‹O·ÝΩ©è>®ǝ]ε0Û

Try it online!

Explanation

5Å0                         # initialize with a list of 5 zeroes
   ₄F                       # 1000 times do:
     D                      # duplicate the list
      „,;ÇI‹                # check if the input is larger than 44 and/or 59
            O·              # sum and double, yielding (0,2 or 4)
             ÝΩ             # pick a random number between and 0 and the number above
               ©è           # get the count in that level
                 >          # increment it
                  ®ǝ        # insert it at the same position
                     ]      # end loop
                      ε0Û   # remove leading zeroes on each level
  • 1
    Nice answer! I like the way you've used 5Å0 and ǝ, and ε0Û at the end. I tried to come up with something shorter, but I'm unable to. I have the feeling it can somehow still be golfed, but I'm currently not seeing it (perhaps it cannot and it's just a random feeling). •A–•60в is 1 byte longer than 44 59‚ instead of shorter. And ε0Û to replace the 0s with empty strings also seems to be the shortest possible, since 0K simply removes the 0-items completely and removes any digit 0 in all numbers. – Kevin Cruijssen Sep 11 at 10:00
  • 1
    @KevinCruijssen: Yeah I've looked and looked to find a shorter way of doing 44 59‚, but I can't find it (•H|•2ô is the same count). My previous solution (also 27 bytes) used 45 and 60 which are easier to generate in different ways, but I think that was invalid as it output 1, 3 or 5 levels depending on input and not always 5. – Emigna Sep 11 at 10:04
  • Ah, •H|•2ô is indeed also a smart way, hadn't thought about that. And it should indeed output 5 lines. I saw your previous answer indeed and was about to comment it only outputted 1 line for n < 45, but then you deleted it. Glad you've found another 27-byte solution. :) – Kevin Cruijssen Sep 11 at 10:07
  • 2
    I think ŽH|2ô is what you are looking for? – Adnan Sep 11 at 10:11
  • 2
    @KevinCruijssen It acts exactly like that. Did some research using previous answers using 05AB1E and this was one of the things I added in the rewrite. It does not have any other use cases right now. – Adnan Sep 11 at 16:28

JavaScript (Node.js), 87 86 bytes

f=(n,w=1e3,s=5,r=n<45|n<60&s<4|s<2?w:Math.random()*w|0)=>s?`${r||""}
`+f(n,w-r,s-1):""

Try it online!

The 83-byte solution ((n/15-2|0)*s<4) is reserved first because I need to check for larger n.

UPDATE: Yeah, (n/15-2|0)*s<4 didn't work because for larger n because n large enough makes the sum fail to reach 1000.

PHP, 92 bytes

$i=5;for($n=1e3;$i--;$n-=$x)echo($x=rand($i?0:$n,$i<($argn<60?$argn<45?:3:5)?$n:0))?:"","
";

Run as pipe with -R or try it online.

Clean, 215 bytes

import StdEnv,Math.Random,Text
? ::!Int->Int
?_=code{ccall time "I:I"
}
$n#l=take(max(2*min(n/15-2)2)0+1)(genRandReal(?0))
#l=map toInt[1E3*e/sum l\\e<-l]
|sum l==1000=map(\v|v>0=v<+"\n"="\n")(l++repeat 0)%(0,4)= $n

Try it online!

So I've finally found a shorter way to get a random seed than importing System._Unsafe, System.Time and using toInt(accUnsafe time)...
And boy is it truly in the spirit of codegolf - embedding a call to C, ignoring the world state type normally used to ensure the evaluation order of such things.

Java (JDK 10), 121 117 113 111 bytes

m->{for(int w=1000,j,i=5;i-->0;w-=j=i>0?j*=Math.random():w,System.out.println(j<1?"":j))j=m>59|m>44&i<3?w+1:0;}

Try it online!

It's biased towards putting more wax near the top, but it's theoretically possible for any legal arrangement of wax to appear.

edit: 4 bytes were saved by @KevinCruijssen

In Human-readable Java:

(int minutes /* golfed variable m */) -> {
  int waxRemaining = 1000; // golfed variable w

  // golfed version goes from index 4 to 0 in a bit of a roundabout way
  // starting at 5 but decrementing right away
  for (int level = 4 /* golfed variable i */; level <= 0; level--) {
    // golfed variable j
    // the golfed version initializes this to (waxRemaining + 1)
    // in order to juice out some extra bytes during the Math.random() call
    int waxAtLevel = 0;

    // the golfed version does all of these ifs as ternary operations
    // and avoids using 2-character operators wherever possible
    // so e.g. "a == 0" becomes "a<1" and "a && b" becomes "a&b"
    // since here we are certain things can't be negative,
    // and took a good look at the Java operator precedence cheat-sheet
    // to make sure "&" and "|" would work properly to give a truthy value
    if (level == 0) {
      // if we are at the bottom level, just put the rest of the wax there
      waxAtLevel = waxRemaining;
    } else if (minutes >= 60 || (minutes >= 45 && level < 3)) {
      // otherwise if we are at a legal level put a random portion of the remaining wax there
      // note: the random portion can be between 0 and waxRemaining inclusive
      waxAtLevel = (int) (Math.random() * (waxRemaining + 1));
    }

    if (waxAtLevel > 0) {
      // only print the amount of way at this level if its greater than 0
      System.out.print(waxAtLevel);
    }
    System.out.println();

    waxRemaining -= waxAtLevel;
  }
}
  • 2
    Math.random()*(w+1) can be Math.random()*-~w for -2 bytes. Here the relevant tip as reference why.. Nice answer! +1 from me. EDIT: Actually, 2 more bytes can be saved by using j temporary as variable for w+1 (since it will be overwritten right after in the print anyway) and use j*=Math.random() instead so you won't need the cast to (int) (117 bytes). – Kevin Cruijssen Sep 11 at 18:48
  • @KevinCruijssen nice! Also I just noticed that the &i>2 condition isn't necessary – SamYonnou Sep 11 at 20:28

Pascal (FPC), 192 190 bytes

var n,a:word;z:array[0..4]of word;begin read(n);if n>44then a:=a+3;if n>59then a:=a+2;Randomize;for n:=0to 999do inc(z[random(a)]);for n:=0to 4do if z[n]>0then writeln(z[n])else writeln end.

Try it online!

Using packing into bins method by TFeld. Prints bottom row first with a trailing newline.

It seems that FPC doesn't have problems with random(0), so I have some unusual adding there.


My original submission, golfed down to 209 bytes:

var n,i,a,r:int32;begin read(n);if n>44then a:=a-2;if n>59then a:=a-2;r:=1000;Randomize;for i:=-3to-0do begin if i>a then begin n:=random(r+1);if n>0then write(n);r:=r-n;end;writeln;end;if r>0then write(r)end.

Try it online!

Charcoal, 37 bytes

F²F²⊞υ∧‹³⁺ι÷Iθ¹⁵‽⊕⁻φΣ∨υω⊞υ⁻φΣυEυ⎇ιIιω

Try it online! Link is to verbose version of code. Explanation:

F²F²

Loop twice, twice. Alternatively I could have integer divided the loop index by 2 for the same byte count.

‹³⁺ι÷Iθ¹⁵

If the outer index plus a fifteenth of the temperature is greater than three...

⊞υ∧...‽⊕⁻φΣ∨υω

... then push a random integer up to and including 1000 - the sum so far. Unfortunately Charcoal can't calculate the sum of an empty list so I have to substitute the empty string instead.

⊞υ⁻φΣυ

Push the leftover amount to the list.

Eυ⎇ιIιω

Convert the list to string, but use the empty string instead of zero.

Jelly, 28 bytes

>“,;‘SḤ‘µȷŻṗS⁼¥ƇȷX;0ẋ5¤ḣ5Yḟ0

A full program printing the result (upside down, as has been allowed).

Try it online! - this is altered to use 7 rather than ȷ (1000) because the implementation is golf-tastically slow! (...for \$n>59\$ a list of \$10^{15}\$ 5-tuples is built and then filtered, from which to choose)

How?

>“,;‘SḤ‘µȷŻṗS⁼¥ƇȷX;0ẋ5¤ḣ5Yḟ0 - Main Link: integer, n
 “,;‘                        - list of code-page indices = [44,59]
>                            - greater than? (vectorises)
     S                       - sum (i.e. 0, 1 or 2)
      Ḥ                      - double (i.e 0, 2 or 4)
       ‘                     - increment (i.e. 1, 3 or 5)
        µ                    - start a new monadic link, call that x (i.e. f(x))
         ȷ                   - literal 1000
          Ż                  - zero-range = [0,1,2,...,1000]
           ṗ                 - Cartesian power (all tuples of length x using those numbers)
               Ƈ             - filter keep if:
              ¥              -   last two links as a dyad:
            S                -     sum
             ⁼  ȷ            -     equals 1000? (i.e. only valid tuples)
                 X           - random choice (get one of these tuples)
                      ¤      - nilad followed by link(s) as a nilad:
                   0         -   zero
                    ẋ5       -   repeat five times = [0,0,0,0,0]
                  ;          - concatenate     (e.g. [354,388,258,0,0,0,0,0])
                       ḣ5    - head to index 5 (e.g. [354,388,258,0,0])
                         Y   - join with newlines
                          ḟ0 - filter out zeros
                             - implicit print
  • 1
    "You are also allowed to reverse the output (I.e. 1000\n\n\n\n instead of \n\n\n\n1000 or [87, null, 913, null, null] instead of [null, null, 913, null, 87])." So yes, you are allowed to use the 28-byte version without the . – Kevin Cruijssen Sep 12 at 6:54

Twig, 126 bytes

This was an actually fun challenge!

This code creates a macro that has to be imported.

{%macro a(s,z=1000)%}{%for _ in 4..1%}{%set t=s>59or(s>44and _<3)?random(z):''%}{%set z=z-t%}{{t}}
{%endfor%}{{z}}{%endmacro%}

To import it, just do this:

{%- import 'macro.twig' as a -%}
{{- a.a(50) -}}

This should do the trick.

You can try it on https://twigfiddle.com/t4dfgy
Notice: Due to the page removing whitespaces, I was forced to add an - at the end of the line, to prove that it is outputting the correct number of lines.

On a regular installation, you would just see the newlines without issues.

Perl 6, 62 bytes

{($!=1e3)||@,|((+$!-($!-=$!.rand+|0)||@)xx($_/15+|0)*2-4)[^4]}

Try it online!

An anonymous code block that takes a string and returns a list of integers, with Nil or an empty list ([]) in place of 0s.

Explanation:

{($!=1e3)||@,|((+$!-($!-=$!.rand+|0)||@)xx($_/15+|0)*2-4)[^4]}
{                                                            }  # Anonymous code block
 ($!=1e3)  # Initialise $! to 1000
                +$!-($!-=$!.rand+|0)     # Pick a random value from 0 to $!
                                    ||@  # Or an empty array if it is zero
            ,  (                       )xx  # Repeat this
                                          ($_/15+|0)*2-4  # The given value mapped to 0,2,4
             |(                                         )[^4] # Get the first four values
 ($!    )||@  # Where the first value is the leftover number in $! or an empty array

PHP, 113 108 99 97 93 bytes

<?php $i=$argv[1];while($a++<1e3){${r.rand(1,$i<60?$i<45?:3:5)}++;}echo"$r5
$r4
$r3
$r2
$r1";

Try it online!

-11 bytes thanks to @titus
-9 bytes because everything is a string

Ruby, 62 bytes

->n{w,t=1e3;[4,4,3,3].map{|r|r>n/15||w-=t=(rand*w).to_i;t}<<w}

Try it online!

Tests are limited to 0-99 degrees, because lava lamps could be dangerous at higher temperatures:

  • Hi there. I'm afraid your answer is invalid. It currently has 0 for the empty lines. The empty lines in the array can be anything except for 0, false or a negative number. So it can be null, "", [], etc., but not 0. Not sure if Ruby has object-arrays/lists so you can transform the 0s to something else, but if not you'll have to print them instead of returning an array/list. – Kevin Cruijssen Sep 12 at 10:59
  • Fixed, but I think it's a little too arbitrary. – G B Sep 12 at 12:01

Powershell, 188 162 bytes

param($m);$t=0;$a=,0*5;$s=if($m-lt45){4}elseif($m-lt60){2}else{0};$s..4|%{$t+=$a[$_]=if($_-eq4){1e3-$t}elseif($t-ne1e3){Random(1000-$t)}}$a|%{if($_){$_}else{''}}

Try it online!

-2 bytes by @Kevin Cruijssen
-4 bytes by removing optional Get- verb
-20 bytes by shortning loop and removing spaces

  • Hi, welcome to PPCG! Great first answer! I did some basic testing, and everything seems to work great. I know barely anything about Powershell, but is it possible to change else{if($t-ne 1e3){Get-Random(1000-$t)}} to elseif($t-ne 1e3){Get-Random(1000-$t)}? I see you've used an elseif earlier in your code, so this should save you 2 bytes. Also, maybe Tips for golfing in Powershell or Tips for golfing in <all languages> might give some inspiration for more? Enjoy your stay! :) – Kevin Cruijssen Sep 13 at 20:04
  • 1
    totally correct about the ifelse. Removed its else counterpart earlier in the process. Link gave some inspiration too! – Edwin Sep 14 at 6:26

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.