Perjalanan Waktu Utama

23

Jangan bilang siapa-siapa, tapi saya sudah mencambuk mesin perjalanan waktu paman saya! Paman saya terobsesi dengan bilangan prima, dan itu menunjukkan di mesin - ia telah memprogramnya sehingga hanya bisa pergi ke tanggal yang jumlah bilangan prima.

Jadi tidak bisa pergi ke 1947-08-15karena 1947 + 8 + 15 = 1970, yang bukan bilangan prima. Hal bisa pergi ke 1947-07-25, karena 1947 + 7 + 25 = 1979, yang merupakan perdana. Jadi jika saya ingin kembali menonton perayaan kemerdekaan India, sepertinya saya harus pergi beberapa minggu sebelumnya dan menunggu 20 hari itu.

Saya memiliki beberapa kencan lain yang ingin saya tuju, dan saya juga harus pergi ke kencan sebelumnya (atau jika saya beruntung, sama dengan) tanggal target saya, yang meringkas ke nomor utama. Tapi saya tidak sabar, dan tidak ingin menunggu terlalu lama - jadi saya ingin mencari tanggal yang bisa saya gunakan yang paling dekat dengan tanggal target saya.

Dapatkah Anda menulis saya sebuah program yang mengambil tanggal target saya dan memberi saya tanggal yang harus saya masukkan ke mesin waktu - tanggal terdekat sebelum atau sama dengan tanggal yang diberikan yang bagian-bagiannya menambahkan hingga bilangan prima?

(Untuk tantangan ini, kami menggunakan proleptik Gregorian yang - yang berarti kami menggunakan kalender Gregorian saat ini bahkan untuk periode ketika orang-orang saat itu menggunakan kalender Julian yang lebih tua.)

Memasukkan

  • Kencan
    • idealnya, setiap tanggal di Era Saat Ini (AD); praktis, apa pun bagian dari bahasa Anda yang secara alami dapat menangani
    • dalam format tunggal yang dapat dibaca manusia⁺ yang Anda suka

Keluaran

  • Tanggal yang paling dekat dengan tanggal input, yang kurang dari atau sama dengan input dan yang tanggal + bulan + tahun jumlah hingga bilangan prima.
    • dalam format tunggal yang dapat dibaca manusia⁺ yang Anda suka

⁺: "dapat dibaca manusia" seperti pada hari, bulan dan tahun yang secara terpisah dijabarkan, dalam urutan apa pun

Uji kasus

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

(Terima kasih kepada @Shaggy, @PeterTaylor, dan @Arnauld untuk bantuannya.)

sundar - Pasang kembali Monica
sumber
Apakah OK untuk memiliki waktu yang tidak masuk akal dalam output? (mis. Fri Jul 25 02:46:39 CEST 1947)
wastl
@wastl Ya, selama info tanggal adalah panjang substring output yang bersebelahan (jadi tidak untuk contoh khusus itu).
sundar - Reinstate Monica

Jawaban:

4

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

Cobalah online!

Lebih mudah dibaca:

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

JavaScript (Node.js) , 94 byte

Mengambil input sebagai 3 bilangan bulat dalam sintaks currying (year)(month)(day). Mengembalikan string yang dipisahkan dengan tanda hubung dengan tanda hubung terkemuka.

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

Cobalah online!

Bagaimana?

Kami pertama kali mengkonversi tanggal ke format JSON yyyy-mm-ddT00:00:00.000Z( ISO 8601 ), membaginya pada 'T', hanya menyimpan bagian kiri dan menambahkan tanda hubung utama, yang memberi -yyyy-mm-dd.

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

Ungkapan ini s sekarang bisa eval()'uated untuk mendapatkan sebaliknya n dari jumlah tahun + bulan + hari .

n = eval(s)

Kami menggunakan fungsi helper P () untuk menguji apakah -n adalah prima (dalam hal ini mengembalikan 0 ). Jika ya, kami mengembalikan s . Kalau tidak, kami coba lagi dengan hari sebelumnya.

(P = k => n % ++k ? P(k) : ~k)(n) ? g(d - 1) : s
Arnauld
sumber
1
Saya merasa seperti saya perlu hari libur hanya dari memahami bagaimana cek perdana itu bekerja dan berakhir. Golf yang bagus!
sundar - Reinstate Monica
3

Python 2 , 130 127 byte

Masukan adalah year, month, day.

-3 byte terima kasih kepada 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

Cobalah online!

ovs
sumber
You are allowed to take a date-object as input, so you can save 3 bytes.
Kevin Cruijssen
1
@KevinCruijssen thank you. Do you think this is a valid input format?
ovs
I don't see why it wouldn't be, so that's another -4. Hadn't thought about that.
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;}}

Try it online.

java.time.LocalDate class has been an improvement in comparison to the old java.util.Date, but why did they had to make those names longer (getMonthValue and getDayOfMonth instead of getMonth and getDay).. >.>

Explanation:

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

Ruby, 94 bytes

Try it online!

Takes a single Date input, and returns a string in the ISO 8601 format (YYYY-MM-DD).

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

It uses Ruby's prime module. If that's not allowed, or frowned upon, then for two bytes more I present this abomination:


Ruby, 97 bytes

Try it online!

It uses a check for a number being prime from this stackoverflow answer. I have no idea how this works, it looks a bit like witchcraft. Same input as above, and same output.

require'date'
->d{d.downto(0){|i|break i.to_s if ?1*(i.day+i.month+i.year)!~ /^1?$|^(11+?)\1+$/}}
IMP1
sumber
Using modules is perfectly fine as long as the import lines are included in the byte count (which you've done here). It seems like you don't need the parantheses around the initial d and the space after the if though, so you can shave off 3 bytes from your first answer removing those. TIO link
sundar - Reinstate Monica
3
I do like the witchcrafty abomination though. It's pretty neat and simple once you look into it: ?x*n !~ /^x?$|^(xx+?)\1+$/ = to check if n is prime, make a string of n 'x's, check that it's not 0 or 1 x's (which are not prime), and that it doesn't match any 2 or more x's repeating itself (matching ^(xxxxx)\1+$ would mean n is divisible by 5). It abuses the regex engine's backtracking to do our looping for us - it's brilliant, it's monstrous, and animal sacrifice was probably involved in its discovery.
sundar - Reinstate Monica
Good spot about the parentheses and the space! Thanks.
IMP1
The "witchcraft" version can be done in 92 bytes, see here. Because the sum we want to check for primality is at least 3 (since minimum date 0001-01-01 sums to 1+1+1=3), we can remove the part of the regex that is specifically to handle input being 0 or 1. Removing that and simplifying gives a 91 byte version.
sundar - Reinstate Monica
An interesting approach. Save 2 bytes by using 'mon' instead of 'month'
G B
2

Ruby, 57 53 bytes

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

Try it online!

Not my idea - stolen from the "abomination" by IMP1


Original idea:

Ruby, 59 bytes

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

Try it online!

G B
sumber
1
Would using 8e4 instead work?
Kritixi Lithos
Yes, of course it works. It also works using 9 or any other smaller number. It only takes a lot longer to run. Thanks.
G B
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")))

Try it online!

ngm
sumber
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 thanks to from sundar.

Try it online!

Total the day, month and year and see if it's prime. If it is, return that date. If not, decrement the date by 1 day and try again.

Ciaran_McCarthy
sumber
1
You can save a byte by writing -1.0 as -1., in the AddDays call.
sundar - Reinstate Monica
You're right... that's really weird. But useful. Thanks.
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

Try it online!

Thanks to sundar for -13 bytes.

Takes input as a DateTime 2018-06-20 and saves it into $a. Then we're in a for loop. Each iteration, we're taking $a -formatted like yyyy+MM+dd (i.e., the current date we're on separated by + signs) added together with |iex (similar to eval), string-multiplying that with 1s to form a unary number, and using a prime-checking regex to determine if the current date is prime or not. If it is not prime, we .AddDays(-1) to go backwards a day and continue the loop. If it is prime, we break out of the loop and place $a onto the pipeline with implicit output.

The resulting output is culture-dependent. On TIO, which uses en-us, the output is long-date format, which looks like Saturday, July 1, 1319 12:00:00 AM.

AdmBorkBork
sumber
You can save a few bytes by sending the argument as a datetime object. Also, the regex can be simplified to match composites above 2 (since minimum date is 0001-01-01 whose sum is 3). I took a crack at these changes here.
sundar - Reinstate Monica
(note though that I'm a powershell newbie and that linked code is only minimally tested, haven't even tried all the test cases from here.)
sundar - Reinstate Monica
@sundar I thought about that input, but it seemed a little "cheaty" to me, so I went with string input instead. Thanks for the tip on the regex -- I don't fully understand how it works, so I just smile and nod when it comes up. 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

Try it online!

My first ever bash golf. Honestly, my first real bash program ever ... primality test taken from here.

This might sometimes fail if there is a timezone change, but TIO uses UTC, so there it should work.

wastl
sumber
Apakah "9" di baris pertama salah ketik? Menghapus itu dan tanda kutip di sekitarnya (karena kita dapat mengharuskan input tidak boleh mengandung spasi), dan menambahkan tanda a di akhir setelah itu @$, memberikan kode kerja pada 110 byte .
sundar - Reinstate Monica
@sundar Saya berpikir bahwa mungkin ada masalah dengan waktu musim panas, tapi saya akan memeriksanya besok lagi
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);}

Cobalah online!

Kehabisan

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

Fungsi anti-prime-checking. Karena tahun paling awal yang valid yang perlu kita tangani adalah 0001-01-01, jumlah terendah yang perlu kita khawatirkan adalah 3, sehingga pemeriksaan case khusus untuk n == 2 atau n <2 dicoret. r diatur ke nilai kebenaran jika n bukan bilangan prima. r tetap global, karena tidak harus mengembalikannya menghemat dua byte ( i=n;untuk kembali vs ,runtuk memeriksa global). saya diatur ke 1 oleh pemanggil fungsi, untuk menyimpan 2 byte lainnya.

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

Kami mengambil tanggal sebagai tiga bilangan bulat terpisah dan memulai loop utama, yang berlangsung sampai y + m + d adalah prima. Lalu kita sampai pada daging fungsi:

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

Mungkin tampak rapuh untuk menggunakan m dan y baik di tahun kabisat dan sebagai indeks string, ketika urutan evaluasi tidak ditentukan. Untungnya, kami hanya memeriksa tahun kabisat jika m == 2, yang tidak dapat terjadi pada saat yang sama dengan kami mengubah m dan y, karena itu hanya terjadi dari Januari hingga Desember, jadi tahun kabisat tidak pernah terganggu oleh urutan evaluasi.

Akhirnya, hasilnya dicetak ke STDOUT:

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

Membuat kode kurang efisien tetapi lebih kecil. Prime loop sekarang akan naik ke integer daripada root kuadrat. Ini juga akan memproses semua angka genap.

Kami
sumber
Anda mungkin dapat menghapus public. Selain itu, karena sepertinya tidak diizinkan untuk mendapatkan input tanggal sebagai parameter panggilan, Anda dapat memiliki Main(string[]a)dan kemudianDateTime.Parse(a[0])
Corak