¿Cuándo es el año común especial más cercano?

11

Un año común es un año que no es bisiesto y donde el primer y último día del año son el mismo día. Un año común especial es aquel que comienza un lunes y también termina un lunes.

Su desafío es crear un programa / función que, cuando se le da un año como entrada, encuentre el año común especial más cercano y se genere si es un año común. Si el año está tan cerca del anterior como el que está al lado, se obtiene el más grande.

Entrada

Un entero que representa el año para probar en el rango 1600 <= x <= 2100.

Salida

Un entero que representa el año común especial más cercano.

Casos de prueba

2017 -> 2018
2018 -> 2018
1992 -> 1990
1600 -> 1601
2100 -> 2103
1728 -> 1731 (lies between 1725 and 1731)

Notas

Los 54 años en el rango dado ya se muestran en el artículo de Wikipedia vinculado. También los proporcionaré aquí como referencia:

1601, 1607, 1618, 1629, 1635, 1646, 1657, 1663, 1674, 1685, 1691
1703, 1714, 1725, 1731, 1742, 1753, 1759, 1770, 1781, 1787, 1798
1810, 1821, 1827, 1838, 1849, 1855, 1866, 1877, 1883, 1894, 1900
1906, 1917, 1923, 1934, 1945, 1951, 1962, 1973, 1979, 1990
2001, 2007, 2018, 2029, 2035, 2046, 2057, 2063, 2074, 2085, 2091
2103 (Needed for 2097 to 2100)
TheLethalCoder
fuente
1
solo como referencia para ayudar a las personas, la secuencia parece irse 6, 11, 11. IE 6 años después de la primera, es otro de 11 años después de eso es otra, 11 años después de que es otro, 6 años después de eso es otro, etc.
Skidsdev
66
@Mayube No del todo. La secuencia real es "6, 11, 11, 6, 11, 11, 6, 11, 11, 6, 12, 11, 11, 6, 11, 11, 6, 11, 11, 6, 11, 12, 11 , 6, 11, 11, 6, 11, 11, 6, 11, 6, 6, 11, 6, 11, 11, 6, 11, 11, 6, 11, 11, 6, 11, 11, 6, 11 , 11, 6, 11, 11, 6 "(tenga en cuenta los 12 y los 6, 11, 6, 6, 11, 6)
Martin Ender
1
Como el calendario se repite cada 400 años, la parte relevante (periódica) de la secuencia es "6, 11, 11, 6, 11, 11, 6, 11, 11, 6, 12, 11, 11, 6, 11, 11 , 6, 11, 11, 6, 11, 12, 11, 6, 11, 11, 6, 11, 11, 6, 11, 6, 6, 11, 6, 11, 11, 6, 11, 11, 6 , 11, 11 ". Me impresionará si alguien puede guardar bytes con esto, debido a las tres irregularidades.
Martin Ender
55
¡Felicidades por 2k para mí! : P
TheLethalCoder
1
a year that is not a leap year and where the first and last day of the year are on the same dayLa segunda parte de esa definición es redundante. Todos los años no bisiestos comienzan y terminan el mismo día, con una duración exacta de 52 semanas y un día (365 días).
John Gordon

Respuestas:

1

Jalea , 30 bytes

“Þıİs|9ṗ[¿¶F’ṃ“©€¿‘⁽£d;+\ạÐṂ⁸Ṁ

Un enlace monádico que toma y devuelve un año entero.

Pruébalo en línea! o ver un conjunto de pruebas .

¿Cómo?

Al igual que otras respuestas, esto crea la lista de años necesarios para el dominio de entrada a partir de los incrementos, y encuentra el año máximo de diferencia absoluta mínima de la entrada.

“Þıİs|9ṗ[¿¶F’ṃ“©€¿‘⁽£d;+\ạÐṂ⁸Ṁ - Main link: number y
                   ⁽£d         - augmented base 250 literal = 1601
“Þıİs|9ṗ[¿¶F’                  - base 250 literal = 20129386383114231907032071
              “©€¿‘            - code page index list = [6,12,11]
             ṃ                 - base decompression = [6,11,11,6,11,11,6,11,11,6,12,11,11,6,11,11,6,11,11,6,11,12,11,6,11,11,6,11,11,6,11,6,6,11,6,11,11,6,11,11,6,11,11,6,11,11,6,11,11,6,11,11,6,12]
                      ;        - concatenate = [1601,6,11,11,6,11,11,6,11,11,6,12,11,11,6,11,11,6,11,11,6,11,12,11,6,11,11,6,11,11,6,11,6,6,11,6,11,11,6,11,11,6,11,11,6,11,11,6,11,11,6,11,11,6,12]
                       +\      - reduce with addition = [1601,1607,1618,1629,1635,1646,1657,1663,1674,1685,1691,1703,1714,1725,1731,1742,1753,1759,1770,1781,1787,1798,1810,1821,1827,1838,1849,1855,1866,1877,1883,1894,1900,1906,1917,1923,1934,1945,1951,1962,1973,1979,1990,2001,2007,2018,2029,2035,2046,2057,2063,2074,2085,2091,2103]
                            ⁸  - link's left argument, y
                          ÐṂ   - filter keep if maximal:
                         ạ     -   absolute difference
                             Ṁ - maximum (alternatively tail, Ṫ, since increasing)
Jonathan Allan
fuente
9

PHP, 67 bytes

for(;date(LN,mktime(0,0,0,1,1,$y=$argn+$i))>1;)$i=($i<1)-$i;echo$y;

Pruébalo en línea!

o

for(;date(LN,strtotime("1/1/".$y=$argn+$i))>1;)$i=($i<1)-$i;echo$y;

Pruébalo en línea!

Expandido

for(;
date(LN,mktime(0,0,0,1,1,$y=$argn+$i)) # N is 1 for Monday and L is 0 for Non leap year
>1;) # loop so long as expression is not 1
  $i=($i<1)-$i; # set $i 0,1,-1,2,-2 ...
echo$y; # Output Year

fecha

Jörg Hülsermann
fuente
1
Guardar un byte:$i=($i<1)-$i;
Christoph
8

Python 2 , 129 124 118 bytes

a=[11,11,6]*13
a[29:29]=a[19:19]=12,
a[10:10]=6,6
n=input()
o=[2401-n]
for i in a*2:o+=o[-1]-i,
print n+min(o,key=abs)

Pruébalo en línea! o Pruebe todos los casos de prueba
Primero, la secuencia se genera (se invierte) a, luego 2401 - input_yearse usa como valor inicial para restar sobre la secuencia.
De esta manera, la lista ocontendrá las diferencias entre todos los años comunes y la entrada, el año más cercano será el número más cercano a cero (positivo o negativo), luego se extraerá (min, key=abs)y se agregará nuevamente a la entrada.

Con datetime119 bytes

lambda i:i+min([y-i for y in range(2200,1500,-1)if datetime(y,1,1).weekday()<1and y%400],key=abs)
from datetime import*

Pruébalo en línea!

varilla
fuente
¿Esto genera la lista de años basada en la secuencia?
TheLethalCoder
@TheLethalCoder, agregó una pequeña explicación
Rod
7

05AB1E , 41 bytes

6xD<Š)•HΘ%A°,SΔA)u•3вè.pO0¸ì1601+DI-ÄWQϤ

Pruébalo en línea!

Explicación

6xD<Š)                                     # push the list [11,6,12]
      •HΘ%A°,SΔA)u•                        # push the number 20129386383114231907032071
                   3в                      # convert to a base-3 digit list
                     è                     # use this to index into the first list
                      .p                   # get list of prefixes
                        O                  # sum each sublist
                         0¸ì               # prepend 0
                            1601+          # add 1601 to each
                                 D         # duplicate
                                  I-       # subtract input from each
                                    Ä      # calculate absolute value
                                     WQÏ   # keep only the years that have the 
                                           # smallest absolute difference from input
                                        ¤  # get the last one
Emigna
fuente
5

JavaScript (ES6), 77 bytes

f=(y,z=y,d=m=>new Date(y,m,!m||31).getDay()-1)=>d(0)|d(11)?f(z<y?z-1:z+1,y):y
<input type=number value=2001 oninput=o.textContent=f(+this.value)><pre id=o>2001

Neil
fuente
4

Mathematica, 70 bytes

Max@Nearest[Select[Range[7!],!LeapYearQ@{#}&&DayName@{#}==Monday&],#]&

Genera una lista de todos los años comunes especiales hasta el año 5040 (¡= 7!) Y luego encuentra el más cercano a la entrada, tomando el máximo en caso de empate.

Martin Ender
fuente
Este era el tipo de respuesta que esperaba, generar la lista y compararla. Sería interesante ver si alguien puede usar la "secuencia" para encontrar una respuesta.
TheLethalCoder
44
¿Qué ... PHP supera a Mathematica?
obispo
Estaba jugando con su código y se me ocurrió esto: (n = 1; t = #; Mientras que [! DayName @ {t} == Monday || LeapYearQ @ {t}, n ++; t = # - (- 1 ) ^ n * Floor [n / 2]]; t) & puedes jugar golf reemplazando mientras con //.t/; etc? He intentado pero no puedo ...
J42161217
3

Java 7, 217 bytes

import java.util.*;int c(int y){return d(y,1);}int d(int y,int x){Calendar c=Calendar.getInstance(),d=Calendar.getInstance();c.set(y,0,1);d.set(y,11,31);return c.get(7)==d.get(7)&c.get(7)==2?y:d(y+x,x>0?-++x:-(--x));}

Explicación:

Pruébalo aquí.

import java.util.*;                   // Required import for Calendar

int c(int y){                         // Method with integer parameter and integer return-type
  return d(y,1);                      //  Call second method with additional parameter
}                                     // End of method (1)

int d(int y,int x){                   // Method (2) with two integer parameters and integer return-type
  Calendar c=Calendar.getInstance(),  //  Create two Calendar instances
           d=Calendar.getInstance();
  c.set(y,0,1);                       //  Set one to 01 January yyyy
  d.set(y,11,31);                     //  and one to 31 December yyyy
  return c.get(7)==d.get(7)           //  If both are the same day of the week
         &c.get(7)==2?                //  and it is a Monday:
          y                           //   Return the input-year
         :                            //  Else:
          d(y+x,                      //   Recursive-call with year + `x`
                x>0?-++x:-(--x));     //   and change `x` to the next to check
                                      //   +1,-2,+3,-4,+5,-6,etc.
}                                     // End of method (2)
Kevin Cruijssen
fuente
si x siempre va a ser 1, ¿por qué no simplemente eliminar int c () {} y cambiar int d(int y, int x){}ad(int y){int x = 1;...}
Brian H.
@BrianH. Debido a que hago una llamada recursiva que usa x, por lo que si lo restablezco a 1cada vez en la parte superior del método, xes incorrecto y la llamada recursiva fallará.
Kevin Cruijssen
1

C #, 183 bytes

Para que la pelota ruede un poco, aquí hay una implementación que hice por mi cuenta. Estoy bastante seguro de que aún se puede jugar golf, así que si alguien quiere sentirse libre de publicar una nueva respuesta.

namespace System.Linq{n=>Enumerable.Range(1,9999).Where(y=>!DateTime.IsLeapYear(y)&(int)new DateTime(y,1,1).DayOfWeek==1).GroupBy(y=>Math.Abs(n-y)).OrderBy(g=>g.Key).First().Last();}

Pruébalo en línea!

Versión completa / formateada, esto también muestra todas las salidas para el rango dado cuando se ejecuta.

namespace System.Linq
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int> f = n =>
                Enumerable.Range(1, 9999)
                          .Where(y => !DateTime.IsLeapYear(y)
                                    & (int)new DateTime(y, 1, 1).DayOfWeek == 1)
                          .GroupBy(y => Math.Abs(n - y))
                          .OrderBy(g => g.Key)
                          .First()
                          .Last();

            for (int y = 1600; y <= 2100; ++y)
            {
                Console.WriteLine($"{y} -> {f(y)}");
            }

            Console.ReadLine();
        }
    }
}
TheLethalCoder
fuente
1

Ruby, 145 bytes

f=->i{i+(1.upto(i).map{|m|Time.new(y=i+m).monday?&&Time.new(y,6).friday?? m:Time.new(y=i-m).monday?&&Time.new(y,6).friday?? -m :nil}.find{|a|a})}

Define una lambda tomando el año de inicio como entrada - f[2017] => 2018

¡Tengo que amar la biblioteca estándar de Ruby! wday==1tiene la misma longitud monday?e infinitamente menos genial :). La verificación especial del año común se realiza por el hecho de que en un año común que comienza el lunes, el 1 de junio es un viernes (¡"viernes" es el nombre del día más corto!)

Desafortunadamente, no es tan bueno buscando en ambas direcciones.

Chowlett
fuente