Let's build an advent Calendar for this Christmas!

Many Advent calendars for children take the form of a large rectangular card with numbered windows for each day of December starting from 1 ( although advent time begins on Advent Sunday, which is the fourth Sunday before Christmas day and often happens to be on November) and leading up to and including Christmas Eve (24) or in some cases Christmas day (25).
Windows are distributed across the calendar at a random position.
Every day children open the corresponding calendar window to reveal a small gift(usually a chocolate)

The task is to display an advent calendar up to date following these rules:

• Include Christmas day : 1 to 25
• For days that have passed put an opened empty window [ ] ( no different characters allowed ), so if i run the same code the next day there must be a new window opened.
• At the current day put an opened window with a gift in it [@] ( instead of @ you can use every printable character excep for space, [ , ] and digits ).
• For the remaining days put only the day number.
• At Christmas all the windows will be open, the next day they are all closed ( a new calendar ).
• Windows must open only on December, windows must stay closed on every month except for December.
• It should work the same way the next year, and every year, that is for example on December 2099 Windows start opening.
• Windows are laid down in random order on a 5 rows x 5 columns grid.
• The grid has not to be accurate, just consider that every windows must have at least one character space separating them on every side: left, top, right and bottom hence numbers must have left and right spaces of at least two characters.

# Example

Today (15 December) :



23   21   [ ]   18   [ ]

[ ]   [ ]   [ ]   [ ]   16

24   22   [ ]   17   [ ]

[ ]   [ ]   [ ]   25   19

[ ]   [ ]   [@]   [ ]   20



Tomorrow (16 December) :



[ ]   17   25   [ ]   [ ]

[ ]   19   [ ]   18   21

[ ]   23   24   [ ]   [ ]

22   [@]   [ ]   [ ]   [ ]

[ ]   20   [ ]   [ ]   [ ]



On every month different than December

18 23 21 12 19
25 24 3 15 14
16 9 17 20 4
8 2 11 5 7
6 13 10 22 1


Live example

All rules apply.

• Is it supposed to work as well for the next coming years or only for this year? (I suppose it's possible to golf a few bytes on some implementations by assuming a 2019 timestamp.) Dec 15, 2019 at 0:41
• So this was in the Sandbox for… 8 minutes?
Dec 15, 2019 at 0:43
• @Adám sorry but Christmas is just around the corner, since there was no Christmas challenge I felt a bit sad, I used the sandbox to check if my script worked but as I expected it didn't. This is an exception, I'll continue to use the sandbox in the future. Dec 15, 2019 at 0:57
• @Jo King I don't want to see only open windows, at this time we have a good open/closed ratio Dec 15, 2019 at 1:06
• Earlier this year, I saw an Advent calendar where the gift was a different bottle of wine, so it's not just for kids to enjoy the gifts! Dec 15, 2019 at 1:59

# APL (Dyalog Extended), 57 bytesSBCS

Full program.

5 5⍴('[ ]'¨@{⍵∊⍳d}'[@]'¨@{⍵=d})⍣(</11 25≥m d←2↑1↓⎕TS)?⍨25


Try it online!

?⍨25 random selection without replacement of 25 out of 1…25

⍣() if:

⎕TS date in [Y,M,D,h,m,s,t] format

1↓ drop one element; [M,D,h,m,s,t]

2↑ take two elements; [M,D]

m d← distribute to variables m=M and d=D (for month-of-year and day-of-month numbers)

11 25≥ are [11,25] greater than or equal to these (gives [0,1] during advent, [1,0] or [1,1] before, and [0,0] after)

</ if the first number is less than the second…

() then apply the following function:

@{} at elements where the following condition is true:

⍵=d the elements are equal to d (today's day-of-month number)

'[@]'¨ replace each with the constant "[@]"

@{} at elements where the following condition is true:

⍵∊⍳d the elements are members of 1…d (today's day-of-month number)

'[ ]'¨ replace each with the constant "[ ]"

5 5⍴ reshape into a five-by-five matrix

• I started learning APL but I'm still at early stages (chapter 10) , I suppose it checks for months as </11 25≥m , can I ask you why you used p in the input? Is it something like an anonymous function? Dec 15, 2019 at 1:19
• @AZTECCO p is just the name of the program. TIO's Input corresponds to APL's session (REPL), so p is there to run the program.
Dec 15, 2019 at 1:20
• @AZTECCO I'm always happy to assist with your APL learning over in the APL Orchard.
Dec 15, 2019 at 1:27
• @AZTECCO And regarding the checking for months, yes indeed. I've added a full explanation now. Let me know if you want any further explanation of the algorithm.
Dec 15, 2019 at 1:28

# Python 2, 181189181 179 Bytes

### Original Code

Since I can't comment on other answers yet, this is a slight improvement on ElPedro's previous answer. Try it online! I changed ElPedro's 5th line to save an additional 9 bytes.

i=__import__
t=i("datetime").date.today();n=t.day
c=[('['+(' ','@')[d==n]+']',d)[t.month<12or d>n]for d in i("random").sample(range(1,26),25)]
while c:print' '.join(c[:5]);c=c[5:]


### Correction #1

Gained 6 bytes in order to fix an error where windows remain open after December 25th until the new year. Try it online!
See corrected version of line 3 below:

c=[('['+(' ','@')[d==n]+']',d)[t.month<12or n>25or d>n]for d in i("random").sample(range(1,26),25)]


### Correction #2

As per AZTECCO's suggestions, I'm back at 181 bytes :) Try it online!

c=[('['+' @'[d==n]+']',d)[t.month-12|25-n|n-d<0]for d in i("random").sample(range(1,26),25)]


### Final

With streamlined import statements (Thanks to Reinstate Monica)

import random,datetime as D
t=D.date.today();n=t.day
c=[('['+' @'[d==n]+']',d)[t.month-12|25-n|n-d<0]for d in random.sample(range(1,26),25)]
while c:print' '.join(c[:5]);c=c[5:]

• Hi and welcome to the site! Thanks for crediting me with the original answer. There seems to be a small problem with dates after 25 Dec Try it online!. If you fix that you will certainly get an upvote from me :) Dec 16, 2019 at 19:48
• Nice catch! Thanks for pointing that out. The new version should work past Dec 25th now :) Dec 16, 2019 at 22:15
• Suggestion c=[('['+' @'[d==n]+']',d) Dec 16, 2019 at 23:52
• [t.month-12|25-n|n-d<0] saves 2 more (if one of the 3 sets some negative bits the expression becomes true) Dec 17, 2019 at 0:15
• You can get this even shorter in Python 3 Dec 17, 2019 at 16:55

# Perl 6, 91 bytes

-1 bytes thanks to nwellnhof

.put for (("[@]"if Date.today~~/12.(0?@(^26))$/),"[ ]"xx+$0,+$0^..25)[*;*].pick(*).rotor(5)  Try it online! ### Explanation: .put for ( ... ) # Print for each of ("[@]"if Date.today~~/12.(0?@(^26))$/), # [@] if today is within the Christmas period
"[ ]"xx+$0, # As many [ ]s as the current date +$0^..25        # All the number from today to the 25th
[*;*]                  # Flatten
.pick(*)          # Randomise
.rotor(5) # And split into chunks of 5

• I think you need xx+$0 if the regex doesn't match. But @(^26) saves a byte. Dec 15, 2019 at 9:37 # JavaScript (ES6), 158 ... 150 148 bytes Saved 2 bytes thanks to @Deckerz Note: Strictly speaking, this should be marked as ES9 (ECMAScript 2018), in which the output format of Date.prototype.toString has been standardized. f=(k=25,m,d=Math.random()*25+1|0,t=(new Date+0).match(/c ([01].|2[0-5])|:/)[1])=>k?(m^(m|=1<<d)?(d^t?d<t?'[ ]':d:'[@]')+ [--k%5&&1]:'')+f(k,m):''  Try it online! ### How? (new Date).toString() returns the current date in the following format: DDD MMM dd yyyy hh:mm:ss TimeZoneString  For instance: Sun Dec 15 2019 12:29:35 GMT+0000 (Coordinated Universal Time)  We apply the following regular expression to this string: /c ([01].|2[0-5])|:/  It attempts to match a day of December less than $$\26\$$ (it's the only month whose 3-letter abbreviation ends in "c"). If not found, we force the first : separator to be matched instead, in order to prevent match() from returning null. Therefore, the variable $$\t\$$ (for 'today') is set to either a valid day of December, or undefined if we're outside the relevant period: t = (new Date + 0).match(/c ([01].|2[0-5])|:/)[1]  $$\f\$$ is a recursive function that generates a random day $$\d\$$ in $$\[1-25]\$$ at each iteration and draws the corresponding slot in the calendar. It keeps track of drawn days in the bitmask $$\m\$$. f = ( // f is a recursive function taking: k = 25, // k = remaining number of days to draw m, // m = bitmask of drawn days d = Math.random() * 25 // d = random day in [1-25] + 1 | 0, // t = ... // t = current day or undefined (see above) ) => // k ? // if k is not equal to 0: ( m ^ (m |= 1 << d) ? // if m is modified by setting the d-th bit: ( d ^ t ? // if d is not equal to t: d < t ? // if t is defined and d is less than t: '[ ]' // draw an opened window : // else: d // draw a closed window : // else: '[@]' // draw today's gift ) + // \n  // decrement k; append a linefeed at the end of a row [--k % 5 && 1] // or a space otherwise : // else: '' // we need to pick another day: leave k unchanged and // append nothing ) + f(k, m) // append the result of a recursive call : // else: '' // done: stop recursion  • does it check for months? Dec 15, 2019 at 1:13 • although I found your motivation convincing I'm glad you updated your answer. And it's a very valuable one! Dec 15, 2019 at 15:22 • @AZTECCO No worries. On second thought, I think it actually makes much more sense to test the month. Dec 15, 2019 at 15:51 • Saved you 2 bytes f=(a=25,b,c=0|25*Math.random()+1,d=(new Date+0).match(/c ([01].|2[0-5])|:/)[1])=>a?(b^(b|=1<<c)?(c^d?c<d?"[ ]":c:"[@]")+ [--a%5&&1]:"")+f(a,b):"" Dec 16, 2019 at 17:18 • @Deckerz Good catch. Thanks! Dec 16, 2019 at 19:57 # 05AB1E, 38373231 30 bytes žeD₂‹žfÂ‹P'@ú€…[ÿ]Dg25Ÿ«¦.r5ô»  -6 bytes thanks to @Grimmy. Explanation: že # Push the current day D # Duplicate it ₂‹ # Check if it's smaller than 26 žf # Push the current month Â # Bifurcate it (short for Duplicate & Reverse copy) ‹ # And check if this is smaller than the month itself # (this will check 1-9 < 1-9 (falsey); 10 < 01 (falsey); 11 < 11 (falsey); # and 12 < 21 (truthy) - so this will only be truthy for 12 / December) P # Take the product of the day and both checks, # which result in either the day, or 0 if either check was falsey '@ '# Push character "@" ú # Pad it with the earlier number amount of spaces € # Map over each of these characters: …[ÿ] # Push string "[ÿ]", where the ÿ is automatically filled with the character Dg # Duplicate the list, and pop and push its length 25Ÿ # Create a list in the range [length, 25] « # And merge it to the earlier created list ¦ # Then remove the first item (either a "[ ]", or the "[@]" if the checks # were falsey) .r # Randomly shuffle the list 5ô # Split the list into sublists of size 5 » # Join each inner list by spaces, and these strings by newlines # (after which the result is output implicitly)  • 32 Dec 17, 2019 at 16:13 • @Grimmy I was about to save the edits of the 33 byte version.. And that one 32-byte version can be golfed further to 31 by using €…[ÿ]. :) Dec 17, 2019 at 16:19 • Alternative 31 Dec 17, 2019 at 16:34 • 12Q to Â‹ for -1. Dec 18, 2019 at 16:46 • @Grimmy Oh, very smart, thanks! :) Dec 18, 2019 at 17:50 # R, 113 103 bytes x=as.POSIXlt(Sys.time()) a=sample(25) if(x$mo>10&(y=x$md)<26){a[a<y]="[ ]";a[a==y]="[@]"} write(a,"",5)  Try it online! A full program that prints an advert calendar as specified. # Python 2, 231222216202197193 189 bytes i=__import__ t=i("datetime").date.today() y=t.day d=[(((x,"[ ]")[x<y],"[@]")[x==y],x)[t.month<12or y>25]for x in i("random").sample(range(1,26),25)] while d:print' '.join(d[:5]);d=d[5:]  Try it online! -3 with many thanks to @AZTECCO Examples below use an earlier version of the answer but the formula is the same. Before December: Try it online! December after 25th: Try it online! # Red, 135 bytes d: now c: collect[repeat n 25[keep n]]if all[d/3 = 12 d/4 < 26][repeat n d/4[c/:n:"[ ]"]c/:n:"[@]"]random c loop 5[print take/part c 5]  Try it online! # Jelly, 76 75 bytes ⁶o”@;Ø[jⱮ;@Jị@ “j⁶ṖgqS^OßƭẸ#pÆẸ¥aRŀçĠrṬỤ{½9?ȷ²Yḅ»ḲḢ;Ɱ$ŒV12;Ɱ25¤i+Ɱ25ẊÇs5K€Y


Try it online!

A full program that prints an advent calendar. Longer than most Jelly programs because it has to call __import__('datetime').datetime.today().month and __import__('datetime').datetime.today().day in Python.

If the date and time could be provided as an argument, it could be much shorter:

# Jelly, 35 34 bytes

⁶o”@;Ø[jⱮ;@Jị@
12;Ɱ25¤i+Ɱ25ẊÇs5K€Y


Try it online!

• How would the code look if given month and day as arguments?
Dec 15, 2019 at 16:08
• @Adám I’ve added a version that does this. Dec 15, 2019 at 16:26

# Ruby, 112 bytes

x=[*1..25].shuffle;5.times{|c|puts x[c*5,5].map{|w|['[@]','[ ]',w][((d=Time.now).day-(d.month-12)*30)<=>w]}*" "}


Try it online!

# C#, 267 bytes

using System;using System.Linq;class _{static void Main(){var n=DateTime.Now;var t=n.Month==12?n.Day:0;Console.WriteLine(string.Join(" ",Enumerable.Range(1,25).OrderBy(_=>new Random().Next(-9,9)).Select((d,i)=>(i%5==0?"\r\n":"")+(d<t?$"[ ]":d>t?$"{d}":"[@]"))));}}


.Net Fiddle