黄金时间旅行


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-恢复莫妮卡

Answers:



4

JavaScript(Node.js),94字节

以currying语法将输入作为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.000ZISO 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谢谢。您认为是有效的输入格式吗?
ovs

我不知道为什么不会这样,所以这是另一个-4。没想到。
Kevin Cruijssen

2

爪哇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与以前的版本相比,class有了改进java.util.Date,但是为什么他们不得不使这些名称更长(getMonthValuegetDayOfMonth不是getMonthand 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字节

在线尝试!

接受单个Date输入,并返回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的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+$/}}

只要导入行包含在字节计数中(使用此操作即可),使用模块就可以了。似乎您不需要在首字母d和空格之后的括号if,因此您可以从第一个答案中删除3个字节,以删除这些字节。TIO链接
sundar-恢复莫妮卡

3
我确实喜欢巫术可憎的事。一看就很整洁:?x*n !~ /^x?$|^(xx+?)\1+$/=检查n是否为素数,输入n'x'的字符串,检查它不是0还是1 x'(不是素数),并且不匹配任何2个或多个x自身重复(匹配^(xxxxx)\1+$将意味着n被5整除)。它滥用了正则表达式引擎的回溯功能来为我们执行循环-出色,令人吃惊,其发现可能涉及动物牺牲。
sundar-恢复莫妮卡

关于括号和空格的好地方!谢谢。
IMP1

“巫术”版本可以用92个字节完成,请参见此处。因为我们要检查素数的和至少为3(因为最小日期0001-01-01的总和为1 + 1 + 1 = 3),所以我们可以删除正则表达式中专门用于处理输入为0或0的部分。 1.删​​除并简化后得到一个91字节的版本。
sundar-恢复莫妮卡

一个有趣的方法。保存2个字节用“星期一”而不是“月”
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或任何其他较小的数字。运行只需要更长的时间。谢谢。
GB

2

R,117字节

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

在线尝试!


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
您可以通过在AddDays调用中将编写-1.0为来保存一个字节-1.
sundar-恢复莫妮卡

你是对的...那真的很奇怪。但是有用。谢谢。
Ciaran_McCarthy

1

PowerShell105个 90字节

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

在线尝试!

感谢sundar -13个字节。

将输入作为a 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-恢复莫妮卡

(请注意,尽管我是一名Powershell新手,并且仅对链接代码进行了最低限度的测试,甚至还没有从这里进行过所有测试用例的测试。)
sundar-恢复莫妮卡

@sundar我考虑了该输入,但是对我来说似乎有点“老套”,所以我改用字符串输入。感谢您提供的正则表达式提示-我不完全了解它的工作原理,所以当它出现时我只是微笑着点头。呵呵。
AdmBorkBork

1

重击114108字节

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,因此应该可以使用。


第一行中的“ 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的特殊情况检查。如果n 不是质数,则r设置为真实值。r保持全局,因为不必返回就节省了两个字节(i=n;返回vs ,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.

在未指定评估顺序的情况下,在check年检查中以及将m和y用作字符串的索引时,似乎很困难。幸运的是,我们仅检查m == 2时的leap年,这不能与我们更改m和y的同时发生,因为这只发生在1月到12月之间,因此the年检查永远不会受到评估顺序。

最后,将结果打印到STDOUT:

printf("%04d-%02d-%02d",y,m,d);}

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

松散:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.