Prime Time Travel

23

¡No se lo digas a nadie, pero he robado la máquina de viaje en el tiempo de mi tío! Sin embargo, mi tío está obsesionado con los números primos, y eso se nota en la máquina: lo ha programado para que solo pueda ir a fechas que sumen un número primo.

Entonces no puede ir 1947-08-15porque 1947 + 8 + 15 = 1970, que no es un número primo. Se puede ir a 1947-07-25, ya que 1947 + 7 + 25 = 1979, que es primo. Entonces, si quiero volver a ver las celebraciones de independencia de la India, parece que tendré que ir unas semanas antes y esperar esos 20 días.

Tengo otras fechas a las que quiero ir, y de manera similar tendré que ir a una fecha anterior (o si tengo suerte, igual a) mi fecha objetivo, que se resume en un número primo. Sin embargo, soy impaciente y no quiero esperar demasiado, así que quiero encontrar la fecha que pueda usar que sea más cercana a mi fecha objetivo.

¿Me puede escribir un programa que tome mi fecha objetivo y me dé la fecha que debo ingresar en la máquina del tiempo, la fecha más cercana antes o igual a la fecha dada cuyas partes suman un número primo?

(Para este desafío, estamos utilizando el calendario gregoriano proleptico , lo que simplemente significa que usamos el calendario gregoriano actual incluso para los períodos en que las personas usaban el calendario juliano más antiguo).

Entrada

  • Una cita
    • idealmente, cualquier fecha en la Era Actual (AD); prácticamente, cualquier subconjunto de ese que su idioma pueda manejar naturalmente
    • en cualquier formato legible por humanos que desee

Salida

  • La fecha más cercana a la fecha de entrada, que es menor o igual a la entrada y cuya fecha + mes + año suma un número primo.
    • en cualquier formato legible por humanos que desee

⁺: "legible por humanos" como en el día, mes y año, todo enunciado por separado, en cualquier orden

Casos de prueba

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

(Gracias a @Shaggy, @PeterTaylor y @Arnauld por su ayuda con la pregunta).

sundar - Restablece a Monica
fuente
¿Está bien tener un tiempo sin sentido en la salida? (p Fri Jul 25 02:46:39 CEST 1947. ej. )
wastl
@wastl Sí, siempre que la información de la fecha sea una subcadena contigua de longitud fija de la salida (por lo tanto, no para ese ejemplo en particular).
sundar - Restablecer Monica

Respuestas:

4

Rojo , 87 bytes

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]

Pruébalo en línea!

Más legible:

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
]
Galen Ivanov
fuente
4

JavaScript (Node.js) , 94 bytes

Toma la entrada como 3 enteros en la sintaxis de curry (year)(month)(day). Devuelve una cadena separada por guiones con un guión inicial.

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

Pruébalo en línea!

¿Cómo?

Primero convertimos la fecha al formato JSON yyyy-mm-ddT00:00:00.000Z( ISO 8601 ), la dividimos en 'T', conservamos solo la parte izquierda y agregamos un guión inicial, que da -yyyy-mm-dd.

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

Esta expresión s ahora se puede calcular eval()para obtener el opuesto n de la suma de año + mes + día .

n = eval(s)

Usamos la función auxiliar P () para probar si -n es primo (en cuyo caso devuelve 0 ). Si es así, devolvemos s . De lo contrario, intentamos nuevamente con el día anterior.

(P = k => n % ++k ? P(k) : ~k)(n) ? g(d - 1) : s
Arnauld
fuente
1
Siento que necesito un día libre solo para entender cómo funciona y termina esa verificación principal. Buen golf!
sundar - Restablecer Monica
3

Python 2 , 130 127 bytes

Entrada es year, month, day.

-3 bytes gracias a 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

Pruébalo en línea!

ovs
fuente
Se le permite tomar un objeto de fecha como entrada, por lo que puede guardar 3 bytes .
Kevin Cruijssen
1
@KevinCruijssen gracias. ¿Crees que este es un formato de entrada válido?
ovs
No veo por qué no sería así que ese es otro -4. No había pensado en eso.
Kevin Cruijssen
2

Java 8, 144128 bytes

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

Pruébalo en línea.

java.time.LocalDateLa clase ha sido una mejora en comparación con la anterior java.util.Date, pero ¿por qué tuvieron que hacer esos nombres más largos ( getMonthValuey en getDayOfMonthlugar de getMonthy getDay) ..>.>

Explicación:

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`
Kevin Cruijssen
fuente
2

Ruby , 94 bytes

Pruébalo en línea!

Toma una sola entrada de fecha y devuelve una cadena en el formato 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?}}

Utiliza el módulo principal de Ruby. Si eso no está permitido, o está mal visto, entonces para dos bytes más presento esta abominación:


Ruby , 97 bytes

Pruébalo en línea!

Utiliza un cheque para un número que es primo de esta respuesta de stackoverflow . No tengo idea de cómo funciona esto, se parece un poco a la brujería. Misma entrada que arriba y misma salida.

require'date'
->d{d.downto(0){|i|break i.to_s if ?1*(i.day+i.month+i.year)!~ /^1?$|^(11+?)\1+$/}}
IMP1
fuente
El uso de módulos está perfectamente bien siempre que las líneas de importación se incluyan en el recuento de bytes (que ha hecho aquí). Parece que no necesita las paréntesis alrededor de la inicial dy el espacio después de ifeso, por lo que puede eliminar 3 bytes de su primera respuesta para eliminarlos. TIO link
sundar - Restablecer Monica
3
Sin embargo, me gusta la abominación bruja. Es bastante ordenado y simple una vez que lo miras: ?x*n !~ /^x?$|^(xx+?)\1+$/= para verificar si n es primo, haz una cadena de n 'x's, verifica que no sea 0 o 1 x (que no son primos), y que no coincide con ninguno Se repiten 2 o más x (la coincidencia ^(xxxxx)\1+$significaría que n es divisible por 5). Abusa de la marcha atrás del motor regex para hacer nuestro bucle por nosotros: es brillante, es monstruoso, y el sacrificio de animales probablemente estuvo involucrado en su descubrimiento.
sundar - Restablecer Monica
Buen lugar sobre los paréntesis y el espacio! Gracias.
IMP1
La versión de "brujería" se puede hacer en 92 bytes, ver aquí . Debido a que la suma que queremos verificar para primalidad es al menos 3 (ya que la fecha mínima 0001-01-01 suma a 1 + 1 + 1 = 3), podemos eliminar la parte de la expresión regular que es específicamente para manejar la entrada que es 0 o 1. Quitar eso y simplificar da una versión de 91 bytes.
sundar - Restablecer Monica
Un enfoque interesante. Ahorre 2 bytes usando 'mon' en lugar de 'mes'
GB
2

Ruby , 57 53 bytes

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

Pruébalo en línea!

No es mi idea, robada de la "abominación" por IMP1


Idea original:

Ruby , 59 bytes

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

Pruébalo en línea!

GB
fuente
1
¿Usar en su 8e4lugar funcionaría?
Kritixi Lithos
Sí, por supuesto que funciona. También funciona usando 9 o cualquier otro número más pequeño. Solo lleva mucho más tiempo correr. Gracias.
GB
2

R , 117 bytes

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

Pruébalo en línea!

ngm
fuente
2

F #, 134 133 bytes

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 byte gracias a desde sundar .

Pruébalo en línea!

Totalice el día, mes y año y vea si es primo. Si es así, devuelva esa fecha. Si no, disminuya la fecha en 1 día e intente nuevamente.

Ciaran_McCarthy
fuente
1
Puede guardar un byte escribiendo -1.0como -1., en la llamada AddDays.
sundar - Restablecer Monica
Tienes razón ... eso es realmente extraño. Pero útil. Gracias.
Ciaran_McCarthy
1

PowerShell , 105 90 bytes

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

Pruébalo en línea!

Gracias a sundar por -13 bytes.

Toma la entrada como a DateTime 2018-06-20y la guarda en $a. Entonces estamos en un forbucle. Cada iteración, tomamos $a -formatted como yyyy+MM+dd(es decir, la fecha actual en la que estamos separados por +signos) sumados con |iex(similar a eval), multiplicando la cadena con 1s para formar un número unario y usando una expresión regular de verificación de primos para determinar si la fecha actual es primo o no. Si no es primo, debemos .AddDays(-1)retroceder un día y continuar el ciclo. Si es primo, salimos del bucle y lo colocamos $aen la tubería con salida implícita.

El resultado resultante depende de la cultura. En TIO, que utiliza en-us, el resultado es un formato de fecha larga, que se parece Saturday, July 1, 1319 12:00:00 AM.

AdmBorkBork
fuente
Puede guardar algunos bytes enviando el argumento como un objeto de fecha y hora. Además, la expresión regular se puede simplificar para que coincida con los compuestos superiores a 2 (ya que la fecha mínima es 0001-01-01cuya suma es 3). Tomé una grieta en estos cambios aquí .
sundar - Restablecer Monica
(Ten en cuenta que soy un novato PowerShell y que el código relacionado está comprobado solamente mínimamente, ni siquiera han intentado todos los casos de prueba desde aquí.)
Sundar - Restablecer Monica
@sundar Pensé en esa entrada, pero me pareció un poco "engañosa", así que en lugar de eso, elegí la entrada de cadena. Gracias por el consejo sobre la expresión regular: no entiendo completamente cómo funciona, así que solo sonrío y asiento cuando aparece. Jeje.
AdmBorkBork
1

Bash , 114108 bytes

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

Pruébalo en línea!

Mi primer golpe de golf. Honestamente, mi primer programa real de bash ... prueba de primigenia tomada desde aquí .

Esto a veces puede fallar si hay un cambio de zona horaria, pero TIO usa UTC, por lo que debería funcionar.

wastl
fuente
¿Es el "9" en la primera línea un error tipográfico? Al eliminar eso y las comillas a su alrededor (ya que podemos requerir que la entrada no contenga espacios), y agregar una a al final después @$, se obtiene un código de trabajo de 110 bytes .
Sundar - Restablecer Monica
@sundar Pensé que podría haber problemas con el horario de verano, pero lo comprobaré mañana otra vez
fue el
1

C (gcc) , 167 bytes

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

Pruébalo en línea!

Atropellar

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

La función de control anti-cebado. Dado que el primer año válido con el que tenemos que lidiar es 0001-01-01, el número más bajo del que debemos preocuparnos es 3, por lo que se eliminan las verificaciones de casos especiales para n == 2 o n <2. r se establece en un valor verdadero si n no es primo. r se mantiene global, ya que al no tener que devolverlo se ahorran dos bytes ( i=n;para devolver vs ,rverificar el global). i se establece en 1 por la persona que llama la función, para guardar otros 2 bytes.

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

Tomamos la fecha como tres enteros separados y comenzamos el ciclo principal, que continúa hasta que y + m + d es primo. Luego llegamos a la carne de la función:

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

Puede parecer dudoso usar my e tanto en la verificación del año bisiesto como en el índice de la cadena, cuando el orden de evaluación no está especificado. Afortunadamente, solo verificamos el año bisiesto si m == 2, lo que no puede suceder al mismo tiempo que cambiamos my e, ya que eso solo ocurre de enero a diciembre, por lo que la verificación del año bisiesto nunca se ve afectada por orden de evaluación.

Finalmente, el resultado se imprime en STDOUT:

printf("%04d-%02d-%02d",y,m,d);}
gastropner
fuente
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);}}

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

Hizo que el código fuera menos eficiente pero más pequeño. Prime loop ahora irá al entero en lugar de a la raíz cuadrada. También procesará todos los números pares.

Kami
fuente
Puede probablemente retire public. Además, dado que no parece estar prohibido obtener la entrada de la fecha como parámetro de llamada, podría haberlo hecho Main(string[]a)y luegoDateTime.Parse(a[0])
Corak