Monday Mini-Golf # 1: Reverse Fibonacci Solver


28

Mini-golf del lunedì: una serie di sfide da corto , pubblicate (si spera!) Ogni lunedì.

Una sequenza simile a Fibonacci è ottenuta usando lo stesso metodo della famosa sequenza di Fibonacci ; cioè, ogni numero F (n) viene trovato aggiungendo i due numeri precedenti nella sequenza ( F (n) = F (n-1) + F (n-2) ) o sottraendo i due numeri successivi ( F (n) = F (n + 2) - F (n + 1) ). La differenza principale è che queste sequenze possono iniziare con due numeri qualsiasi. L'indicizzazione zero di queste sequenze è discutibile, ma per ora useremo questa regola:

  • Il numero 0 in una sequenza simile a Fibonacci è l'ultimo numero che è più piccolo del numero precedente.

Ad esempio, la sequenza di Fibonacci potrebbe essere scritta come 1, 0, 1, 1, 2, 3, 5..., quindi il numero 0 nella sequenza è il solo 0.

Sfida

L'obiettivo della sfida è scrivere un programma o una funzione che accetta tre numeri interi, in qualsiasi formato:

  • A e B , i due numeri con cui iniziare a generare una sequenza.
  • N , la lunghezza della sequenza risultante da emettere.

E genera i primi N numeri della sequenza, a partire dal 0 °.

Dettagli

  • A , B e N possono essere presi in qualsiasi ordine e formato, purché siano visibilmente separati. Se usi un ordine / formato diverso, specifica di cosa si tratta.
  • Puoi presumere che A , B e N siano sempre numeri interi positivi.
  • Puoi supporre che N non sia più di 100 e che la sequenza risultante non conterrà x >= 2^31.
  • Se A è maggiore di B , allora B è il numero 0 nella sequenza.
  • L'output deve essere separato da spazi, virgole e / o newline.
  • È consentito uno spazio finale o una nuova riga, ma non una virgola finale.

Casi test

Esempio 1:

8 13 10

Lavorando all'indietro 8 13fino a quando non troviamo un numero maggiore del precedente, otteniamo 13 8 5 3 2 1 1 0 1. Pertanto, 0è il numero 0 in questa sequenza. A partire da questo, stampiamo 0e i prossimi 9 membri:

0 1 1 2 3 5 8 13 21 34

Esempio 2:

23 37 5

Troviamo di nuovo lavorando all'indietro per trovare il numero 0 37 23 14 9 5 4 1 3. Il numero 0 questa volta è 1, quindi lo stampiamo, insieme ai prossimi 4 membri:

1 4 5 9 14

Esempio 3:

4 3 8

Con questo, non dobbiamo lavorare all'indietro per trovare il numero 0, perché 3è inferiore a 4:

3 7 10 17 27 44 71 115

Esempio 4:

29 47 11

Risultato:

1 3 4 7 11 18 29 47 76 123 199

punteggio

Questo è , quindi vince il codice valido più breve in byte. Tiebreaker passa alla presentazione precedentemente pubblicata. Il vincitore verrà scelto lunedì prossimo, 28 settembre. Buona fortuna!

Modifica: Congratulazioni al tuo vincitore, @Jakube, usando Pyth per 23 byte incredibili !


10
Ho rimosso il tag [monday-mini-golf] che hai creato. Non penso che dovremmo creare tag per gruppi di sfide più o meno arbitrari. Il tag non ti dice davvero nulla della sfida e, se vuoi trovarli tutti, potresti semplicemente cercare la frase nella barra di ricerca. In alternativa, se includi un link a questa prima sfida in ogni puntata futura, saranno tutti collegati sotto "Domande collegate" nella barra laterale.
Martin Ender,

@ MartinBüttner OK, grazie; Lo terro 'a mente.
ETHproductions,

Posso prendere l'input come lo voglio (un elenco di Python letterale [8, 13, 10])?
Blue

3
La sfida attualmente dice scrivere un programma . Ciò significa che le funzioni non sono consentite? (CC @LuisMendo)
Dennis

3
@Dennis Spiacente, mi è sfuggito di mente. Sono anche ammesse funzioni. Grazie per la segnalazione!
ETHproductions,

Risposte:


12

Pyth, 23 byte

AQWgHGA,-HGG)VvwHA,H+GH

Provalo online: dimostrazione o suite di test

Stile abbastanza insolito di programmazione Pyth. A volte la programmazione funzionale ha i suoi lati negativi.

Spiegazione:

AQWgHGA,-HGG)VvwHA,H+GH  Q = input list of the two starting numbers
AQ                       G, H = Q (unpacking Q)
  WgHG                   while H >= G:
      A,-HGG                G, H = [H - G, G]
            )            end while
              vw         read a number from input
             V           for N in range(^):
                H           print H
                 A,H+GH     G, H = [H, G + H]

12

Retina , 65 54 byte

+`(1*),\1(1*)
$2,$1
+`(1*)(,1*);1\B
$1$2$2$1;
^1*,|;1
<empty>

Qui, <empty>rappresenta una riga finale vuota. Esegui il codice come un singolo file con il -sflag.

Il formato di input è

A,B;N

dove i numeri sono rappresentati in unario . L'output è un elenco separato da virgole, anche in unario. Per esempio:

8 13 10

sarebbe

11111111,1111111111111;1111111111

e cedere

,1,1,11,111,11111,11111111,1111111111111,111111111111111111111,1111111111111111111111111111111111

Spiegazione

+`(1*),\1(1*)
$2,$1

In primo luogo, riduciamo Ae Bal 0 ° e -1 ° elemento. La +dice Retina continuare a ripetere questa sostituzione regex finché la regex arresta corrispondente o la sostituzione non modifica la stringa. Il regex acquisisce Anel gruppo 1 con (1*), e quindi si assicura che Bsia grande almeno quanto Adurante l'acquisizione B-Acon \1(1*)nel gruppo 2. Questo assicura che questo ciclo termina una volta A>B.

La sostituzione trasforma semplicemente A,Bin B-A,Aimpostando la partita di $2,$1.

+`(1*)(,1*);1\B
$1$2$2$1;

Ora abbiamo già il primo numero dell'output richiesto nella stringa (oltre a quello precedente, che dovremo eliminare in seguito). Questa sostituzione ora aggiunge un altro numero come la somma degli ultimi due numeri mentre prende un 1da N. Poiché abbiamo già un numero, vogliamo che ciò accada solo N-1. Lo facciamo assicurandoci \Bche ci sia ancora almeno ;11alla fine della stringa. Se chiamiamo gli ultimi due valori della sequenza Ce D, quindi la regex acquisisce Cnel gruppo 1 e ,Dnel gruppo due. Riscriviamo quelli con $1$2. Quindi scriviamo anche ciò $2$1che si traduce in ,D+C. Nota che non riscriviamo il singolo in cui 1ci siamo trovatiN, diminuendo così.

^1*,|;1
<empty>

Infine, occorre sbarazzarsi di elemento-1 ° della sequenza, così il residuo ;1da Nche facciamo semplicemente associando uno di questi e la sua sostituzione con la stringa vuota.


7

Python 2, 93 87 67 61 60 byte

i,j,l=input()
while j/i:i,j=j-i,i
exec"i,j=j,i+j;print i;"*l

Ottiene l'input (come un elenco letterale di Python [8,10,13])

Risolve il 0o termine

Quindi stampa la sequenza di aggiunte fino a raggiungere la lunghezza


1
Bel metodo. Per il ciclo senza indice for _ in[1]*l:, è un po 'più breve da fareexec"stuff;"*l
xnor

@xnor: mi sembra significativamente più lungo.
ricorsivo il

Confronta for _ in[1]*l:stuffcon exec"stuff;"*l. @xnor non ha inserito la parte roba nel ciclo for. O for _ in[1]*l:aexec";"*l
Blue

2
È possibile sostituire j>=icon j/i. L'ho appena scoperto! (Perché puoi presumere che A, B e N siano sempre numeri interi positivi )
mbomb007

6

CJam, 26 23 byte

Grazie a Dennis per aver salvato 3 byte.

q~{_@\-_g)}g\@{_@+_p}*t

Accetta l'input in ordine N B A(separato da qualsiasi tipo di spazio bianco). Stampa il risultato come un elenco separato da una nuova riga e termina con un errore .

Provalo qui.

Spiegazione

Questo fa un passo ulteriore quando si trova il 0 ° elemento. Cioè, termina quando uno dei valori è negativo.

q~      e# Read and evaluate input, pushing N, B and A on the stack.
{       e# do while...
  _@\-  e#   B, A = A, B-A
  _W>   e#   Check if A is still non-negative.
}g
\@      e# Reorder N B A into A B N.
{       e# Run the following N times...
  _@+   e#   A, B = B, A+B
  _p    e#   Print B.
}*
t       e# The last A, B are still on the stack. We remove them by trying to
        e# execute a ternary operator: it pops the first two values but then
        e# terminates the program with an error, because there is no third value.

q~{_@\-_g)}g\@{_@+_p}*t( N B A) salva tre byte.
Dennis,

Mentre stavo cercando di risolvere questo problema in CJam, ho avuto problemi con l'input dell'esempio 1. Ora vedo che questa soluzione non fornisce neanche l'output previsto. Dov'è il difetto qui? Penso che invece di controllarlo B>Adebba cercare B not smaller than Aqualcosa o qualcosa del genere, ma non riesco a capire come farlo in CJam. EDIT: la soluzione di Dennis stampa l'output corretto.
Cabbie407,

Bene, l'ho risolto nella mia soluzione.
Cabbie407,

@ Cabbie407 Hai ragione, avrei dovuto usare <!invece di >.
Martin Ender,

Ah ok. Mi chiedevo dove metterlo !in questo. Ne ho semplicemente aggiunto uno per farlo funzionare;)
Cabbie407,

5

Labyrinth , 58 54 49 46 44 byte

Grazie a Sp3000 per aver suggerito l'uso della negazione bit a bit, che ha salvato due byte.

??#"{=
  ;  -
@"~~:}
~""
?
"}}:=
(   +
{{\!:

Il formato di input è B A N. L'output è un elenco separato da una nuova riga.

Spiegazione

(Leggermente obsoleto. L'idea di base è sempre la stessa, ma ora il layout del codice è diverso.)

Questo usa la stessa idea della mia risposta CJam (quindi i crediti vanno ancora a Dennis): quando facciamo un backtracking della sequenza non ci fermiamo fino a quando non otteniamo un valore negativo (che ci lascia con il -1 ° e -2 ° elemento della sequenza). Quindi, iniziamo ad aggiungerli prima di stampare il primo valore.

Questo utilizza un paio di astuti trucchi da golf Labyrinth. Esaminiamo il codice nelle sezioni:

?"
}

L'IP inizia a ?destra (che legge A). Sul "(un no-op) colpisce un vicolo cieco, quindi si gira, eseguendo di ?nuovo (lettura B). Infine, }passa Ballo stack ausiliario. Il vicolo cieco salva un byte sull'ingenuo

?
?
}

Ora il loop che trova l'inizio della sequenza:

)(:{
"  -
" "`?...
=}""

L' )((incremento-decremento) è un no-op, ma è necessario garantire che la parte superiore della pila è positivo sulla giunzione (tale che il PI gira est). :duplicati A, {si sposta Bindietro alla pila principale, -calcola A-B. Ciò che vogliamo davvero è B-Aperò, quindi `nega il valore.

Questo è ora un incrocio a quattro vie. Per risultati negativi, l'IP fa una svolta a sinistra verso ?, leggendo Ne passando alla parte successiva del programma. Se il risultato è zero, l'IP continua a spostarsi verso sud, fa una curva in un angolo e rimane nel loop. Se il risultato è positivo, l'IP fa una svolta a destra (ovest), gira in un angolo e fa un'altra svolta a destra (di nuovo ovest) in modo che rimanga nel ciclo. Penso che questo potrebbe diventare un modello comune, per distinguere i valori negativi da quelli non negativi (o positivi da non positivi):

                v
                "
               """>negative
non-negative <"""

Almeno non sono ancora riuscito a trovare un layout più compatto / utile per questo caso.

Comunque, mentre Anon è negativo, il loop continua, si }sposta Anello stack ausiliario e =scambia Ae B.

Once Ais negative, ?legge Ne ci spostiamo nel secondo loop:

 }:=+:
 }   !
?"({{\

Sappiamo che Nè positivo, quindi possiamo fare affidamento sul fatto che l'IP faccia una svolta a sinistra (nord). Il corpo del loop ora è semplicemente:

}}:=+:!\{{(

A parole: sposta entrambi Ne Asulla pila ausiliaria. Duplica B, scambia la copia con Ae aggiungi Aall'altra copia di B. Duplicalo di nuovo per stampare il valore corrente di B. Stampa una nuova riga. Sposta Be Ntorna allo stack principale e decrementa N.

Mentre Nè positivo, l'IP prenderà una svolta a destra (nord) continuando il ciclo. Una volta Nraggiunto lo zero, il codice termina in modo piuttosto elaborato:

L'IP continua a muoversi dritto (ovest). Il ?tentativo di leggere un altro numero intero, ma abbiamo già raggiunto EOF, quindi in realtà spinge 0invece. `prova a negarlo, ma è ancora zero. Quindi l'IP si sposta ancora verso ovest, fa una svolta in un angolo e continua a spostarsi verso il basso sul @quale termina il programma.

Mi chiedo se potrei mettere il @in una posizione ancora più economica (al momento costa 3 caratteri di spazi bianchi) trasformando i tre "intorno a `in no-op composti (come )(), ma non sono ancora riuscito a farlo funzionare.


5

C, 105 102 100 byte

main(a,b,n,t){for(scanf("%d%d%d",&a,&b,&n);t=b-a,t>=0;a=t)b=a;for(;n--;b=t)t=a+b,printf("%d ",a=b);}

Grazie a @ C0deH4cker per giocare a golf con 2 byte!

Provalo online su Ideone .


4

Matlab / Octave, 115 125 byte

function x=f(x,n)
while x(2)>=x(1)
x=[abs(x(1)-x(2)) x];end
x=x([2 1]);for k=1:n-1
x=[x(1)+x(2) x];end
x=x(n:-1:1);

La funzione dovrebbe essere chiamata come f([8 13],10).

Esempio (Matlab):

>> f([8 13],10)
ans =
     0     1     1     2     3     5     8    13    21    34

Oppure provalo online (Octave) .


Secondo le regole, è possibile modificare l'input, quindi f([a b],n)dovrebbe essere consentito.
bicchiere

@beaker Grazie! Stavo per farlo ... ma poi ho letto la regola "L'input e l'output possono essere separati da spazi, virgole o nuove righe" e mi sono confuso. Chiederò chiarimenti
Luis Mendo,

Sì, non so se x=f(x,n)nell'intestazione della funzione conta ...
Becher

@AlexA. Stavo rispondendo al commento di Luis sulla regola "L'input e l'output possono essere separati da spazi, virgole o nuove righe" e gli OP "A, B e N possono essere presi in qualsiasi ordine e formato, purché siano visibilmente separati ". Poiché A e B non si sarebbero più separati visibilmente nell'intestazione della funzione, mi chiedevo se fosse consentito solo 2 argomenti di funzione.
becher

3

Haskell, 67 65 56 byte

a#b|a>b=b:scanl(+)(a+b)(a#b)|1>0=(b-a)#a
n%a=take n.(a#)

Grazie a @nimi per i suggerimenti

Questo definisce una funzione di infusione ternaria %, che viene invocata nel formato (n%a)b, ad esempio:

> (10%8)13
[0,1,1,2,3,5,8,13,21,34]

Spiegazione

La funzione infisso binaria #, definita sulla prima linea, prende in due interi aed be restituisce l'infinito Fibonacci simile sequenza in cui ae bverificano come elementi consecutivi.

a#b                                       -- Define a#b:
   |a>b=                                  -- if a>b, then a#b is
        b:                                -- the sequence that starts with b and
          scanl(+)     (a#b)              -- continues with the sums of prefixes of a#b
                  (a+b)                   -- plus the additional term a+b;
                            |1>0=(b-a)#a  -- otherwise, it's (b-a)#a.

La funzione %prende semplicemente i primi nelementi di a#b.


È possibile creare la sequenza fibonacci con let f=a:scanl(+)(a+b)f in f(-> pieno #: a#b|a>b=let f=a:scanl(+)(a+b)f in f|1>0=(b-a)#ae salvare due byte.
nimi

@nimi Grazie; Ho corso con la tua idea e ho salvato un totale di 9 byte.
Zgarb,

3

> <>, 33 31 + 1 per -v = 32 byte

&:{:@(?v:}-$&
-1;!?:&<$+{oan::$&

L'input deve essere inserito nello stack usando -v poiché l'analisi dei numeri decimali non è banale in> <>.

Spiegazione :

Rappresenterò lo stack dopo ogni (gruppo di) operazioni. Inizia con [F (n), F (n + 1), N]

Le prime righe scendono dalla serie al suo nono termine:

& removes N from the stack to put it into a register. [F(n), F(n+1)]
:{:@ move the stack and duplicate items to get [F(n+1), F(n), F(n+1), F(n)]
(?v compares the two top items of the stack and branch to the second line if F(n+1) < F(n) [F(n+1), F(n)]
:} move the stack and duplicate its top to get [F(n), F(n+1), F(n)]
- substracts the two top items and put the result on top of the stack [F(n), F(n+1) - F(n)]
$ switchs the top two values of the stack. [F(n+1) - F(n), F(n)]
& retrieve the value from the register. iteration complete, since [F(n+1) - F(n), F(n), N] can also be read as [F(n-1), F(n), N]

La seconda riga sale fino alla serie fino a quando non ha stampato N termini:

< changes the code pointer direction to the left [F(0), F(-1)]
& retrieves the stored value back from the stack [F(0), F(-1), N]
:?!; copies N to compare it to 0, stops if it is [F(0), F(-1), N]
1- decreases it [F(0), F(-1), N-1]
& stores it back [F(0), F(-1)]
$:: makes the stack [F(-1), F(0), F(0), F(0)]
n{ prints the top of the stack then left shifts it [F(0), F(0), F(-1)]
ao displays a line feed (ascii character 0x0a) [F(0), F(0), F(-1)]
+ adds the two top values [F(0), F(-1) + F(0)]
$ switch the two top values. iteration complete since [F(-1) + F(0), F(0)] which can be read as [F(1), F(0)]

Dovresti essere in grado di ridurre il numero di byte di 2 cambiando 00.sulla prima riga in &. Teoricamente, !dovrebbe funzionare, ma penso che> <> ridimensiona la larghezza delle linee in modo che corrisponda alla larghezza di quella più lunga (modifica: ecco perché immagino tu abbia avuto 00.in primo luogo).
Cole

Sì, non ne sono troppo sicuro, ho visto gente qui usare! In un modo che ha ignorato gli spazi. So che l'interprete online su fishlanguage.com non funziona in questo modo, ma forse l'interprete di Python funziona. e lo fa bene comunque, grazie!
Aaron,

L'interprete online lavora con !o ?(alla fine della riga) se è sulla riga più lunga. Puoi provarlo con qualcosa di simile 1n!e si verificherà un errore, ma se c'è una linea sotto di esso con qualcosa di più lungo di esso, come lorumipsum, non lo farà.
Cole

"L'output deve essere separato da spazi, virgole e / o newline." Siamo spiacenti, ma dovrai usare l'altra versione. Ottimo lavoro, però!
Produzioni ETH il

Risolto il problema, ho usato \ n invece degli spazi per salvare 2 byte
Aaron,

2

Java, 113 78 76 byte

Il merito va alla produzione ETH per aver fornito l'algoritmo che utilizzo in questa risposta.

(a,b,n)->{for(;a<=b;b-=a)a=b-a;for(;n-->0;b+=a,a=b-a)System.out.println(b);}

Prova qui .

Spiegazione:

(a,b,n)->{
    for (;a<=b;b=b-a)a=b-a;  //Compute previous terms while a <= b
    for (;n-->0;b=a+b,a=b-a) //Compute and print next terms while n > 0
    System.out.println(b);   //Print term
}

Approccio originale, 113 93 byte

Sembra più golfy;)

String a(int a,int b,int n){return n<0?a+" "+a(b,a+b,n+1):n>0?a>b?a(b,a+b,-n):a(b-a,a,n):"";}

Provalo qui .

Spiegazione:

String a(int a, int b, int n){
    return 
    n < 0 ?                           //If n < 0
        a + " " + a(b, a + b, n + 1)  //Return a + next terms and increment n.
    :                                 //Else
        n > 0 ?                       //If n > 0
            a > b ?                   //If a > b
                a(b, a + b, -n)       //Negate n and return terms.
            :                         //If a <= b
                a(b - a, a, n)        //Generate previous term.
        :                             //If n == 0
            ""                        //Return nothing.
    ;
}

3
Che cosa? Java è più corto di JS?!?
Dev'esserci

@ETHproductions Ho effettivamente copiato il tuo algoritmo (e poi l'ho giocato a golf): P
TheNumberOne,

Va bene per me, ho preso alcuni dei tuoi miglioramenti;) Ho dimenticato di stampare ogni articolo separatamente era valido in JS.
ETHproductions,

È possibile ridurre b=b-aal b-=a, e lo stesso con a=b+a. Salverà 2 byte
Javier Diaz,

+1 per una presentazione in lingua dettagliata così breve. Di solito gli invii Java sono i più lunghi!
DankMemes,

2

Javascript (ES6), 83 73 63 byte

Questo potrebbe essere stato giocato al massimo. Vedremo.

(a,b,n)=>{while(a<=b)b-=a=b-a;for(;n--;console.log(a=b-a))b+=a}

Ungolfed:

function f(a,b,n) {
  // repeat until we find the 0th item...
  while (a <= b) {  // if a = 5, b = 8:
    a = b - a;      // a = (8 - 5) = 3
    b = b - a;      // b = (8 - 3) = 5
  }
  // repeat n times...
  while (n-- > 0) { // if a = 5, b = 8:
    b += a;         // b = (8 + 5) = 13
    a = b - a;      // a = (13 - 5) = 8
    console.log(a); // print out each item
  }
}

1

Mathematica 112

Sarà golf alla fine

z[a_, b_, n_] := (
  f[0] := Min[a, b];
  f[1] := Max[a, b];
  f[x_] := f[x - 1] + f[x - 2];
  f /@ Range[n]
  )

1

CJam, 40 byte

l~:A;{_@_@)<}{_@\-\}w\{A(:A0>}{_p_@+}w\;

Piccoli passi. Questo è il mio primo programma CJam di sempre, quindi sono orgoglioso che funzioni affatto.

Prende l'input nella stessa forma degli esempi.

Ora ho visto che potevo ridurlo a 33 byte usando il { ... }*costrutto.

l~:A;{_@_@)<}{_@-z\}w\A{_p_@+}*;;

E potrei addirittura ridurlo di un altro utilizzo dell'operatore ternario per pulire lo stack e produrre un errore.


1

Rubino, 141 byte

def u a,b,n,z=""
n<1 ? z.chop : u(b,a+b,n-1,z+"#{a} ")
end 
def d a,b,z=0
a.abs>b ? z : d(b-a,a,[a,b]) 
end 
def f a,b,n
x,y=d a,b 
u x,y,n
end 

Esecuzione

La funzione f produce l'output desiderato, i nomi degli argomenti corrispondono ai nomi delle variabili dalla domanda

f(8,13,10) # returns => "0 1 1 2 3 5 8 13 21 34"

Niente di intelligente:

  • La funzione u ( su ) calcola n elementi nella sequenza fibonacci iniziando con a, b usando la ricorsione
  • La funzione d ( giù ) trova il 0 ° e il 1 ° elemento dati due elementi finali usando la ricorsione
  • La funzione f ( fibonacci ) unisce i due elementi

1

Mathematica, 59 byte

If[#>#2,LinearRecurrence[{1,1},#2+{0,#},#3],#0[#2-#,#,#3]]&

0

Ruby, 81 75 73

a,b,n=23,37,5;while(c=b-a)<a;b,a=a,c;end;p a;[*2..n].map{b=c+a;c,a=a,b;p b}

Ridotto di 6 byte quando si sostituisce for-loop con range.map

a,b,n=23,37,5;while(c=b-a)<a;b,a=a,c;end;p a;[*2..n].map{p b=c+a;c,a=a,b}

Salvati altri 2 byte spostando la dichiarazione di stampa




0

Lisp comune, 91 byte

(lambda(a b n)(do((x a(- y x))(y b x))((> x y)(dotimes(k n)(print y)(psetf y(+ y x)x y)))))

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.