Let it snow()

Let it snow()

juliasnow

The code could definitely be golfed…

function snow(io = stdout)
    h, w = displaysize(io)
    iob = IOBuffer()
    ioc = IOContext(IOContext(iob, io), :displaysize=>(h,w))
    print(io, repeat("\n", h), "\e[", h, "A\e[1G") # new lines and move back up
    air = ones(Int, w, h)
    flakes = [" ", "*", "❄︎", "❅", "❆"]
    scsin(t) = ((sin(t) / 2) + 0.5) * (0.1 / 3)
    likelihood(t) = scsin(t) + scsin(t * 1.00001) + scsin(t * 0.9999)
    try
        while true
            for x in 1:w, y in h:-1:1
                air[x,y] = if y == 1 # new flakes
                    rand() < likelihood(time()) ? rand(2:length(flakes)) : 1
                elseif y == h # accumulate bottom
                    ((rand() < 0.95 && air[x,y] > 1) || (air[x, y-1] > 1 && rand() < 0.2)) ? 2 : 1
                elseif all(>(1), air[x, y:end]) # melt pile sometimes
                    rand() < 0.95 ? 2 : 1
                elseif (air[x, y-1] > 1 && all(>(1), air[x, (y+1):end])) # if flake coming and piled up below
                    rand() < 0.1 ? 2 : 1
                else # fall downwards otherwise
                    air[x, y-1]
                end
            end
            print(ioc, "\e[", h, "A\e[1G") # move back to start
            print.((ioc,), flakes[air])
            print(ioc, "\e[", h, "A\e[1G") # move back to start
            Base.banner(ioc)
            printstyled(ioc, "julia> ", color = :green, bold = true)
            println(ioc, "snow()")
            print(io, String(take!(iob)))
            sleep(1/8)
        end
    catch e
        isa(e,InterruptException) || rethrow()
    end
    nothing
end
116 Likes

❄︎❅❆ options? :rofl:

15 Likes

This is awesome! Please share it on Twitter and Tag the Julia account. I also want to set my REPL up to show this in the background when I am running code :smile:

13 Likes

@ianshmean: https://twitter.com/JuliaLanguage/status/1470423267576008704?s=20

4 Likes

This could be a perfect Easter Egg for Julia 1.8…

EDIT: By the way, does Julia have any ?

1 Like

julia --lisp might count.

4 Likes

The first snowflakes * were falling vertically on my REPL.

However, the last ones *, ❄︎, ❅, ❆ seem to fall with strong side winds…

Aren’t the JuliaMono fonts mono-flake?

2 Likes

Might be that your terminal app is struggling with the adverse weather conditions - it looks good in my MacOS Terminal.

4 Likes

If you want to control the wind, change the width of the terminal window after starting it.
It’s a bug feature

12 Likes

I was just trying to find this! Just in time for that time of year! :snowflake: :christmas_tree: :santa: :coffee:

8 Likes

Hah, that’s great, thanks for the bump.

1 Like

Adding a tree under the snow:

using Printf
foreach(i-> @printf("%19s%-19s\n", "❅".^(i,i-1)...), 1:9)
foreach(_-> @printf("%19s\n", "❅"), 1:3)

Happy Holidays!

6 Likes

Adding the tree to the scene (and making it work on 1.11 given the banner moved to REPL)

using REPL, Printf
function snow(io = stdout)
    h, w = displaysize(io)
    iob = IOBuffer()
    ioc = IOContext(IOContext(iob, io), :displaysize=>(h,w))
    print(io, repeat("\n", h), "\e[", h, "A\e[1G") # new lines and move back up
    air = ones(Int, w, h)
    flakes = [" ", "*", "❄︎", "❅", "❆"]
    scsin(t) = ((sin(t) / 2) + 0.5) * (0.1 / 3)
    likelihood(t) = scsin(t) + scsin(t * 1.00001) + scsin(t * 0.9999)
    try
        while true
            for x in 1:w, y in h:-1:1
                air[x,y] = if y == 1 # new flakes
                    rand() < likelihood(time()) ? rand(2:length(flakes)) : 1
                elseif y == h # accumulate bottom
                    ((rand() < 0.95 && air[x,y] > 1) || (air[x, y-1] > 1 && rand() < 0.2)) ? 2 : 1
                elseif all(>(1), air[x, y:end]) # melt pile sometimes
                    rand() < 0.95 ? 2 : 1
                elseif (air[x, y-1] > 1 && all(>(1), air[x, (y+1):end])) # if flake coming and piled up below
                    rand() < 0.1 ? 2 : 1
                else # fall downwards otherwise
                    air[x, y-1]
                end
            end
            print(ioc, "\e[H") # move back to home
            foreach(space -> print(ioc, flakes[space]), air)
            print(ioc, "\e[H") # move back to home
            print(ioc, "\e[$(h-13)B\e[1G") # move to 12th row from bottom, col 1
            foreach(i-> @printf(ioc, "%19s%-19s\n", "❅".^(i,i-1)...), 1:9) # tree
            foreach(_-> @printf(ioc, "%19s\n", "❅"), 1:3) # trunk
            print(ioc, "\e[H") # move back to home
            @static VERSION > v"1.11.0-0" ? REPL.banner(ioc) : Base.banner(ioc)
            printstyled(ioc, "julia> ", color = :green, bold = true)
            println(ioc, "snow()")
            print(io, String(take!(iob)))
            sleep(1/8)
        end
    catch e
        isa(e,InterruptException) || rethrow()
    end
    nothing
end
6 Likes

This is cool, wouldn’t it be worthy of being released as a Julia package on Github or even the General registry?

3 Likes

Removing the snowless rectangle around the tree:

using REPL

function snow(io = stdout)
    h, w = displaysize(io)
    iob = IOBuffer()
    ioc = IOContext(IOContext(iob, io), :displaysize=>(h,w))
    print(io, repeat("\n", h), "\e[", h, "A\e[1G") # new lines and move back up
    air = ones(Int, w, h)
    flakes = [" ", "*", "❄︎", "❅", "❆"]
    scsin(t) = ((sin(t) / 2) + 0.5) * (0.1 / 3)
    likelihood(t) = scsin(t) + scsin(t * 1.00001) + scsin(t * 0.9999)
    try
        while true
            for x in 1:w, y in h:-1:1
                air[x,y] = if y == 1 # new flakes
                    rand() < likelihood(time()) ? rand(2:length(flakes)) : 1
                elseif y == h # accumulate bottom
                    ((rand() < 0.95 && air[x,y] > 1) || (air[x, y-1] > 1 && rand() < 0.2)) ? 2 : 1
                elseif all(>(1), air[x, y:end]) # melt pile sometimes
                    rand() < 0.95 ? 2 : 1
                elseif (air[x, y-1] > 1 && all(>(1), air[x, (y+1):end])) # if flake coming and piled up below
                    rand() < 0.1 ? 2 : 1
                else # fall downwards otherwise
                    air[x, y-1]
                end
            end
            foreach(space -> print(ioc, flakes[space]), air)
            for itree in 1:12
                print(ioc, "\e[H") # move back to home
                if itree <= 9
                    print(ioc, "\e[$(h-14+itree)B\e[$(19-itree)G")
                    printstyled(ioc, "x"^(2*itree-1), color=:green)
                else # Trunk
                    print(ioc, "\e[$(h-14+itree)B\e[18G")
                    printstyled(ioc, "-", color=:reverse)
                end
            end
            print(ioc, "\e[H") # move back to home
            @static VERSION > v"1.11.0-0" ? REPL.banner(ioc) : Base.banner(ioc)
            printstyled(ioc, "julia> ", color = :green, bold = true)
            println(ioc, "snow()")
            print(io, String(take!(iob)))
            sleep(1/8)
        end
    catch e
        isa(e,InterruptException) || rethrow()
    end
    nothing
end
8 Likes

shouldn’t snowflakes be random and not following some trig function?

The trig part is introducing slow variations to the likelihood of the random generation of flakes to simulate wind flurries.

5 Likes