ท่องเที่ยวเวลาไพร์ม


23

อย่าบอกใครเลย แต่ฉันได้เปิดเครื่องการเดินทางข้ามเวลาของลุงของฉันแล้ว! ลุงของฉันหมกมุ่นอยู่กับตัวเลขสำคัญและนั่นแสดงให้เห็นในเครื่อง - เขาได้ตั้งโปรแกรมไว้เพื่อให้สามารถไปยังวันที่ที่รวมกันเป็นจำนวนเฉพาะเท่านั้น

มันไม่สามารถไปได้1947-08-15เพราะ 1947 + 8 + 15 = 1970 ซึ่งไม่ใช่จำนวนเฉพาะ มันสามารถไปได้1947-07-25เพราะ 1947 + 7 + 25 = 1979 ซึ่งสำคัญมาก ดังนั้นหากฉันต้องการกลับไปดูการเฉลิมฉลองเอกราชของอินเดียดูเหมือนว่าฉันจะต้องไปไม่กี่สัปดาห์ก่อนหน้านี้และรอ 20 วันเหล่านั้น

ฉันมีวันที่อื่นที่ฉันต้องการไปและฉันก็ต้องไปเดทก่อนเช่นกัน (หรือถ้าฉันโชคดีเท่ากับ) วันที่เป้าหมายของฉันซึ่งรวมกันเป็นจำนวนเฉพาะ แม้ว่าฉันใจร้อนและไม่ต้องการรอมากเกินไป - ดังนั้นฉันต้องการค้นหาวันที่ที่ฉันสามารถใช้ที่ใกล้เคียงที่สุดกับวันที่เป้าหมายของฉัน

คุณสามารถเขียนโปรแกรมที่ใช้วันที่เป้าหมายของฉันและให้วันที่ฉันควรป้อนลงในไทม์แมชชีน - วันที่ที่ใกล้ที่สุดก่อนหน้าหรือเท่ากับวันที่ที่กำหนดซึ่งส่วนต่าง ๆ รวมกันเป็นจำนวนเฉพาะ?

(สำหรับความท้าทายนี้เรากำลังใช้ปฏิทินเกรกอเรียนแบบproleptic - ซึ่งหมายความว่าเราใช้ปฏิทินเกรกอเรียนปัจจุบันแม้จะเป็นช่วงเวลาที่ผู้คนใช้ปฏิทินจูเลียนรุ่นเก่ากว่า)

อินพุต

  • วันที่
    • นึกคิดวันที่ใด ๆ ในยุคปัจจุบัน (AD); ในทางปฏิบัติชุดย่อยของภาษาของคุณสามารถจัดการได้อย่างเป็นธรรมชาติ
    • ในรูปแบบที่มนุษย์อ่านได้เดียวที่คุณต้องการ

เอาท์พุต

  • วันที่ที่ใกล้เคียงที่สุดกับวันที่ป้อนซึ่งน้อยกว่าหรือเท่ากับอินพุทและวันที่ + เดือน + ปีรวมกันเป็นจำนวนเฉพาะ
    • ในรูปแบบที่มนุษย์อ่านได้เดียวที่คุณต้องการ

⁺: "มนุษย์สามารถอ่านได้" เช่นเดียวกับในวันเดือนและปีที่สะกดออกมาแยกกันตามลำดับ

กรณีทดสอบ

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

(ขอบคุณ @Shaggy, @PeterTaylor และ @Arnauld สำหรับความช่วยเหลือเกี่ยวกับคำถาม)


ตกลงหรือไม่ที่จะมีเวลาไร้สาระในเอาต์พุต (เช่นFri Jul 25 02:46:39 CEST 1947)
กำจัด

@wastl ใช่ตราบใดที่ข้อมูลวันที่เป็นสตริงย่อยความยาวคงที่ต่อเนื่องของเอาท์พุท (ดังนั้นไม่มีสำหรับตัวอย่างเฉพาะนั้น)
sundar - Reinstate Monica

คำตอบ:



4

JavaScript (Node.js) , 94 ไบต์

จะเข้าเป็นจำนวนเต็ม 3 (year)(month)(day)ในไวยากรณ์ ส่งคืนสตริงที่คั่นด้วยยัติภังค์ด้วยยัติภังค์ชั้นนำ

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

ลองออนไลน์!

อย่างไร?

ครั้งแรกที่เราแปลงวันที่เพื่อรูปแบบ JSON yyyy-mm-ddT00:00:00.000Z( การรับรองมาตรฐาน ISO 8601 ), แยกบน'T', -yyyy-mm-ddเก็บเฉพาะส่วนด้านซ้ายและเพิ่มยัติภังค์ชั้นนำซึ่งจะช่วยให้

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

สำนวนนี้sขณะนี้คุณสามารถeval()'uated ที่จะได้รับตรงข้ามnของผลรวมของปี + เดือน + วัน

n = eval(s)

เราใช้ฟังก์ชั่นตัวช่วยP ()เพื่อทดสอบว่า-nนั้นดีเลิศ (ซึ่งในกรณีนี้มันจะคืนค่า0 ) หากเป็นเช่นนั้นเราจะกลับs มิฉะนั้นเราจะลองอีกครั้งในวันก่อนหน้า

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

1
ฉันรู้สึกว่าฉันต้องการหยุดงานหนึ่งวันเพียงแค่เข้าใจว่าการตรวจสอบยอดเยี่ยมนั้นทำงานอย่างไร การเล่นกอล์ฟที่ดี!
sundar - Reinstate Monica

3

Python 2 , 130 127 bytes

year, month, dayการป้อนข้อมูลเป็น

-3 ไบต์ต้องขอบคุณเควิน 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

ลองออนไลน์!


คุณได้รับอนุญาตให้ใช้วันที่วัตถุเป็น input เพื่อให้คุณสามารถบันทึก 3 ไบต์
Kevin Cruijssen

1
@KevinCruijssen ขอบคุณ คุณคิดว่านี่เป็นรูปแบบอินพุตที่ถูกต้องหรือไม่
OVS

ฉันไม่เห็นว่าทำไมมันจะไม่เป็นอย่างนั้น -4 ไม่ได้คิดเรื่องนั้น
Kevin Cruijssen

2

Java 8, 144 128 ไบต์

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

ลองออนไลน์

java.time.LocalDateชั้นเรียนได้รับการปรับปรุงเมื่อเทียบกับแบบเก่าjava.util.Dateแต่ทำไมพวกเขาถึงทำให้ชื่อเหล่านั้นยาวขึ้น ( getMonthValueและgetDayOfMonthแทนที่จะเป็นgetMonthและgetDay) .. >.>

คำอธิบาย:

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 ไบต์

ลองออนไลน์!

รับอินพุตวันที่เดียวและส่งคืนสตริงในรูปแบบ 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?}}

มันใช้โมดูลเฉพาะของรูบี้ หากไม่ได้รับอนุญาตหรือขมวดคิ้วฉันจะนำเสนอสิ่งที่น่ารังเกียจนี้อีกสองไบต์


Ruby , 97 ไบต์

ลองออนไลน์!

มันใช้การตรวจสอบตัวเลขที่เป็นสำคัญจากคำตอบ stackoverflowนี้ ฉันไม่รู้ว่ามันใช้งานได้อย่างไรมันดูเหมือนเป็นคาถา อินพุตเหมือนข้างบนและเอาต์พุตเดียวกัน

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

การใช้โมดูลนั้นสมบูรณ์แบบตราบใดที่บรรทัดการนำเข้ารวมอยู่ในจำนวนไบต์ (ซึ่งคุณได้ทำไว้ที่นี่) ดูเหมือนว่าคุณไม่ต้องการ parantheses รอบแรกdและเว้นวรรคหลังจากifนั้นดังนั้นคุณสามารถโกน 3 ไบต์จากคำตอบแรกของคุณเพื่อลบมัน ลิงก์ TIO
sundar - Reinstate Monica

3
ฉันชอบสิ่งที่น่ารังเกียจอย่างน่าพิศวง มันสวยและเรียบง่ายเมื่อคุณมองเข้าไป: ?x*n !~ /^x?$|^(xx+?)\1+$/= เพื่อตรวจสอบว่า n เป็นไพรม์, สร้างสตริงของ n 'x's, ตรวจสอบว่ามันไม่ใช่ 0 หรือ 1 x's (ซึ่งไม่ใช่ไพร์ม) ทำซ้ำ x อย่างน้อย 2 ตัว (การจับคู่^(xxxxx)\1+$หมายถึง n หารด้วย 5) มันใช้การย้อนรอยเครื่องยนต์ย้อนกลับของ Regex เพื่อทำลูปมันให้เรา - มันยอดเยี่ยมมันใหญ่โตและสัตว์บูชายัญอาจเกี่ยวข้องกับการค้นพบมัน
sundar - Reinstate Monica

จุดที่ดีเกี่ยวกับวงเล็บและพื้นที่! ขอบคุณ
IMP1

ว่า "คาถา" รุ่นที่สามารถทำได้ใน 92 ไบต์ดูที่นี่ เนื่องจากผลรวมที่เราต้องการตรวจสอบอันดับแรกคืออย่างน้อย 3 (ตั้งแต่วันที่ขั้นต่ำ 0001-01-01 รวมเป็น 1 + 1 + 1 = 3) เราสามารถลบส่วนของ regex ที่ใช้จัดการอินพุตเป็น 0 หรือโดยเฉพาะ 1. การลบและทำให้เป็นเวอร์ชั่น 91 ไบต์ได้ง่ายขึ้น
sundar - Reinstate Monica

แนวทางที่น่าสนใจ บันทึก 2 ไบต์โดยใช้ 'จันทร์' แทน 'เดือน'
GB

2

Ruby , 57 53 ไบต์

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

ลองออนไลน์!

ไม่ใช่ความคิดของฉัน - ถูกขโมยมาจาก "สิ่งที่น่ารังเกียจ" โดย IMP1


แนวคิดดั้งเดิม:

Ruby , 59 ไบต์

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

ลองออนไลน์!


1
จะใช้8e4แทนการทำงานหรือไม่
Kritixi Lithos

ใช่แน่นอนมันใช้งานได้ นอกจากนี้ยังใช้งานได้ 9 หรือจำนวนที่น้อยกว่าอื่น ๆ ใช้เวลาทำงานนานกว่ามาก ขอบคุณ
GB


2

F #, 134 133 ไบต์

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 ไบต์ขอบคุณจากsundar Sundar

ลองออนไลน์!

รวมวันเดือนและปีและดูว่ามันเป็นนายก ถ้าเป็นเช่นนั้นกลับวันที่ ถ้าไม่ลดลงวันที่ 1 วันและลองอีกครั้ง


1
คุณสามารถบันทึกไบต์โดยเขียน-1.0เป็น-1.ในการโทร AddDays
sundar - Reinstate Monica

คุณพูดถูก ... มันแปลกจริง ๆ แต่มีประโยชน์ ขอบคุณ
Ciaran_McCarthy

1

PowerShell , 105 90 ไบต์

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

ลองออนไลน์!

ขอบคุณ sundar สำหรับ -13 ไบต์

จะเข้าเป็นและบันทึกลงในDateTime 2018-06-20 $aถ้าอย่างนั้นเราก็จะforวนซ้ำ การวนซ้ำแต่ละครั้งเรากำลังทำหรือจัด$a -fรูปแบบเช่นyyyy+MM+dd(วันที่ปัจจุบันที่เราอยู่คั่นด้วย+เครื่องหมาย) รวมกับ|iex(คล้ายกับeval) การคูณสตริงที่มี1s เพื่อสร้างตัวเลขเป็นเอกและใช้regex ตรวจสอบเฉพาะเพื่อตรวจสอบว่าวันที่ปัจจุบันเป็นวันสำคัญหรือไม่ ถ้ามันไม่ได้สำคัญเรา.AddDays(-1)จะย้อนกลับไปหนึ่งวันและทำต่อไป ถ้ามันเป็นไพรม์เราจะแบ่งลูปออกและวาง$aลงบนไพพ์ไลน์ด้วยเอาต์พุตโดยปริยาย

ผลลัพธ์ที่ได้นั้นขึ้นอยู่กับวัฒนธรรม เมื่อวันที่ติ้วซึ่งใช้การส่งออกเป็นรูปแบบวันที่ยาวซึ่งมีลักษณะเหมือนen-usSaturday, July 1, 1319 12:00:00 AM


คุณสามารถบันทึกไม่กี่ไบต์โดยส่งอาร์กิวเมนต์เป็นวัตถุ datetime นอกจากนี้ regex ยังสามารถทำให้ตรงกับคอมโพสิตด้านบน 2 (เนื่องจากวันที่ขั้นต่ำคือ0001-01-01ผลรวมคือ 3) ผมเอาแตกที่การเปลี่ยนแปลงเหล่านี้ที่นี่
sundar - Reinstate Monica

(โปรดทราบว่าฉันเป็นมือใหม่ที่มีพลังและรหัสที่เชื่อมโยงได้รับการทดสอบเพียงเล็กน้อยเท่านั้นยังไม่ได้ลองกรณีทดสอบทั้งหมดจากที่นี่)
sundar - Reinstate Monica

@Sundar ฉันคิดเกี่ยวกับอินพุตนั้น แต่ดูเหมือนว่า "cheaty" เล็กน้อยสำหรับฉันดังนั้นฉันจึงไปกับอินพุตสตริงแทน ขอบคุณสำหรับเคล็ดลับในการ regex - ฉันไม่เข้าใจวิธีการทำงานอย่างสมบูรณ์ดังนั้นฉันเพียงแค่ยิ้มและพยักหน้าเมื่อมันเกิดขึ้น ฮิฮิ.
AdmBorkBork

1

Bash , 114 108 ไบต์

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

ลองออนไลน์!

ครั้งแรกที่ฉันทุบตีกอล์ฟ สุจริตโปรแกรมทุบตีจริงครั้งแรกของฉันที่เคย ... การทดสอบเบื้องต้นที่นำมาจากดั้งเดิมที่นี่

บางครั้งสิ่งนี้อาจล้มเหลวหากมีการเปลี่ยนแปลงเขตเวลา แต่ TIO ใช้ UTC ดังนั้นจึงควรใช้งานได้


"9" ในบรรทัดแรกพิมพ์ผิดหรือไม่ การถอดคำพูดที่และรอบ ๆ (ตั้งแต่เราสามารถกำหนดให้การป้อนข้อมูลที่ไม่ต้องมีช่องว่าง) และเพิ่มในตอนท้ายหลังจากที่@$ให้รหัสการทำงานที่110 ไบต์
sundar - Reinstate Monica

@sundar ฉันคิดว่าอาจมีปัญหากับการปรับเวลาตามฤดูกาล แต่ฉันจะตรวจสอบอีกครั้งในวันพรุ่งนี้
wastl

1

C (gcc) , 167 ไบต์

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

ลองออนไลน์!

rundown

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

ฟังก์ชั่นป้องกันการตรวจสอบเฉพาะ ตั้งแต่ปีที่ถูกต้องเร็วที่สุดที่เราต้องจัดการคือ 0001-01-01 จำนวนต่ำสุดที่เราต้องกังวลคือ 3 ดังนั้นการตรวจสอบกรณีพิเศษสำหรับ n == 2 หรือ n <2 ถูกแยกออก r ถูกตั้งค่าเป็นความจริงหาก n ไม่ใช่ตัวอักษร r ถูกเก็บเป็นโกลบอลเนื่องจากไม่ต้องส่งคืนจะบันทึกสองไบต์ ( i=n;เพื่อกลับ vs ,rเพื่อตรวจสอบโกลบอล) ฉันถูกตั้งค่าเป็น 1 โดยผู้เรียกฟังก์ชั่นเพื่อบันทึกอีก 2 ไบต์

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

เราใช้วันที่เป็นจำนวนเต็มสามตัวและเริ่มวนรอบหลักซึ่งจะดำเนินต่อไปจนกระทั่ง y + m + d เป็นไพร์ม จากนั้นเรามาถึงเนื้อของฟังก์ชั่น:

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

อาจดูเหมือนว่าใช้ m และ y ทั้งคู่ในการตรวจสอบ leap year และเป็นดัชนีของสตริงเมื่อไม่ได้ระบุลำดับการประเมินผล โชคดีที่เราตรวจสอบปีอธิกสุรทินเท่านั้นหาก m == 2 ซึ่งไม่สามารถเกิดขึ้นได้ในเวลาเดียวกับที่เราเปลี่ยน m และ y เนื่องจากสิ่งนั้นเกิดขึ้นตั้งแต่เดือนมกราคมถึงธันวาคมดังนั้นการตรวจสอบปีอธิกสุรทินจึงไม่เคยใส่ใจ คำสั่งของการประเมินผล

ในที่สุดผลลัพธ์จะถูกพิมพ์ไปยัง 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);
    }
}

ทำให้รหัสมีประสิทธิภาพน้อยลง แต่เล็กลง Prime loop จะขึ้นไปสู่จำนวนเต็มแทนที่จะเป็นสแควร์รูท มันจะประมวลผลตัวเลขทั้งหมดด้วยซ้ำ


คุณสามารถอาจpublicลบ นอกจากนี้เนื่องจากมันไม่ได้ดูเหมือนจะไม่ได้รับอนุญาตจะได้รับการป้อนข้อมูลวันที่เป็นพารามิเตอร์เรียกคุณอาจมีMain(string[]a)แล้วDateTime.Parse(a[0])
Corak

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.