20
\$\begingroup\$

Your challenge is extremely simple. Given a year as input, print all the months in that year that will contain a Friday the 13th according to the Gregorian calendar. Note that even though the Gregorian Calendar wasn't introduced until 1582, for simplicity's sake we will pretend that it has been in use since 0001 AD.

Rules

  • Full programs or functions are allowed.

  • You can take input as function arguments, from STDIN, or as command line arguments.

  • You are not allowed to use any date and time builtins.

  • You can safely assume that the input will be a valid year. If the input is smaller than 1, not a valid integer, or larger than your languages native number type, you do not have to handle this, and you get undefined behaviour.

  • Output can be numbers, in English, or in any other human readable format, so long as you specify the standard.

  • Make sure you account for leap-years. And remember, leap-years do not happen every 4 years!

Tips

Since there are so many different ways to go about this, I don't want to tell you how to do it. However, it might be confusing where to start, so here are a couple different reliable ways of determining the day of the week from a date.

Sample IO

2016 --> May
0001 --> 4, 7
1997 --> Jun
1337 --> 09, 12
123456789 --> January, October

As usual, this is code-golf, so standard-loopholes apply, and shortest answer wins.

var QUESTION_ID=69510,OVERRIDE_USER=31716;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"http://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

\$\endgroup\$
8
  • 5
    \$\begingroup\$ When run on Friday the 13th, it should reverse and output months that don't have a Friday the 13th. (Freaky Friday references for the win) \$\endgroup\$ Commented Jan 16, 2016 at 1:05
  • 1
    \$\begingroup\$ Related \$\endgroup\$ Commented Jan 16, 2016 at 2:08
  • \$\begingroup\$ Is this example right: 0001 --> 5? According to this page (and my code) it should be April and July. \$\endgroup\$
    – faubi
    Commented Jan 17, 2016 at 4:02
  • \$\begingroup\$ @faubiguy my bad, you're right. That was on The Julian Calendar. Let me fix that. \$\endgroup\$
    – DJMcMayhem
    Commented Jan 17, 2016 at 4:07
  • \$\begingroup\$ By "you are not allowed to use any date or time builtins", is it that I can't convert to unix time either? \$\endgroup\$
    – busukxuan
    Commented Jan 26, 2016 at 8:56

6 Answers 6

2
\$\begingroup\$

Python 2, 157 144 136 Bytes

My solution uses the Gauss-Algorithm. Input is the year as Integer. Output is the list of months with a friday 13th as numbers (1-12). Probably some more golfing possible, but its getting late... Gonna edit this one tomorrow und get this down a bit more. Suggestions are always welcome in the meantime!

def f(i):y=lambda m:(i-1,i)[m>2];print[m for m in range(1,13)if(13+int(2.6*((m-2)%12,12)[m==2]-.2)+y(m)%4*5+y(m)%100*4+y(m)%400*6)%7==5]

edit: Got it down to 144 by replacing the for-loop with a list comprehesion und making some other small adjustments.

edit2: Golfed it down to 136 with the suggestions from Morgan Thrapp and fixed the bug he discovered. Thanks a lot! :)

\$\endgroup\$
0
2
\$\begingroup\$

C - 164 153 112 bytes

I found a nice little solution using a heavily modified version of Schwerdtfeger's method. It encodes the necessary table in an integer using base 7, modified to fit in a signed 32-bit word. It outputs the month as an ASCII-character, with January encoded as 1, February as 2 and so on, with October encoded as :, November encoded as ; and December encoded as <.

t=1496603958,m;main(y){for(scanf("%d",&y),y--;(y%100+y%100/4+y/100%4*5+t+5)%7||putchar(m+49),t;t/=7)2-++m||y++;}

Here it is slightly ungolfed:

t=1496603958,m;
main(y){
  for(
    scanf("%d",&y),y--;
    (y%100+y%100/4+y/100%4*5+t+5)%7||putchar(m+49),t;
    t/=7
  )
    2-++m||y++;
}

I am sure there are a few ways to make it even smaller, but I think the algorithm, or a slight variation thereof, is nearly ideal for finding the months where Friday the 13th occurs (with respect to code size). Notes:

  1. If a 64-bit word could have been used it would be possible to get rid of an annoying addition (+5).
  2. The variable m isn't actually necessary, since the month we are looking at is deducible from t.

I leave my older answer below, seeing as it uses a completely different method not seen in other answers here.


This is based on a solution to a related problem (https://codegolf.stackexchange.com/a/22531/7682).

Y,M,D,d;main(y){for(scanf("%d",&y);Y<=y;++D>28+(M^2?M+(M>7)&1^2:!(Y&3)&&(Y%25||!(Y&15)))&&(D=1,M=M%12+1)<2&&Y++)(d=++d%7)^1||D^13||y^Y||printf("%d,",M);}

It basically simulates the Gregorian calendar, advancing one day at a time, printing the month when it is a Friday and the 13th. Here it is in a slightly more readable form:

Y,M,D,d;
main(y){
  for(
    scanf("%d",&y);
    Y<=y;
    ++D>28+(
      M^2
        ?M+(M>7)&1^2
        :!(Y&3)&&(Y%25||!(Y&15))
    )&&(
      D=1,
      M=M%12+1
    )<2&&Y++
  )
    (d=++d%7)^1||D^13||y^Y||
      printf("%d,",M);
}
\$\endgroup\$
3
  • \$\begingroup\$ impressive ecc but not find in 123456789 --> January, October october \$\endgroup\$
    – user58988
    Commented Oct 28, 2016 at 23:50
  • \$\begingroup\$ Hmm, it does for me. Might me some platform dependent reason? It works for me on a fairly modern Macbook Pro when compiling with Clang. Note that it outputs 1: for 123456789, where : denotes October. I clarified the encoding above. \$\endgroup\$
    – Fors
    Commented Oct 29, 2016 at 17:25
  • \$\begingroup\$ Yes 1: here too; I not understood ':' was for October... \$\endgroup\$
    – user58988
    Commented Oct 29, 2016 at 19:57
1
\$\begingroup\$

Pyth, 73 Bytes

L?>b2QtQfq%+++13+/-*2.6?qT2 12%-T2 12 .2 1*5%yT4*4%yT100*6%yT400 7 5r1 13

Try it online!

Using the Gauss-Algorithm, like in my Python answer. ~55 bytes of the code are for the weekday calculation, so choosing a better algorithm could get this down by a lot I suppose...but hey, at least its working now! :)

\$\endgroup\$
0
1
\$\begingroup\$

Perl - 141 107 103 bytes

$y=<>-1;map{$y++if++$i==3;print"$i "if($y+int($y/4)-int($y/100)+int($y/400))%7==$_}'634163152042'=~/./g

This uses a modified version of the formula for the Julian day to calculate the day of the week of March 13th, then uses the number of days of the week each month is offset from January to find the day of the week for the rest of the months, starting with the last 2 months of the previous year beginning in March then the first 10 months of the current year (to avoid calculating leap years twice).

\$\endgroup\$
0
\$\begingroup\$

Excel, 137 bytes

Takes input year in A1. Output is non-separated list of Hexidecimal. (January = 0, December = B)

Uses Gauss's Algorithm for January and August.

=CHOOSE(MOD(6+5*MOD(A1-1,4)+4*MOD(A1-1,400),7)+1,"","",1,"","",0,"")&CHOOSE(MOD(5*MOD(A1-1,4)+4*MOD(A1-1,400),7)+1,9,35,"8B",5,"2A",7,4)
\$\endgroup\$
2
  • \$\begingroup\$ This answer currently uses date and time builtins, which is explicitly stated as against the rules in the challenge. \$\endgroup\$
    – Fors
    Commented Oct 27, 2016 at 18:34
  • \$\begingroup\$ @Fors, Thanks for pointing that out. Updated. \$\endgroup\$
    – Wernisch
    Commented Oct 28, 2016 at 13:28
0
\$\begingroup\$

C, 276 219 bytes

#define R return
#define L(i) for(;i-->0;) 
u(y,m){R m-1?30+((2773>>m)&1):28+(y%4==0&&y%100||y%400==0);}s(y,m,g){g+=4;L(m)g+=u(y,m),g%=7;L(y)g+=1+u(y,1),g%=7;R g;}z(y,m,r){m=12;L(m)s(y,m,13)-4||(r|=1<<(m+1));R r;}

input from stdin output in stdout try to http://ideone.com/XtuhGj [the debug function is z]

w(y,m,r){m=12;L(m)s(y,m,u(y,m))||(r|=1<<(m+1));R r;}
/*    
// ritorna il numero dei giorni di anno=y mese=m con mese in 0..11
// m==1 significa febbraio   y%4?0:y%100?1:!(y%400) non funziona
u(y,m){R m-1?30+((2773>>m)&1):28+(y%4==0&&y%100||y%400==0);}

// argomenti anno:y[0..0xFFFFFFF]  mese:m[0..11]  giorno:g[1..u(y,m)]
// ritorna il numero del giorno[0..6]
s(y,m,g)
{g+=4; // correzione per il giorno di partenza anno mese giorno = 0,1,1
 L(m)g+=  u(y,m),g%=7; // m:0..m-1  somma mod 7 i giorni del mese dell'anno y
 L(y)g+=1+u(y,1),g%=7; // y:0..y-1  somma mod 7 gli anni da 0..y-1
                       // g+=1+u(y,1) poiche' (365-28)%7=1 e 1 e' febbraio
 R g;
}

// argomenti anno:y[0..0xFFFFFFF], m=0 r=0 
// calcola tutti gli ultimi giorni del mese dell'anno y che cadono di lunedi'
// e mette tali mesi come bit, dal bit 1 al bit 12 [il bit 0 sempre 0] in r
w(y,m,r){m=12;L(m)s(y,m,u(y,m))||(r|=1<<(m+1));R r;}

// argomenti anno:y[0..0xFFFFFFF], m=0 r=0 
//ritorna in r il numero dei mesi che ha giorno 13 di venerdi[==4]
// e mette tali mesi come bit, dal bit 1 al bit 12 [il bit 0 sempre 0] in r
z(y,m,r){m=12;L(m)s(y,m,13)-4||(r|=1<<(m+1));R r;}
*/

#define P printf
#define W while 
#define M main 
#define F for
#define U unsigned
#define N int
#define B break
#define I if
#define J(a,b)  if(a)goto b
#define G goto
#define P printf
#define D double
#define C unsigned char
#define A getchar()
#define O putchar
#define Y malloc
#define Z free
#define S sizeof
#define T struct
#define E else
#define Q static
#define X continue
M()
{N y,m,g,r,arr[]={1,297,1776,2000,2016,3385}, arr1[]={2016,1,1997,1337,123456789};
 C*mese[]={"gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic"};
 C*giorno[]={"Lun","Mar","Mer","Gio","Ven","Sab","Dom"};
 P("Inserisci Anno mese giorno>");r=scanf("%d %d %d", &y, &m, &g);
 P("Inseriti> %d %d %d r=%d\n", y, m, g, r);
 I(r!=3||m>12||m<=0||g>u(y,m-1))R 0;
 r=s(y,m-1,g);// 12-> 11 -> 0..10
 P("Risultato=%d giorno=%s\n", r, giorno[r]);
 r=w(y,0,0);P(" r=%d ", r);P("\n");
 F(m=0;m<6;++m)
        {P("N anno=%d -->",arr[m]); 
         r=w(arr[m],0,0); // ritorna in r i mesi tramite i suoi bit...
         F(y=1;y<13;++y) I(r&(1<<y))P("%s ",mese[y-1]);
         P("\n");
        }
 F(m=0;m<4;++m)
        {P("N anno=%d -->",arr1[m]); 
         r=z(arr1[m],0,0); // ritorna in r i mesi tramite i suoi bit...
         F(y=1;y<13;++y) I(r&(1<<y))P("%s ",mese[y-1]);
         P("\n");
        }

}
\$\endgroup\$

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.