Prime Time Travel


23

Non dirlo a nessuno, ma ho intaccato la macchina da viaggio nel tempo di mio zio! Mio zio è ossessionato dai numeri primi, e ciò si vede nella macchina - l'ha programmato in modo che possa solo andare a date che si sommano a un numero primo.

Quindi non può andare a 1947-08-15perché 1947 + 8 + 15 = 1970, che non è un numero primo. Si può andare a 1947-07-25, perché 1947 + 7 + 25 = 1979, che è primo. Quindi, se voglio tornare a guardare le celebrazioni per l'indipendenza dell'India, sembra che dovrò andare qualche settimana prima e aspettare quei 20 giorni.

Ho alcune altre date a cui voglio andare e allo stesso modo dovrò andare a una data precedente (o se sono fortunato, uguale a) la mia data target, che si somma a un numero primo. Sono impaziente, però, e non voglio aspettare troppo - quindi voglio trovare la data che posso usare quella più vicina alla mia data target.

Puoi scrivermi un programma che prende la mia data target e mi dà la data che dovrei inserire nella macchina del tempo - la data più vicina prima o uguale alla data indicata le cui parti si sommano a un numero primo?

(Per questa sfida, stiamo usando il proletico calendario gregoriano - il che significa semplicemente che usiamo l'attuale calendario gregoriano anche per i periodi in cui le persone usavano il vecchio calendario giuliano.)

Ingresso

  • Una data
    • idealmente, qualsiasi data nell'era corrente (AD); praticamente, qualunque sottoinsieme di quella lingua può gestire naturalmente
    • in qualsiasi formato leggibile dall'uomo⁺ che ti piace

Produzione

  • La data più vicina alla data di input, che è inferiore o uguale all'input e la cui data + mese + anno si somma a un numero primo.
    • in qualsiasi formato leggibile dall'uomo⁺ che ti piace

⁺: "leggibile dall'uomo" come nel giorno, nel mese e nell'anno tutti indicati separatamente, in qualunque ordine

Casi test

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

(Grazie a @Shaggy, @PeterTaylor e @Arnauld per l'aiuto con la domanda.)


Va bene avere un tempo senza senso nell'output? (ad es. Fri Jul 25 02:46:39 CEST 1947)
wastl,

@wastl Sì, purché le informazioni sulla data siano una sottostringa contigua di lunghezza fissa dell'output (quindi no per quel particolare esempio).
Sundar - Ripristina Monica il

Risposte:


4

Rosso , 87 byte

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]

Provalo online!

Più leggibile:

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
]

4

JavaScript (Node.js) , 94 byte

Accetta input come 3 numeri interi nella sintassi del curry (year)(month)(day). Restituisce una stringa separata da trattino con un trattino iniziale.

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

Provalo online!

Come?

Per prima cosa convertiamo la data nel formato JSON yyyy-mm-ddT00:00:00.000Z( ISO 8601 ), la dividiamo su 'T', manteniamo solo la parte sinistra e aggiungiamo un trattino iniziale, che dà -yyyy-mm-dd.

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

Questa espressione s possono ora essere eval()'uated per ottenere il contrario n della somma di anno + mese + giorno .

n = eval(s)

Usiamo la funzione helper P () per verificare se -n è primo (nel qual caso restituisce 0 ). Se lo è, restituiamo s . Altrimenti, riproviamo con il giorno precedente.

(P = k => n % ++k ? P(k) : ~k)(n) ? g(d - 1) : s

1
Mi sento come se avessi bisogno di un giorno libero solo per capire come funziona e termina quel primo controllo. Buon golf!
Sundar - Ripristina Monica il

3

Python 2 , 130 127 byte

L'input è year, month, day.

-3 byte grazie 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

Provalo online!


Puoi prendere un oggetto data come input, quindi puoi salvare 3 byte .
Kevin Cruijssen,

1
@KevinCruijssen grazie. Pensi che questo sia un formato di input valido?
Ovs,

Non vedo perché non sarebbe, quindi è un altro -4. Non ci avevo pensato.
Kevin Cruijssen,

2

Java 8, 144 128 byte

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

Provalo online.

java.time.LocalDateclass è stato un miglioramento rispetto al vecchio java.util.Date, ma perché hanno dovuto allungare quei nomi ( getMonthValuee getDayOfMonthinvece di getMonthegetDay ) ..>.>

Spiegazione:

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`

2

Rubino , 94 byte

Provalo online!

Accetta un singolo input per la data e restituisce una stringa nel 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?}}

Utilizza il modulo principale di Ruby. Se ciò non è permesso o non è visto di buon occhio, allora per altri due byte vi presento questo abominio:


Rubino , 97 byte

Provalo online!

Usa un controllo per un numero primo di questa risposta di StackOverflow . Non ho idea di come funzioni, sembra un po 'stregoneria. Stesso input come sopra e stesso output.

require'date'
->d{d.downto(0){|i|break i.to_s if ?1*(i.day+i.month+i.year)!~ /^1?$|^(11+?)\1+$/}}

L'uso dei moduli va benissimo purché le righe di importazione siano incluse nel conteggio dei byte (che hai fatto qui). Sembra che tu non abbia bisogno delle parentesi attorno all'iniziale de allo spazio dopo il ifpensiero, quindi puoi radere 3 byte dalla tua prima risposta rimuovendole. Collegamento TIO
Sundar - Ripristina Monica il

3
Mi piace però l'abominio stregato. È abbastanza pulito e semplice una volta esaminato: ?x*n !~ /^x?$|^(xx+?)\1+$/= per verificare se n è primo, crea una stringa di n 'x, controlla che non sia 0 o 1 x (che non sono primi) e che non corrisponde a nessuno 2 o più x si ripetono (la corrispondenza ^(xxxxx)\1+$significherebbe che n è divisibile per 5). Abusa del backtracking del motore regex per fare il nostro looping per noi - è geniale, è mostruoso e probabilmente il sacrificio di animali è stato coinvolto nella sua scoperta.
Sundar - Ripristina Monica il

Buon posto tra parentesi e spazio! Grazie.
IMP1

La versione "stregoneria" può essere eseguita in 92 byte, vedi qui . Poiché la somma che vogliamo verificare per primalità è almeno 3 (poiché la data minima 0001-01-01 è pari a 1 + 1 + 1 = 3), possiamo rimuovere la parte del regex che è specificamente per gestire l'input essendo 0 o 1. Rimuovendolo e semplificandolo si ottiene una versione a 91 byte.
Sundar - Ripristina Monica il

Un approccio interessante Salva 2 byte utilizzando 'mon' invece di 'mese'
GB

2

Rubino , 57 53 byte

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

Provalo online!

Non è una mia idea - rubata dall'abominio di IMP1


Idea originale:

Rubino , 59 byte

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

Provalo online!


1
Usando 8e4invece funzionerebbe?
Kritixi Lithos,

Sì, certo che funziona. Funziona anche usando 9 o qualsiasi altro numero più piccolo. Ci vuole solo molto più tempo per correre. Grazie.
GB

2

R , 117 byte

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

Provalo online!


2

F #, 134 133 byte

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 grazie a da Sundar .

Provalo online!

Totale il giorno, il mese e l'anno e vedere se è primo. In tal caso, restituire quella data. In caso contrario, decrementa la data di 1 giorno e riprova.


1
È possibile salvare un byte scrivendo -1.0come -1., nella chiamata AddDays.
Sundar - Ripristina Monica il

Hai ragione ... è davvero strano. Ma utile. Grazie.
Ciaran_McCarthy,

1

PowerShell , 105 90 byte

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

Provalo online!

Grazie a Sundar per -13 byte.

Prende l'input come a DateTime 2018-06-20e lo salva in $a. Quindi siamo in forloop. Ad ogni iterazione, stiamo prendendo o $a -fmatte come yyyy+MM+dd(ovvero, la data corrente in cui siamo separati da+ segni) aggiunti insieme a |iex(simile a eval), moltiplicando la stringa con 1s per formare un numero unario e usando una regex a controllo primo per determinare se la data corrente è prima o meno. Se non è primo, dobbiamo .AddDays(-1)tornare indietro di un giorno e continuare il ciclo. Se è primo, usciremo dal circuito e ci posizioneremo$a sulla pipeline con output implicito.

L'output risultante dipende dalla cultura. Su TIO, che utilizza en-us, l'output è in formato long-date, che sembra Saturday, July 1, 1319 12:00:00 AM.


È possibile salvare alcuni byte inviando l'argomento come oggetto datetime. Inoltre, il regex può essere semplificato per abbinare i compositi sopra 2 (poiché la data minima è la 0001-01-01cui somma è 3). Ho preso una crepa a questi cambiamenti qui .
Sundar - Ripristina Monica il

(nota che sono un principiante di PowerShell e che il codice collegato è solo minimamente testato, non ho nemmeno provato tutti i casi di test da qui.)
Sundar - Ripristina Monica il

@sundar Ho pensato a quell'input, ma mi è sembrato un po '"economico", quindi sono andato invece con l'input della stringa. Grazie per il suggerimento su regex: non capisco bene come funziona, quindi sorrido e annuisco appena si presenta. Hehe.
AdmBorkBork,

1

Bash , 114 108 byte

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

Provalo online!

Il mio primo golf bash in assoluto. Onestamente, il mio primo vero programma bash di sempre ... test di primalità preso da qui .

A volte ciò potrebbe non riuscire se si verifica una modifica del fuso orario, ma TIO utilizza UTC, quindi dovrebbe funzionare.


Il "9" nella prima riga è un refuso? Rimuovendo questo e le virgolette attorno ad esso (dal momento che possiamo richiedere che l'input non debba contenere spazi) e l'aggiunta di una a alla fine @$, si ottiene un codice funzionante a 110 byte .
Sundar - Ripristina Monica il

@sundar Ho pensato che potrebbero esserci problemi con l'ora legale, ma lo controllerò di nuovo domani
wastl

1

C (gcc) , 167 byte

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

Provalo online!

Corri giù

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

La funzione di controllo anti-prime. Dal momento che il primo anno valido di cui dobbiamo occuparci è 0001-01-01, il numero più basso di cui dobbiamo mai preoccuparci è 3, quindi i controlli dei casi speciali per n == 2 o n <2 vengono eliminati. r è impostato su un valore di verità se n non è un numero primo. r viene mantenuto globale, poiché non è necessario restituirlo, salva due byte ( i=n;per restituire vs ,rper controllare il globale). i è impostato su 1 dal chiamante della funzione, per salvare altri 2 byte.

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

Prendiamo la data come tre numeri interi separati e iniziamo il ciclo principale, che continua fino a quando y + m + d è primo. Quindi arriviamo alla carne della funzione:

!--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.

Potrebbe sembrare incerto usare mey sia nel controllo dell'anno bisestile sia come indice della stringa, quando l'ordine di valutazione non è specificato. Fortunatamente, controlliamo per l'anno bisestile solo se m == 2, che non può avvenire contemporaneamente alla modifica di me, poiché ciò avviene solo da gennaio a dicembre, quindi il controllo dell'anno bisestile non è mai disturbato dal ordine di valutazione.

Infine, il risultato viene stampato su STDOUT:

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

0

C # - 281 239 232 Char

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

Ha reso il codice meno efficiente ma più piccolo. Il ciclo principale ora passa all'intero anziché alla radice quadrata. Elaborerà anche tutti i numeri pari.


Probabilmente puoi rimuoverlo public. Inoltre, poiché non sembra essere vietato ottenere l'input della data come parametro chiamante, potresti avere Main(string[]a)e quindiDateTime.Parse(a[0])
Corak,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.