Quando é o ano comum especial mais próximo?

11

Um ano comum é um ano que não é bissexto e onde o primeiro e o último dia do ano são no mesmo dia. Um ano comum especial é aquele que começa na segunda-feira e termina na segunda-feira também.

Seu desafio é criar um programa / função que, quando dado um ano como entrada, encontre o ano comum especial mais próximo, produzindo-se se for um ano comum. Se o ano estiver tão próximo do ano anterior quanto o próximo, produz o maior.

Entrada

Um número inteiro que representa o ano para o teste no intervalo 1600 <= x <= 2100.

Resultado

Um número inteiro que representa o ano comum especial mais próximo.

Casos de teste

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

Notas

Todos os 54 anos no intervalo fornecido já são mostrados no artigo vinculado da Wikipedia. Também os fornecerei aqui para referência:

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
fonte
1
apenas para referência para ajudar as pessoas, a sequência parece desaparecer 6, 11, 11. IE 6 anos após o primeiro é outra, 11 anos depois que é outra, 11 anos depois que é outra, 6 anos após essa é outra, etc.
Skidsdev
6
@ Mayube Não é bem assim. A sequência real é "6, 11, 11, 6, 11, 11, 6, 11, 11, 6, 12, 11, 11, 6, 11, 11, 6, 11, 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 "(observe os 12s e os 6, 11, 6, 6, 11, 6)
Martin Ender
1
Como o calendário se repete a cada 400 anos, a parte relevante (periódica) da sequência é "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, 11, 6, 11, 11, 6 , 11, 11 ". Ficarei impressionado se alguém puder salvar bytes com isso, devido às três irregularidades.
Martin Ender
5
Parabéns em 2k por mim! : 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 dayA segunda parte dessa definição é redundante. Todos os anos não bissextos começam e terminam no mesmo dia, com exatamente 52 semanas e um dia (365 dias).
John Gordon

Respostas:

1

Gelatina , 30 bytes

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

Um link monádico recebendo e retornando um ano inteiro.

Experimente online! ou veja uma suíte de testes .

Quão?

Assim como outras respostas, isso cria a lista de anos necessária para o domínio de entrada a partir dos incrementos e encontra o ano máximo da diferença absoluta mínima da 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
fonte
9

PHP, 67 bytes

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

Experimente online!

ou

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

Experimente online!

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

encontro

Jörg Hülsermann
fonte
1
Salvar um 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)

Experimente online! ou Experimente todos os casos de teste
Primeiro, a sequência é gerada (revertida) e a, em seguida, 2401 - input_yearé usada como valor inicial a ser subtraído pela sequência.
Dessa forma, a lista oconterá as diferenças entre todos os anos comuns e a entrada, o ano mais próximo será o número mais próximo de zero (positivo ou negativo) e será extraído (min, key=abs)e adicionado novamente à entrada.

Com datetime, 119 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*

Experimente online!

Cajado
fonte
Isso gera a lista de anos com base na sequência?
TheLethalCoder
@TheLethalCoder meio, acrescentou uma pequena explicação
Rod
7

05AB1E , 41 bytes

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

Experimente online!

Explicação

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
fonte
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
fonte
4

Mathematica, 70 bytes

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

Gera uma lista de todos os anos comuns especiais até o ano 5040 (= 7!) E, em seguida, localiza o mais próximo da entrada, utilizando o máximo em caso de empate.

Martin Ender
fonte
Esse era o tipo de resposta que eu esperava, gerar a lista e comparar com isso. Seria interessante ver se alguém pode usar a "sequência" para encontrar uma resposta.
TheLethalCoder
4
O que ... PHP vence o Mathematica?
bispo
Eu estava brincando com seu código e vim com isso: (n = 1; t = #; While [! DayName @ {t} == Monday || LeapYearQ @ {t}, n ++; t = # - (- 1 ) ^ n * Andar [n / 2]]; t) & você pode jogar golfe substituindo enquanto com //.t/; etc? Eu tentei, mas eu não posso ...
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));}

Explicação:

Experimente aqui.

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
fonte
Se x é sempre vai ser 1, porque não basta remover c int () {} e mudança int d(int y, int x){}parad(int y){int x = 1;...}
Brian H.
@BrianH. Como eu faço uma chamada recursiva que usa x, por isso, se eu a redefinir sempre que estiver 1na parte superior do método, xestá incorreta e a chamada recursiva falhará.
Kevin Cruijssen
1

C #, 183 bytes

Para fazer a bola rolar um pouco, aqui está uma implementação que eu mesmo fiz. Tenho certeza de que ainda pode ser jogado para baixo, por isso, se alguém quiser ficar à vontade para postar como uma nova resposta.

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

Experimente online!

Versão completa / formatada, isso também mostra todas as saídas para o intervalo especificado quando executado.

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
fonte
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 um lambda tomando o ano inicial como entrada - f[2017] => 2018

Conseguiu amar a biblioteca padrão do Ruby! wday==1tem o mesmo comprimento monday?e é infinitamente menos legal :). A verificação especial do ano comum é feita pelo fato de que em um ano comum a partir de segunda-feira, 1º de junho, é uma sexta-feira ("sexta-feira" é o nome do dia com o menor número de dias!)

Infelizmente, não é tão bom pesquisar nas duas direções.

Chowlett
fonte