每年13号星期五星期五?


28

您的挑战是编写一个程序,该程序在给定的一年内输出其中的“星期五13日”数字。

规则和详细信息:

  • 您可以通过STDIN或作为传递给程序的参数来接受输入。
  • 您应该将结果输出到STDOUT
  • 您可以假定输入将是有效年份,并且未提前输入公历(在这些情况下允许未定义的行为)。
  • 日历/日期库是允许的。

这是一个,因此最短的代码(以字节为单位)获胜。

(相关挑战链接)


7
要求的输入范围是多少?如果它在1800年之前进行得很久,那么应该对从儒略历转换为公历做出什么假设?
彼得·泰勒

@PeterTaylor我没想过。如果日期早于公历,那么您可能会有不确定的行为。
Cruncher 2013年

1
格里高利本人之后,最早采用公历的国家在1582年10月采用了公历。后来采用新日历的国家直到20世纪才改变,例如希腊于1923
。– Jeppe Stig Nielsen

@JeppeStigNielsen我对日历等并不了解。他们是否采用它们不会改变公历日期。图书馆应该能够从我认为的相当多种方式计算日期?
Cruncher 2013年

3
我猜我在这里没意思。英美编程人员编写的许多图书馆都使用1752年9月作为更改日历的“正确”时间。这是大英帝国发生变化的时候。当然,新日历是在美国成立时保留的。(出于好奇,某些SQL软件将1753作为最小年份,因为他们不想应付1752年9月的问题。)但是,使用1752年9月是高度英语中心的。没错,格里高利历日期是相同的,无论它们是否曾使用过。那就是所谓的多事公历。
Jeppe Stig Nielsen

Answers:


3

APL(Dyalog APL),带有 来自dfns的cal,29 个字节

+/{13∊⍎,⍉3↑¯5↑⍉2cal⍵}¨⎕,¨⍳12

在线尝试!

⍳ 12 整数1到12

⎕ ,¨ 接受数字输入并在十二个数字的前面

{ 在每对上应用该功能…

cal⍵ 获取该年月份的日历

2 ↓ 放两行(标题和天)

 转置(因此我们可以寻址列而不是行)

¯5 ↑ 取最后五个数字(星期五和星期六每个数字两位,再加上一个空格)

3 ↑ 取前两位(星期五两位,另加一个空格)

 转置(以便获得阅读顺序)

, 拉夫

 作为APL表达式执行(提供星期五的日期列表)

13 ∊ 那个名单中有十三名吗?

+/ 对12个布尔值求和


使用@Wrzlprmft的算法,我们可以不用53个字节的库就可以做到:

'21232211321211'⊃⍨14|2 3 ¯1+.×⊢,0≠.=400 100 4∘.|-∘0 1

-∘0 1 减去零和一

400 100 4 ∘.| 两年(整个)的除法余数表除以这些数字(向下)

0 ≠.= 内部“乘积”为0,但使用≠和=而不是+。×

⊢ , 在未修改的参数年份之前

2 3 ¯1 +.× 具有这些数字的内部产品

14 | 除数除以十四

'21232211321211' ⌷⍨ 索引到这个字符串


它是29个字符,但这些字符超过1个字节,对不对?
Cruncher

@Cruncher我在标题中添加了说明性链接。如果打开TIO链接,则会看到它在右侧显示“ 29个字符,29个字节(SBCS)”,即“单字节字符集”。
阿达姆(Adám)'17

好吧,我想这是新的赢家,在这个SE中,标准实践会在问题问世很久之后就改变接受的答案吗?
Cruncher

@Cruncher是的。在OP之后很久甚至还需要获得徽章。
亚当

12

Mathematica 49 46 45 44 42

作为纯函数:42个字符

DayName@{#,m,6}~Table~{m,12}~Count~Friday&

DayName@{#,m,6}~Table~{m,12}~Count~Friday&[2013]

2


作为命名函数:44个字符

f=DayName@{#,m,6}~Table~{m,12}~Count~Friday&

例子

f[1776]
f[2012]
f[2013]
f[2014]

2
3
2
1


短一个字符:f=DayName@{#,m,6}~Table~{m,12}~Count~Friday&
Mr.Wizard

@Wizard先生是的。Mathematica可以解析中缀表示法的多种情况,这让我感到惊讶。
DavidC 2013年

戴维(David)令惊讶的是,您还没有看到我对这种联合表示法的过度使用。:^)(范例:(1)(2)
威兹德先生

8

红宝石,49 48 47 46

f=->m{(1..12).count{|i|Time.gm(m,i,6).friday?}}

编辑:感谢扬,通过回一周来剃光了角色,并通过从Time.new切换到Time.gm来剃光了另一个角色

编辑:以更多的混淆为代价,我可以达到46

f=->m{(1..12).count{|i|Time.gm(m,i,8).wday<1}}

5
如果您计算6日的星期五的次数,则可节省一元钱
约翰·德沃夏克

2
@JanDvorak聪明!
histocrat

为什么是6?我没听懂
NARKOZ

3
如果6号是星期五,那么13号也是星期五
TwiNight 2013年

如果8号是星期天,则1号也是星期天,因此您可以使用Time.gm(m,i).wday<1。另外,我不知道您为什么要命名该功能。
李W

8

Powershell,68 63 58 52 50

感谢Iszi的提示。

$n=$args;(1..12|?{!+(date $n-$_).DayOfWeek}).Count

使用以下事实:如果一个月的第一天是星期天,则第13天将是星期五。

我也尝试过:

(1..12|?{!+(date $args-$_).DayOfWeek}).Count

但是$args在脚本块内部却不一样。


1
我喜欢使用每月的第一天的想法。
Cruncher

好招,在那里。但是@是不必要的。
Iszi 2013年

另一件事,尽管我在很多脚本中都对此感到内gui。挑战确实指定了输入可以来自参数。在循环中替换$n$args,您可以完全不用$n=read-host;。保存8.拆下@,如上面提到的,和你到54
Iszi

更正:降至52!
Iszi 2013年

试图弄清楚为什么您的第二个脚本不起作用,我很茫然。有趣的是,我能变出$args$input,因而从管道喂养一年,并且将运行该脚本,但它总是输出3
Iszi

5

R 76 72 57

sum(format(as.Date(paste(scan(),1:12,1,sep="-")),"%w")<1)

可以很容易地替换您得到这个下降4 "%a %d")=="Fri 13""%w%d)=="513")使用陶氏的数和删除的空间。
chmullig

非常感激!
flodel

+1虽然只做seq一个月实际上在这里要短一些!sum(format(as.Date(paste(scan(),1:12,13,sep="-")),"%w%d")=="513")只有65个字符!
plannapus

哇,我不会猜到<会把字符强制为整数。好招!
plannapus 2013年

@plannapus这很常见。由于字符代码都是数字。甚至Java也可以比较int和char
Cruncher 2013年

5

Python2.7 90 86

from datetime import*
s=c=0
exec's+=1;c+=date(%d,s,9).weekday()<1;'%input()*12
print c

9月9日星期一的铃声可能不太一样,但效果也一样。

编辑:一年半,注意到datedatetime:) 短


真的很好的解决方案!
leancz 2013年

2
您可以通过执行以下操作来保存字符from datetime import*
user80551'4

真好!我最终得到了一些实际上相同的东西,但是避免了exec:f=lambda y:sum([date(y,m,13).weekday()==4 for m in range(1,13)]).... 但是,与导入(86字节)的大小相同的解决方案。
iwaseatenbyagrue '17

5

不使用任何库或内置日期函数:

Golfscript – 51

~..({4/.25/.4/--@}2*2*\3*+-
14%' [3/=RI[)a%:*.'\=5%

' [3/=RI[)a%:*.' 可能是 'feefefgeeffgfe'

Python – 82 79

本质上是相同的算法。

l=lambda y:y/4-y/100+y/400
i=input()
print"21232211321211"[(2*i+3*l(i)-l(i-1))%14]

使用此技巧,可以进一步深入研究:

l=lambda y:y/4-y/100+y/400
i=input()
print 94067430>>(4*i+6*l(i)-2*l(i-1))%28&3

这利用了以下事实:在压延机方面,只有14个不同的年份,这些年份可以通过它们的最后一天以及它们是否在飞跃来区分。l计算到其参数为止的of年数(如果公历向后扩展到1年)。(2*i+3*l(i)-l(i-1))%14是的缩写l(i)-l(i-1)+(i+l(i))%7*2,它l(i)-l(i-1)告诉我们参数是否为a年,并i+l(i)总结最后一天的变化(正常年份中的一个,one年中的两个)。


由于这是我的第一个golfscript高尔夫,因此对进一步打高尔夫球的任何提示,我将不胜感激。
Wrzlprmft

我当时考虑的是这样一种解决方案,即实际上只有14个独特的年份,但不确定是否有使它具有竞争力的最佳语言。我认为这是没有库的最短答案。如果leap年平均每4年一次,那么您也许可以赢得大奖
Cruncher 2014年

4

C 301+ 287

main(int x,char**v){char p[400],*a[]={"abbababbacaacbac","bacabbb","baabbaca","abbb","aabbacaac","abbbbcaac","abbbbaabb"},*b="adcadcadcaebcadcadcafbcadcadcagbcadcadcadc";int c=0,i,y=atoi(v[0]);for(i=0;i<42;i++)strcpy(&p[c],a[b[i]-'a']),c+=strlen(a[b[i]-'a']);printf("%d",p[y%400]-'`');}

不是最短的答案,但不使用任何库。


嘿,您愿意为未回答的问题提供解释吗?我对您所做的事情很感兴趣
Cruncher 2013年

1
@Cruncher,它是一个查询表,它基于公历遵循400年的周期。
彼得·泰勒

1
更明确地说(和更长),C#: static char GetNumberOfFriday13s(int year) { const string perpetualCalendar = "1221212213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213112213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122131"; return perpetualCalendar[year % 400];。不会负数年。
Jeppe Stig Nielsen

可爱!作为一个小错误,v[0]应该是v[1]。您也可以打高尔夫球。考虑使用strcat,存储字符以直接在中打印a[],并减去数字常量而不是字符常量。:)
user1354557

1
我也改善了压缩率:main(int x,char**v){char p[400],*a[]={"1221212213113213","2131222","21122131","1222","112213113","122223113","122221122"},*b="adcadcadcaebcadcadcafbcadcadcagbcadcadcadc";*p=0;for(;*b;b++)strcat(p,a[*b-97]);putchar(p[atoi(v[1])%400]);}(215个字符)
user1354557 2013年

4

C(151 145 137 131 130个字符)

我很惊讶地发现,只有另一种解决方案不使用内置日历工具。这也是一种(高度混淆的)数学方法,同样在C语言中:

f(x){return(x+(x+3)/4-(x+99)/100+!!x)%7;}main(int x,char**v){int y=atoi(v[1])%400,a=f(y+1);putchar('1'+((f(y)&3)==1)+(a>2&&a-5));}

(以上内容在GCC中编译,没有错误)

替代解决方案:C(287-> 215个字符)

我更喜欢Williham Totland的解决方案以及他对压缩的使用。我修复了两个小错误,并调整了代码以缩短其长度:

main(int x,char**v){char p[400],*a[]={"1221212213113","213122221122131","12213113","22213113","22221122","2131"},*b="abababafcbababafdbababafebababab";*p=0;for(;*b;b++)strcat(p,a[*b-97]);putchar(p[atoi(v[1])%400]);}


4

bash 47 36

seq -f$1-%g-6 12|date -f-|grep -c ^F

感谢@DigitalTrauma使用seq默认的start到保存10个字符1

date -f<(printf "%s\n" $1-{1..12}-6)|grep -c ^F

(使用以前的版本echo,因为空行的存在错误时<(echo $1-{1..12}-6$'\n'),所以此功能工作的罚款,直至今天星期五)使用。

让我们来看看:

set -- 2013
seq -f$1-%g-6 1 12|date -f-|grep -c ^F
2

date -f<(printf "%s\n" $1-{1..12}-13)|grep -c ^F
2

是取决于语言环境的,因为它不起作用,您可能必须

export LANG=C

要么

LANG=C date -f<(printf "%s\n" $1-{1..12}-13)|grep -c ^F

转化为功能;+7-> 43

f(){ seq -f$1-%g-6 12|date -f-|grep -c ^F;}

f 2013
2

for i in {2010..2017};do echo $i $(f $i) ;done
2010 1
2011 1
2012 3
2013 2
2014 1
2015 3
2016 1
2017 2

奖励:+78-> 121

从那里开始,如果我的功能变为:

f(){ o=();for t in $(seq -f$1-%g-6 12|date -f- +%a,%b);do [ "${t:0:1}" = "F" ]&&o+=(${t#*,});done;echo ${#o[@]} ${o[@]};}

要么

f(){ o=();
     for t in $(seq -f$1-%g-6 1 12|date -f- +%a,%b);do
         [ "${t:0:1}" = "F" ]&&o+=(${t#*,})
       done
     echo ${#o[@]} ${o[@]}
}

for i in {2010..2017};do echo $i $(f $i) ;done
2010 1 Aug
2011 1 May
2012 3 Jan Apr Jul
2013 2 Sep Dec
2014 1 Jun
2015 3 Feb Mar Nov
2016 1 May
2017 2 Jan Oct

这似乎是与语言环境相关的。
彼得·泰勒

是的,这是基于default的C。但是有一个错误……
F. Hauri 2013年

通过取消引用您的printf格式字符串并转义\来保存字符,而不是:%s\\n
Digital Trauma

1
或用于seq丢弃8个字符:date -f<(seq -f$1-%g-6 1 12)|grep -c ^F
Digital Trauma 2014年

1
实际上,您可以再刮除2个字符。如果省略起始序列号,默认情况下seq将从1开始,即您想要的序列号:seq -f$1-%g-6 12|date -f-|grep -c ^F
Digital Trauma 2014年

4

JavaScript,70岁

f=function(a){b=0;for(c=12;c--;)b+=!new Date(a,c,1).getDay();return b}

为什么是-1?
Lukasz'Severiaan'Grela 2013年

1
看起来不错!您可以保存几个字节,除去,b,c由函数声明(!它的确定泄漏瓦尔高尔夫),也为b被投作为一个Number可以+=测试的结果,而不是&&b++b+=/^F/.test(new Date(a,c,6))。但是,您可以使用保存另一个字节!new Date(a,c,1).getDay()(这是有效的,因为getDay返回0代表星期日,如果13号是星期五,则1号将是星期日),而不是test总共可以节省7个字节!
Dom Hastings 2013年

@DomHastings:谢谢你的提示!
guy777 2013年

3

ķ

64个字符

{+/6={x-7*x div 7}(.:')x,/:(".",'"0"^-2$'$:1+!:12),\:".13"}[0:0]

从stdin读取


好的,这是怎么回事?:P
Williham Totland 2013年

读入年份,构建每月第13天的日期列表,每周的测试日=星期五,求和布尔值的结果列表的总和
skeevey 2013年

3

普通Lisp(CLISP),149

(print 
    (loop for i from 1 to 12 count 
        (= 4 (nth-value 6 
            (decode-universal-time
                (encode-universal-time 0 0 0 13 i
                    (parse-integer (car *args*)) 0))))))

哦,上帝,我从来没有能读口齿不清..
排排坐

2

C# 110 101 93 92

int f(int y){int c=0;for(int i=1;i<13;i++)c+=new DateTime(y,i,8).DayOfWeek>0?0:1;return c;}

C#Linq 88

int g(int y){return Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0);}

感谢捷普·斯蒂格·尼尔森(Jeppe Stig Nielsen)的来信,并建议8日检查星期日。

Thanks to Danko Durbić for suggesting > instead of ==.


Instead of c+=(int)new DateTime(y,i,13).DayOfWeek==5?1:0;, use the equivalent c+=new DateTime(y,i,8).DayOfWeek==0?1:0;. The trick is to subtract 5, because then you can get rid of the cast to int, and also the number 8 has one digit less than the number 13. Sunday the Eighth!
Jeppe Stig Nielsen

With Linq: int g(int y){return Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0);}. Of course as a lambda this is y=>Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0).
Jeppe Stig Nielsen

You can save one character by comparing .DayOfWeek<1.
Danko Durbić

@DankoDurbić This can apply to the c# answer but not sure how to apply it to linq .
Kami

My mistake; apparently you can't compare DayOfWeek with any other integer than 0 - error CS0019: Operator '<' cannot be applied to operands of type 'System.DayOfWeek' and 'int'.
Danko Durbić

2

PHP, 55 bytes

for(;++$i<13;)$c+=!date(w,strtotime($argn.-$i));echo$c;

Run with echo <year> | php -nR '<code>'.

Basically the same that Oleg tried and Damir Kasipovic did, just with better golfing:
Every month that starts with a sunday, has a Friday the 13th.
So I loop through the months and count the first days that are sundays.

breakdown

for(;++$i<13;)          // loop $i from 1 to 12
    $c+=!                   // 4. if result is not truthy (weekday==0), increment $c
        date(w,             // 3. get weekday (0 stands for Sunday)
            strtotime(      // 2. convert to timestamp (midnight 1st day of the month)
                $argn.-$i   // 1. concatenate year, "-" and month
            )
        )
    ;
echo$c;                 // output

1

K, 42

{+/1={x-7*x div 7}"D"$"."/:'$+(x;1+!12;1)}

.

k){+/1={x-7*x div 7}"D"$"."/:'$+(x;1+!12;1)}'1776 2012 2013 2014
2 3 2 1

1

Bash (52 47 characters)

for m in {1..12};do cal $m $Y;done|grep -c ^15

1

Rebol, 63

f: 0 repeat m 12[d: do ajoin["6-"m"-"y]if d/weekday = 5[++ f]]f

Usage example in Rebol console:

>> y: 2012
== 2012

>> f: 0 repeat m 12[d: do ajoin["6-"m"-"y]if d/weekday = 5[++ f]]f
== 3

Alternative solution which collects all the Friday 13th in given year is:

>> collect[repeat m 12[d: do ajoin["13-"m"-"y]if d/weekday = 5[keep d]]]
== [13-Jan-2012 13-Apr-2012 13-Jul-2012]

1

Bash and Sed, 39

ncal $1|sed '/F/s/13/\
/g'|grep -c ^\ 2

ncal prints a calendar for the given year with days of the week down the left.

sed with a /g flag subs out all 13s with newlines

grep -c counts the lines that start with " 2" (20 always follows 13)

Thanks to @DigitalTrauma for finding a bug in my old version and proposing a solution!


Doesn't quite work for me - Friday lines are only printed once even if they contain more than one 13.
Digital Trauma

1
I think the best I can do with something like this is 38: ncal $1|sed /F/s/13/\\n/g|grep -c ^\ 2
Digital Trauma

1
@DigitalTrauma You're right. At some point this script was working. let me fix it.
Not that Charles

1
@DigitalTrauma looks like some much longer version was working. thanks for the fix!
Not that Charles

Interesting, the unquoted sed expression I proposed works with GNU sed (Linux) but not with BSD sed (OSX). I guess you can gain 1 char at the cost of portability if you choose the GNU version.
Digital Trauma

1

Scala, 76 68 characters

In 78 chars:

def f(y:Int)=0 to 11 count(new java.util.GregorianCalendar(y,_,6).get(7)==6)

Nothing out of ordinary, except for using magical numbers for DAY_OF_WEEK = 7 and FRIDAY = 6.

68 character version:

def f(y:Int)=0 to 11 count(new java.util.Date(y-1900,_,6).getDay==5)

Yes, Java changed values of day of the week constants between API's.


It's a shame new java.util.GregorianCalendar has to be so long :(
Cruncher

1

Python 195 / 204

Works only for previous years, because monthdatescalendar returns a calendar for the given year until now. I think there is a lot of optimizing potential left :).

import calendar, sys
c=calendar.Calendar()
f=0
for m in range(1,12):
 for w in c.monthdatescalendar(int(sys.argv[1]),m):
  for d in w:
   if d.weekday() == 4 and d.day == 13:
    f=f+1
print(f)

Another solution, works for every date but it isn't smaller:

import datetime,sys
y=int(sys.argv[1])
n=datetime.date
f=n(y,1,1)
l=n(y,12,31)
i=0
for o in range(f.toordinal(), l.toordinal()):
 d=f.fromordinal(o)
 if d.day == 13 and d.weekday() == 4:
  i=i+1
print(i)

In your first example the range should be (1,13) otherwise you'd miss December Friday 13ths, like in 2013.
leancz

1
You didn't even bother golfing. Remove some of those spaces.
mbomb007

1

Perl 6, 55 53

{sum (1..12).map: {Date.new($_,$^a,1).day-of-week>6}}

Old answer:

{sum (1..12).map: {Date.new($_,$^a,13).day-of-week==5}}


0

Python(v2) 120

import datetime as d,sys
s=0
for m in range(1, 13):
    if d.datetime(int(sys.argv[1]),m,6).weekday()==4: s=s+1
print s

0

Perl + lib POSIX 55

With the idea of not looking for 13th but first, and as sunday is 0 this let save 3 chars! Thanks @ Iszi and Danko Durbić!

$==$_;$_=grep{!strftime"%w",0,0,0,1,$_,$=-1900}(0..11)

Could compute 2010 to 2017 (for sample) in this way:

perl -MPOSIX -pE '$==$_;$_=grep{!strftime"%w",0,0,0,1,$_,$=-1900}(0..11)' <(
    printf "%s\n" {2010..2017})
11321312

(Ok, there is no newline, but that was not asked;)

Old post: 63

$==grep{5==strftime"%w",0,0,0,13,$_,$ARGV[0]-1900}(0..11);say$=

In action:

for i in {2010..2017};do
    echo $i $(
        perl -MPOSIX -E '
            $==grep{5==strftime"%w",0,0,0,13,$_,$ARGV[0]-1900}(0..11);say$=
            ' $i );
  done
2010 1
2011 1
2012 3
2013 2
2014 1
2015 3
2016 1
2017 2

0

In Smalltalk (Squeak/Pharo flavour), implement this method in Integer (86 chars)

countFriday13^(1to:12)count:[:m|(Date year:self month:m day:13)dayOfWeekName='Friday']

Then use it like this: 2014countFriday13.

Of course, we could use a shorter name, but then it would not be Smalltalk


0

C++ - Too many bytes :(

I tried a solution which doesn't make use of any date libraries.

I found a pretty cool (if I may say so myself) solution. Unfortunately I can't get it shorter than this, which really bugs me because it feels like there should be a better way.

The solution hinges on this algorithm which is only 44 bytes in itself. Unfortunately I need another 100 bytes to wrap it nicely...

#include<stdlib.h>
main(int,char**v){int f=0,d,m,y;for(m=1;m<13;++m)d=13,y=atoi(v[1]),(d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7-5||++f;return f;}

Output through the return code (in C++, using cout or printf or anything like that requires another #include, which would blow up the solution even more).

Driver / test program:

# Make sure we're not running an old version
rm doomsday.exe

gcc doomsday.cpp -o doomsday.exe

./doomsday.exe 1776
echo 1766: $?

./doomsday.exe 2012
echo 2013: $?

./doomsday.exe 2013
echo 2013: $?

./doomsday.exe 2014
echo 2014: $?

echo `wc doomsday.cpp -c` characters

Output of the driver program:

$ ./test_doomsday 
1766: 2
2013: 3
2013: 2
2014: 1
150 doomsday.cpp characters

I count 88 for the algorithm, not 44. What is the algorithm and what is the warpping? ($m<3?$y--:$y-2)+3 instead of d=13,, d+=m<3?y--:y-2, and d+4 should work as well and saves a lot. +5 instead of +3 and -5 should work too and saves 2 bytes. for(m=0;++m<13;) saves one byte. Moving m=0 to the function head saves another byte; and moving ()%7||++f to the loop head saves another one. Down from 149 to 136 bytes.
Titus

0

Clojure, 207 187 bytes

-20 bytes by getting rid of the import, and some whitespace I missed.

(import '[java.time LocalDate DayOfWeek])#(loop[d(LocalDate/parse(str %"-01-01"))c 0](if(=(.getYear d)%)(recur(.plusDays d 1)(if(and(=(.getDayOfMonth d)13)(= (.getDayOfWeek d) DayOfWeek/FRIDAY))(inc c)c))c))

Starting on Janauary 1st of the given year, it loops over each day. If the day is Friday the 13th, it increments the count. It continues to loop until it reaches the next year.

(import '[java.time LocalDate DayOfWeek])

(defn count-friday-13ths [year]
  (loop [d (LocalDate/parse (str year "-01-01")) ; Starting date
         c 0] ; The count
    (if (= (.getYear d) year) ; If we haven't moved onto the next year...
      (recur (.plusDays d 1) ; Add a day...
             (if (and (= (.getDayOfMonth d) 13) ; And increment the count if it's Friday the 13th
                      (= (.getDayOfWeek d) DayOfWeek/FRIDAY))
               (inc c) c))
      c))) ; Return the count once we've started the next year.

0

PHP, no builtins, 81 bytes

echo 0x5da5aa76d7699a>>(($y=$argn%400)+($y>102?$y>198?$y>299?48:32:16:0))%28*2&3;

Run with echo <year> | php -nR '<code>'.

breakdown

Weekdays repeat every 400 years.
In the results for 1600 to 1999 (for example), there is a 28-length period with just three gaps:

  0:2212122131132131222211221311
 28:2212122131132131222211221311
 56:2212122131132131222211221311
 84:2212122131132131122
103:       131132131222211221311
124:2212122131132131222211221311
152:2212122131132131222211221311
180:2212122131132131222
199:       131132131222211221311
220:2212122131132131222211221311
248:2212122131132131222211221311
276:221212213113213122221122
300:            2131222211221311
316:2212122131132131222211221311
344:2212122131132131222211221311
372:2212122131132131222211221311

After adjusting the year for these gaps, we can get the result with a simple hash:

$y=$argn%400;foreach([300,199,103]as$k)$y<$k?:$y+=16;
echo"2212122131132131222211221311"[$y%28];

Not short (95 bytes) but pretty. And we can golf

  • 4 bytes by using a ternary chain for the offset,
  • 8 bytes by converting the hash map from a base4 string to integer,
  • one more by using the hex representation,
  • and one by merging the expressions.

A port of CompuChip´s C++ answer can be golfed down to 84 bytes: for(;++$m<13;23*$m/9+($m<3?$y--:$y-2)+5+$y/4-$y/100+$y/400)%7?:$f++)$y=$argn;echo$f;
Titus

0

Japt -x, 10 bytes

CÆ5¥ÐUXD e

Try it

CÆ5¥ÐUXD e     :Implicit input of integer U
C              :12
 Æ             :  Map each X in the range [0,C) (months are 0-indexed in JavaScript)
  5¥           :  Check if 5 is equal to
    ÐUXD       :  new Date(U,X,13)
         e     :  0-based index of day of the week
               :Implicitly reduce by addition and output
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.