Prime Time Travel

23

Não conte a ninguém, mas eu cortei a máquina de viagem no tempo do meu tio! Meu tio é obcecado por números primos, no entanto, e isso é mostrado na máquina - ele o programou para que ele só possa ir a datas que somam um número primo.

Portanto, não pode ser 1947-08-15porque 1947 + 8 + 15 = 1970, que não é um número primo. Ele pode ir para 1947-07-25, porque 1947 + 7 + 25 = 1979, que é primo. Então, se eu quiser voltar para assistir às celebrações da independência da Índia, parece que terei que ir algumas semanas antes e esperar esses 20 dias.

Tenho outras datas em que quero ir e também terei que ir a uma data anterior (ou, se tiver sorte, igual a) à minha data prevista, que totalize um número primo. No entanto, sou impaciente e não quero esperar muito; portanto, quero encontrar a data que posso usar que seja a mais próxima da minha data prevista.

Você pode me escrever um programa que atinja minha data prevista e me forneça a data em que devo inserir a máquina do tempo - a data mais próxima antes ou igual à data especificada cujas partes somam um número primo?

(Para esse desafio, estamos usando o calendário gregoriano proléptico - o que significa simplesmente que usamos o calendário gregoriano atual, mesmo em períodos em que as pessoas usavam o calendário juliano mais antigo.)

Entrada

  • Um encontro
    • idealmente, qualquer data na era atual (AD); praticamente, qualquer subconjunto do seu idioma possa lidar naturalmente
    • em qualquer formato legível por humanos⁺ que você gosta

Saída

  • A data mais próxima da data de entrada, que é menor ou igual à entrada e cuja data + mês + ano soma um número primo.
    • em qualquer formato legível por humanos⁺ que você gosta

":" Legível por humanos ", como no dia, mês e ano, todos explicitados separadamente, em qualquer ordem

Casos de teste

1947-08-15
=> 1947-07-25
1957-10-04
=> 1957-09-27
1776-07-04
=> 1776-07-04
999-12-12
=> 0999-12-10
2018-06-20
=> 2018-06-15
1999-01-02
=> 1998-12-29
1319-12-29
=> 1319-07-01

(Obrigado a @Shaggy, @PeterTaylor e @Arnauld pela ajuda na pergunta.)

sundar - Restabelecer Monica
fonte
É bom ter um tempo sem sentido na saída? (ex. Fri Jul 25 02:46:39 CEST 1947)
wastl
@wastl Sim, desde que a informação da data seja uma substring de comprimento fixo contíguo da saída (portanto, não para esse exemplo em particular).
sundar - Restabelece Monica

Respostas:

4

Vermelho , 87 bytes

func[d][d: d + 1 until[d: d - 1 n: d/2 + d/3 + d/4 i: 1 until[n %(i: i + 1)= 0]i = n]d]

Experimente online!

Mais legível:

f: func [ d ] [ 
    d: d + 1
    until [
        d: d - 1
        n: d/day + d/month + d/year
        i: 1
        until [
            i: i + 1
            n % i = 0
        ]
        i = n
    ] 
    d
]
Galen Ivanov
fonte
4

JavaScript (Node.js) , 94 bytes

Recebe a entrada como 3 números inteiros na sintaxe de currying (year)(month)(day). Retorna uma sequência separada por hífen com um hífen à esquerda.

y=>m=>g=d=>(P=k=>n%++k?P(k):~k)(n=eval(s='-'+new Date(y,m-1,d).toJSON().split`T`[0]))?g(d-1):s

Experimente online!

Quão?

Primeiro convertemos a data para o formato JSON yyyy-mm-ddT00:00:00.000Z( ISO 8601 ), dividimos no arquivo'T' , mantemos apenas a parte esquerda e adicionamos um hífen à esquerda, que fornece -yyyy-mm-dd.

s = '-' + new Date(y, m - 1, d).toJSON().split`T`[0]

Agora, essa expressão s pode ser eval()alterada para obter o n oposto da soma do ano + mês + dia .

n = eval(s)

Usamos a função auxiliar P () para testar se -n é primo (nesse caso, ele retorna 0 ). Se for, retornamos s . Caso contrário, tentamos novamente com o dia anterior.

(P = k => n % ++k ? P(k) : ~k)(n) ? g(d - 1) : s
Arnauld
fonte
1
Sinto que preciso de um dia de folga apenas para entender como essa verificação básica funciona e termina. Bom golfe!
sundar - Restabelece Monica
3

Python 2 , 130 127 bytes

Entrada é year, month, day.

-3 bytes graças a Kevin Cruijssen .

from datetime import*
def f(a):
  while(lambda n:any(n%m<1for m in range(2,n)))(a.year+a.month+a.day):a-=timedelta(1)
  print a

Experimente online!

ovs
fonte
Você tem permissão para pegar um objeto de data como entrada, para salvar 3 bytes .
Kevin Cruijssen
1
@KevinCruijssen obrigado. Você acha que este é um formato de entrada válido?
ovs
Não vejo por que não seria, então isso é outro -4. Não tinha pensado nisso.
Kevin Cruijssen
2

Java 8, 144 128 bytes

d->{for(;;d=d.minusDays(1)){int n=d.getYear()+d.getMonthValue()+d.getDayOfMonth(),i=2;for(;i<n;n=n%i++<1?0:n);if(n>1)return d;}}

Experimente online.

java.time.LocalDateclasse foi uma melhoria em comparação com a antiga java.util.Date, mas por que eles tiveram que prolongar esses nomes ( getMonthValuee getDayOfMonthnão getMonthe getDay) ..>.>

Explicação:

d->{                      //  Method with LocalDate as both parameter and return-type
  for(;;                  //  Loop indefinitely
      d=d.minusDays(1)){  //    Going one day back after every iteration
    int n=d.getYear()+d.getMonthValue()+d.getDayOfMonth(),
                          //   Set `n` to the sum of year+month+day
    i=2;for(;i<n;n=n%i++<1?0:n);if(n>1)
                          //   If `n` is a prime:
      return d;}}         //    Return the now modified input-LocalDate `d`
Kevin Cruijssen
fonte
2

Ruby , 94 bytes

Experimente online!

Toma uma única entrada de data e retorna uma sequência no formato ISO 8601 ( YYYY-MM-DD).

require'date'
require'prime'
->d{d.downto(0){|i|break i.to_s if (i.day+i.month+i.year).prime?}}

Ele usa o módulo principal do Ruby. Se isso não for permitido, ou desaprovado, então por mais dois bytes apresento essa abominação:


Ruby , 97 bytes

Experimente online!

Ele usa a verificação de um número sendo primo a partir desta resposta do stackoverflow . Não tenho ideia de como isso funciona, parece um pouco com bruxaria. A mesma entrada acima e a mesma saída.

require'date'
->d{d.downto(0){|i|break i.to_s if ?1*(i.day+i.month+i.year)!~ /^1?$|^(11+?)\1+$/}}
IMP1
fonte
O uso de módulos é perfeitamente adequado, desde que as linhas de importação estejam incluídas na contagem de bytes (o que você fez aqui). Parece que você não precisa dos parênteses ao redor da inicial de do espaço após o ifporém, para poder cortar 3 bytes da sua primeira resposta, removendo-os. TIO link
sundar - Reinstate Monica
3
Eu gosto da abominação de bruxaria. É bem legal e simples quando você olha para ele: ?x*n !~ /^x?$|^(xx+?)\1+$/= para verificar se n é primo, faça uma sequência de n 'x' s, verifique se não é 0 ou 1 x (que não é primo) e se não corresponde a nenhum 2 ou mais x se repetem (a correspondência ^(xxxxx)\1+$significaria que n é divisível por 5). Abusa do retorno do mecanismo regex para fazer nosso loop por nós - é brilhante, é monstruoso e o sacrifício de animais provavelmente esteve envolvido em sua descoberta.
sundar - Restabelece Monica
Bom local sobre os parênteses e o espaço! Obrigado.
IMP1
A versão "bruxaria" pode ser feita em 92 bytes, veja aqui . Como a soma que queremos verificar a primalidade é pelo menos 3 (como a data mínima 0001-01-01 é igual a 1 + 1 + 1 = 3), podemos remover a parte do regex que é especificamente para manipular a entrada como 0 ou 1. A remoção e simplificação fornece uma versão de 91 bytes.
sundar - Restabelece Monica
Uma abordagem interessante. Guardar 2 bytes usando 'mon' em vez de 'mês'
GB
2

Ruby , 57 53 bytes

->d{d-=9until/^(11+)\1+$/!~?1*(d.day+d.year+d.mon);d}

Experimente online!

Não é minha ideia - roubada da "abominação" do IMP1


Ideia original:

Ruby , 59 bytes

->d{d-=9until((2...w=d.day+d.year+d.mon).all?{|x|w%x>0});d}

Experimente online!

GB
fonte
1
Em 8e4vez disso, usando o trabalho?
Kritixi Lithos
Sim, claro que funciona. Também funciona usando 9 ou qualquer outro número menor. Leva muito mais tempo para ser executado. Obrigado.
GB
2

R , 117 bytes

function(d){while(!numbers::isPrime(y(d))){d=d-1};d}
`<`=format
y=function(d)sum(as.integer(c(d<"%Y",d<"%m",d<"%d")))

Experimente online!

ngm
fonte
2

F #, 134 133 bytes

let rec s(d:System.DateTime)=
 let x=d.Year+d.Month+d.Day
 if(Seq.tryFind(fun i->x%i=0){2..x-1}).IsNone then d else d.AddDays(-1.)|>s

-1 byte graças a partir de sundar .

Experimente online!

Total do dia, mês e ano e veja se é excelente. Se for, retorne essa data. Caso contrário, diminua a data em 1 dia e tente novamente.

Ciaran_McCarthy
fonte
1
Você pode salvar um byte escrevendo -1.0como -1., na chamada AddDays.
sundar - Restabelece Monica
Você está certo ... isso é realmente estranho. Mas útil. Obrigado.
Ciaran_McCarthy
1

PowerShell , 105 90 bytes

for($a=$args[0];'1'*((Date $a -f yyyy+MM+dd)|iex)-match'^(..+)\1+$';$a=$a.AddDays(-1)){}$a

Experimente online!

Graças ao sundar por -13 bytes.

Pega a entrada como a DateTime 2018-06-20e a salva $a. Então estamos em um forloop. A cada iteração, tomamos $a -formatted como yyyy+MM+dd(ou seja, a data atual em que estamos separados por +sinais) adicionados juntamente com |iex(semelhante a eval), multiplicando por string com 1s para formar um número unário e usando uma regex de verificação primária para determinar se a data atual é primária ou não. Se não for primo, devemos .AddDays(-1)retroceder um dia e continuar o ciclo. Se for primo, sairemos do loop e colocaremos $ano pipeline com saída implícita.

A saída resultante é dependente da cultura. No TIO, que usa en-us, a saída é de formato de data longa, que parece Saturday, July 1, 1319 12:00:00 AM.

AdmBorkBork
fonte
Você pode salvar alguns bytes enviando o argumento como um objeto de data e hora. Além disso, a regex pode ser simplificada para corresponder aos compostos acima de 2 (já que a data mínima é 0001-01-01cuja soma é 3). Fiz uma rachadura nessas mudanças aqui .
sundar - Restabelece Monica
(note que embora eu sou um novato PowerShell e que o código vinculado é apenas minimamente testada, nem sequer tentei todos os casos de teste a partir daqui.)
sundar - Reintegrar Monica
@ Sundar Eu pensei sobre essa entrada, mas parecia um pouco "barato" para mim, então fui com a entrada de string. Obrigado pela dica sobre o regex - eu não entendo completamente como ele funciona, então apenas sorrio e aceno quando aparece. Ele Ele.
AdmBorkBork
1

Bash , 114 108 bytes

a=`date +%s -d$1`
while [ "`date +%d+%m+%Y -d@$a|bc|factor|awk NF!=2`" ]
do a=$[a-86400]
done
date +%F -d@$a

Experimente online!

Meu primeiro bash golf. Sinceramente, meu primeiro programa de bash real ... teste de primalidade feito daqui .

Às vezes, isso pode falhar se houver uma alteração de fuso horário, mas o TIO usa o UTC, portanto deve funcionar.

wastl
fonte
O "9" na primeira linha é um erro de digitação? Removendo isso e as aspas (como podemos exigir que a entrada não deva conter espaços) e adicionando um a no final depois @$, fornece código de trabalho em 110 bytes .
sundar - Restabelece Monica
@sundar eu pensei que poderia haver problemas com o horário de verão, mas vou verificar que amanhã novamente
Wastl
1

C (gcc) , 167 bytes

r;P(n,i){for(r=0;++i<n;)r|=n%i<1;}f(y,m,d){for(;P(y+m+d,1),r;)!--d?d=" >8><><>><><>"[!--m?y--,m=12:m]/2+(m==2&!(y%4)&y%100|!(y%400)):0;printf("%04d-%02d-%02d",y,m,d);}

Experimente online!

Atropelar

r;P(n,i){for(r=0;++i<n;)r|=n%i<1;}

A função de verificação anti-prime. Como o primeiro ano válido com o qual precisamos lidar é 0001-01-01, o número mais baixo com o qual precisamos nos preocupar é 3, portanto as verificações de casos especiais para n == 2 ou n <2 são eliminadas. r é definido como um valor verdadeiro se n não for primo. r é mantido global, pois, sem precisar retornar, ele salva dois bytes ( i=n;para retornar vs ,rpara verificar o global). i é definido como 1 pelo chamador da função, para salvar outros 2 bytes.

f(y,m,d){for(;P(y+m+d,1),r;)

Tomamos a data como três números inteiros separados e iniciamos o loop principal, que continua até que y + m + d seja primo. Então chegamos à carne da função:

!--d?                           Decrement day and check if zero, which means we go back to last day of previous month.
d=" >8><><>><><>"               The string contains the number of days of each month times 2, to bring them into printable ASCII range.
                                We begin the string with a space, to avoid having to substract from index later.
[!--m?y--,m=12:m]/2+            Decrement month and check if zero. If so, go back a year and set m to 12. Use m as index in string.
(m==2&!(y%4)&y%100|!(y%400))    If the new month is February, add 1 to day if it's a leap year.
:0;                             Do nothing if day did not become zero.

Pode parecer duvidoso usar m e y tanto na verificação do ano bissexto quanto no índice da sequência, quando a ordem de avaliação não é especificada. Felizmente, só checamos o ano bissexto se m == 2, o que não pode acontecer ao mesmo tempo em que mudamos me, já que isso acontece apenas entre janeiro e dezembro, portanto a verificação do ano bissexto nunca é incomodada pelo ordem de avaliação.

Finalmente, o resultado é impresso em STDOUT:

printf("%04d-%02d-%02d",y,m,d);}
gastropner
fonte
0

C # - 281 239 232 Car

using System;class P{static void Main(){var d=DateTime.Parse(Console.ReadLine());do{int c=d.Year+d.Month+d.Day;if(c%2!=0){int i=3;for(;i<=c;i+=2)if(c%i==0)break;if(i>=c)break;}d=d.AddDays(-1);}while(d>DateTime.MinValue);Console.WriteLine(d);}}

ungolfed:

using System;
class P
{
    static void Main()
    {
        var d = DateTime.Parse(Console.ReadLine());
        do
        {
            int c = d.Year + d.Month + d.Day;
            // minimum datetime in c# is 0001-01-01
            // therefore do not need to check for the first two primes 
            int i = 3;
            for (; i < c; i += 2) if (c % i == 0) break;
            // check to break the date decrement loop if counter passed the input value
            // ie, no factor could be found
            if (i >= c) break;

            d = d.AddDays(-1);
        } while (d > DateTime.MinValue);
        Console.WriteLine(d);
    }
}

Tornou o código menos eficiente, mas menor. O loop primário agora subirá para o número inteiro, em vez da raiz quadrada. Ele também processará todos os números pares.

Kami
fonte
Você provavelmente pode remover public. Além disso, uma vez que não parece ser impedido de obter a entrada de data como um parâmetro de chamada, você poderia ter Main(string[]a)e depoisDateTime.Parse(a[0])
Corak