Подорож у прайм-тайм


23

Нікому не кажіть, але я прозвав машину подорожі в часі мого дядька! Мій дядько одержимий простими номерами, і це показує на машині - він запрограмував це так, що він може переходити лише до дат, які підсумовують простому номеру.

Тож до цього не може йти, 1947-08-15тому що 1947 + 8 + 15 = 1970, що не є простим числом. Це може піти 1947-07-25, тому що 1947 + 7 + 25 = 1979, що є простим. Тож якщо я хочу повернутися, щоб подивитися урочистості незалежності Індії, схоже, мені доведеться поїхати на кілька тижнів раніше і вичекати ці 20 днів.

У мене є деякі інші дати, на які я хочу піти, і я також повинен зайти на побачення раніше (або, якщо мені пощастить, дорівнює) моїй цільовій даті, яка підсумовує максимальну кількість. Однак я нетерплячий і не хочу занадто довго чекати - тому я хочу знайти дату, яку я можу використати, найближчу до моєї цільової дати.

Чи можете ви написати мені програму, яка приймає мою цільову дату і дає мені дату, яку я повинен ввести у машину часу - найближчу дату до або дану дату, частини якої складаються з простим числом?

(Для цього виклику ми використовуємо пролептичний григоріанський календар - що означає, що ми використовуємо поточний григоріанський календар навіть для періодів, коли люди тоді використовували старіший юліанський календар.)

Вхідні дані

  • Дата
    • в ідеалі будь-яка дата поточної епохи (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

@wastl Так, якщо інформація про дату є суперечливою підстрокою виводу з фіксованою довжиною (так що ні для цього конкретного прикладу).
sundar

Відповіді:



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()використати для отримання протилежного n суми року + місяць + день .

n = eval(s)

Ми використовуємо хелперну функцію P (), щоб перевірити, чи є -n простим (у такому випадку він повертає 0 ). Якщо це так, повертаємо s . Інакше ми спробуємо ще раз із попереднім днем.

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

1
Я відчуваю, що мені потрібен вихідний день, просто розуміючи, як працює ця та перевірка. Гарного гольфу!
sundar

3

Python 2 , 130 127 байт

Введення є year, month, day.

-3 байти завдяки 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

Спробуйте в Інтернеті!


Вам дозволяється взяти об’єкт дати як вхідний, щоб ви могли зберегти 3 байти .
Кевін Крейссен

1
@KevinCruijssen дякую. Як ви вважаєте, це правильний формат введення?
ов

Я не бачу, чому б цього не було, тож це ще -4. Я не думав про це.
Кевін Круїссен

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

Рубін , 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+$/}}

Використання модулів ідеально добре, якщо імпортні рядки включені до числа байтів (що ви тут зробили). Здається, вам не потрібні парантези навколо початкового dта пробілу після цього if, тому ви можете збрити 3 байти з першої відповіді, видаливши їх. TIO посилання
sundar

3
Мені подобається гидота у чаклунстві. Це досить акуратно і просто, коли ви заглянете в нього: ?x*n !~ /^x?$|^(xx+?)\1+$/= щоб перевірити, чи n є простим, зробіть рядок n 'x's, переконайтеся, що це не 0 або 1 x (які не є простими), і що він не відповідає жодному 2 або більше x повторюється (відповідність ^(xxxxx)\1+$означатиме, що n ділиться на 5). Це зловживає зворотним відстеженням двигуна регексу, щоб зробити наш цикл для нас - це геніально, це жахливо, і жертва тварин, ймовірно, була залучена до його відкриття.
sundar

Гарне місце про дужки та простір! Спасибі.
IMP1

Версію "чаклунства" можна виконати в 92 байтах, дивіться тут . Оскільки сума, яку ми хочемо перевірити на предмет первинності, становить щонайменше 3 (починаючи з мінімальної дати 0001-01-01 до 1 + 1 + 1 = 3), ми можемо видалити частину регулярного вираження, яка спеціально обробляє вхід 0 або 1. Видалення та спрощення дає версію на 91 байт.
sundar

Цікавий підхід. Збережіть 2 байти, скориставшись "mon" замість "month"
GB

2

Рубі , 57 53 байти

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

Спробуйте в Інтернеті!

Не моя ідея - вкрадена від "гидоти" IMP1


Оригінальна ідея:

Рубін , 59 байт

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

Спробуйте в Інтернеті!


1
Чи використовуватиме 8e4замість цього роботу?
Kritixi Lithos

Так, звичайно, це працює. Він також працює з використанням 9 або будь-якого іншого меншого числа. Бігати потрібно лише набагато більше часу. Спасибі.
ГБ


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 .

Спробуйте в Інтернеті!

Підсумовуйте день, місяць і рік, і подивіться, чи це найголовніше. Якщо це так, поверніть цю дату. Якщо ні, зменшіть дату на 1 день і повторіть спробу.


1
Ви можете зберегти байт, записавши -1.0як -1., під час виклику AddDays.
sundar

Ти маєш рацію ... це справді дивно. Але корисно. Спасибі.
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

Спробуйте в Інтернеті!

Завдяки сундару на -13 байт.

Приймає дані як а DateTime 2018-06-20та зберігає їх у $a. Тоді ми в forпетлі. Кожну ітерацію ми приймаємо в $a -fорфограмі на зразок yyyy+MM+dd(тобто поточну дату, на якій ми розділили +знаки), додану разом із |iex(аналогічно eval), помножуючи рядок з 1s, щоб утворити одинарне число, та використовуючи регулярний контрольний регулярний вираз щоб визначити, чи є поточна дата основною чи ні. Якщо це не просто, ми .AddDays(-1)повинні йти назад за день і продовжувати цикл. Якщо це просто, ми вириваємося з циклу і розміщуємо $aна трубопроводі з неявним виходом.

Отриманий результат залежить від культури. Для TIO, який використовує en-us, вихід має формат давності, який виглядає так Saturday, July 1, 1319 12:00:00 AM.


Ви можете зберегти кілька байтів, надіславши аргумент як об’єкт дати. Крім того, вираз може бути спрощений для відповідності композитам вище 2 (оскільки мінімальна дата 0001-01-01, сума якої 3). Я взяв тріщину в цих змінах тут .
sundar

(зауважте, що я є новачком в повному складі, і зв'язаний код перевіряється лише мінімально, навіть тут не пробував усіх тестових випадків.)
sundar - Поновіть Моніку

@sundar Я подумав про цей вхід, але він здався мені трохи "шахрайським", тому я пішов із рядковим введенням. Дякую за підказку про регулярний вираз - я не повністю розумію, як це працює, тому я просто посміхаюся і киваю, коли з’являється. Хе-хе.
AdmBorkBork

1

Баш , 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

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

Спробуйте в Інтернеті!

Спуститися

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;для повернення проти, ,rщоб перевірити глобальний). i встановлюється на 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 як у перевірному високосному році, так і в якості індексу рядка, коли порядок оцінки не визначено. На щастя, ми перевіряємо лише високосний рік, якщо 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);}}

неозорений:

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

Зробив код менш ефективним, але меншим. Простір циклу тепер підніметься до цілого числа, а не квадратного кореня. Він також обробить усі парні числа.


Ви, ймовірно, можете видалити public. Крім того, оскільки, здається, не заборонено отримувати введення дати як параметр виклику, ви могли б мати Main(string[]a)і тодіDateTime.Parse(a[0])
Corak,

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.