1
Let it snow()

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
❄︎❅❆ options? ![]()
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 ![]()
This could be a perfect Easter Egg for Julia 1.8…
EDIT: By the way, does Julia have any ?
julia --lisp might count.
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?
Might be that your terminal app is struggling with the adverse weather conditions - it looks good in my MacOS Terminal.
If you want to control the wind, change the width of the terminal window after starting it.
It’s a bug feature
mcreel 11
Hah, that’s great, thanks for the bump.
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!
ianshmean 13
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
GHTaarn 14
This is cool, wouldn’t it be worthy of being released as a Julia package on Github or even the General registry?
GHTaarn 15
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
shouldn’t snowflakes be random and not following some trig function?
ianshmean 17
The trig part is introducing slow variations to the likelihood of the random generation of flakes to simulate wind flurries.
ianshmean 18
Hey ChatGPT. It’s 2024, the tree has grown, and other trees have started to grow around it. Also someone has put flashing lights on the trees…
using REPL
function snow(io = stdout)
# Grab terminal dimensions
h, w = displaysize(io)
iob = IOBuffer()
ioc = IOContext(IOContext(iob, io), :displaysize=>(h,w))
# Clear the screen, move cursor up
print(io, repeat("\n", h), "\e[$(h)A\e[1G")
# The grid that holds falling snow
air = ones(Int, w, h)
# Snowflake characters (index 1 is empty space)
flakes = [" ", "*", "❄︎", "❅", "❆"]
# Small sinusoidal helper to vary snowfall probability
scsin(t) = ((sin(t) / 2) + 0.5) * (0.1 / 3)
likelihood(t) = scsin(t) + scsin(t * 1.00001) + scsin(t * 0.9999)
# Print a single tree line with random “lights”
function printtreeline(ioc, length_of_line)
for i in 1:length_of_line
if rand() < 0.12
# White light
printstyled(ioc, "o", color=:white, bold=true)
else
# Standard green branch
printstyled(ioc, "x", color=:green)
end
end
end
# Draw a single “pine” at (base_row, center_col) with specified height + trunk
function draw_tree(ioc, base_row, center_col; height=12, trunk_height=3)
# Print each level from top to bottom
for lvl in 1:height
row = base_row - height + lvl
col = center_col - (lvl - 1)
print(ioc, "\e[$(row);$(col)H")
printtreeline(ioc, 2*lvl - 1)
end
# Print trunk
for trunk_lvl in 1:trunk_height
row = base_row + trunk_lvl
print(ioc, "\e[$(row);$(center_col)H")
printstyled(ioc, "│", color=:reverse)
end
end
try
while true
# Update the snowfall in 'air'
for x in 1:w, y in h:-1:1
air[x,y] = if y == 1
# Spawn new snowflakes at top
rand() < likelihood(time()) ? rand(2:length(flakes)) : 1
elseif y == h
# Accumulate at 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]))
rand() < 0.1 ? 2 : 1
else
# Normal falling
air[x, y-1]
end
end
# Print updated snow
foreach(space -> print(ioc, flakes[space]), air)
# Draw main (bigger) tree
main_tree_height = 14
trunk_height = 4
main_base_row = h - 2
main_center_col = div(w, 2)
draw_tree(ioc, main_base_row, main_center_col;
height=main_tree_height, trunk_height=trunk_height)
# Draw some smaller trees around it
draw_tree(ioc, main_base_row-2, main_center_col - 20; height=10, trunk_height=3)
draw_tree(ioc, main_base_row-2, main_center_col + 20; height=10, trunk_height=3)
draw_tree(ioc, main_base_row-6, main_center_col - 35; height=8, trunk_height=2)
draw_tree(ioc, main_base_row-6, main_center_col + 35; height=8, trunk_height=2)
# Move cursor home
print(ioc, "\e[H")
# REPL banner + prompt
@static VERSION > v"1.11.0-0" ? REPL.banner(ioc) : Base.banner(ioc)
printstyled(ioc, "julia> ", color = :green, bold = true)
println(ioc, "snow()")
# Flush buffer
print(io, String(take!(iob)))
# Slight pause
sleep(1/8)
end
catch e
isa(e, InterruptException) || rethrow()
end
nothing
end
Genius! Our favorite snow master is back.
cjdoris 20
For those of us on phone can we get a gif?