Prime Time Travel


23

Nikomu nie mów, ale naciągnąłem maszynę podróży w czasie mojego wuja! Mój wujek ma jednak obsesję na punkcie liczb pierwszych, co widać na maszynie - zaprogramował ją tak, aby mogła przechodzić tylko do dat, które sumują się do liczby pierwszej.

Tak więc nie można tego zrobić, 1947-08-15ponieważ 1947 + 8 + 15 = 1970, co nie jest liczbą pierwszą. To może iść do 1947-07-25, bo 1947 + 7 + 25 = 1979, co jest pierwsze. Więc jeśli chcę wrócić, by obejrzeć uroczystości niepodległości Indii, wygląda na to, że będę musiał pójść kilka tygodni wcześniej i czekać 20 dni.

Mam inne daty, na które chcę iść, i podobnie muszę iść na randkę przed (lub, jeśli mam szczęście, równą) mojej docelowej dacie, co sumuje się do liczby pierwszej. Jestem jednak niecierpliwy i nie chcę zbyt długo czekać - chcę więc znaleźć datę, której mogę użyć, najbliższą mojej docelowej dacie.

Czy możesz napisać mi program, który przyjmuje moją datę docelową i podaje datę, którą powinienem wprowadzić do wehikułu czasu - najbliższą datę przed lub równą podanej dacie, której części składają się na liczbę pierwszą?

(Do tego wyzwania używamy proleptycznego kalendarza gregoriańskiego - co oznacza po prostu, że używamy bieżącego kalendarza gregoriańskiego nawet w okresach, gdy ludzie używali wtedy starszego kalendarza juliańskiego.)

Wkład

  • Randka
    • idealnie, każda data w obecnej erze (AD); praktycznie każdy podzbiór tego języka może naturalnie sobie poradzić
    • w dowolnym formacie czytelnym dla człowieka like lubisz

Wydajność

  • Data najbliższa wejściu, która jest mniejsza lub równa wprowadzeniu i której data + miesiąc + rok sumuje się do liczby pierwszej.
    • w dowolnym formacie czytelnym dla człowieka like lubisz

⁺: „czytelny dla człowieka” jak w dniu, miesiącu i roku, wszystkie oddzielnie, w dowolnej kolejności

Przypadki testowe

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

(Podziękowania dla @Shaggy, @PeterTaylor i @Arnauld za pomoc przy pytaniu.)


Czy to jest w porządku mieć nonsensowny czas na wyjściu? (np. Fri Jul 25 02:46:39 CEST 1947)
odpadł

@wastl Tak, o ile informacja o dacie jest ciągłym podciągiem o stałej długości wyniku (więc nie dla tego konkretnego przykładu).
sundar - Przywróć Monikę

Odpowiedzi:


4

Czerwony , 87 bajtów

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]

Wypróbuj online!

Bardziej czytelny:

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 bajty

Pobiera dane wejściowe jako 3 liczby całkowite w składni curry (year)(month)(day). Zwraca ciąg rozdzielany łącznikiem z wiodącym łącznikiem.

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

Wypróbuj online!

W jaki sposób?

Najpierw konwertujemy datę do formatu JSON yyyy-mm-ddT00:00:00.000Z( ISO 8601 ), dzielimy na 'T', zachowujemy tylko lewą część i dodajemy wiodący łącznik, co daje -yyyy-mm-dd.

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

To wyrażenie s można teraz eval()„uated dostać przeciwnego n sumy lat + miesiąc + dzień .

n = eval(s)

Używamy funkcji pomocniczej P (), aby sprawdzić, czy -n jest liczbą pierwszą (w którym to przypadku zwraca 0 ). Jeśli tak, zwracamy s . W przeciwnym razie próbujemy ponownie z poprzedniego dnia.

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

1
Wydaje mi się, że potrzebuję dnia wolnego od samego zrozumienia, jak działa ta kontrola wstępna i jak się kończy. Dobra gra w golfa!
sundar - Przywróć Monikę

3

Python 2 , 130 127 bajtów

Dane wejściowe to year, month, day.

-3 bajty dzięki 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

Wypróbuj online!


Możesz wziąć obiekt daty jako dane wejściowe, dzięki czemu możesz zapisać 3 bajty .
Kevin Cruijssen

1
@KevinCruijssen dziękuję. Czy uważasz, że to jest poprawny format wejściowy?
ovs

Nie rozumiem, dlaczego tak nie byłoby, więc to kolejne -4. Nie myślałem o tym.
Kevin Cruijssen

2

Java 8, 144 128 bajtów

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

Wypróbuj online.

java.time.LocalDateklasa poprawiła się w porównaniu do starej java.util.Date, ale dlaczego musieli wydłużyć te nazwy ( getMonthValuei getDayOfMonthzamiast getMonthi getDay) ..>.>

Wyjaśnienie:

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

Ruby , 94 bajty

Wypróbuj online!

Pobiera dane wejściowe z pojedynczą datą i zwraca ciąg znaków w formacie 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?}}

Wykorzystuje główny moduł Ruby. Jeśli nie jest to dozwolone, lub marszczy brwi, to przez dwa kolejne bajty przedstawiam tę obrzydliwość:


Ruby , 97 bajtów

Wypróbuj online!

Wykorzystuje sprawdzanie, czy liczba jest liczbą pierwszą z tej odpowiedzi przepełnienia stosu . Nie mam pojęcia, jak to działa, wygląda trochę jak czary. Takie same dane wejściowe jak powyżej i takie same dane wyjściowe.

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

Korzystanie z modułów jest w porządku, o ile wiersze importu są uwzględnione w liczbie bajtów (co zrobiono tutaj). Wygląda na to, że nie potrzebujesz nawiasów wokół inicjału di spacji po nim if, więc możesz ogolić 3 bajty z pierwszej odpowiedzi, usuwając je. Link do TIO
zegar słoneczny - Przywróć Monikę

3
Jednak podoba mi się wstrętna wiedźma. Kiedy się w to spojrzy, jest całkiem fajnie: ?x*n !~ /^x?$|^(xx+?)\1+$/= aby sprawdzić, czy n jest liczbą pierwszą, utwórz ciąg n 'x, sprawdź, czy nie jest to 0 lub 1 x (które nie są liczbami pierwszymi) i czy nie pasuje do żadnego 2 lub więcej x się powtarza (dopasowanie ^(xxxxx)\1+$oznacza, że ​​n można podzielić przez 5). Nadużywa cofania się silnika regex, aby wykonać dla nas pętlę - jest genialny, monstrualny, a ofiara zwierząt prawdopodobnie była zaangażowana w jego odkrycie.
sundar - Przywróć Monikę

Dobre miejsce na nawiasy i przestrzeń! Dzięki.
IMP1

Wersję „czarów” można wykonać w 92 bajtach, patrz tutaj . Ponieważ suma, którą chcemy sprawdzić pod kątem pierwszeństwa, wynosi co najmniej 3 (ponieważ minimalna data 0001-01-01 sumuje się do 1 + 1 + 1 = 3), możemy usunąć część wyrażenia regularnego, która konkretnie obsługuje dane wejściowe równe 0 lub 1. Usunięcie tego i uproszczenie daje wersję 91-bajtową.
sundar - Przywróć Monikę

Ciekawe podejście. Zaoszczędź 2 bajty, używając „mon” zamiast „miesiąc”
GB

2

Ruby , 57 53 bajtów

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

Wypróbuj online!

Nie mój pomysł - skradziony z „obrzydliwości” przez IMP1


Oryginalny pomysł:

Ruby , 59 bajtów

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

Wypróbuj online!


1
Czy 8e4zamiast tego działałoby?
Kritixi Lithos

Tak, oczywiście, że działa. Działa również przy użyciu 9 lub dowolnej innej mniejszej liczby. Uruchomienie zajmuje tylko dużo dłużej. Dzięki.
GB

2

R , 117 bajtów

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

Wypróbuj online!


2

F #, 134 133 bajtów

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 bajt dzięki sundar .

Wypróbuj online!

Zsumuj dzień, miesiąc i rok i sprawdź, czy jest to liczba pierwsza. Jeśli tak, zwróć tę datę. Jeśli nie, zmniejsz datę o 1 dzień i spróbuj ponownie.


1
Możesz zapisać bajt pisząc -1.0jako -1.w wywołaniu AddDays.
Sundar - Przywróć Monikę

Masz rację ... to naprawdę dziwne. Ale przydatne. Dzięki.
Ciaran_McCarthy

1

PowerShell , 105 90 bajtów

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

Wypróbuj online!

Dzięki sundar za -13 bajtów.

Pobiera dane wejściowe jako a DateTime 2018-06-20i zapisuje je $a. Więc jesteśmy w forpętli. Każdej iteracji bierzemy $a -formatowane jak yyyy+MM+dd(tj. Bieżącą datę oddzieloną +znakami) dodawane razem z |iex(podobnie jakeval ), mnożąc ciąg znaków przez 1s, aby utworzyć liczbę jednoznaczną, i używając wyrażenia regularnego sprawdzającego liczbę pierwszą aby ustalić, czy bieżąca data jest liczbą pierwszą, czy nie. Jeśli nie jest to liczba pierwsza, musimy .AddDays(-1)cofnąć się o dzień i kontynuować pętlę. Jeśli jest to liczba pierwsza, wyrywamy się z pętli i umieszczamy $ana rurociągu z niejawnym wyjściem.

Wynikowy wynik zależy od kultury. W TIO, który korzysta en-us, dane wyjściowe mają format długiej daty, który wygląda Saturday, July 1, 1319 12:00:00 AM.


Możesz zapisać kilka bajtów, wysyłając argument jako obiekt daty i godziny. Również wyrażenie regularne można uprościć, aby dopasować kompozyty powyżej 2 (ponieważ minimalna data to 0001-01-01suma 3). Zaskoczyłem te zmiany tutaj .
sundar - Przywróć Monikę

(zauważ jednak, że jestem nowicjuszem PowerShell i że linkowany kod jest tylko minimalnie testowany, nawet nie wypróbowałem wszystkich przypadków testowych stąd).
Sundar - Przywróć Monikę

@sundar Myślałem o tym wejściu, ale wydawało mi się to trochę „oszukiwane”, więc zamiast tego wybrałem ciąg znaków. Dziękuję za wskazówkę dotyczącą wyrażenia regularnego - nie do końca rozumiem, jak to działa, więc po prostu się uśmiecham i kiwam głową, gdy się pojawia. Hehe
AdmBorkBork,

1

Bash , 114 108 bajtów

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

Wypróbuj online!

Mój pierwszy w historii golf. Szczerze mówiąc, mój pierwszy prawdziwy program bash w historii ... wzięty z testu pierwotności stąd .

Czasami może się to nie powieść, jeśli nastąpi zmiana strefy czasowej, ale TIO używa UTC, więc powinno działać.


Czy „9” w pierwszym wierszu to literówka? Usunięcie tego i cudzysłowów wokół niego (ponieważ możemy wymagać, aby dane wejściowe nie zawierały spacji), i dodanie a na końcu po @$, daje kod roboczy o wielkości 110 bajtów .
sundar - Przywróć Monikę

@sundar Myślałem, że mogą występować problemy z czasem letnim, ale sprawdzę to jutro
marn

1

C (gcc) , 167 bajtów

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

Wypróbuj online!

Zniszczony

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

Funkcja kontroli zalewania. Ponieważ najwcześniejszy ważny rok, z którym musimy się zmierzyć, to 0001-01-01, najniższa liczba, o którą musimy się martwić, to 3, więc kontrole przypadków specjalnych dla n == 2 lub n <2 są usuwane. r jest ustawione na prawdę, jeśli n nie jest liczbą pierwszą. r jest zachowywany globalnie, ponieważ bez konieczności zwracania zapisuje dwa bajty ( i=n;powrót ,rdo sprawdzenia globalnego). i jest ustawiane na 1 przez funkcję wywołującą, aby zapisać kolejne 2 bajty.

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

Przyjmujemy datę jako trzy oddzielne liczby całkowite i rozpoczynamy główną pętlę, która trwa, aż y + m + d będzie liczbą pierwszą. Następnie dochodzimy do sedna funkcji:

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

Może wydawać się niewygodne użycie miy zarówno podczas sprawdzania roku przestępnego, jak i jako indeksu ciągu, gdy kolejność oceny nie jest określona. Na szczęście sprawdzamy, czy rok przestępny jest sprawdzany tylko wtedy, gdy m == 2, co nie może się zdarzyć w tym samym czasie, kiedy zmieniamy m i y, ponieważ dzieje się tak tylko od stycznia do grudnia, więc sprawdzenie roku przestępnego nigdy nie przeszkadza kolejność oceny.

Na koniec wynik jest drukowany do 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);}}

bez golfa:

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

Sprawił, że kod był mniej wydajny, ale mniejszy. Pętla Prime przejdzie teraz do liczby całkowitej zamiast pierwiastka kwadratowego. Przetwarza również wszystkie liczby parzyste.


Prawdopodobnie możesz to usunąć public. Ponadto, ponieważ wydaje się, że wprowadzanie daty jako parametru wywołującego nie jest niedozwolone, możesz mieć, Main(string[]a)a następnieDateTime.Parse(a[0])
Corak

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.