La tua auto gira solo a destra!


49

introduzione

Hai la sfortuna di essere bloccato in una macchina in fuga su una corsa ad ostacoli. Tutte le caratteristiche dell'auto sono non reattive, ad eccezione del sistema di sterzo, che è danneggiato. Può guidare dritto o può girare a destra. L'auto può essere guidata in sicurezza?

Meccanica

La tua auto inizia nell'angolo in alto a sinistra di una mappa 8x8 e sta cercando di mettersi in salvo nell'angolo in basso a destra. L'auto ha un orientamento (inizialmente a destra), misurato con incrementi di 90 gradi. L'auto può eseguire una delle due azioni:

  1. Guidare un quadrato in avanti, o
  2. Ruota di 90 gradi in senso orario, quindi guida di un quadrato in avanti

Si noti che l'auto non è in grado di girare abbastanza bruscamente da eseguire una svolta di 180 gradi su un singolo quadrato.

Alcune piazze sono ostacoli. Se l'auto entra in una piazza ad ostacoli, si schianta. Si presume che tutto al di fuori del percorso 8x8 sia un ostacolo, quindi guidare fuori dal percorso equivale a schiantarsi.

Il quadrato in basso a destra è il quadrato sicuro, che consente all'auto di sfuggire alla corsa ad ostacoli. Si presume che il quadrato di partenza e il quadrato sicuro non siano ostacoli.

Compito

È necessario scrivere un programma o una funzione che assume come input un array 8x8 (matrice, elenco di elenchi, ecc.), Che rappresenta la corsa ad ostacoli. Il programma restituisce o stampa un valore booleano o qualcosa di altrettanto vero. Se è possibile per l'auto arrivare al quadrato sicuro senza schiantarsi (cioè, se la mappa è risolvibile), l'output è True, altrimenti lo è False.

punteggio

Regole standard del codice golf: il vincitore è il codice con il minor numero di byte.

bonus:

  • Se, per una mappa risolvibile, il tuo codice genera una serie valida di input del conducente che guidano l'auto verso il quadrato sicuro, deduci 10 punti percentuali dal tuo punteggio. Un formato di output di esempio potrebbe essere SRSSR(che indica Straight, Right, Straight, Straight, Right). Questa uscita sostituirà l' Trueoutput standard .

  • Se, per una mappa irrisolvibile, l'output del tuo codice distingue tra situazioni in cui un incidente è inevitabile e situazioni in cui è possibile percorrere per sempre la corsa ad ostacoli, dedurre 10 punti percentuali dal punteggio. Un esempio potrebbe essere Crashse un incidente è inevitabile o Stuckse la macchina è bloccata per sempre nella corsa ad ostacoli. Questi output sostituiranno l' Falseoutput standard per una mappa irrisolvibile.

Esempio

Se al programma viene assegnato un array 8x8 come questo:

[[0, 0, 0, 0, 0, 1, 0, 0],
 [0, 0, 0, 0, 0, 0, 1, 0], 
 [1, 1, 0, 0, 0, 0, 0, 0], 
 [0, 1, 0, 1, 0, 0, 0, 0], 
 [0, 0, 1, 1, 0, 0, 0, 0], 
 [0, 0, 0, 0, 1, 0, 1, 0], 
 [0, 0, 0, 0, 0, 0, 1, 0], 
 [0, 1, 1, 0, 0, 0, 1, 0]]

Sarebbe interpretato come una mappa come questa, con quadrati neri che indicano ostacoli:

inserisci qui la descrizione dell'immagine

E una possibile soluzione potrebbe essere:

inserisci qui la descrizione dell'immagine

Poiché esiste una soluzione, il programma dovrebbe restituire / stampare Trueper questa mappa. La sequenza di mosse mostrata qui è SSSSRSRRRSRSSRRRSSRSSS.


2
Ho scritto alcuni casi di test incredibilmente semplici per Crashe Stuck. Sono qui per quanto tempo sono. Riga 2 riempita, tutto il resto vuoto -> Crash. Riga 7 riempita, tutto il resto vuoto ->Stuck
undergroundmonorail

3
Sono confuso riguardo ai punti percentuali (al contrario delle percentuali). Ottenere uno dei bonus moltiplica il tuo punteggio per 0,9. Ottenere entrambi lo moltiplica per 0,8 o 0,9 ^ 2?
undergroundmonorail,

3
Certo, S e C stanno bene. Le mie uscite erano solo suggerimenti.
fosgene,

13
"Due errori non fanno un diritto, ma tre sinistre lo fanno." - Papà.
hoosierEE,

2
"La tua auto può fare solo zero o tre sinistre!"
feersum

Risposte:


17

JavaScript (ES6) - 122 124 148 162 172 178 187 190 193 208 byte

Mille grazie a Optimizer e DocMax per suggerimenti utili su come migliorare questo codice:

F=a=>(D=(x,y,d)=>!D[i=[x,y,d]]&&(D[i]=1,x-=~d%2,y-=~-~d%2,x*y==49||!((x|y)&8||a[y][x])&&(D(x,y,d)||D(x,y,~-d%4))),D(-1,0))

Restituisce true(verità) per risolvibile e false(falsa) per irrisolvibile.

Funziona solo con Firefox a partire da oggi grazie alle funzionalità di JavaScript 1.7.

Scheda di test


1
Questo è 193 byte: D=(x,y,d,t,a)=>!t[i=x+y*8+d*64]&&(t[i]=1,x+=d==0?1:d==2?-1:0,y+=d==1?1:d==3?-1:0,x==7&&y==7||!((x|y)&~7||a[y][x])&&G(x,y,d,t,a));G=(x,y,d,t,a)=>D(x,y,d,t,a)||D(x,y,d+1&3,t,a);F=a=>G(0,0,0,[],a).
Ottimizzatore

1
172: D=d=>!t[i=x+y*8+d/4]&&(t[i]=1,x+=d?d^2?0:-1:1,y+=d^1?d^3?0:-1:1,x==7&&y==7||!((x|y)&~7||b[y][x])&&G(x,y,d));G=(X,Y,d)=>D(d,x=X,y=Y)||D(d+1&3,x=X,y=Y);F=a=>G(0,0,0,b=a,t={})- Testato.
Ottimizzatore

1
@Optimizer Sto ancora diventando realtà per il secondo caso di test [[0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]. Questo dovrebbe dare falso.
io e il mio gatto,

2
Questo perché dal momento xe ysono entrambi globali, non è possibile eseguire due casi di test prima di ricaricare la pagina ...
Optimizer

1
Puoi salvare un totale di altri 9 sostituendo x+=d?d^2?0:-1:1con x+=d&1?0:1-de y+=d^1?d^3?0:-1:1con y+=d&1&&2-d.
DocMax,

10

Python 2 - 123 125 133 146 148 150 154 160

Truesul successo, Falsesul fallimento.

def f(h=1,v=0,b=0,x=0,y=0,c=[]):s=x,y,h,v;a=b,x+h,y+v,c+[s];return(s in c)==(x|y)&8==b[y][x]<(x&y>6or f(h,v,*a)|f(-v,h,*a))

È necessario fornire input come f(b=var_containing_board).

Versione Lambda - 154

Restituisce 0(falsa) per fallimento, Trueper successo.

F=lambda b,x=0,y=0,h=1,v=0,c=[]:0if[x,y,h,v]in c or x|y>7or x|y<0 or b[y][x]else x&y==7or F(b,x+h,y+v,h,v,c+[[x,y,h,v]])or F(b,x+h,y+v,-v,h,c+[[x,y,h,v]])

Grazie a Will e Brandon per aver reso la funzione più corta della lambda. Anche per aggiungere più scorrimento orizzontale: D

Grazie a xnor per bit-bashing e logica superiori!

Modifica nota: sono ragionevolmente fiducioso che b[y][x]non verrà mai eseguito quando si esce dal range. Dal momento che siamo fuori dal tabellone, il controllo della cronologia s in csarà False. Quindi (x|y)&8sarà il controllo dei confini 8. Quindi Python non controllerà nemmeno l'ultimo valore di ==perché i primi due sono già diversi.


1
La versione funzionale può combinare i due if che ritornano entrambi; dato che il ritorno da solo restituisce Nessuno che è falso, non è necessario restituire 0. Solo ritorno al favore;)
Will

Se lanci i controlli puoi anche combinare entrambi i se
Will

Puoi combinare entrambe le dichiarazioni di reso?
Brandon,

1
@Will Grazie, sapevo che c'era un modo migliore per farlo: D Um, non sono riuscito a trovare spazi da rimuovere che non mi causassero errori di sintassi. Non capisco perché x|y>7orx|y<0or
funzioni,

1
Puoi fare un inizio letterale ottale con 0o.
feersum

9

C (GNU-C), 163 byte * 0,9 = 146,7

#C (GNU-C), 186 byte * 0,9 = 167,4

La mia nuova versione utilizza un numero intero con segno anziché senza segno. In precedenza avevo paura del turno giusto firmato, ma mi sono reso conto che il bit del segno è il quadrato dell'obiettivo, non importa cosa succede dopo.

La funzione accetta una matrice di bit (quelli rappresentano quadrati bloccati) sotto forma di un numero intero a 64 bit. I bit sono disposti dal meno significativo al più nello stesso modo in cui si legge un libro. Restituisce -1 per un incidente, 0 per la guida per sempre o 1 per la fuga nell'angolo in basso a destra.

g(long long o) {
    typeof(o) a=0,i=255,r=1,u=0,l=0,d=0,M=~0LLU/i,D;
    for( ;i--;d = D<<8&~o)
        a |= D = d|r,
        r = (r|u)*2&~M&~o,
        u = (u|l)>>8&~o,
        l = ((l|d)&~M)/2&~o;
    return a<0?:-!(d|r|u|l);
}

Programma di test

f(long long o){typeof(o)a=0,i=255,r=1,u=0,l=0,d=0,M=~0LLU/i,D;for(;i--;d=D<<8&~o)a|=D=d|r,r=(r|u)*2&~M&~o,u=(u|l)>>8&~o,l=((l|d)&~M)/2&~o;return a<0?:-!(d|r|u|l);}
{
    char* s[] = {"Crash", "Stuck", "Escape"};
    #define P(x) puts(s[f(x)+1])
    L ex = 0x4640500C0A034020;
    P(ex);
    L blocked = 0x4040404040404040;
    P(blocked);

    L dead = 0x10002;
    P(dead);

    return 0;
}

Produzione

Escape
Stuck
Crash

Convertitore da array a esadecimale Python:

a2b=lambda(A):"0x%X"%sum(A[i/8][i%8]<<i for i in range(64))

1
Sostituire memset(&M,~1,8)(15 caratteri) con M=~(-1ULL/255)(14 caratteri).
R ..

@R .. Bello! -4 byte da quello.
feersum

2
Mi piace il formato di input - molto bello!
fosgene,

Sto ottenendo 'crash' per P(0x00fefefefefefefe);= (Dovrebbe essere sparato dritto in alto a destra, un giro, dritto in angolo. Lo stesso per P(0x00eeeeeeeeeeeeee);(vicolo cieco al 4 ° passo). Non credo che devi assegnare ainizialmente.

@tolos Hai trasposto l'ordine di riga / colonna-maggiore. Per avere la riga superiore e la colonna destra aperte, dovrebbe essere 0x7f7f7f7f7f7f7f00. Inoltre è necessario inizializzare aperché in seguito viene modificato solo da ORing in bit aggiuntivi, quindi non posso permettermi di impostare inizialmente un bit indesiderato.
feersum

6

Python, 187 213

207 caratteri, bonus del 10% per il percorso di stampa

b=map(ord," "*9+" ".join("".join("o "[i]for i in j)for j in input())+" "*9)
def r(p,d,s):
 p+=(1,9,-1,-9)[d]
 if b[p]&1<<d:b[p]^=1<<d;return(s+"S")*(p==79)or r(p,d,s+"S")or r(p,(d+1)%4,s+"R")
print r(8,0,"")

Nell'input del test trova un percorso leggermente diverso: SSSSRSRSRRSSRSSRRSRSSRSSSSS

L'approccio generale consiste nel trasformare prima l'input in spazi e os. Gli spazi hanno un esagono di 20, quindi tutti e quattro i bit inferiori non sono impostati. oha un esagono di 6F, quindi i quattro bit bassi sono tutti impostati.

Un bordo di os è posizionato attorno al tabellone, quindi non dobbiamo preoccuparci di indici negativi.

Mentre camminiamo sul tabellone, usiamo i bit di ogni tessera per vedere se ci è permesso di passare quando arriviamo da quel lato. In questo modo, evitiamo loop infiniti. Non è sufficiente avere un solo booleano per tessera, poiché la direzione di uscita dipende dalla direzione di entrata, quindi le tessere possono essere visitate due volte.

Facciamo quindi una ricerca ricorsiva per un percorso sicuro.


3
"La tua auto inizia nell'angolo in alto a sinistra di una mappa 8x8" - non puoi hardcode 9al posto di w=len(b[0])+1, ecc.?
FryAmTheEggman,

@FryAmTheEggman grazie, come ho potuto ignorarlo? : D
Sarà il

È possibile invertire la dichiarazione ternaria e sostituirla p==79con p-79. Ho riscontrato un errore di sintassi nel fare ciò in entrambi i modi senza uno spazio prima di else. Penso che quel trucco funzioni solo con if.
FryAmTheEggman,

@FryAmTheEggman Penso che il test di profondità debba essere eseguito prima della recurse? Invece ho giocato con una moltiplicazione booleana.
Sarà il

7
Ho appena trovato un trucco davvero pulito. Probabilmente sai che -~x== x+1ma entrambi gli operatori unari hanno una precedenza maggiore rispetto a moltiplicazione, divisione e modulo! Quindi (d+1)%4potrebbe essere -~d%4! Funzionerebbe anche con questo, x-1ma basta usare ~-xinvece.
FryAmTheEggman,

6

Javascript - 270 - 20% = 216 262 - 20% = 210 byte

Dal momento che dovrebbe esserci almeno una soluzione che guadagna entrambi i bonus (e non porta a una ridicola profondità dello stack;) ...

minified:

V=I=>{n=[N=[0,0,0]];v={};v[N]='';O='C';for(S='';n[0];){m=[];n.map(h=>{[x,y,d]=h;D=i=>[1,0,-1,0][d+i&3];p=v[h];for(j=2;j--;){O=v[c=[X=x+D(j),Y=y+D(3-3*j)),d+j&3]]?'K':O;J=X|Y;J<0||J>7||I[Y][X]||v[c]?O:(m.push(c),v[c]=p+'SR'[j])}S=(x&y)>6?p:S});n=m;}return S||O;};

Allargato:

V = I => {
    n = [N=[0,0,0]];
    v = {};
    v[N] = '';
    O = 'C';

    for( S = ''; n[0]; ) {
        m = [];
        n.map( h => {
            [x,y,d] = h;
            D = i => [1,0,-1,0][d+i&3];
            p = v[h];
            for( j = 2; j--; ) {
                O = v[c = [X = x+D(j),Y = y+D(3-3*j),d+j&3]] ? 'K' : O;
                J = X|Y;
                J<0 || J>7 || I[Y][X] || v[c] ? O : (
                    m.push( c ),
                    v[c] = p + 'SR'[j]
                );
            }

            S = (x&y) > 6 ? p : S;
        } );
        n = m;
    }
    return S || O;
};

vè una tabella hash con chiavi che sono triple di stato (x,y,d)corrispondenti alla coordinata (x, y) e alla direzione di entrata d. Ogni chiave ha un valore associato che è la stringa di mosse S(diritte) e R(svolta a destra) necessarie per raggiungere lo stato rappresentato dalla chiave.

Il codice mantiene anche una pila di triple (in variabile n) che non sono state ancora elaborate. Lo stack inizialmente contiene solo il triplo (0,0,0), corrispondente allo stato in cui l'auto si trova proprio nella cella (0,0). Nel ciclo esterno for( S = ... ), la routine controlla se rimangono delle triple non elaborate. In caso affermativo, viene eseguito ogni greggio tripla attraverso l'anello interno, n.map( ....

Il ciclo interno fa cinque cose:

  1. calcola le due mosse possibili (guida dritta, svolta a destra) fuori dallo stato attuale
  2. se una di queste mosse porta a uno stato già registrato nella tabella hash, viene ignorato per ulteriori elaborazioni. Contrassegniamo l'uscita FALSO come K(bloccato), tuttavia, poiché abbiamo trovato almeno un loop in cui l'auto può continuare a circolare per sempre senza schiantarsi.
  3. se uno stato è legale e nuovo, viene aggiunto all'hashtable ( v) e alla pila di triple non elaborate ( m) per il passaggio successivo del ciclo esterno
  4. quando il nuovo stato è registrato v, il suo valore è impostato sul valore dello stato di origine (la sequenza di mosse) più Ro in Sbase alla mossa corrente
  5. se xe lo ysono 7, il valore dello stato di origine (la sequenza di mosse prese per raggiungere lo stato di origine) viene copiato S, poiché questa sequenza di mosse è una soluzione al problema

Al termine del ciclo interno, n(lo stack) viene sostituito da m(il nuovo stack).

Al termine del loop esterno (non sono stati raggiunti nuovi stati), la funzione restituisce il suo output. Se la cella (7,7) è stata raggiunta, Sconterrà una sequenza di mosse che portano a questa cella, e questo viene emesso. Se la cella non è stata raggiunta, Ssarà la stringa vuota e la routine cadrà in uscita O, che conterrà K(bloccato) se e solo se è stato trovato un ciclo, o C(incidente) se la macchina si arresta inevitabilmente.


1
Ottenuta conferma da OP, puoi rinominare "Crash" e "Stuck" in "C" e "S".
FryAmTheEggman,

Ah. Ciò consente di risparmiare un po ', quindi. Grazie. ;)
COTO

Puoi spiegare cosa sta facendo il tuo codice? Non riesco a capirlo.
fosgene,

@phosgene: ho incluso una spiegazione dettagliata in linea.
COTO

Questa è una procedura intelligente. Niente è sprecato.
fosgene

4

Python 339 - 10% = 305 byte

Ho usato una ricerca ricorsiva approfondita, che termina presto con successo exit. Anche il percorso di stampa sul successo sotto forma di 00001010101010101010101110100111001000, 0per dritto, 1per giusto. La risposta sarà più lunga che ottimale, poiché è la prima in profondità. Sono sicuro che alcune ottimizzazioni dell'algoritmo potrebbero far abbassare un po 'il conteggio dei byte.

b=input()
D=[(-1,0),(0,-1),(1,0),(0,1)]
def a(l):
 x,y=0,0
 v=2
 for d in l:
  if d=='1':v=(v+1) % 4
  x+=D[v][0]
  y+=D[v][1]
  if x<0 or x>7 or y<0 or y>7:return 0,x,y
  if b[y][x]:return -1,x,y
 return 1,x,y
def c(l):
 if len(l) < 39:
  t,x,y=a(l)
  if t==1:
   if (x,y)==(7,7):
    print l;exit(0)
   c(l+"0")
   c(l+"1")
c("")
print 0

3
Poiché si tratta di Python 2, è possibile mescolare le schede e gli spazi per i rientri, come in a's forciclo. Inoltre, non sono necessari spazi attorno agli operatori, ad es. (v+1) % 4-> (v+1)%4. Puoi anche unire più istruzioni su una riga usando ;se non ci sono ifo for, ecc. Sulla riga, ad es c(l+"0");c(l+"1"). Alcuni altri golf: x,y,v=0,0,2, x|y>7 or x|y<0, x==y==7. Buona fortuna :)
FryAmTheEggman,
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.