Prime Time Travel

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 за помощь в вопросе.)

sundar - Восстановить Монику
источник
Нормально ли иметь бессмысленное время на выходе? (например Fri Jul 25 02:46:39 CEST 1947)
wastl
@wastl Да, если информация о дате является непрерывной подстрокой фиксированной длины выходных данных (поэтому нет для этого конкретного примера).
sundar - Восстановить Монику

Ответы:

4

Красный , 87 байт

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]

Попробуйте онлайн!

Более читабельно:

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 байта

Вводит как 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
Arnauld
источник
1
Я чувствую, что мне нужен выходной только из-за понимания того, как эта первичная проверка работает и заканчивается. Хороший гольф!
sundar - Восстановить Монику
3

Python 2 , 130 127 байтов

Вход есть year, month, day.

-3 байта благодаря Кевину Круйссену .

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

Он использует основной модуль Руби. Если это не разрешено или осуждается, то еще на два байта я представляю эту мерзость:


Рубин , 97 байт

Попробуйте онлайн!

Он использует проверку числа, являющегося простым из этого ответа stackoverflow . Я понятия не имею, как это работает, это похоже на колдовство. Тот же вход, что и выше, и тот же вывод.

require'date'
->d{d.downto(0){|i|break i.to_s if ?1*(i.day+i.month+i.year)!~ /^1?$|^(11+?)\1+$/}}
IMP1
источник
Использование модулей прекрасно, если строки импорта включены в число байтов (что вы сделали здесь). Кажется, что вам не нужны паратезы вокруг начального dи пробела после него if, так что вы можете сбрить 3 байта из вашего первого ответа, удалив их. Ссылка
TIO
3
Мне нравится ведьма мерзости. Это довольно аккуратно и просто, как только вы посмотрите на него: ?x*n !~ /^x?$|^(xx+?)\1+$/= проверить, является ли n простым, сделать строку из n 'x, проверить, что это не 0 или 1 x (которые не являются простыми), и что он не совпадает ни с одним 2 или более х повторяются (совпадение ^(xxxxx)\1+$будет означать, что n делится на 5). Он злоупотребляет возвратом движка регулярных выражений, чтобы сделать нашу петлю для нас - это замечательно, это чудовищно, и жертва животных, вероятно, была вовлечена в его открытие.
sundar - Восстановить Монику
Хорошее место о скобках и месте! Спасибо.
IMP1
Версия "колдовство" может быть выполнена в 92 байта, см. Здесь . Поскольку сумма, которую мы хотим проверить на первичность, равна по крайней мере 3 (поскольку минимальная дата 0001-01-01 суммируется с 1 + 1 + 1 = 3), мы можем удалить часть регулярного выражения, специально предназначенную для обработки ввода, равную 0 или 1. Удаление и упрощение дает 91-байтовую версию.
sundar - Восстановить Монику
Интересный подход. Сохраните 2 байта, используя «mon» вместо «month»
ГБ
2

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

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

Попробуйте онлайн!

Не моя идея - украденная у "мерзости" ИМП1


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

Рубин , 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 день и попробуйте снова.

Ciaran_McCarthy
источник
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

Попробуйте онлайн!

Спасибо sundar за -13 байтов.

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

Полученный результат зависит от культуры. На TIO, который используетen-us , вывод имеет формат длинной даты, который выглядит следующим образом Saturday, July 1, 1319 12:00:00 AM.

AdmBorkBork
источник
Вы можете сохранить несколько байтов, отправив аргумент в качестве объекта datetime. Кроме того, регулярное выражение может быть упрощено для сопоставления композитов выше 2 (поскольку минимальная дата равна 0001-01-01сумме 3). Я взял трещину на эти изменения здесь .
sundar - Восстановить Монику
(обратите внимание, что я новичок PowerShell и что связанный код проверен лишь минимально, отсюда даже не пробовали все контрольные примеры.)
sundar - Восстановите Monica
@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

Попробуйте онлайн!

Мой первый в истории гольф Честно говоря, моя первая настоящая bash-программа ... тест на первичность, взятый отсюда .

Иногда может произойти сбой при изменении часового пояса, но TIO использует UTC, поэтому он должен работать.

Wastl
источник
Является ли «9» в первой строке опечаткой? Удаление этого и кавычек вокруг него (поскольку мы можем требовать, чтобы входные данные не содержали пробелов) и добавление a в конце после @$, дает рабочий код на 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;чтобы вернуть v ,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 как в проверке високосного года, так и в качестве индекса строки, когда порядок оценки не указан. К счастью, мы проверяем только високосный год, если m == 2, что не может произойти одновременно с изменением m и y, поскольку это происходит только с января по декабрь, поэтому проверка високосного года никогда не беспокоит порядок оценки.

Наконец, результат выводится на STDOUT:

printf("%04d-%02d-%02d",y,m,d);}
gastropner
источник
0

C # - 281 239 232 символов

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 теперь будет идти к целому числу, а не к квадратному корню. Это также обработает все четные числа.

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