Prime Time Reisen

23

Sag es niemandem, aber ich habe die Zeitreisemaschine meines Onkels geklaut! Mein Onkel ist jedoch von Primzahlen besessen, und das zeigt sich in der Maschine - er hat sie so programmiert, dass sie nur Daten enthält, die eine Primzahl ergeben.

Es kann also nicht nach 1947-08-151947 + 8 + 15 = 1970 gehen, was keine Primzahl ist. Es kann gehen 1947-07-25, weil 1947 + 7 + 25 = 1979, das ist prime. Wenn ich mir also Indiens Unabhängigkeitsfeier ansehen möchte, muss ich wohl ein paar Wochen früher gehen und diese 20 Tage abwarten.

Ich habe einige andere Daten, zu denen ich gehen möchte, und ich muss ebenfalls zu einem Datum gehen, das vor meinem Zieldatum liegt (oder, wenn ich Glück habe, gleich meinem Zieldatum ist) und eine Primzahl ergibt. Ich bin jedoch ungeduldig und möchte nicht zu lange warten. Deshalb möchte ich das Datum finden, das meinem Zieldatum am nächsten kommt.

Können Sie mir ein Programm schreiben, das mein Zieldatum und das Datum angibt, das ich in die Zeitmaschine eingeben soll - das nächstliegende Datum vor oder gleich dem angegebenen Datum, dessen Teile sich zu einer Primzahl addieren?

(Für diese Herausforderung verwenden wir den proleptischen Gregorianischen Kalender - was einfach bedeutet, dass wir den aktuellen Gregorianischen Kalender auch für Zeiträume verwenden, in denen Menschen den älteren Julianischen Kalender verwendeten.)

Eingang

  • Ein Treffen
    • im Idealfall jedes Datum in der aktuellen Ära (AD); praktisch kann jede Untergruppe Ihrer Sprache auf natürliche Weise damit umgehen
    • in jedem von Menschen lesbaren Format, das Sie mögen

Ausgabe

  • Das Datum, das dem Eingabedatum am nächsten liegt und kleiner oder gleich dem Eingabedatum ist und dessen Datum + Monat + Jahr eine Primzahl ergibt.
    • in jedem von Menschen lesbaren Format, das Sie mögen

⁺: "vom Menschen lesbar", wie in Tag, Monat und Jahr, alle getrennt, in welcher Reihenfolge auch immer

Testfälle

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

(Danke an @Shaggy, @PeterTaylor und @Arnauld für die Hilfe bei der Frage.)

Sundar - Setzen Sie Monica wieder ein
quelle
Ist es in Ordnung, eine Unsinnszeit in der Ausgabe zu haben? (zB Fri Jul 25 02:46:39 CEST 1947)
Wastl
@wastl Ja, solange die Datumsinformation eine zusammenhängende Unterzeichenfolge mit fester Länge der Ausgabe ist (also nein für dieses bestimmte Beispiel).
Sundar - Wiedereinsetzung von Monica

Antworten:

4

Rot , 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]

Probieren Sie es online!

Besser lesbar:

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

JavaScript (Node.js) , 94 Byte

Nimmt die Eingabe als 3 Ganzzahlen in die aktuelle Syntax auf (year)(month)(day). Gibt eine durch Bindestriche getrennte Zeichenfolge mit einem führenden Bindestrich zurück.

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

Probieren Sie es online!

Wie?

Wir konvertieren zuerst das Datum in das JSON-Format yyyy-mm-ddT00:00:00.000Z( ISO 8601 ), teilen es auf 'T', behalten nur den linken Teil bei und fügen einen führenden Bindestrich hinzu, der ergibt -yyyy-mm-dd.

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

Dieser Ausdruck s kann nun eval()‚uated das Gegenteil zu bekommen n der Summe von Jahr + Monat + Tag .

n = eval(s)

Wir verwenden die Hilfsfunktion P () , um zu testen, ob -n eine Primzahl ist (in diesem Fall wird 0 zurückgegeben ). Wenn es so ist, geben wir s zurück . Ansonsten versuchen wir es nochmal mit dem Vortag.

(P = k => n % ++k ? P(k) : ~k)(n) ? g(d - 1) : s
Arnauld
quelle
1
Ich habe das Gefühl, ich brauche einen freien Tag, nur weil ich nicht verstehe, wie dieser Prime Check funktioniert und endet. Gutes Golfen!
Sundar - Wiedereinsetzung von Monica
3

Python 2 , 130 127 Bytes

Eingabe ist year, month, day.

-3 Bytes dank 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

Probieren Sie es online!

ovs
quelle
Sie können ein Datumsobjekt als Eingabe verwenden, um 3 Bytes zu sparen .
Kevin Cruijssen
1
@ KevinCruijssen danke. Denken Sie, dass dies ein gültiges Eingabeformat ist?
Ovs
Ich verstehe nicht, warum es nicht so wäre. Hatte nicht darüber nachgedacht.
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;}}

Probieren Sie es online aus.

java.time.LocalDateKlasse war eine Verbesserung im Vergleich zu den alten java.util.Date, aber warum mussten sie diese Namen länger machen ( getMonthValueund getDayOfMonthanstelle von getMonthund getDay) ..>.>

Erläuterung:

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
quelle
2

Ruby , 94 Bytes

Probieren Sie es online!

Nimmt eine einzelne Datumseingabe entgegen und gibt eine Zeichenfolge im ISO 8601-Format zurück ( YYYY-MM-DD).

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

Es verwendet Rubys Hauptmodul. Wenn das nicht erlaubt oder verpönt ist, dann stelle ich für zwei Bytes mehr diesen Gräuel vor:


Ruby , 97 Bytes

Probieren Sie es online!

Aus dieser Stapelüberlaufantwort wird geprüft, ob eine Zahl Primzahlen enthält . Ich habe keine Ahnung, wie das funktioniert, es sieht ein bisschen wie Hexerei aus. Gleiche Eingabe wie oben und gleiche Ausgabe.

require'date'
->d{d.downto(0){|i|break i.to_s if ?1*(i.day+i.month+i.year)!~ /^1?$|^(11+?)\1+$/}}
IMP1
quelle
Die Verwendung von Modulen ist vollkommen in Ordnung, solange die Importzeilen in der Anzahl der Bytes enthalten sind (was Sie hier getan haben). Anscheinend brauchen Sie die Klammern um die Initiale dund das Leerzeichen nach dem Gedanken nicht if, also können Sie 3 Bytes von Ihrer ersten Antwort entfernen, indem Sie diese entfernen. TIO Link
Sundar - Wiedereinsetzung von Monica
3
Ich mag die Hexerei Abscheulichkeit. Es ist ziemlich ordentlich und einfach, wenn Sie es sich ansehen: ?x*n !~ /^x?$|^(xx+?)\1+$/= Um zu überprüfen, ob n Primzahl ist, erstellen Sie eine Folge von n 'x' s, stellen Sie sicher, dass es nicht 0 oder 1 x 's (die keine Primzahl sind) sind und dass es mit keinem übereinstimmt 2 oder mehr x wiederholen sich (Matching ^(xxxxx)\1+$würde bedeuten, dass n durch 5 teilbar ist). Es missbraucht das Backtracking der Regex-Engine, um unsere Loopings für uns durchzuführen - es ist brillant, monströs und wahrscheinlich war Tieropfer an ihrer Entdeckung beteiligt.
Sundar - Wiedereinsetzung von Monica
Guter Ort über die Klammern und den Raum! Vielen Dank.
IMP1
Die "Hexerei" -Version kann in 92 Bytes erstellt werden, siehe hier . Da die Summe, die auf Primalität geprüft werden soll, mindestens 3 beträgt (da das Mindestdatum 0001-01-01 1 + 1 + 1 = 3 ergibt), können wir den Teil des regulären Ausdrucks entfernen, der speziell für die Eingabe 0 oder 0 vorgesehen ist 1. Wenn Sie das entfernen und vereinfachen, erhalten Sie eine 91-Byte-Version.
Sundar - Wiedereinsetzung von Monica
Ein interessanter Ansatz. Speichern Sie 2 Bytes, indem Sie 'mon' anstelle von 'month' verwenden
GB
2

Ruby , 57 53 Bytes

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

Probieren Sie es online!

Nicht meine Idee - von IMP1 aus dem "Greuel" gestohlen


Originale Idee:

Ruby , 59 Bytes

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

Probieren Sie es online!

GB
quelle
1
Würde die Verwendung 8e4stattdessen funktionieren?
Kritixi Lithos
Ja, natürlich funktioniert es. Es funktioniert auch mit 9 oder einer anderen kleineren Zahl. Es dauert nur viel länger zu laufen. Vielen Dank.
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")))

Probieren Sie es online!

ngm
quelle
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 dank von sundar .

Probieren Sie es online!

Zählen Sie Tag, Monat und Jahr zusammen und prüfen Sie, ob es optimal ist. Wenn dies der Fall ist, geben Sie das Datum zurück. Wenn nicht, verringern Sie das Datum um 1 Tag und versuchen Sie es erneut.

Ciaran_McCarthy
quelle
1
Sie können ein Byte speichern, indem Sie im AddDays-Aufruf -1.0als -1.schreiben.
Sundar - Wiedereinsetzung von Monica
Du hast recht ... das ist wirklich komisch. Aber nützlich. Vielen Dank.
Ciaran_McCarthy
1

PowerShell , 105 bis 90 Byte

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

Probieren Sie es online!

Dank Sundar für -13 Bytes.

Nimmt Eingaben als ein DateTime 2018-06-20und speichert sie in $a. Dann sind wir in einer forSchleife. Jede Iteration, sind gehen wir $a -fwie ormatted yyyy+MM+dd(durch das heißt, das aktuelle Datum , wir sind getrennt auf +Zeichen) hinzugefügt zusammen mit |iex(ähnlich eval), String-Multiplikation , dass mit 1s zur Bildung einer unären Zahl und unter Verwendung eines Prime-Überprüfung regex um festzustellen, ob das aktuelle Datum prim ist oder nicht. Wenn es keine Primzahl ist .AddDays(-1), gehen wir einen Tag zurück und setzen die Schleife fort. Wenn es eine Primzahl ist, brechen wir aus der Schleife aus und platzieren es $amit impliziter Ausgabe auf der Pipeline.

Die resultierende Ausgabe ist kulturabhängig. Bei TIO, das verwendet wird en-us, ist die Ausgabe im Langzeitformat, wie es aussieht Saturday, July 1, 1319 12:00:00 AM.

AdmBorkBork
quelle
Sie können einige Bytes sparen, indem Sie das Argument als datetime-Objekt senden. Der reguläre Ausdruck kann auch vereinfacht werden, um Verbundwerkstoffe über 2 abzugleichen (da das Mindestdatum 0001-01-01dessen Summe 3 ist). Ich habe mir diese Änderungen hier angesehen .
Sundar - Reinstate Monica
(Beachten Sie jedoch, dass ich ein PowerShell-Neuling bin und der verknüpfte Code nur minimal getestet wurde. Ich habe noch nicht einmal alle Testfälle von hier aus ausprobiert.)
Sundar - Setzen Sie Monica am
@sundar Ich habe über diese Eingabe nachgedacht, aber sie schien mir ein wenig "betrügerisch" zu sein, also habe ich mich stattdessen für die Eingabe von Zeichenfolgen entschieden. Vielen Dank für den Regex-Tipp - ich verstehe nicht ganz, wie es funktioniert, also lächle ich nur und nicke, wenn es auftaucht. Hehe
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

Probieren Sie es online!

Mein erstes Schlaggolf. Ehrlich gesagt, mein erstes richtiges Bash-Programm überhaupt ... von hier aus wurde ein Primalitätstest durchgeführt .

Dies kann manchmal fehlschlagen, wenn sich die Zeitzone ändert, TIO jedoch UTC verwendet. Daher sollte dies funktionieren.

wastl
quelle
Ist die "9" in der ersten Zeile ein Tippfehler? Wenn Sie dies und die Anführungszeichen entfernen (da die Eingabe keine Leerzeichen enthalten darf) und am Ende danach ein a hinzufügen, erhalten Sie einen @$Arbeitscode von 110 Byte .
Sundar - Reinstate Monica
@sundar Ich dachte, dass es Probleme mit der Sommerzeit geben könnte, aber ich werde das morgen noch einmal überprüfen
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);}

Probieren Sie es online!

Heruntergewirtschaftet

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

Die Anti-Prime-Check-Funktion. Da das früheste gültige Jahr, mit dem wir uns befassen müssen, 0001-01-01 ist, ist die niedrigste Zahl, um die wir uns jemals Sorgen machen müssen, 3, sodass die Sonderfallprüfungen für n == 2 oder n <2 gestrippt werden. r wird auf einen Wahrheitswert gesetzt, wenn n keine Primzahl ist. r wird global gehalten, da es, wenn es nicht zurückgegeben werden muss, zwei Bytes spart ( i=n;um zurückzugeben, vs ,r, um das globale zu überprüfen). i wird vom Funktionsaufrufer auf 1 gesetzt, um weitere 2 Bytes zu speichern.

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

Wir nehmen das Datum als drei separate Ganzzahlen und starten die Hauptschleife, die so lange dauert, bis y + m + d die Primzahl ist. Dann kommen wir zum Fleisch der Funktion:

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

Es mag zweifelhaft erscheinen, m und y sowohl in der Schaltjahrprüfung als auch als Index des Strings zu verwenden, wenn die Auswertungsreihenfolge nicht angegeben ist. Zum Glück überprüfen wir nur das Schaltjahr, wenn m == 2, was nicht gleichzeitig mit der Änderung von m und y geschehen kann, da dies nur von Januar bis Dezember geschieht, so dass die Schaltjahrüberprüfung niemals von der Störung betroffen ist Reihenfolge der Bewertung.

Schließlich wird das Ergebnis an STDOUT ausgegeben:

printf("%04d-%02d-%02d",y,m,d);}
Gastropner
quelle
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);
    }
}

Der Code wurde weniger effizient, aber kleiner. Die Prime-Schleife steigt jetzt auf die ganze Zahl und nicht auf die Quadratwurzel. Es werden auch alle geraden Zahlen verarbeitet.

Kami
quelle
Sie können wahrscheinlich entfernen public. Da es nicht unzulässig zu sein scheint, das Datum als aufrufenden Parameter einzugeben, könnten Sie auch haben Main(string[]a)und dannDateTime.Parse(a[0])
Corak