プライムタイムトラベル


23

誰にも言わないでください、しかし、私は叔父のタイムトラベルマシンにニックを入れました!私の叔父は素数に取りつかれていますが、それは機械に表示されます。彼はそれをプログラムして、合計が素数になる日付までしか行かないようにしています。

1947-08-151947 + 8 + 15 = 1970であるため、移動できません。これは素数ではありません。1947 + 7 + 25 = 1979であるため、に進むことができ1947-07-25ます。これは素数です。ですから、インドの独立記念日を見に戻りたいのなら、数週間前に行って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はい、日付情報が出力の連続した固定長部分文字列である限り(その特定の例ではnoです)。
スンダ

回答:



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.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
プライムチェックがどのように機能して終了するかを理解するだけで、休みが必要だと感じています。良いゴルフ!
スンダ

3

Pythonの2130 127バイト

入力は year, month, dayです。

Kevin Cruijssenのおかげで-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バイト節約できます
ケビンCruijssen

1
@KevinCruijssenありがとうございます。これは有効な入力形式だと思いますか?
ovs

なぜそうならないのか分からないので、それはまた-4です。それについて考えていませんでした。
ケビンクルーッセン

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クラスは古いと比較して改善されているjava.util.Dateが、なぜ彼らはそれらの名前は長くしなければならなかったんでした(getMonthValuegetDayOfMonth代わりにgetMonthgetDay)..>。>

説明:

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のプライムモジュールを使用します。それが許可されていない、または眉をひそめている場合は、さらに2バイト、この憎悪を示します。


ルビー、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リンク
スンダー

3
私は魔術の忌み嫌いが好きです。それを見てみると、かなりきれいでシンプルです:?x*n !~ /^x?$|^(xx+?)\1+$/= nが素数であるかどうかを確認し、n個の文字列を作成し、xが0または1 x(素数ではない)であり、いずれとも一致しないことを確認します2つ以上のxが繰り返される(一致する^(xxxxx)\1+$とは、nが5で割り切れることを意味します)。正規表現エンジンのバックトラックを悪用してループ処理を実行します。それは見事であり、怪物であり、おそらく動物の犠牲がその発見に関係していたのでしょう。
スンダ

括弧とスペースについての良いスポット!ありがとう。
IMP1

「魔術」バージョンは92バイトで実行できますこちらを参照してください。素数性をチェックする合計が少なくとも3であるため(最小日付0001-01-01の合計は1 + 1 + 1 = 3であるため)、入力が0であるか、または1.これを削除して簡略化すると、91バイトバージョンになります。
スンダ

興味深いアプローチ。「月」ではなく「mon」を使用して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

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バイトのおかげ

オンラインでお試しください!

日、月、年を合計し、それが素数であるかどうかを確認します。そうであれば、その日付を返します。そうでない場合は、日付を1日減らして再試行してください。


1
あなたは書くことによってバイトを保存することができます-1.0よう-1.AddDays呼び出しで、。
スンダ

あなたは正しい...それは本当に奇妙です。しかし有用です。ありがとう。
Ciaran_McCarthy

1

PowerShell105 90バイト

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

オンラインでお試しください!

-13バイトのsundarに感謝します。

入力をaとして取得し、DateTime 2018-06-20に保存し$aます。その後、forループになります。各反復では、($a -fたとえばyyyy+MM+dd、現在の日付を+記号で区切って)に|iex()を追加し、evalそれを1s で文字列乗算して単項数を形成し、プライムチェック正規表現を使用して、現在の日付がプライムかどうかを判断します。素数でない場合は.AddDays(-1)、1日前に戻り、ループを続けます。素数であれば、ループを抜けて配置します$a暗黙的な出力でパイプラインに配置します。

結果の出力はカルチャに依存します。を使用するTIOではen-us、出力はのような長い日付形式ですSaturday, July 1, 1319 12:00:00 AM


引数を日時オブジェクトとして送信することで、数バイトを節約できます。また、正規表現は、2以上の複合に一致するように簡略化できます(最小日付の0001-01-01合計は3であるため)。ここでこれらの変更に亀裂を取りました。
スンダ-

(ただし、私はパワーシェルの初心者であり、リンクされたコードのテストは最小限であり、ここからすべてのテストケースを試していないことに注意してください。)
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夏時間に問題があるかもしれないと思っていましたが、明日もう一度確認します
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はグローバルに保持されます。返す必要がないため、2バイトを節約できます(グローバルを確認するi=n;ために返す,rため)。iは、さらに2バイトを節約するために、関数呼び出し元によって1に設定されます。

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

日付を3つの独立した整数として受け取り、メインループを開始します。これは、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シャア

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.