Ile piątek trzynasty w ciągu roku?

28

Twoim wyzwaniem jest napisanie programu, który, biorąc pod uwagę rok, generuje w nim liczbę „piątek trzynastych”.

Zasady i szczegóły:

  • Możesz przyjmować dane wejściowe za pośrednictwem STDINlub jako argument przekazywany do programu.
  • Powinieneś wypisać wynik na STDOUT.
  • Możesz założyć, że dane wejściowe będą ważne i nie będą poprzedzać kalendarza gregoriańskiego (w takich przypadkach dozwolone jest niezdefiniowane zachowanie).
  • Biblioteki kalendarza / daty są dozwolone.

To jest , więc wygrywa najkrótszy kod (w bajtach).

(Powiązany link do wyzwania)

Cruncher
źródło
7
Jaki jest wymagany zakres danych wejściowych? Jeśli pójdzie dużo przed 1800 rokiem, jakie założenia należy przyjąć odnośnie przejścia z kalendarza juliańskiego na gregoriański?
Peter Taylor,
@PeterTaylor Nie myślałem o tym. Jeśli data wcześniejsza niż gregoriańska, możesz mieć niezdefiniowane zachowanie.
Cruncher,
1
Pierwsze kraje, które przyjęły kalendarz gregoriański, zrobiły to w październiku 1582 r., Zaraz po byku samego Grzegorza. Kraje, które przyjęły nowy kalendarz późno, nie zmieniły się aż do XX wieku, na przykład Grecja wprowadziła go 1 marca 1923 r.
Jeppe Stig Nielsen
@JeppeStigNielsen Nie wiem wiele o kalendarzach i tym podobnych. To, czy je adoptowali, czy nie, nie zmienia tego, jakie są daty gregoriańskie. Biblioteki powinny być w stanie obliczyć daty z całkiem sprecyzowanych wcześniej założeń?
Cruncher,
3
Chyba jestem tu nie na temat. Wiele bibliotek napisanych przez anglo-amerykańskich programistów używa września 1752 r. Jako „poprawnego” czasu zmiany kalendarzy. Wtedy zmieniło się Imperium Brytyjskie. Oczywiście nowy kalendarz został zachowany w momencie założenia USA. (Co ciekawe, niektóre oprogramowanie SQL ma rok 1753 jako minimalny rok, ponieważ nie chcą poradzić sobie z problemem z września 1752 r.) Jednak korzystanie z września 1752 r. Jest wysoce anglocentryczne. Masz rację, daty gregoriańskie są takie same, niezależnie od tego, czy były używane historycznie, czy nie. To jest tak zwany proleptyczny kalendarz gregoriański.
Jeppe Stig Nielsen,

Odpowiedzi:

3

APL (Dyalog APL) z cal z dfns , 29 bajtów

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

Wypróbuj online!

⍳ 12 liczby całkowite od jednego do dwunastu

⎕ ,¨ wprowadź dane numeryczne i wstaw do każdej z dwunastu liczb

{ Na każdej z par zastosuj funkcję…

cal⍵ dostać kalendarz na ten rok-miesiąc

2 ↓ upuść dwa wiersze (podpis i dni)

 transponuj (abyśmy mogli adresować kolumny zamiast wierszy)

¯5 ↑ weź ostatnie pięć (dwie cyfry dla każdego piątku i soboty plus jedna spacja)

3 ↑ weź dwie pierwsze (dwie cyfry w piątek plus spację)

 transponuj (więc otrzymujemy kolejność czytania)

, strzępy

 wykonać jako wyrażenie APL (podaje listę dat piątków)

13 ∊ czy trzynaście jest członkiem tej listy?

+/ zsumuj 12 booleanów


Korzystając z algorytmu @ Wrzlprmft , możemy to zrobić bez bibliotek dla 53 bajtów:

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

-∘0 1 odejmij zero i jeden

400 100 4 ∘.| tabela reszty podziału dla dwóch lat (w poprzek) podzielona przez te liczby (w dół)

0 ≠.= wewnętrzny „produkt” z 0, ale używając ≠ i = zamiast +. ×

⊢ , wstaw niezmodyfikowany rok argumentu

2 3 ¯1 +.× produkt wewnętrzny z tymi numerami

14 | pozostała część podziału po podzieleniu przez czternaście

'21232211321211' ⌷⍨ indeks do tego ciągu

Adám
źródło
Ma 29 znaków, ale to więcej niż 1 bajt, prawda?
Cruncher
@Cruncher Dodałem link wyjaśniający w nagłówku. Jeśli otworzysz łącze TIO, zobaczysz, że po prawej stronie znajduje się „29 znaków, 29 bajtów (SBCS)”, tj. Zestaw znaków jednobajtowych.
Adám
Cóż, myślę, że to nowy zwycięzca. Czy standardową praktyką w tej SE jest zmiana przyjętej odpowiedzi tak długo po pytaniu?
Cruncher
@Cruncher Tak. I są nawet odznaki za zaakceptowanie długo po OP.
Adám
12

Mathematica 49 46 45 44 42

Jako czysta funkcja : 42 znaki

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

Przykład

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

2)


Jako nazwana funkcja : 44 znaki

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

Przykłady

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

2
3
2
1

DavidC
źródło
Jedna postać krótsza:f=DayName@{#,m,6}~Table~{m,12}~Count~Friday&
Mr.Wizard,
@ Mr.Wizard Tak. Zaskakuje mnie, że Mathematica może analizować wiele przypadków notacji infiksowych.
DavidC,
David, zaskakuje mnie , że nie widziałeś mojego (nadmiernego) użycia tego połączonego zapisu. : ^) (Przykłady: (1) , (2) )
Mr.Wizard,
8

Ruby, 49 48 47 46

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

Edycja: Ogoliłem postać, cofając się o tydzień, dzięki Janowi, a drugą, przechodząc z Time.new do Time.gm

Edycja: Kosztem trochę zaciemnienia, mogę dostać się do 46 za pomocą

f=->m{(1..12).count{|i|Time.gm(m,i,8).wday<1}}
histocrat
źródło
5
oszczędność jednego znaku, jeśli policzymy piątek 6.
John Dvorak,
2
@JanDvorak sprytny!
histocrat
dlaczego 6? Nie rozumiem
NARKOZ,
3
Jeśli szósty to piątek, to trzynasty również jest piątek
TwiNight,
Jeśli ósma to niedziela, to również jest pierwsza i możesz z niej skorzystać Time.gm(m,i).wday<1. Nie wiem też, dlaczego nazywasz tę funkcję.
Lee W
8

PowerShell, 68 63 58 52 50

Dzięki Iszi za wskazówkę.

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

Biorąc pod uwagę fakt, że jeśli pierwszym dniem miesiąca jest niedziela, 13 będzie piątek.

Próbowałem też:

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

ale to nie to samo $argsw bloku skryptu.

Danko Durbić
źródło
1
Podoba mi się pomysł wykorzystania pierwszego dnia miesiąca.
Cruncher,
Dobra sztuczka. @ Jest jednak niepotrzebne.
Iszi
Kolejna sprawa, chociaż jestem winny tego samego w wielu moich skryptach. Wyzwanie określa, że ​​dane wejściowe mogą pochodzić z argumentu. Wymień $nsię $argsw pętli, a można to zrobić bez $n=read-host;końca. Zapisuje 8. Usuń @, jak wspomniano powyżej, i jesteś w dół do 54.
Iszi
Korekta: sprowadza się do 52!
Iszi
Próbuję dowiedzieć się, dlaczego Twój drugi skrypt nie działa, a ja jestem zagubiony. Co ciekawe jest to, że mogę zmienić się $argsna $input, więc karmienie rok z rurociągu, a skrypt będzie działał, ale zawsze wyprowadza 3.
Iszi
5

R 76 72 57

sum(format(as.Date(paste(scan(),1:12,1,sep="-")),"%w")<1)
flodel
źródło
Można łatwo uzyskać to w dół 4 zastępując swoimi "%a %d")=="Fri 13"ze "%w%d)=="513")używając dow jako liczba i usunięcie spacji.
chmullig,
bardzo mile widziane!
flodel
+1 Chociaż robienie seqjedynych w miesiącu jest tutaj naprawdę krótsze! sum(format(as.Date(paste(scan(),1:12,13,sep="-")),"%w%d")=="513")ma tylko 65 znaków!
plannapus,
wow, nie zgadłbym, że <to zmusiłoby znak do liczby całkowitej. Niezła sztuczka!
plannapus,
@plannapus To dość powszechne. Ponieważ kody znaków to wszystkie cyfry. Nawet java może porównać int i char
Cruncher,
5

Python 2,7 90 86

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

Poniedziałek 9 może nie mieć tego samego pierścienia, ale działa równie dobrze.

Edycja: półtora roku, aby zauważyć, że datejest krótszy niż datetime:)

ejrb
źródło
Naprawdę fajne rozwiązanie!
leancz
2
Możesz zapisać znak, wykonującfrom datetime import*
użytkownik80551
Miły! Skończyło się na czymś faktycznie identycznym, ale unikając exec: f=lambda y:sum([date(y,m,13).weekday()==4 for m in range(1,13)]).... Rozwiązanie tego samego rozmiaru z importem (86 bajtów).
iwaseatenbyagrue
5

Nieużywanie żadnych bibliotek ani wbudowanych funkcji daty:

Golfscript - 51

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

' [3/=RI[)a%:*.' równie dobrze może być 'feefefgeeffgfe'

Python - 82 79

Zasadniczo ten sam algorytm.

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

Za pomocą tej sztuczki można ją pograć w golfa w celu:

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

Wykorzystuje to fakt, że pod względem kalendarza istnieje tylko 14 różnych lat, które można odróżnić po ich ostatnim dniu i tym, czy skaczą. loblicza liczbę lat przestępnych do jego argumentu (jeśli kalendarz gregoriański rozciągnął się wstecz do roku 1). (2*i+3*l(i)-l(i-1))%14jest skrótem od l(i)-l(i-1)+(i+l(i))%7*2, gdzie l(i)-l(i-1)mówi nam, czy argument jest rokiem przestępnym, i i+l(i)podsumowuje zmiany ostatniego dnia (jeden w normalnym roku, dwa w roku przestępnym).

Wrzlprmft
źródło
Ponieważ jest to moja pierwsza gra w golfa, byłbym wdzięczny za wszelkie wskazówki dotyczące dalszej gry w golfa.
Wrzlprmft
Myślałem o takim rozwiązaniu, wykorzystując fakt, że faktycznie istnieje tylko 14 unikatowych lat, ale nie byłem pewien, czy to najlepszy język, aby był konkurencyjny. Myślę, że to najkrótsza odpowiedź bez bibliotek. Jeśli lata przestępne były równomiernie co 4 lata, możesz wygrać z tym
Cruncher
4

do 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]-'`');}

Nie jest to najkrótsza odpowiedź, ale nie korzysta z bibliotek.

Williham Totland
źródło
Hej, czy zechciałby Pan udzielić nieokreślonej odpowiedzi wyjaśnienia? Interesuje mnie to, co dokładnie zrobiłeś
Cruncher,
1
@Cruncher, jest to tabela przeglądowa na podstawie tego, że kalendarz gregoriański przebiega przez 400-letni cykl.
Peter Taylor,
1
Bardziej wyraźny (i dłużej), C #: static char GetNumberOfFriday13s(int year) { const string perpetualCalendar = "1221212213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213112213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122131"; return perpetualCalendar[year % 400];. Nie będzie działać przez lata negatywne.
Jeppe Stig Nielsen,
Uroczy! Jako mały błąd v[0]powinien być v[1]. Możesz też trochę zagrać w golfa; rozważ użycie strcat, przechowywanie znaków do bezpośredniego drukowania a[]i odjęcie stałych numerycznych zamiast stałych znakowych. :)
user1354557,
1
Poprawiłem także kompresję: 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 znaków)
użytkownik1354557,
4

C ( 151 145 137 131 130 130 znaków)

Jestem zaskoczony, widząc, że istnieje tylko jedno inne rozwiązanie, które nie korzysta z wbudowanych narzędzi kalendarza. Oto (matowe) podejście matematyczne, również w 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));}

(Powyższe kompiluje się w GCC bez błędów)

Alternatywne rozwiązanie: C (287-> 215 znaków)

Raczej podobało mi się rozwiązanie Williama Totlanda i jego użycie kompresji. Naprawiłem dwa małe błędy i poprawiłem kod, aby skrócić jego długość:

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]);}
użytkownik1354557
źródło
4

PHP, 82

<?for($i=1,$c=0;$i<13;$i++)$c+=(date("N",mktime(0,0,0,$i,1,$argv[1]))==7);echo $c;

Oparte na

„Każdy miesiąc, który zaczyna się w niedzielę, zawiera piątek trzynasty, a co najmniej jeden piątek trzynastego w każdym roku kalendarzowym”.

From http://en.wikipedia.org/wiki/Friday_the_13th

Damir Kasipovic
źródło
4

bash 47 36

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

Dzięki @DigitalTrauma za zapisanie 10 znaków przy użyciu seqdomyślnego startu do 1.

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

(Poprzednia wersja używała echobłędu z powodu pustej linii kiedy <(echo $1-{1..12}-6$'\n'). Więc ta funkcja działała dobrze do dzisiaj jest piątek.

Zobaczmy:

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

To zależy od ustawień regionalnych , jeśli nie działa, być może trzeba

export LANG=C

lub

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

W funkcję; +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

Premia: +78 -> 121

Stamtąd, jeśli moja funkcja stanie się:

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[@]};}

lub

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
F. Hauri
źródło
Wydaje się, że jest to zależne od ustawień regionalnych.
Peter Taylor,
Tak, opiera się na domyślnej C. Ale jest błąd ...
F. Hauri,
Zapisz znak, odznaczając ciąg formatu printf i usuwając znak \ zamiast:%s\\n
Digital Trauma
1
Lub użyj, seqaby zrzucić 8 znaków:date -f<(seq -f$1-%g-6 1 12)|grep -c ^F
Cyfrowa trauma
1
W rzeczywistości możesz ogolić jeszcze 2 znaki. Jeśli pominiesz początkowy numer sekwencyjny, sekwencja rozpocznie się domyślnie od 1, co chcesz:seq -f$1-%g-6 12|date -f-|grep -c ^F
Digital Trauma
4

JavaScript, 70

f=function(a){b=0;for(c=12;c--;)b+=!new Date(a,c,1).getDay();return b}
guy777
źródło
i dlaczego jest -1?
Łukasz „Severiaan” Grela,
1
Wygląda dobrze! Możesz zapisać jeszcze kilka bajtów, usuwając ,b,cz deklaracji funkcji (! Jest OK do wycieku vars do golfa), jak również bzostanie wyrzucony jak Numbermożesz +=wynikiem testu zamiast &&b++: b+=/^F/.test(new Date(a,c,6)). Możesz jednak zapisać kolejny bajt, używając !new Date(a,c,1).getDay()(to działa, ponieważ getDayzwraca 0 dla niedzieli, a jeśli 13 to piątek, 1 to niedziela) zamiast tego, testktóry w sumie powinien zaoszczędzić 7 bajtów!
Dom Hastings,
@DomHastings: dzięki za wskazówki !!!
guy777,
3

k

64 znaków

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

Czyta ze standardowego

skeevey
źródło
Ok, co tu się dzieje? : P
Williham Totland,
Czytaj w roku, buduj listę dat 13 dnia każdego miesiąca, testowy dzień tygodnia = piątek,
sumuj
3

Common 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))))))
Pål GD
źródło
O Boże, nigdy nie umiałem czytać seplenienia.
Cruncher,
2

DO# 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);}

Podziękowania dla Jeppe Stiga Nielsena za linq i sugestię sprawdzenia w niedzielę 8.

Dzięki Danko Durbić za sugestie >zamiast ==.

Kami
źródło
Zamiast tego c+=(int)new DateTime(y,i,13).DayOfWeek==5?1:0;użyj odpowiednika c+=new DateTime(y,i,8).DayOfWeek==0?1:0;. Sztuką jest odjąć 5, ponieważ wtedy możesz pozbyć się rzutowania int, a także liczba 8ma jedną cyfrę mniej niż liczba 13. Niedziela ósma!
Jeppe Stig Nielsen,
Z LINQ: int g(int y){return Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0);}. Oczywiście jako lambda y=>Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0).
Jeppe Stig Nielsen,
Możesz zapisać jedną postać, porównując .DayOfWeek<1.
Danko Durbić,
@ DankoDurbić Może to dotyczyć c#odpowiedzi, ale nie wiadomo, jak ją zastosować linq.
Kami,
Mój błąd; najwyraźniej nie można porównać DayOfWeekz żadną inną liczbą całkowitą niż 0- error CS0019: Operator '<' cannot be applied to operands of type 'System.DayOfWeek' and 'int'.
Danko Durbić,
2

PHP, 55 bajtów

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

Uruchom z echo <year> | php -nR '<code>'.

Zasadniczo to samo, co Oleg próbował i Damir Kasipovic , tylko z lepszym golfem:
każdy miesiąc, który zaczyna się w niedzielę, ma piątek 13.
Więc przeglądam miesiące i liczę pierwsze dni w niedziele.

awaria

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
Tytus
źródło
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
tartin
źródło
1

Bash ( 52 47 znaków)

for m in {1..12};do cal $m $Y;done|grep -c ^15
zazdrosny
źródło
1

Rebol, 63

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

Przykład użycia w konsoli Rebol:

>> y: 2012
== 2012

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

Alternatywnym rozwiązaniem, które zbiera cały piątek 13 w danym roku, jest:

>> 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]
draegtun
źródło
1

Bash and Sed, 39

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

ncal drukuje kalendarz na dany rok z dniami tygodnia w dół po lewej stronie.

sedz /gflagą wypada wszystkie 13 z nowymi liniami

grep -c liczy linie zaczynające się od „2” (20 zawsze następuje po 13)

Dzięki @DigitalTrauma za znalezienie błędu w mojej starej wersji i zaproponowanie rozwiązania!

Nie ten Charles
źródło
Dla mnie to nie działa - wiersze piątkowe są drukowane tylko raz, nawet jeśli zawierają więcej niż jeden 13.
Cyfrowa trauma
1
Myślę, że najlepsze, co mogę zrobić z czymś takim, to 38:ncal $1|sed /F/s/13/\\n/g|grep -c ^\ 2
Digital Trauma
1
@DigitalTrauma Masz rację. W pewnym momencie ten skrypt działał. pozwól mi to naprawić.
Nie to, że Karol
1
@DigitalTrauma wygląda na to, że działała jakaś znacznie dłuższa wersja. dzięki za poprawkę!
Nie to, że Karol
Interesujące, że cytowane wyrażenie sed, które zaproponowałem, działa z GNU sed (Linux), ale nie z BSD sed (OSX). Myślę, że możesz zyskać 1 znak kosztem przenośności, jeśli wybierzesz wersję GNU.
Digital Trauma
1

Scala, 76 68 znaków

W 78 znakach:

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

Nic nadzwyczajnego, z wyjątkiem używania magicznych liczb dla DAY_OF_WEEK = 7i FRIDAY = 6.

Wersja 68 znaków:

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

Tak, Java zmieniła wartości stałych dnia tygodnia między interfejsami API.

Karol S.
źródło
Szkoda, że new java.util.GregorianCalendarmusi być tak długo :(
Cruncher
1

Python 195/204

Działa tylko w poprzednich latach, ponieważ monthdatescalendarzwraca kalendarz na dany rok do chwili obecnej . Myślę, że zostało jeszcze wiele możliwości optymalizacji :).

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)

Inne rozwiązanie działa na każdą datę, ale nie jest mniejsze:

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)
klingt.net
źródło
W pierwszym przykładzie zakres powinien wynosić (1,13), w przeciwnym razie przegapiłbyś 13 grudnia w piątek, jak w 2013 r.
leancz
1
Nawet nie zawracałeś sobie głowy graniem w golfa. Usuń niektóre z tych spacji.
mbomb007
1

Perl 6, 55 53

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

Stara odpowiedź:

{sum (1..12).map: {Date.new($_,$^a,13).day-of-week==5}}
bb94
źródło
48 bajtów
Jo King
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
leancz
źródło
0

Perl + lib POSIX 55

Z ideą nie szuka 13th, ale po pierwsze, i jak sundayjest 0to let Zapisz 3 znaków! Dzięki @ Iszi i Danko Durbić!

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

Można obliczyć 2010 do 2017 (dla próbki) w następujący sposób:

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

(Ok, nie ma nowej linii , ale o to nie pytano;)

Stary post: 63

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

W akcji:

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
F. Hauri
źródło
0

W Smalltalk (Squeak / Pharo flavour) zaimplementuj tę metodę w Integer ( 86 znaków)

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

Następnie używać go tak: 2014countFriday13.

Oczywiście moglibyśmy użyć krótszej nazwy, ale wtedy nie byłby to Smalltalk

aka.nice
źródło
0

C ++ - Zbyt wiele bajtów :(

Wypróbowałem rozwiązanie, które nie korzysta z żadnych bibliotek dat.

Znalazłem całkiem fajne (jeśli sam mogę to powiedzieć) rozwiązanie. Niestety nie mogę go skrócić, co naprawdę mnie wkurza, ponieważ wydaje mi się, że powinien istnieć lepszy sposób.

Rozwiązanie opiera się na tym algorytmie, który sam w sobie ma tylko 44 bajty. Niestety potrzebuję kolejnych 100 bajtów, aby ładnie ją owinąć ...

#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;}

Wyjście przez kod powrotu (w C ++, użycie coutlub printfcokolwiek podobnego wymaga innego #include, co jeszcze bardziej rozwaliłoby rozwiązanie).

Program sterownika / testu:

# 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

Dane wyjściowe programu sterownika:

$ ./test_doomsday 
1766: 2
2013: 3
2013: 2
2014: 1
150 doomsday.cpp characters
CompuChip
źródło
Dla algorytmu liczę 88, a nie 44. Co to jest algorytm i co to jest wypaczanie? ($m<3?$y--:$y-2)+3zamiast d=13,, d+=m<3?y--:y-2,i d+4powinny działać jak dobrze i oszczędza dużo. +5zamiast +3i -5powinien też działać i oszczędza 2 bajty. for(m=0;++m<13;)oszczędza jeden bajt. Przejście m=0do funkcji head oszczędza kolejny bajt; a przejście ()%7||++fdo głowicy pętli ratuje kolejną. Zmniejszono z 149 do 136 bajtów.
Tytus
0

Clojure, 207 187 bajtów

-20 bajtów poprzez pozbycie się importi niektórych białych spacji, za którymi tęskniłem.

(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))

Począwszy od 1 stycznia danego roku, pętla każdego dnia. Jeśli dzień jest w piątek trzynastego, zwiększa się zliczanie. Pętla trwa aż do następnego roku.

(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.
Carcigenicate
źródło
0

PHP, brak wbudowanych, 81 bajtów

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

Uruchom z echo <year> | php -nR '<code>'.

awaria

Dni powtarza się co 400 lat.
W wynikach dla 1600 do 1999 (na przykład) istnieje 28-letni okres z zaledwie trzema przerwami:

  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

Po skorygowaniu roku o te luki możemy uzyskać wynik za pomocą prostego skrótu:

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

Nie krótkie (95 bajtów), ale ładne. I możemy grać w golfa

  • 4 bajty przy użyciu łańcucha trójskładnikowego dla przesunięcia,
  • 8 bajtów poprzez konwersję mapy skrótu z ciągu base4 na liczbę całkowitą,
  • jeszcze jeden, używając reprezentacji szesnastkowej,
  • i jeden przez połączenie wyrażeń.
Tytus
źródło
Port odpowiedzi C ++ CompuChip można zagrać w golfa do 84 bajtów: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 bajtów

CÆ5¥ÐUXD e

Spróbuj

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
Kudłaty
źródło