¿Cuántos viernes 13 en un año?

28

Su desafío es escribir un programa que, dado un año, arroje el número de "Viernes 13" en él.

Reglas y detalles:

  • Puede recibir información a través de STDIN, o como un argumento pasado a su programa.
  • Debe enviar el resultado a STDOUT.
  • Puede suponer que la entrada será un año válido y no es anterior al calendario gregoriano (se permite un comportamiento indefinido en estos casos).
  • Se permiten bibliotecas de calendario / fecha.

Este es un , por lo que gana el código más corto (en bytes).

(Enlace de desafío relacionado)

Cruncher
fuente
77
¿Cuál es el rango de entrada requerido? Si va mucho antes de 1800, ¿qué suposiciones deberían hacerse sobre el cambio del calendario juliano al gregoriano?
Peter Taylor
@PeterTaylor No lo había pensado. Si una fecha es anterior a Gregory, entonces puede tener un comportamiento indefinido.
Cruncher
1
Los primeros países en adoptar el calendario gregoriano lo hicieron en octubre de 1582, siguiendo el toro del propio Gregorio. Los países que adoptaron el nuevo calendario tarde no cambiaron hasta el siglo XX, por ejemplo, Grecia lo introdujo el 1 de marzo de 1923.
Jeppe Stig Nielsen
@JeppeStigNielsen No sé mucho sobre calendarios y demás. Si los adoptaron o no, no cambia cuáles son las fechas gregorianas. Las bibliotecas deberían poder calcular fechas desde hace mucho tiempo, supongo.
Cruncher
3
Estoy siendo fuera de tema aquí, supongo. Muchas bibliotecas escritas por programadores angloamericanos utilizan septiembre de 1752 como la hora "correcta" de cambio de calendarios. Esto fue cuando el Imperio Británico cambió. El nuevo calendario se mantuvo cuando se fundó EE. UU., Por supuesto. (Como curiosidad, algunos softwares SQL tienen 1753 como el año mínimo ya que no quieren hacer frente al problema de septiembre de 1752). Sin embargo, usar septiembre de 1752 es muy anglocéntrico. Tienes razón, las fechas gregorianas son las mismas independientemente de si se usaron históricamente o no. Ese es el llamado calendario gregoriano proleptico .
Jeppe Stig Nielsen

Respuestas:

3

APL (Dyalog APL) con cal de dfns , 29 bytes

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

Pruébalo en línea!

⍳ 12 los enteros del uno al doce

⎕ ,¨ tomar entrada numérica y anteponer a cada uno de los doce números

{...  en cada uno de los pares, aplique la función ...

cal⍵ obtener un calendario para ese año-mes

2 ↓ soltar dos filas (título y días)

 transposición (para que podamos direccionar columnas en lugar de filas)

¯5 ↑ tome los últimos cinco (dos dígitos para cada viernes y sábado más un espacio)

3 ↑ tome los dos primeros (dos dígitos para el viernes más un espacio)

 transponer (para que podamos leer el orden)

, enmarañar

 ejecutar como expresión APL (da una lista de las fechas de los viernes)

13 ∊ ¿Trece es miembro de esa lista?

+/ suma los 12 booleanos


Usando el algoritmo de @ Wrzlprmft , podemos hacerlo sin bibliotecas para 53 bytes:

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

-∘0 1 restar cero y uno

400 100 4 ∘.| tabla de resto de división para los dos años (a través) dividida por estos números (abajo)

0 ≠.= "producto" interno con 0, pero usando ≠ y = en lugar de +. ×

⊢ , anteponer el año del argumento no modificado

2 3 ¯1 +.× producto interno con estos números

14 | resto de división cuando se divide por catorce

'21232211321211' ⌷⍨ indexar en esta cadena

Adán
fuente
Son 29 caracteres, pero estos son más de 1 byte ¿verdad?
Cruncher
@Cruncher He agregado un enlace explicativo en el encabezado. Si abre el enlace TIO, verá que dice "29 caracteres, 29 bytes (SBCS)" a la derecha, es decir, Conjunto de caracteres de un solo byte.
Adám
Bueno, supongo que este es el nuevo ganador, ¿es una práctica estándar en este SE cambiar la respuesta aceptada tanto tiempo después de la pregunta?
Cruncher
@Cruncher Sí. E incluso hay insignias para ser aceptado mucho después de OP.
Adám
12

Mathematica 49 46 45 44 42

Como una función pura : 42 caracteres

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

Ejemplo

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

2


Como una función con nombre : 44 caracteres

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

Ejemplos

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

2
3
2
1

DavidC
fuente
Un personaje más corto:f=DayName@{#,m,6}~Table~{m,12}~Count~Friday&
Mr.Wizard
@ Mr.Wizard Sí. Me sorprende que Mathematica pueda analizar los múltiples casos de notación infija.
DavidC
David, me sorprende que no hayas visto mi (sobre) uso de esta notación conjunta. : ^) (Ejemplos: (1) , (2) )
Mr.Wizard
8

Rubí, 49 48 47 46

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

Editar: afeitó a un personaje retrocediendo una semana, gracias a Jan, y otro cambiando de Time.new a Time.gm

Editar: a expensas de ofuscarlo un poco más, puedo llegar a 46 con

f=->m{(1..12).count{|i|Time.gm(m,i,8).wday<1}}
histocrat
fuente
55
one-char ahorro si cuenta los números del viernes 6
John Dvorak
2
@JanDvorak inteligente!
histocrat
¿Por qué 6? No lo entendí.
NARKOZ
3
Si el 6 es viernes, el 13 también es viernes
TwiNight
Si el octavo es domingo, entonces el primero también lo es, y así puede usarlo Time.gm(m,i).wday<1. Además, no sé por qué estás nombrando la función.
Lee W
8

Powershell, 68 63 58 52 50

Gracias Iszi por el dato.

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

Usando el hecho de que si el primer día del mes es domingo, el 13 será el viernes.

También he intentado:

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

pero no es lo mismo $argsdentro del bloque de script.

Danko Durbić
fuente
1
Me gusta la idea de usar el primer día del mes.
Cruncher
Buen truco, ahí. Sin embargo, el @ es innecesario.
Iszi
Otra cosa, aunque soy culpable de lo mismo en muchos de mis guiones. El desafío especifica que la entrada puede provenir de un argumento. Reemplace $ncon $argsen el bucle, y puede prescindir por $n=read-host;completo. Guarda 8. Elimina @, como se mencionó anteriormente, y tienes 54.
Iszi
Corrección: ¡se reduce a 52!
Iszi
Tratando de averiguar por qué su segundo script no funcionará y estoy perdido. Lo que es interesante es que puedo cambiar a cabo $argspara $input, alimentando así el año en el de la tubería, y el script se ejecutará, pero siempre da salida 3.
Iszi
5

R 76 72 57

sum(format(as.Date(paste(scan(),1:12,1,sep="-")),"%w")<1)
flodel
fuente
Puede bajar esto fácilmente 4 al reemplazar su "%a %d")=="Fri 13"con el "%w%d)=="513")uso de dow como número y eliminar los espacios.
chmullig
¡muy apreciado!
flodel
+1 ¡Aunque hacer el seqúnico en el mes es más corto aquí! sum(format(as.Date(paste(scan(),1:12,13,sep="-")),"%w%d")=="513")solo tiene 65 caracteres!
plannapus
wow, no habría imaginado que eso <obligaría a un personaje a un entero ¡Buen truco!
plannapus
@plannapus Es bastante común. Dado que los códigos de caracteres son todos números. Incluso Java puede comparar int y char
Cruncher
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

El lunes 9 puede no tener el mismo tono pero funciona igual de bien.

Editar: Un año y medio para notar que datees más corto que datetime:)

ejrb
fuente
Muy buena solución!
leancz
2
Puede guardar un from datetime import*
personaje
¡Agradable! Terminé con algo efectivamente idéntico, pero evitando exec: f=lambda y:sum([date(y,m,13).weekday()==4 for m in range(1,13)]).... Solución del mismo tamaño con la importación (86 bytes), sin embargo.
iwaseatenbyagrue
5

No usar ninguna biblioteca o funciones de fecha integradas:

Golfscript - 51

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

' [3/=RI[)a%:*.' bien podría ser 'feefefgeeffgfe'

Python - 82 79

Esencialmente el mismo algoritmo.

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

Usando este truco , esto se puede reducir aún más para:

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

Esto explota el hecho de que, en cuanto al calendario, solo hay 14 años diferentes, que se distinguen por su último día y si están saltando. lcalcula el número de años bisiestos hasta su argumento (si el calendario gregoriano se extendió hacia atrás hasta el año 1). (2*i+3*l(i)-l(i-1))%14es la abreviatura de l(i)-l(i-1)+(i+l(i))%7*2, donde l(i)-l(i-1)nos dice si el argumento es un año bisiesto y i+l(i)resume los turnos del último día (uno en un año normal, dos en un año bisiesto).

Wrzlprmft
fuente
Dado que este es mi primer golfscript, agradecería cualquier pista para seguir jugando al golf.
Wrzlprmft
Estaba pensando en una solución de este tipo utilizando el hecho de que solo hay 14 años únicos en realidad, pero no estaba seguro del mejor lenguaje para hacerlo competitivo. Creo que esta es la respuesta más corta sin bibliotecas. Si los años bisiestos fueran uniformes cada 4 años, es posible que pueda ganar con esto
Cruncher el
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]-'`');}

No es la respuesta más corta, pero no usa bibliotecas.

Williham Totland
fuente
Oye, ¿estarías dispuesto a dar una respuesta sin respuesta con una explicación? Estoy interesado en lo que hiciste exactamente
Cruncher
1
@Cruncher, es una tabla de búsqueda sobre la base de que el calendario gregoriano sigue un ciclo de 400 años.
Peter Taylor
1
Más explícitamente (y más), C #: static char GetNumberOfFriday13s(int year) { const string perpetualCalendar = "1221212213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213112213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122131"; return perpetualCalendar[year % 400];. No funcionará por años negativos.
Jeppe Stig Nielsen
¡Linda! Como un pequeño error, v[0]debería ser v[1]. También puedes jugar golf un poco; considere usar strcat, almacenar caracteres para imprimir directamente a[]y restar constantes numéricas en lugar de constantes de caracteres. :)
user1354557
1
También mejoré la compresión: 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 caracteres)
user1354557
4

C ( 151 145 137 131 130 caracteres)

Me sorprende ver que solo hay otra solución que no utiliza herramientas de calendario integradas. Aquí hay un enfoque matemático (altamente ofuscado), también en 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));}

(Lo anterior se compila en GCC sin errores)

Solución alternativa: C (287-> 215 caracteres)

Disfruté bastante la solución de Williham Totland y su uso de la compresión. Arregle dos pequeños errores y modifiqué el código para acortar su longitud:

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]);}
usuario1354557
fuente
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;

Residencia en

"Cualquier mes que comienza un domingo contiene un viernes 13, y hay al menos un viernes 13 en cada año calendario".

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

Damir Kasipovic
fuente
4

fiesta 47 36

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

Gracias @DigitalTrauma por guardar 10 caracteres usando seqel inicio predeterminado en 1.

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

(La versión anterior usaba echopresente un error debido a la línea vacía cuando <(echo $1-{1..12}-6$'\n'). Así que esta función funcionó bien hasta hoy es viernes.

Veamos:

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

Es dependiente de la configuración regional , si no funciona, es posible que deba

export LANG=C

o

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

En una función; +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

Bono: +78 -> 121

A partir de ahí, si mi función se convierte en:

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

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
F. Hauri
fuente
Esto parece depender de la localidad.
Peter Taylor
Sí, esto se basa en el valor predeterminado C. Pero hay un error ...
F. Hauri
Ahorre un carácter entrecomillando su cadena de formato printf y escapando del \ en su lugar:%s\\n
Digital Trauma
1
O use seqpara soltar 8 caracteres:date -f<(seq -f$1-%g-6 1 12)|grep -c ^F
Digital Trauma
1
En realidad, puedes eliminar 2 caracteres más. Si omite el número de secuencia de inicio, seq comenzará en 1 de forma predeterminada, que es lo que desea: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
fuente
y por que es -1?
Lukasz 'Severiaan' Grela
1
¡Se ve bien! Usted puede ahorrar unos cuantos bytes, mediante la eliminación ,b,cde la declaración de la función (! Está bien que la fuga vars para el golf), como también bse presenta como un Numberpuedas +=el resultado de la prueba en lugar de la &&b++: b+=/^F/.test(new Date(a,c,6)). Sin embargo, puede guardar otro byte usando !new Date(a,c,1).getDay()(esto funciona porque getDaydevuelve 0 para el domingo, y si el 13 es un viernes, el primero será un domingo) en lugar del testque debería ahorrarle 7 bytes.
Dom Hastings
@DomHastings: gracias por tus consejos !!!
guy777
3

k

64 caracteres

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

Lecturas de stdin

skeevey
fuente
Ok, ¿qué está pasando aquí? : P
Williham Totland
Lea el año, cree una lista de fechas del día 13 de cada mes, día de prueba de la semana = viernes, suma de la lista resultante de booleanos
skeevey
3

Lisp común (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
fuente
Oh dios, nunca pude leer lisp ..
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);}

Gracias a Jeppe Stig Nielsen por linq y sugerencia de verificar el domingo 8.

Gracias a Danko Durbić por sugerir en >lugar de ==.

Kami
fuente
En lugar de c+=(int)new DateTime(y,i,13).DayOfWeek==5?1:0;usar el equivalente c+=new DateTime(y,i,8).DayOfWeek==0?1:0;. El truco es restar 5, porque entonces puedes deshacerte del yeso int, y también el número 8tiene un dígito menos que el número 13. ¡Domingo 8!
Jeppe Stig Nielsen
Con LINQ: int g(int y){return Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0);}. Por supuesto, como lambda esto es y=>Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0).
Jeppe Stig Nielsen
Puedes guardar un personaje comparando .DayOfWeek<1.
Danko Durbić
@ DankoDurbić Esto puede aplicarse a la c#respuesta pero no está seguro de cómo aplicarla linq.
Kami
Mi error; aparentemente no se puede comparar DayOfWeekcon ningún otro número entero que no sea 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;

Corre con echo <year> | php -nR '<code>'.

Básicamente lo mismo que intentó Oleg y Damir Kasipovic hizo, solo que con un mejor golf:
cada mes que comienza con un domingo, tiene un viernes 13.
Así que recorro los meses y cuento los primeros días que son domingos.

Descompostura

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
Titus
fuente
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
tmartin
fuente
1

Bash ( 52 47 caracteres)

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

Rebol, 63

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

Ejemplo de uso en la consola Rebol:

>> y: 2012
== 2012

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

La solución alternativa que recoge todo el viernes 13 en un año determinado es:

>> 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
fuente
1

Bash y Sed, 39

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

ncal imprime un calendario para el año dado con los días de la semana a la izquierda.

sedcon una /gbandera subscribe los 13 con nuevas líneas

grep -c cuenta las líneas que comienzan con "2" (20 siempre sigue a 13)

¡Gracias a @DigitalTrauma por encontrar un error en mi versión anterior y proponer una solución!

No es que Charles
fuente
No me funciona del todo: las líneas de los viernes solo se imprimen una vez, incluso si contienen más de un 13.
Digital Trauma
1
Creo que lo mejor que puedo hacer con algo como esto es 38:ncal $1|sed /F/s/13/\\n/g|grep -c ^\ 2
Digital Trauma
1
@ DigitalTrauma Tienes razón. En algún momento este script estaba funcionando. Déjame arreglarlo.
No es que Charles
1
@DigitalTrauma parece que alguna versión mucho más larga estaba funcionando. gracias por la solucion!
No es que Charles
Interesante, la expresión sed no citada que propuse funciona con GNU sed (Linux) pero no con BSD sed (OSX). Supongo que puedes ganar 1 personaje a costa de la portabilidad si eliges la versión GNU.
Trauma digital
1

Scala, 76 68 caracteres

En 78 caracteres:

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

Nada fuera de lo común, excepto el uso de números mágicos para DAY_OF_WEEK = 7y FRIDAY = 6.

Versión de 68 caracteres:

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

Sí, Java cambió los valores de las constantes del día de la semana entre las API.

Karol S
fuente
Es una pena que new java.util.GregorianCalendartenga que ser tan largo :(
Cruncher
1

Pitón 195/204

Solo funciona para años anteriores, porque monthdatescalendardevuelve un calendario para el año dado hasta ahora . Creo que queda mucho potencial de optimización :).

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)

Otra solución, funciona para cada fecha pero no es más pequeña:

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
fuente
En su primer ejemplo, el rango debería ser (1,13), de lo contrario, se perdería el viernes 13 de diciembre, como en 2013.
leancz
1
Ni siquiera te molestaste en jugar golf. Elimina algunos de esos espacios.
mbomb007
1

Perl 6, 55 53

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

Vieja respuesta:

{sum (1..12).map: {Date.new($_,$^a,13).day-of-week==5}}
bb94
fuente
48 bytes
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
fuente
0

Perl + lib POSIX 55

Con la idea de no buscar 13thsino primero, y como sundayes 0esto, ¡ahorre 3 caracteres! Gracias @ Iszi y Danko Durbić!

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

Podría calcular 2010 a 2017 (para muestra) de esta manera:

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

(Ok, no hay nueva línea , pero eso no se preguntó;)

Mensaje antiguo: 63

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

En acción:

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
fuente
0

En Smalltalk (sabor Squeak / Pharo), implemente este método en Integer ( 86 caracteres)

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

A continuación, utilizar de esta manera: 2014countFriday13.

Por supuesto, podríamos usar un nombre más corto, pero entonces no sería Smalltalk

aka.nice
fuente
0

C ++ - Demasiados bytes :(

Intenté una solución que no utiliza ninguna biblioteca de fechas.

Encontré una solución bastante buena (si puedo decirlo yo mismo). Lamentablemente, no puedo hacerlo más corto que esto, lo que realmente me molesta porque parece que debería haber una mejor manera.

La solución depende de este algoritmo que tiene solo 44 bytes en sí mismo. Desafortunadamente necesito otros 100 bytes para envolverlo bien ...

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

La salida a través del código de retorno (en C ++, usar couto printfalgo así requiere otro #include, lo que haría explotar aún más la solución).

Conductor / programa de prueba:

# 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

Salida del programa controlador:

$ ./test_doomsday 
1766: 2
2013: 3
2013: 2
2014: 1
150 doomsday.cpp characters
CompuChip
fuente
Cuento 88 para el algoritmo, no 44. ¿Cuál es el algoritmo y cuál es la deformación? ($m<3?$y--:$y-2)+3en lugar de d=13,, d+=m<3?y--:y-2,y d+4debería funcionar tan bien y ahorra mucho. +5en lugar de +3y -5debería funcionar también y ahorra 2 bytes. for(m=0;++m<13;)ahorra un byte. Mover m=0a la cabeza de la función guarda otro byte; y pasar ()%7||++fa la cabeza del bucle guarda otro. Bajó de 149 a 136 bytes.
Titus
0

Clojure, 207 187 bytes

-20 bytes al deshacerme del importespacio en blanco que perdí.

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

A partir del 1 de enero del año dado, se repite cada día. Si el día es el viernes 13, aumenta el recuento. Continúa en bucle hasta que alcance el próximo año.

(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
fuente
0

PHP, no incorporado, 81 bytes

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

Corre con echo <year> | php -nR '<code>'.

Descompostura

Los días laborables se repiten cada 400 años.
En los resultados de 1600 a 1999 (por ejemplo), hay un período de 28 períodos con solo tres brechas:

  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

Después de ajustar el año para estas brechas, podemos obtener el resultado con un simple hash:

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

No corto (95 bytes) pero bonito. Y podemos jugar al golf

  • 4 bytes usando una cadena ternaria para el desplazamiento,
  • 8 bytes al convertir el mapa hash de una cadena base4 a entero,
  • uno más usando la representación hexadecimal,
  • y uno fusionando las expresiones.
Titus
fuente
Un puerto de la respuesta C ++ de CompuChip puede reducirse a 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

Intentalo

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
Lanudo
fuente