Raindrops are falling on my... glasses?

23

4

I live in the UK, where it rains. A lot. I also have the unfortunate necessity to need to wear glasses to see, which means that when it rains (as it is now), I can barely see out of them. This challenge is so that you can all experience the same!

Task

Output ASCII art glasses with a drop of water added each second.

Input

None

Output

A pair of glasses with drops of water on them.

Glasses

 ________________________
|          /__\          |
|         /    \         |
|        /      \        |
\_______/        \_______/

Raindrops

A raindrop is denoted by a .. A raindrop is randomly placed on the glasses' lenses. So when a raindrop is placed, the glasses might look like this

 ________________________
|          /__\          |
|    .    /    \         |
|        /      \        |
\_______/        \_______/

If it is placed on a blank space (), an . is placed on the image. If it is placed on a square which already has a raindrop, the drop graduates.

The steps on drops are

  • no drops placed:
  • 1 drop placed: .
  • 2 drops placed: o
  • 3 drops placed: O
  • 4+ drops placed: @

Rules

  • The image should look as though it stays in place. This means that you can either clear the screen or print enough newlines to "clear" the screen. You cannot return a list of steps. Sorry about this, but you should be able to work around that.
  • When outputting newlines to "clear" the screen, you must have at least 3 newlines between the glasses.
  • The code runs until the glasses are full of fully graduated drops i.e. until the output looks like this:
     ________________________
    |@@@@@@@@@@/__\@@@@@@@@@@|
    |@@@@@@@@@/    \@@@@@@@@@|
    |@@@@@@@@/      \@@@@@@@@|
    \_______/        \_______/
  • Shortest code in bytes wins.

caird coinheringaahing

Posted 2017-05-23T21:23:12.907

Reputation: 13 702

"The code runs until the glasses are full of fully graduated drops" Perhaps specify an approximate sleep/wait time? Like 150 or 250 ms? – Kevin Cruijssen – 2017-05-24T08:14:34.293

2Does the code have to stop when the glasses look like the final output or can it keep running but just not affect anything? – TheLethalCoder – 2017-05-24T08:28:25.977

@TheLethalCoder I would imagine until the glasses are full, as written in the spec :v – Jenkar – 2017-05-24T11:24:10.180

Droplet's random fall does have to fall randomly on lenses even on part of the bits of the lens that are @, right? – Jenkar – 2017-05-24T14:17:52.317

@TheLethalCoder it should terminate after all have graduated – caird coinheringaahing – 2017-05-24T15:12:46.187

@KevinCruijssen sleep time can be anything above or equal to 1ms – caird coinheringaahing – 2017-05-24T15:17:31.040

@RandomUser Okay and sleep time doesn't matter does this mean you don't need to sleep at all? – TheLethalCoder – 2017-05-24T15:19:47.450

Answers

11

JavaScript (ES6), 269 267 265 bytes

document.write('<pre id=o>')
a=[...` _8_8_8
| 9 /__\\  9|
| 9/ 4\\ 9|
| 8/ 6\\ 8|
\\_7/ 8\\_7/`.replace(/.\d/g,s=>s[0].repeat(s[1]))]
s=" .oO@@"
g=_=>o.innerHTML=a.join``
f=(i=s.indexOf(a[j=Math.random()*a.length|0])+1)=>i?g(a[j]=s[i]):f()
g()
setInterval(f,1e3)

Edit: Saved 2 4 bytes thanks to @Shaggy.

Neil

Posted 2017-05-23T21:23:12.907

Reputation: 95 035

3something goes wrong at the upper left corner – J42161217 – 2017-05-24T01:51:46.683

-1 because it's bugged (see Jenny's comment) – Destructible Lemon – 2017-05-24T02:13:18.183

1@DestructibleLemon Sorry about that, I got bitten by a "feature" of Firefox's clipboard... should be OK now. – Neil – 2017-05-24T08:05:25.197

Save a couple of bytes with innerText instead of textContent and search instead of indexOf. And a few more by just using <pre id=o as HTML, rather than document.writeing it. – Shaggy – 2017-05-24T08:55:22.587

@Shaggy But that would make it HTML/JS, and I wanted this to be a "pure" JS solution. – Neil – 2017-05-24T09:07:50.827

@Shaggy Also, search will fail on a \... – Neil – 2017-05-24T09:09:21.423

(I used innerHTML because Firefox only recently implemented innerText.) – Neil – 2017-05-24T09:12:06.057

Would f=(i=s.indexOf(a[j=Math.random()*a.length|0])+1)=>i?g(a[j]=s[i]):f() work, for a 2 byte saving? – Shaggy – 2017-05-24T11:54:01.880

1@Shaggy Great find, thanks! – Neil – 2017-05-24T12:00:08.963

5

Java 8, 449 421 bytes

v->{String q="########",g=" ________________________\n|##"+q+"/__\\##"+q+"|\n|#"+q+"/    \\#"+q+"|\n|"+q+"/      \\"+q+"|\n\\_______/        \\_______/\n\n\n";for(int t=0,n,x;g.matches("(?s).*[#\\.oO].*");Thread.sleep(150)){for(;(x=g.charAt(n=(int)(Math.random()*g.length())))!=35&x!=46&x!=111&x!=79;);if(t++>0)g=g.substring(0,n)+(x<36?".":x<47?"o":x<80?"@":"O")+g.substring(n+1);System.out.println(g.replace('#',' '));}}

Explanation:

Try it here. (Thread.sleep is removed so you instantly see the result.)

v->(){                      // Method without empty unused parameter and no return-type
  String q="########",g=" ________________________\n|##"+q+"/__\\##"+q+"|\n|#"+q+"/    \\#"+q+"|\n|"+q+"/      \\"+q+"|\n\\_______/        \\_______/\n\n\n";
                            //  The glasses (with inner spaces replaced by '#')
  for(int t=0,n,x;          //  Index integers
      g.matches("(?s).*[#\\.oO].*");
                            //   Loop (1) as long as the glasses still contain "#.oO"
      Thread.sleep(150)){   //   And sleep 150ms after each iteration to give the animation
    for(;                   //   Inner loop (2)
         (x=g.charAt(n=(int)(Math.random()*g.length())))!=35&x!=46&x!=111&x!=79;
                            //    To find the next '#', '.', 'o' or 'O' randomly
    );                      //   End of inner loop (2)
    if(t++>0)               //   Flag so it prints the initial glasses without a raindrop
      g=g.substring(0,n)+(x<36?".":x<47?"o":x<80?"@":"O")+g.substring(n+1);
                            //    Add a raindrop on this random position
    System.out.println(g    //   And print the glasses
        .replace('#',' ')); //   After we've replaced '#' with spaces
  }                         //  End of loop (1)
}                           // End of method

Output:

NOTE: The dots are a bit weird in the gif, but that's a problem in my ScreenToGif.exe..
enter image description here

Kevin Cruijssen

Posted 2017-05-23T21:23:12.907

Reputation: 67 575

1You know what is dazzling me about, those weird dots (same applies to scaled-down ") really look like there is a real water drop on top of my screen – Khaled.K – 2017-05-24T11:53:12.723

1This does not account for the possibility of a drop falling on an @ :v – Jenkar – 2017-05-24T13:10:12.807

@Jenkar that is the second time you have said that on answers. Please explain what you mean. – caird coinheringaahing – 2017-05-24T15:16:20.730

@RandomUser Basicly, the current code in this answer looks for a spot that is not yet an @ to fall on, rather than falling on the lenses randomly, even if it is an at. The "4+" in requirements seems to indicate that this is not the case to go, but instead one should fall on the lens randomly, including an @. Is this not the correct interpretation? – Jenkar – 2017-05-24T15:59:26.133

@Jenkar It doesn't matter how it does it, just that it does it without violating any rules or standard loopholes. I never said "It must have a uniform random distribution" in the question so this answer is fine. – caird coinheringaahing – 2017-05-24T16:02:47.217

@Jenkar Hmm you're indeed right. Missed the 4+ part. But I guess RandomUser thinks it's fine like this. Personally I think it's better this way, otherwise it might take a very long time before the entire glasses are filled near the end. But well-spotted, nonetheless. – Kevin Cruijssen – 2017-05-24T18:18:01.297

3

F#, non-recursive 379 414 404 bytes

open System
let z=String.replicate
let mutable s,d=z 54" ",new Random()
while Seq.exists((<>)'@')s do printfn" %s\n|%s/__\\%s|\n|%s/    \\%s|\n|%s/%7s%s|\n\\_______/%9s_______/\n\n"(z 24"_")(s.[..9])(s.[10..19])(s.[20..28])(s.[29..37])(s.[38..45])"\\"(s.[46..53])"\\";Threading.Thread.Sleep(1000);d.Next54|>fun i->s<-(s.[i]|>function|' '->"."|'.'->"o"|'o'->"O"|_->"@")|>(fun c->s.Remove(i,1).Insert(i,c))

Try it online!

  • -7 bytes thanks to @vzwick
    • by aliasing String.replicate
    • by opening System instead of referencing it every time
  • -3 bytes by reducing the while loop to one line

I love the premise of this challenge :)

And thanks for the earworm.

F#, 406 441 438 437 423 bytes

open System
let z=String.replicate
let s,d=z 54" ",new Random()
let rec(!)s=s="";printfn" %s\n|%s/__\\%s|\n|%s/    \\%s|\n|%s/%7s%s|\n\\_______/%9s_______/\n\n"(z 24"_")(s.[..9])(s.[10..19])(s.[20..28])(s.[29..37])(s.[38..45])"\\"(s.[46..53])"\\";Threading.Thread.Sleep(1000);if Seq.exists((<>)'@')s then d.Next 54|>fun i-> !((s.[i]|>function|' '->"."|'.'->"o"|'o'->"O"|_->"@")|>(fun c->s.Remove(i,1).Insert(i,c)))else()
!s

Try it online!

  • -3 bytes by constraining s to string by comparing it with string
  • -1 byte, function name is now "!" saving a single space when calling it
  • -7 bytes thanks to @vzwick
    • by aliasing String.replicate
    • by opening System instead of referencing it every time
  • -1 byte, no need for parenthesis when calling d.Next
  • -6 bytes, function is now one line

Explanation

open System
let z = String.replicate    // define alias
let s, d = z 54 " ", new Random() // s holds a flat representation of the glasses.. glasses
let rec(!) s =
    s=""; // type s to string
    printfn" %s\n|%s/__\\%s|\n|%s/    \\%s|\n|%s/%7s%s|\n\\_______/%9s_______/\n\n"
        (z 24 "_")     // top of the glasses
        (s.[..9])      // slice
        (s.[10..19])   // and
        (s.[20..28])   // dice
        (s.[29..37])   // the
        (s.[38..45])   // glasses
        "\\"           // \ gets prepended with 6 spaces thanks to %7s
        (s.[46..53])
        "\\";          // same deal, just 8 spaces this time
    Threading.Thread.Sleep(1000);
    if Seq.exists((<>)'@') s then // if not everything's totally covered
        d.Next 54                 // get new random int < 54 (string has indices 0-53)
        |> fun i->                // passing is shorter than a let binding, saves two spaces and a new line
            !(                    // call the function again with new drop on glasses
              (s.[i]              // get part of the glasses drop fell on
              |>function
              |' '->"."           // promote drop
              |'.'->"o"
              |'o'->"O"
              |_->"@")
              |>(fun c-> s.Remove(i,1).Insert(i,c))) // and insert this in the string
    else ()
!s

Brunner

Posted 2017-05-23T21:23:12.907

Reputation: 331

You can save 1 char by open System and removing System from the Random() and Threading.Thread.Sleep() calls ;) – vzwick – 2017-05-24T22:49:23.790

@vzwick thanks :) found another few bytes as I was editig – Brunner – 2017-05-25T08:44:00.343

2

Ruby, 237 224 228 218 206 198 197 bytes

g=" #{?_*24}
|x##/__ax##|
|x#/    ax#|
|x/      ax|
a#{u=?_*7}/xa#{u}/


".gsub ?x,?#*8;217.times{|t|puts g.tr('#a',' \\');()while t<216&&g[x=rand*106]!~/[#.oO]/;g[x]=g[x].tr '#.oO','.oO@';sleep 1}

Try it online!

Previous answer was wrong, it did not take into account a raindrop falling on a @. Apparently not a requirement. Some bytes saved.

This terminates with an error thrown, but this definitely terminates as soon as the full glasses are printed.

  • Saved 13 bytes by putting the printing into a lambda, and changing the assignment to use tr (duh)
  • 8 bytes loss with the 1 second requirement.
  • 10 bytes gain by using the gsub trick instead of interpolation (seen & adapted from mbomb007's Python answer).
  • 12 bytes gain by removing the lambda printing now that the print is written only once >.>
  • 1 byte gain by making all the \\ be a, then changing back inside the tr
  • 7 byte gain by putting the changing the spaces on the last line with another x (duh). In case some of you guys are wondering why this doesn't affect the main loop : the main loop doesn't consider the last line to determine its x.
  • 1 byte gain by removing the at the end of the top of the glasses

Yay < 200 bytes :D

Gif :

Gif

Jenkar

Posted 2017-05-23T21:23:12.907

Reputation: 211

3For future reference you can edit your previous answer to one that works instead of deleting it and adding a new one. – TheLethalCoder – 2017-05-24T14:02:13.353

Could you add in a gif of this running? – caird coinheringaahing – 2017-05-24T15:15:31.173

@RandomUser Done. – Jenkar – 2017-05-24T17:53:40.237

2

C, 313 309 305 304 bytes

Needs to be golfed down quite a bit;

c;f(r,q){for(char*m=" ________________________\n|**********/__\\**********|\n|*********/    \\*********|\n|********/      \\********|\n\\_______/        \\_______/\n";c<216;r=rand()%144,m-=135)for(system("clear");*m++;putchar(*m^42?*m:32))q=--r?*m:*m^42?*m^46?*m^111?*m^79?*m:64:79:111:46,c+=q!=*m,*m=q;}

I run it with the following test stub

main()
{
    srand(time(0));    
    f();
}

enter image description here

cleblanc

Posted 2017-05-23T21:23:12.907

Reputation: 3 360

2

Python 2, 365 328 bytes

That's a bit better...

import time,random
g=' '+'_'*24+r"""
|xxX/__\Xxx|
|xX/    \Xx|
|X/      \X|
\_______/        \_______/""".replace('X','x'*8)
while 1:
 print'\n'*3+g.replace('x',' ')
 s='x.oO@@'
 if all(c not in g for c in s[:-2]):exit()
 i,c=random.choice([(i,s[s.index(j)+1])for i,j in enumerate(g)if j in s])
 g=g[:i]+c+g[i+1:]
 time.sleep(1)

Try it online

The above link uses 30 lines instead of 3, but you can see it with 3 if you resize your browser window to be small enough vertically. Change time.sleep(1) to time.sleep(.1) for 10x speed.

mbomb007

Posted 2017-05-23T21:23:12.907

Reputation: 21 944

1

Bash, 576 510 429 416 Bytes

j()(IFS=
printf "$*")
for i in {53..0};{ a[$i]= 
b[$i]=@;}
while(($i == 0));do clear
echo  " ________________________
|`j ${a[@]::10}`/__\\`j ${a[@]:10:10}`|
|`j ${a[@]:20:9}`/    \\`j ${a[@]:29:9}`|
|`j ${a[@]:38:8}`/      \\`j ${a[@]:46}`|
\_______/        \_______/"
[ `j ${a[@]}` = `j ${b[@]}` ]&&{
i=1
}
sleep 1
d=`shuf -i0-53 -n1`
c=${a[$d]}
case $c in  )a[$d]=.;;.)a[$d]=o;;o)a[$d]=0;;0)a[$d]=@;esac
done

Wow, golfed a lot. If anyone have any idea for further golfing, I'm open to suggestions

Try it yourself! It has the sleep commented because of the 60 seconds limit

Here is the gif:

enter image description here

DrnglVrgs

Posted 2017-05-23T21:23:12.907

Reputation: 145

1

Perl, 167 bytes

Note that \x1b is a literal escape character.

$_="\x1bc 24_
|10X/__\\10X|
|9X/4 \\9X|
|8X/6 \\8X|
\\7_/8 \\7_/
";s/\d+(.)/$1x$&/ge;do{$a[rand 54]++,sleep print s/X/($",".",o,O)[$a[$-++%54]]||"@"/ger}while grep$_<4,@a

See it online!

Dom Hastings

Posted 2017-05-23T21:23:12.907

Reputation: 16 415

0

Mathematica, 438 bytes

f=Flatten;p=Print;z=32;q=95;l=124;t=Table;v=z~t~8;s={f@{z,q~t~24,z},f@{124,z~t~10,47,q,q,92,z~t~10,l},f@{l,z~t~9,47,z~t~4,92,z~t~9,l},f@{l,v,47,z~t~6,92,v,l},f@{92,q~t~7,47,v,92,q~t~7,47}};c=0;Monitor[While[c<54,a=s[[i=RandomInteger@{2,4},j=RandomChoice[Range[2,13-i]~Join~Range[14+i,25]]]];If[a==z,s[[i,j]]=46,If[a==46,s[[i,j]]=111,If[a==111,s[[i,j]]=48,If[a==48,s[[i,j]]=64]]]];c=Count[Flatten@s,64];Pause@1],Column@FromCharacterCode@s]

here is a 10x speed result gif

enter image description here

J42161217

Posted 2017-05-23T21:23:12.907

Reputation: 15 931

Never used Mathematica but could you assign to Table, 95 and 32? – caird coinheringaahing – 2017-05-23T23:55:31.010

As in t=Table x = 32 and y = 95? – caird coinheringaahing – 2017-05-24T06:16:55.803

yes of course. I golfed it a lot since yesterday – J42161217 – 2017-05-24T07:27:02.810

You might be able to remove 6 bytes by replacing the last Flatten with f? – caird coinheringaahing – 2017-07-24T09:05:39.550

0

PHP, 262 254 bytes

for($t=" 8_8_8_
|Y9Y/__\Y9Y|
|9Y/4 \9Y|
|8Y/6 \8Y|
\\7_/8 \\7_/";$c=$t[$i++];)$s.=$c<1?$c:str_repeat($t[$i++],$c);for(;$c=$s[++$k];)$c!=Y?:$s[$m[]=$k]=" ";for(;$u<216;print str_pad($s,999,"
",sleep(1)))$u+=($c=".oO@"[$a[$p=rand(0,53)]++])&&$s[$m[$p]]=$c;

Run with -nR or try it online.

breakdown

# prep 1: generate template from packed string
for($t=" 8_8_8_\n|Y9Y/__\Y9Y|\n|9Y/4 \9Y|\n|8Y/6 \8Y|\n\\7_/8 \\7_/";
    $c=$t[$i++];)$s.=$c<1?$c:str_repeat($t[$i++],$c);
# prep 2: map substituted spaces and replace with real spaces
for(;$c=$s[++$k];)$c!=Y?:$s[$m[]=$k]=" ";
# loop until glasses are fully wet:
for(;$u<216;
    # 4. print glasses prepended with 865 newlines
    print str_pad($s,999,"\n",
    # 3. wait 1 second
        sleep(1)))
    $u+=($c=".oO@"[
        $a[$p=rand(0,53)    # 1. pick random position
        ]++])               # 2. and increment
        &&$s[$m[$p]]=$c         # if not fully wet, graduate drop
    ;                           # and increment drop count ($u+=)

Titus

Posted 2017-05-23T21:23:12.907

Reputation: 13 814