Prime Time Seyahat


23

Kimseye söyleme, ama amcamın zaman yolculuğu makinesini çaldım! Amcam, asal sayılara takıntılı, ve makinede de gösteriyor - o sadece asal bir sayıya ulaşan tarihlere gidebilmesi için programladı.

Öyleyse gidemez 1947-08-15çünkü 1947 + 8 + 15 = 1970, ki bu bir asal sayı değil. Bu , gidebilir 1947-07-25çünkü 1947 + 7 + 25 = 1979, ki bu asal olan. Yani Hindistan'ın bağımsızlık kutlamalarını izlemeye geri dönmek istersem, birkaç hafta önce gidip 20 gün beklemem gerekecek gibi görünüyor.

Gitmek istediğim bazı başka tarihlerim var ve benzer bir şekilde hedef tarihimden önce (ya da şanslıysam) bir tarihe gitmeliyim, ki bu asal bir sayıya denk geliyor. Yine de sabırsızım ve çok fazla beklemek istemiyorum - bu yüzden kullanabileceğim tarihi hedef tarihime en yakın olanı bulmak istiyorum.

Bana hedef tarihimi alan ve bana zaman makinesine girmem gereken tarihi veren bir program yazabilir misiniz - parçaları asal sayıya ekleyen belirtilen tarihe eşit veya en yakın tarih?

(Bu zorluk için, proleptik Gregoryen takvimini kullanıyoruz - bu sadece insanların eski Julian takvimini kullandığı dönemlerde bile geçerli Gregoryen takvimini kullandığımız anlamına gelir.)

Giriş

  • Buluşma
    • ideal olarak, Cari Dönemde (AD) herhangi bir tarih; pratik olarak, dilinizin hangi alt kümesi olursa olsun, doğal olarak
    • İstediğiniz insanca okunabilir herhangi bir biçimde

Çıktı

  • Giriş tarihine en yakın tarih, girişe eşit veya daha küçük olan ve tarih + ay + yıl bir asal sayıya karşılık gelen tarih.
    • İstediğiniz insanca okunabilir herhangi bir biçimde

⁺: "insan tarafından okunabilir" gün, ay ve yıldaki gibi

Test durumları

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

(Soruyla ilgili yardım için @Shaggy, @PeterTaylor ve @Arnauld'a teşekkürler.)


Çıktıda saçma bir zaman geçirmek sorun olur mu? (örn. Fri Jul 25 02:46:39 CEST 1947)
israf

@wastl Evet, tarih bilgisi çıktının bitişik sabit uzunlukta bir alt dizisi olduğu sürece (bu özel örnek için hayır).
sundar - Monica

Yanıtlar:


4

Kırmızı , 87 bayt

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]

Çevrimiçi deneyin!

Daha okunabilir:

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 bayt

Körleme sözdiziminde girişi 3 tam sayı olarak alır (year)(month)(day). Önde gelen tireli tireyle ayrılmış bir dize döndürür.

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

Çevrimiçi deneyin!

Nasıl?

Öncelikle tarihi JSON formatına dönüştürüyoruz yyyy-mm-ddT00:00:00.000Z( ISO 8601 ), bölüştürüyoruz 'T', sadece soldaki kısmı tutuyor ve veren bir tire işareti ekliyoruz -yyyy-mm-dd.

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

Bu ifade ler şimdi edilebilir eval()'tersini almak için yönlerinden değerlendirmeler yapılmıştır n toplamının yıl + ay + gün .

n = eval(s)

-N asal olup olmadığını test etmek için P () yardımcı fonksiyonunu kullanırız (bu durumda 0 döndürür ). Öyleyse, biz s döneriz . Aksi takdirde önceki gün tekrar deneriz.

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

1
Asıl kontrolün nasıl çalıştığını ve sonlandırdığını anlamaktan bir gün izin aldığımı hissediyorum. İyi golf!
sundar - Monica

3

Python 2 , 130 127 bayt

Girdi olduğunu year, month, day.

Kevin Cruijssen sayesinde -3 bayt .

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

Çevrimiçi deneyin!


Bir tarih nesnesini girdi olarak alma izniniz vardır, böylece 3 bayt kaydedebilirsiniz .
Kevin Cruijssen

1
@KevinCruijssen teşekkür ederim. Sizce bu geçerli bir giriş biçimidir?
ovs

Neden olmayacağını anlamıyorum, bu yüzden başka -4. Bunun hakkında düşünmemiştim.
Kevin Cruijssen

2

Java 8, 144 128 bayt

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

Çevrimiçi deneyin.

java.time.LocalDatesınıf eskiye kıyasla bir iyileşme olmuştur java.util.Date, ama bunu neden daha uzun bu isimleri yapmak zorunda ( getMonthValueve getDayOfMonthyerine getMonthve getDay) ..>.>

Açıklama:

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 bayt

Çevrimiçi deneyin!

Tek bir Tarih girişini alır ve ISO 8601 biçiminde ( YYYY-MM-DD) bir dize döndürür .

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

Ruby'nin ana modülünü kullanır. Buna izin verilmez veya kaşlarını çatmazsa, iki byte daha fazla için bu uyuşmazlığı sunarım:


Ruby , 97 bayt

Çevrimiçi deneyin!

Bu stackoverflow yanıtından asal olan bir sayı için bir kontrol kullanır . Bunun nasıl çalıştığını bilmiyorum, büyücülük gibi gözüküyor. Yukarıdakiyle aynı giriş ve aynı çıkış.

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

Modül kullanımı, alma satırları bayt sayısına dahil edildiği sürece (burada yaptığınız) mükemmel bir şekilde iyidir. Sanki ilk parantezlere dve boşluktan sonra parantezlere ihtiyacınız yok gibi gözüküyor if, bu yüzden ilk cevabınızdakileri 3 byte kadar kaldırabilirsiniz. TIO bağlantısı
sundar - Monica

3
Ben cadılık abomination olsa da seviyorum. İçine baktığınızda oldukça zarif ve basittir: ?x*n !~ /^x?$|^(xx+?)\1+$/n'in asal olup olmadığını kontrol etmek, n ​​'x'in bir dizesini yapmak, 0 veya 1 x'in (asal olmayan) olmadığını ve herhangi bir eşleşme olmadığını kontrol etmek için 2 veya daha fazla x'in kendini tekrar ^(xxxxx)\1+$etmesi (eşleştirme , n'nin 5 ile bölünebildiği anlamına gelir). Regex motorunun bizim için döngümüzü yapmak için geri adım attığı suiistimali kötüye kullanıyor - çok zekice, korkunç ve hayvanların fedakarlığı muhtemelen keşfe dahil oldu.
sundar - Monica

Parantez ve uzay hakkında iyi nokta! Teşekkürler.
IMP1

"Büyücülük" versiyonu 92 baytta yapılabilir, buraya bakınız . İlkelliği kontrol etmek istediğimiz toplam en az 3 olduğundan (minimum 0001-01-01 tarihinden itibaren 1 + 1 + 1 = 3'e denk geliyorsa), regex'in özellikle girişi 0 olarak işlemek için olan kısmını kaldırabiliriz. 1. Bunu çıkarmak ve basitleştirmek 91 baytlık bir versiyon sunar.
sundar - Monica

İlginç bir yaklaşım. 'Ay' yerine 'mon' kullanarak 2 bayttan
GB

2

Ruby , 57 53 bayt

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

Çevrimiçi deneyin!

Benim fikrim değil - IMP1 tarafından "abomination" çalındı


Orijinal fikir:

Ruby , 59 bayt

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

Çevrimiçi deneyin!


1
8e4Bunun yerine çalışmak ister misiniz ?
Kritixi Lithos,

Evet, elbette işe yarıyor. Ayrıca 9 veya daha küçük bir sayı kullanarak da çalışır. Çalıştırması çok daha uzun sürüyor. Teşekkürler.
GB

2

R , 117 bayt

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

Çevrimiçi deneyin!


2

F #, 134 133 bayt

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

Sundar sayesinde -1 bayt .

Çevrimiçi deneyin!

Toplam gün, ay ve yıl ve asal olup olmadığını görmek. Öyleyse, o tarihi döndür. Değilse, tarihi 1 gün azaltın ve tekrar deneyin.


1
Sen yazarak bayt kaydedebilirsiniz -1.0olarak -1.AddDays çağrıda,.
sundar - Monica

Haklısın ... bu gerçekten garip. Fakat faydalı. Teşekkürler.
Ciaran_McCarthy

1

PowerShell , 105 90 bayt

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

Çevrimiçi deneyin!

-13 baytlık sundar sayesinde.

Girişi a olarak alır DateTime 2018-06-20ve içine kaydeder $a. O zaman bir fordöngü içindeyiz . Her bir yineleme, (yani işaretlerle ayrıldığımız şu anki tarih ) ile birlikte eklenmiş (benzeri ) eklenmiş , $a -fsıralı bir sayı oluşturmak için s ile çarparak ve bir birincil kontrol regex kullanarak alıyoruz Geçerli tarihin asal olup olmadığını belirlemek için. Asal değilse, bir gün geriye gider ve döngüye devam ederiz . Asal ise, döngünün dışına çıkar ve örtülü çıktı ile boru hattına yerleştiririz.yyyy+MM+dd+|iexeval1.AddDays(-1)$a

Ortaya çıkan çıktı kültüre bağımlıdır. Kullanılan TIO'da en-usçıktı, uzun tarih formatı gibi görünüyor Saturday, July 1, 1319 12:00:00 AM.


Argümanı datetime nesnesi olarak göndererek birkaç bayt kaydedebilirsiniz. Ayrıca, regex, 2'nin üzerindeki kompozitlerle eşleşecek şekilde basitleştirilebilir (çünkü minimum tarih 0001-01-01toplamı 3'tür). Buradaki değişikliklere bir göz attım .
sundar - Monica

(Bir powershell acemi olduğumu ve bağlantılı kodun sadece minimal bir şekilde test edildiğini unutmayın, ancak tüm test durumlarını buradan bile denemedi.)
sundar - Reinstate Monica

@ sundar Bu girdiyi düşündüm, ama bana biraz "hileli" görünüyordu, bu yüzden string girişi ile gittim. Regex'deki ipucu için teşekkürler - Nasıl çalıştığını tam olarak anlamadım, bu yüzden sadece gülümsedi ve başını salladım. Hehe.
AdmBorkBork

1

Bash , 114 108 bayt

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

Çevrimiçi deneyin!

Benim ilk bash golfüm. Dürüst olmak gerekirse, benim ilk gerçek bash programım ... buradan ilkellik testi yapıldı .

Saat dilimi değişikliği olursa, bu bazen başarısız olabilir, ancak TIO UTC kullanır, bu yüzden çalışması gerekir.


İlk satırdaki "9" yazım hatası mıdır? Bunu ve etrafındaki tırnak işaretlerini kaldırmak (girişin boşluk içermemesini gerektirebileceğimizden dolayı) ve sonradan bir a ekleyerek 110 baytta@$ çalışma kodu verir .
sundar - Monica

@ sundar Gün ışığından yararlanma saati ile ilgili sorunlar olabileceğini düşündüm, ancak yarın tekrar kontrol
edeceğim

1

C (gcc) , 167 bayt

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

Çevrimiçi deneyin!

Bitkin

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

Anti-primer kontrol fonksiyonu. Ele almamız gereken en erken geçerli yıl 0001-01-01 olduğundan, endişelenmemiz gereken en düşük sayı 3'tür, bu nedenle n == 2 veya n <2 için özel durum denetimleri çıkarılır. n ise r bir truthy değerine ayarlanır değil asal. r, global olarak tutulur, çünkü geri dönmek zorunda kalmamak, iki byte kazandırır ( i=n;global'i ,rkontrol etmek için vs döndürmek için). i 2 saniye daha kaydetmek için işlev arayan tarafından 1'e ayarlanır.

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

Tarihi üç ayrı tam sayı olarak alıyoruz ve y + m + d asal olana kadar devam eden ana döngüyü başlatıyoruz. Sonra fonksiyonun etine geliyoruz:

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

Değerlendirme sırasının belirtilmediği zaman, hem artık yıl kontrolünde hem de dizenin endeksi olarak m ve y kullanımı çok yumuşak görünebilir. Neyse ki, yalnızca mp = y, m ve y ile aynı anda gerçekleşemeyen m == 2 olup olmadığını kontrol ediyoruz, çünkü bu yalnızca Ocak-Aralık ayları arasında gerçekleşir, bu nedenle artık yıl kontrolü hiçbir zaman rahatsız olmaz. değerlendirme sırası.

Son olarak, sonuç STDOUT'a yazdırılır:

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

Kodu daha az verimli fakat daha küçük hale getirdi. Asal döngü şimdi karekök yerine tamsayıya gidecektir. Ayrıca tüm çift sayıları da işleyecektir.


Sen olabilir muhtemelen kaldırmak public. Ayrıca, tarih girişini çağıran bir parametre olarak almak için izin verilmediğinden, bunu yapabilirdiniz Main(string[]a)ve sonraDateTime.Parse(a[0])
Corak

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.