Voyage Prime Time


23

Ne le dites à personne, mais j'ai piqué la machine à voyager dans le temps de mon oncle! Mon oncle est obsédé par les nombres premiers, cependant, et cela se voit dans la machine - il l'a programmé de sorte qu'il ne puisse aller qu'aux dates qui se résument à un nombre premier.

Donc ça ne peut pas aller 1947-08-15parce que 1947 + 8 + 15 = 1970, ce qui n'est pas un nombre premier. Il peut aller à 1947-07-25, car 1947 + 7 + 25 = 1979, ce qui est premier. Donc, si je veux revenir pour regarder les célébrations de l'indépendance de l'Inde, il semble que je devrai y aller quelques semaines plus tôt et attendre ces 20 jours.

J'ai d'autres dates auxquelles je veux aller, et je devrai également aller à une date antérieure (ou si j'ai de la chance, égale) à ma date cible, qui se résume à un nombre premier. Je suis impatient, cependant, et je ne veux pas trop attendre - je veux donc trouver la date que je peux utiliser la plus proche de ma date cible.

Pouvez-vous m'écrire un programme qui prend ma date cible et me donne la date que je devrais entrer dans la machine à remonter le temps - la date la plus proche avant ou égale à la date donnée dont les parties totalisent un nombre premier?

(Pour ce défi, nous utilisons le calendrier grégorien proleptique - ce qui signifie simplement que nous utilisons le calendrier grégorien actuel même pour les périodes où les gens utilisaient alors l'ancien calendrier julien.)

Contribution

  • Un rendez-vous
    • idéalement, n'importe quelle date de l'ère actuelle (AD); pratiquement, quel que soit le sous-ensemble de ce que votre langue peut naturellement gérer
    • dans n'importe quel format lisible par l'homme - vous aimez

Sortie

  • La date la plus proche de la date d'entrée, qui est inférieure ou égale à l'entrée et dont la date + mois + année se résume à un nombre premier.
    • dans n'importe quel format lisible par l'homme - vous aimez

⁺: "lisible par l'homme" comme le jour, le mois et l'année, tous énoncés séparément, dans n'importe quel ordre

Cas de test

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

(Merci à @Shaggy, @PeterTaylor et @Arnauld pour leur aide avec la question.)


Est-il OK d'avoir un temps absurde dans la sortie? (par exemple Fri Jul 25 02:46:39 CEST 1947)
wastl

@wastl Oui, tant que les informations de date sont une sous-chaîne contiguë de longueur fixe de la sortie (donc non pour cet exemple particulier).
sundar

Réponses:


4

Rouge , 87 octets

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]

Essayez-le en ligne!

Plus lisible:

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 octets

Prend l'entrée comme 3 entiers dans la syntaxe de curry (year)(month)(day). Renvoie une chaîne séparée par des tirets avec un trait d'union.

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

Essayez-le en ligne!

Comment?

Nous convertissons d'abord la date au format JSON yyyy-mm-ddT00:00:00.000Z( ISO 8601 ), la divisons sur le 'T', ne gardons que la partie gauche et ajoutons un trait d'union, ce qui donne -yyyy-mm-dd.

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

Cette expression s peut maintenant être eval()calculée pour obtenir l'opposé n de la somme de l' année + mois + jour .

n = eval(s)

Nous utilisons la fonction d'assistance P () pour tester si -n est premier (auquel cas il renvoie 0 ). Si tel est le cas, nous renvoyons l' art . Sinon, nous réessayons avec la veille.

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

1
Je sens que j'ai besoin d'un jour de congé juste pour comprendre comment fonctionne et se termine ce chèque principal. Bon golf!
sundar

3

Python 2 , 130 127 octets

L'entrée est year, month, day .

-3 octets grâce à 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

Essayez-le en ligne!


Vous êtes autorisé à prendre un objet date en entrée, vous pouvez donc économiser 3 octets .
Kevin Cruijssen

1
@KevinCruijssen merci. Pensez - vous que c'est un format d'entrée valide?
2018

Je ne vois pas pourquoi ce ne serait pas le cas, c'est donc un autre -4. Je n'y avais pas pensé.
Kevin Cruijssen

2

Java 8, 144 128 octets

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

Essayez-le en ligne.

java.time.LocalDatela classe a été une amélioration par rapport à l'ancienne java.util.Date, mais pourquoi ont-ils dû allonger ces noms ( getMonthValueet getDayOfMonthau lieu de getMonthet getDay) ..>.>

Explication:

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

Rubis , 94 octets

Essayez-le en ligne!

Prend une seule entrée Date et renvoie une chaîne au format 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?}}

Il utilise le module principal de Ruby. Si cela n'est pas autorisé ou désapprouvé, alors pour deux octets de plus, je présente cette abomination:


Rubis , 97 octets

Essayez-le en ligne!

Il utilise une vérification pour un nombre premier de cette réponse stackoverflow . Je n'ai aucune idée de comment ça marche, ça ressemble un peu à de la sorcellerie. Même entrée que ci-dessus et même sortie.

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

L'utilisation de modules est parfaitement correcte tant que les lignes d'importation sont incluses dans le nombre d'octets (ce que vous avez fait ici). Il semble que vous n'ayez pas besoin des parenthèses autour de l'initiale det de l'espace après if, cependant, vous pouvez donc raser 3 octets de votre première réponse en les supprimant. Lien TIO
Sundar

3
J'aime bien l'abomination sorcière. C'est assez net et simple une fois que vous y regardez: ?x*n !~ /^x?$|^(xx+?)\1+$/= pour vérifier si n est premier, faites une chaîne de n 'x, vérifiez que ce n'est pas 0 ou 1 x (qui ne sont pas premiers), et qu'il ne correspond à aucun 2 x ou plus se répétant (l'appariement ^(xxxxx)\1+$signifierait que n est divisible par 5). Il abuse du retour en arrière du moteur regex pour faire notre boucle pour nous - c'est génial, c'est monstrueux, et le sacrifice animal a probablement été impliqué dans sa découverte.
sundar

Bon endroit sur les parenthèses et l'espace! Merci.
IMP1

La version "sorcellerie" peut se faire en 92 octets, voir ici . Étant donné que la somme que nous voulons vérifier pour la primauté est d'au moins 3 (puisque la date minimale 0001-01-01 est égale à 1 + 1 + 1 = 3), nous pouvons supprimer la partie de l'expression régulière qui est spécifiquement destinée à gérer l'entrée étant 0 ou 1. Supprimer cela et simplifier donne une version à 91 octets.
sundar

Une approche intéressante. Économisez 2 octets en utilisant «mon» au lieu de «mois»
GB

2

Rubis , 57 53 octets

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

Essayez-le en ligne!

Pas mon idée - volé de "l'abomination" par IMP1


Idée originale:

Rubis , 59 octets

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

Essayez-le en ligne!


1
Est-ce que l'utilisation à la 8e4place fonctionnerait?
Kritixi Lithos

Oui, bien sûr, cela fonctionne. Il fonctionne également en utilisant 9 ou tout autre nombre plus petit. Cela ne prend que beaucoup plus de temps pour fonctionner. Merci.
GB

2

R , 117 octets

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

Essayez-le en ligne!


2

F #, 134 133 octets

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 octet grâce à de Sundar .

Essayez-le en ligne!

Additionnez le jour, le mois et l'année et voyez si c'est premier. Si c'est le cas, retournez cette date. Sinon, décrémentez la date d'un jour et réessayez.


1
Vous pouvez enregistrer un octet en écrivant -1.0as -1., dans l'appel AddDays.
sundar

Tu as raison ... c'est vraiment bizarre. Mais utile. Merci.
Ciaran_McCarthy

1

PowerShell , 105 90 octets

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

Essayez-le en ligne!

Merci à Sundar pour -13 octets.

Prend l'entrée comme un DateTime 2018-06-20et l'enregistre $a. Ensuite, nous sommes dans une forboucle. À chaque itération, nous prenons ou $a -fmattons comme yyyy+MM+dd(c.-à-d. La date actuelle à laquelle nous sommes séparés par des +signes) ajoutés avec |iex(similaire àeval ), en multipliant les chaînes avec 1s pour former un nombre unaire et en utilisant une expression rationnelle de vérification principale pour déterminer si la date actuelle est prime ou non. S'il n'est pas premier, il .AddDays(-1)faut reculer d'un jour et continuer la boucle. S'il est premier, nous sortons de la boucle et le plaçons $asur le pipeline avec une sortie implicite.

La sortie résultante dépend de la culture. Sur TIO, qui utilise en-us, la sortie est au format longue date, qui ressemble àSaturday, July 1, 1319 12:00:00 AM .


Vous pouvez enregistrer quelques octets en envoyant l'argument en tant qu'objet datetime. En outre, l'expression régulière peut être simplifiée pour correspondre aux composites supérieurs à 2 (puisque la date minimale est 0001-01-01dont la somme est 3). J'ai pris une fissure à ces changements ici .
sundar

(notez cependant que je suis un débutant en PowerShell et que le code lié n'est que peu testé, je n'ai même pas essayé tous les cas de test d'ici.)
Sundar - Réinstallez Monica le

@sundar J'ai pensé à cette entrée, mais elle me semblait un peu "tricheuse", alors j'ai opté pour une entrée de chaîne. Merci pour l'astuce sur l'expression régulière - je ne comprends pas complètement comment cela fonctionne, alors je souris et hoche la tête quand il apparaît. Hehe.
AdmBorkBork

1

Bash , 114 108 octets

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

Essayez-le en ligne!

Mon tout premier golf bash. Honnêtement, mon premier vrai programme bash jamais ... test de primalité pris d' ici .

Cela peut parfois échouer en cas de changement de fuseau horaire, mais TIO utilise UTC, donc cela devrait fonctionner.


Le "9" de la première ligne est-il une faute de frappe? Supprimer cela et les guillemets qui l'entourent (puisque nous pouvons exiger que l'entrée ne contienne pas d'espaces), et ajouter un a à la fin après @$, donne un code de travail à 110 octets .
sundar

@sundar Je pensais qu'il pourrait y avoir des problèmes avec l'heure d'été, mais je vérifierai à nouveau demain
wastl

1

C (gcc) , 167 octets

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

Essayez-le en ligne!

Fatigué

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

La fonction anti-prime-vérification. Étant donné que la première année valide à traiter est 0001-01-01, le nombre le plus bas dont nous devons nous préoccuper est 3, de sorte que les vérifications de cas spécial pour n == 2 ou n <2 sont supprimées. r est réglé sur une valeur vraie si n n'est pas un nombre premier. r est maintenu global, car sans avoir à le retourner, il économise deux octets ( i=n;pour retourner vs ,rpour vérifier le global). i est mis à 1 par l'appelant de la fonction, pour enregistrer encore 2 octets.

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

Nous prenons la date comme trois entiers séparés et commençons la boucle principale, qui continue jusqu'à ce que y + m + d soit premier. Ensuite, nous arrivons à la viande de la fonction:

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

Il peut sembler difficile d'utiliser m et y à la fois dans la vérification de l'année bissextile et comme index de la chaîne, lorsque l'ordre d'évaluation n'est pas spécifié. Heureusement, nous ne vérifions l'année bissextile que si m == 2, ce qui ne peut pas se produire en même temps que nous changeons m et y, car cela ne se produit que de janvier à décembre, de sorte que la vérification de l'année bissextile n'est jamais gênée par le ordre d'évaluation.

Enfin, le résultat est imprimé sur 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);}}

non golfé:

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

Rendu le code moins efficace mais plus petit. La boucle principale montera maintenant à l'entier plutôt qu'à la racine carrée. Il traitera également tous les nombres pairs.


Vous pouvez probablement supprimer public. De plus, comme il ne semble pas interdit d'obtenir l'entrée de la date en tant que paramètre d'appel, vous pourriez avoir Main(string[]a)et ensuiteDateTime.Parse(a[0])
Corak

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.