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!


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




A pair of glasses with drops of water on them.


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


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: @


  • 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.
  • \$\begingroup\$ "The code runs until the glasses are full of fully graduated drops" Perhaps specify an approximate sleep/wait time? Like 150 or 250 ms? \$\endgroup\$ May 24, 2017 at 8:14
  • 2
    \$\begingroup\$ Does the code have to stop when the glasses look like the final output or can it keep running but just not affect anything? \$\endgroup\$ May 24, 2017 at 8:28
  • \$\begingroup\$ @TheLethalCoder I would imagine until the glasses are full, as written in the spec :v \$\endgroup\$
    – Jenkar
    May 24, 2017 at 11:24
  • \$\begingroup\$ Droplet's random fall does have to fall randomly on lenses even on part of the bits of the lens that are @, right? \$\endgroup\$
    – Jenkar
    May 24, 2017 at 14:17
  • \$\begingroup\$ @TheLethalCoder it should terminate after all have graduated \$\endgroup\$ May 24, 2017 at 15:12

10 Answers 10


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@@"

Edit: Saved 2 4 bytes thanks to @Shaggy.

  • 3
    \$\begingroup\$ something goes wrong at the upper left corner \$\endgroup\$
    – ZaMoC
    May 24, 2017 at 1:51
  • \$\begingroup\$ -1 because it's bugged (see Jenny's comment) \$\endgroup\$ May 24, 2017 at 2:13
  • 1
    \$\begingroup\$ @DestructibleLemon Sorry about that, I got bitten by a "feature" of Firefox's clipboard... should be OK now. \$\endgroup\$
    – Neil
    May 24, 2017 at 8:05
  • \$\begingroup\$ 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. \$\endgroup\$
    – Shaggy
    May 24, 2017 at 8:55
  • 1
    \$\begingroup\$ @Shaggy Great find, thanks! \$\endgroup\$
    – Neil
    May 24, 2017 at 12:00

Java 8, 449 421 420 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;);g=t++>0?g.substring(0,n)+(x<36?".":x<47?"o":x<80?"@":"O")+g.substring(n+1):g;System.out.println(g.replace('#',' '));}}

-1 byte thanks to @ceilingcat.


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
                            //   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)
                            //    To find the next '#', '.', 'o' or 'O' randomly
    );                      //   End of inner loop (2)
    g=t++>0??               //   Flag so it prints the initial glasses without a raindrop
                            //    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


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

  • 1
    \$\begingroup\$ You 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 \$\endgroup\$
    – Khaled.K
    May 24, 2017 at 11:53
  • 1
    \$\begingroup\$ This does not account for the possibility of a drop falling on an @ :v \$\endgroup\$
    – Jenkar
    May 24, 2017 at 13:10
  • \$\begingroup\$ @Jenkar that is the second time you have said that on answers. Please explain what you mean. \$\endgroup\$ May 24, 2017 at 15:16
  • \$\begingroup\$ @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? \$\endgroup\$
    – Jenkar
    May 24, 2017 at 15:59
  • \$\begingroup\$ @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. \$\endgroup\$ May 24, 2017 at 16:02

Python 2, 365 328 bytes

That's a bit better...

import time,random
g=' '+'_'*24+r"""
|xX/    \Xx|
|X/      \X|
\_______/        \_______/""".replace('X','x'*8)
while 1:
 print'\n'*3+g.replace('x',' ')
 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])

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.


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()

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


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
        "\\";          // same deal, just 8 spaces this time
    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
              |' '->"."           // promote drop
              |>(fun c-> s.Remove(i,1).Insert(i,c))) // and insert this in the string
    else ()
  • \$\begingroup\$ You can save 1 char by open System and removing System from the Random() and Threading.Thread.Sleep() calls ;) \$\endgroup\$
    – vzwick
    May 24, 2017 at 22:49
  • \$\begingroup\$ A few more characters shaved: tio.run/##TZDfa4NADMff/… \$\endgroup\$
    – vzwick
    May 24, 2017 at 23:07
  • \$\begingroup\$ @vzwick thanks :) found another few bytes as I was editig \$\endgroup\$
    – Brunner
    May 25, 2017 at 8:44

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


enter image description here


Ruby, 237 224 228 218 206 198 197 bytes

g=" #{?_*24}
|x#/    ax#|
|x/      ax|

".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 :


  • 3
    \$\begingroup\$ For future reference you can edit your previous answer to one that works instead of deleting it and adding a new one. \$\endgroup\$ May 24, 2017 at 14:02
  • \$\begingroup\$ Could you add in a gif of this running? \$\endgroup\$ May 24, 2017 at 15:15
  • \$\begingroup\$ @RandomUser Done. \$\endgroup\$
    – Jenkar
    May 24, 2017 at 17:53

Mathematica, 438 bytes


here is a 10x speed result gif

enter image description here

  • \$\begingroup\$ Never used Mathematica but could you assign to Table, 95 and 32? \$\endgroup\$ May 23, 2017 at 23:55
  • \$\begingroup\$ As in t=Table x = 32 and y = 95? \$\endgroup\$ May 24, 2017 at 6:16
  • \$\begingroup\$ yes of course. I golfed it a lot since yesterday \$\endgroup\$
    – ZaMoC
    May 24, 2017 at 7:27
  • \$\begingroup\$ You might be able to remove 6 bytes by replacing the last Flatten with f? \$\endgroup\$ Jul 24, 2017 at 9:05

Bash, 576 510 429 416 Bytes

printf "$*")
for i in {53..0};{ a[$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[@]}` ]&&{
sleep 1
d=`shuf -i0-53 -n1`
case $c in  )a[$d]=.;;.)a[$d]=o;;o)a[$d]=0;;0)a[$d]=@;esac

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


Perl, 167 bytes

Note that \x1b is a literal escape character.

$_="\x1bc 24_
|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!


PHP, 262 254 bytes

for($t=" 8_8_8_
|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,"

Run with -nR or try it online.


# 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_/";
# 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:
    # 4. print glasses prepended with 865 newlines
    print str_pad($s,999,"\n",
    # 3. wait 1 second
        $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+=)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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