Codice Golf: Laser


152

La sfida

Il codice più breve per carattere conta per inserire una rappresentazione 2D di una scheda e produrre "vero" o "falso" in base all'input .

La tavola è composta da 4 tipi di tessere:

 # - A solid wall
 x - The target the laser has to hit
 / or \ - Mirrors pointing to a direction (depends on laser direction)
 v, ^, > or < - The laser pointing to a direction (down, up, right and left respectively)

C'è solo un laser e un solo bersaglio . Le pareti devono formare un solido rettangolo di qualsiasi dimensione, in cui sono posizionati il ​​laser e il bersaglio. Sono possibili pareti all'interno della "stanza".

Il raggio laser spara e viaggia dalla sua origine alla direzione verso cui punta. Se un raggio laser colpisce il muro, si ferma. Se un raggio laser colpisce uno specchio, rimbalza di 90 gradi nella direzione verso cui è rivolto lo specchio. Gli specchi sono a due lati, il che significa che entrambi i lati sono "riflettenti" e possono far rimbalzare un raggio in due modi. Se un raggio laser colpisce il laser ( ^v><) stesso, viene trattato come un muro (il raggio laser distrugge il proiettore e quindi non colpirà mai il bersaglio).

Casi test

Ingresso:
    ##########
    # / \ #
    # #
    # \ X#
    #> / #
    ########## 
Produzione:
    vero

Ingresso:
    ##########
    # vx #
    # / #
    # / #
    # \ #
    ##########
Produzione:    
    falso

Ingresso:
    #############
    # # #
    #> # #
    # # #
    # # X #
    # # #
    #############
Produzione:
    falso

Ingresso:
    ##########
    # / \ / \ / \ #
    # \\ // \\\ #
    # // \ / \ / \\ #
    # \ / \ / \ / X ^ #
    ##########
Produzione:
    vero

Il conteggio del codice include input / output (ovvero programma completo).


84
IMMA CHARGIN 'MAH LAZER!
Ólafur Waage,

37
Questo è impressionante .
GManNickG,

33
NON
ATTRAVERSARE

49
@GameFreak: sta diventando davvero vecchio.
Artelius,

24
Quello è '^' in realtà uno squalo con un lazer strano in testa?
Nathan Feger,

Risposte:


78

Perl, 166 160 caratteri

Perl, 251 248 246 222 214 208 203 201 193 190 180 176 173 170 166 -> 160 caratteri.

La soluzione ha avuto 166 colpi al termine del concorso, ma A. Rex ha trovato un paio di modi per radere altri 6 personaggi:

s!.!$t{$s++}=$&!ge,$s=$r+=99for<>;%d='>.^1<2v3'=~/./g;($r)=grep$d|=$d{$t{$_}},%t;
{$_=$t{$r+=(1,-99,-1,99)[$d^=3*/\\/+m</>]};/[\/\\ ]/&&redo}die/x/?true:false,$/

La prima riga carica l'input in %t, una tabella della board dove $t{99*i+j}contiene il carattere nella riga i , colonna j . Poi,

%d=split//,'>.^1<2v3' ; ($r)=grep{$d|=$d{$t{$_}}}%t

cerca gli elementi di %tun carattere che corrisponde > ^ <o v, e contemporaneamente imposta $dun valore tra 0 e 3 che indica la direzione iniziale del raggio laser.

All'inizio di ogni iterazione nel ciclo principale, aggiorniamo $dse il raggio è attualmente su un mirror. XOR'ing per 3 fornisce il comportamento corretto per un \mirror e XOR'ing per 1 fornisce il comportamento corretto per un /mirror.

$d^=3*/\\/+m</>

Successivamente, la posizione corrente $rviene aggiornata in base alla direzione corrente.

$r+=(1,-99,-1,99)[$d] ; $_ = $t{$r}

Assegniamo il personaggio nella posizione corrente $_per fare comodo uso degli operatori di match.

/[\/\\ ]/ && redo

Continua se ci troviamo su uno spazio vuoto o su un personaggio speculare. Altrimenti terminiamo truese ci troviamo sul target ( $_ =~ /x/) e in falsealtro modo.

Limitazione: potrebbe non funzionare su problemi con più di 99 colonne. Questa limitazione potrebbe essere rimossa a spese di altri 3 caratteri,


Va bene, ho 323 caratteri. = D
strager

5
Posso cambiare da 99 a 1E5 per renderlo molto robusto a spese di 3 caratteri.
mafia il

2
La tua migliore soluzione sarebbe più evidente nella parte superiore del post.
Strager,

13
Ma usando espressioni regolari per ruotare la lavagna? Quello era malato. È come un bonus automatico di 20 colpi.
mob,

1
@mobrule: salva sei tratti: riordina la prima riga come s!.!$t{$s++}=$&!ge,$s=$r+=99for<>; , cambia %d=split//,.." to % d = .. = ~ /./ g , and change grep {..}% t` ingrep..,%t
A. Rex

75

Perl, 177 personaggi

La prima interruzione di riga può essere rimossa; gli altri due sono obbligatori.

$/=%d=split//,' >/^\v';$_=<>;$s='#';{
y/v<^/>v</?do{my$o;$o.=" 
"while s/.$/$o.=$&,""/meg;y'/\\'\/'for$o,$s;$_=$o}:/>x/?die"true
":/>#/?die"false
":s/>(.)/$s$d{$1}/?$s=$1:1;redo}

Spiegazione:

$/ = %d = (' ' => '>', '/' => '^', '\\' => 'v');

Se una trave in movimento a destra corre in uno {spazio vuoto, specchio inclinato in alto, specchio inclinato in basso} diventa un raggio trave destro, trave in movimento, trave in movimento}. Inizializza $/lungo la strada - fortunatamente "6" non è un carattere di input valido.

$_ = <>;

Leggi la lavagna in $_.

$s="#";

$sè il simbolo di qualunque cosa il raggio sia seduto sopra ora. Poiché l'emettitore laser deve essere trattato come un muro, impostarlo come muro per cominciare.

if (tr/v<^/>v</) {
  my $o;
  $o .= "\n" while s/.$/$o .= $&, ""/meg;
  tr,/\\,\\/, for $o, $s;
  $_ = $o;
}

Se il raggio laser punta in qualsiasi modo tranne che a destra, ruotare il suo simbolo, quindi ruotare l'intera scheda in posizione (ruotando anche i simboli per gli specchi). È una rotazione a sinistra di 90 gradi, realizzata efficacemente invertendo le file mentre trasponendo righe e colonne, in modo leggermente diabolico s///econ effetti collaterali. Nel codice golf, il tr è scritto nel modulo y'''che mi permette di saltare una barra rovesciata.

die "true\n" if />x/; die "false\n" if />#/;

Termina con il messaggio giusto se colpiamo il bersaglio o un muro.

$s = $1 if s/>(.)/$s$d{$1}/;

Se c'è uno spazio vuoto davanti al laser, vai avanti. Se c'è uno specchio davanti al laser, spostati in avanti e ruota il raggio. In entrambi i casi, rimetti il ​​"simbolo salvato" nella vecchia posizione del raggio e metti la cosa che abbiamo appena sovrascritto nel simbolo salvato.

redo;

Ripeti fino al termine. {...;redo}è due caratteri in meno di for(;;){...}e tre in meno di while(1){...}.


4
Ruota la scheda ... Pazzo. Regexp ... Più pazzo. O_o
strager,

39
Tu ... Tu mostro!
LiraNuna,

4
LiraNuna: ho scelto di prenderlo come un complimento.
Hobbs,

21
Il golf è finito. Come puoi battere ruotando una scheda 2D con espressioni regolari ?!
Konrad Rudolph,

13
WTF? i programmatori perl sono maghi.
Johannes Schaub - litb,

39

C89 (209 caratteri)

#define M(a,b)*p==*#a?m=b,*p=1,q=p:
*q,G[999],*p=G;w;main(m){for(;(*++p=getchar())>0;)M(<,-1)M
(>,1)M(^,-w)M(v,w)!w&*p<11?w=p-G:0;for(;q+=m,m=*q&4?(*q&1?
-1:1)*(m/w?m/w:m*w):*q&9?!puts(*q&1?"false":"true"):m;);}

Spiegazione

Questa mostruosità sarà probabilmente difficile da seguire se non capisci C. Solo un avvertimento.

#define M(a,b)*p==*#a?m=b,*p=1,q=p:

Questa piccola macro controlla se il carattere corrente ( *p) è uguale a qualsiasi cosa asia in forma di carattere ( *#a). Se sono uguali, imposta il vettore di movimento su b( m=b), contrassegna questo carattere come un muro ( *p=1) e imposta il punto iniziale sulla posizione corrente ( q=p). Questa macro include la parte "else".

*q,G[999],*p=G;
w;

Dichiarare alcune variabili. * qè la posizione corrente della luce. * Gè il tabellone di gioco come un array 1D. * pè la posizione di lettura corrente durante il popolamento G. * wè la larghezza della tavola.

main(m){

Ovvio main. mè una variabile che memorizza il vettore di movimento. (È un parametro maincome ottimizzazione.)

    for(;(*++p=getchar())>0;)

Scorri tutti i personaggi, popolando Gusando p. Salta G[0]come ottimizzazione (non è necessario sprecare un personaggio a scrivere di pnuovo nella terza parte del for).

        M(<,-1)
        M(>,1)
        M(^,-w)
        M(v,w)

Utilizzare la macro di cui sopra per definire il lazer, se possibile. -1e 1corrispondono a sinistra e a destra, rispettivamente, e -we wsu e giù.

        !w&*p<11
            ?w=p-G
            :0;

Se il carattere corrente è un indicatore di fine riga (ASCII 10), imposta la larghezza se non è già stato impostato. Il saltato G[0]ci permette di scrivere w=p-Ginvece di w=p-G+1. Inoltre, questo finisce fuori dalla ?:catena M.

    for(;
        q+=m,

Sposta la luce in base al vettore di movimento.

        m=
        *q&4
            ?(*q&1?-1:1)*(
                m/w?m/w:m*w
            )

Riflette il vettore del movimento.

            :*q&9
                ?!puts(*q&1?"false":"true")
                :m
        ;

Se si tratta di un muro o x, chiudere con il messaggio appropriato ( m=0termina il ciclo). Altrimenti, non fare nulla (noop; m=m)

    );
}

8
Ugh! Stavo lavorando a una soluzione C quando suonò l'allarme antincendio nel mio complesso di appartamenti. Ora mi sono battuto. Bella soluzione però.
rlbond

Penso che usare una variabile temp per i tuoi passaggi di swap e swap / negazione ti salverebbe un paio di caratteri.
Artelius,

@Artelius, Sì, me ne sono reso conto, e poche altre cose. Grazie.
Strager,

1
Al TCC in realtà non piacciono le dichiarazioni non tipizzate e gli errori con g.c:3: declaration expected:(
Mark Rushakoff,

2
La putsdichiarazione di rimozione ha aiutato, ma non abbastanza da portarla sotto 170. 209 è piuttosto buona, comunque, quindi penso che la lascerò. Grazie per il vostro aiuto ragazzi. Lo apprezzo molto. =] (Qualsiasi cosa per detronizzare quelle streghe del Perl!)
Strager,

36

Scommetto che la gente lo sta aspettando da LOOOOONG time. (Che cosa vuoi dire, la sfida è finita e a nessuno importa più?)

Ecco ... io presento qui una soluzione

Befunge-93!

Pesa ben 973 caratteri (o 688 se sei abbastanza caritatevole da ignorare gli spazi bianchi, che viene utilizzato solo per la formattazione e non fa nulla nel codice reale).

Avvertenza : ho scritto il mio interprete Befunge-93 in Perl poco tempo fa, e sfortunatamente questo è tutto quello che ho davvero avuto il tempo con cui testarlo. Sono ragionevolmente fiducioso della sua correttezza in generale, ma potrebbe avere una strana limitazione per quanto riguarda EOF: poiché l' <>operatore Perl restituisce undef alla fine del file, questo viene elaborato come 0 nel contesto numerico. Per le implementazioni basate su C in cui EOF ha un valore diverso (-1 dire), questo codice potrebbe non funzionare.

003pv   >~v>  #v_"a"43g-!#v_23g03p33v>v
>39#<*v   ::   >:52*-!v   >"rorrE",vg2*
######1   >^vp31+1g31$_03g13gp vv,,<15,
    a#3     >0v       vp30+1g30<>,,#3^@
######p $     0vg34"a"<   >       >vp
^<v>  > ^   p3<>-#v_:05g-!|>:15g-!| $
 >     v^     <   <   <   >^v-g52:< $ 
  v _  >52*"eslaf",,vv|-g53:_      v   
  : ^-"#">#:< #@,,,,<<>:43p0 v0 p34< 
  >">"-!vgv<  ^0p33g31p32-1g3<       
 ^     <#g1|-g34_v#-g34_v#-g34"><v^"<<<<
    v!<^<33>13g1v>03g1-v>03g1+03p$v  $$
>^  _#-v 1>g1-1v>+13pv >03p       v  pp
^_:"^"^#|^g30 <3#   $<           $<>^33
 ^!-"<":<>"v"v^># p#$<>            $^44
^      >#^#_ :" "-#v_ ^   >         ^gg
v  g34$<   ^!<v"/":< >$3p$^>05g43p$ ^55
 >,@   |!-"\"  :_$43g:">"-!|>      ^$32
 *v"x":<      >-^    ^4g52<>:"^" -#v_^
 5>-!#v_"ror"vv$p34g51:<>#|  !-"<":<#|
 ^2,,, ,,"er"<>v      #^^#<>05g43p$$^>^
      >52*"eurt",,,,,@>15g4 3p$$$$  ^#
>:"v"\:"<"\: "^"   -!#^_-!#^_-!      ^
               >                       ^

Spiegazione

Se non si ha familiarità con la sintassi e l'operazione di Befunge, controllare qui .

Befunge è un linguaggio basato su stack, ma ci sono comandi che consentono di scrivere caratteri nel codice Befunge. Ne approfitto in due punti. Innanzitutto, copio l'intero input sulla scheda Befunge, ma trovo un paio di righe sotto il codice scritto reale. (Naturalmente, questo non è mai realmente visibile quando viene eseguito il codice.)

L'altro posto è vicino all'angolo in alto a sinistra:

######
    a#
######

In questo caso, l'area che ho evidenziato sopra è dove memorizzo un paio di coordinate. La prima colonna nella riga centrale è dove memorizzo la coordinata x per l'attuale "posizione del cursore"; la seconda colonna è dove memorizzo la coordinata y; le successive due colonne servono per memorizzare le coordinate x e y della sorgente del raggio laser quando viene trovata; e la colonna finale (con il carattere 'a') viene infine sovrascritta per contenere la direzione del raggio corrente, che ovviamente cambia quando viene tracciato il percorso del raggio.

Il programma inizia posizionando (0,27) come posizione iniziale del cursore. Quindi l'input viene letto un carattere alla volta e posizionato nella posizione del cursore; le newline semplicemente fanno aumentare la coordinata y e la coordinata x ritorna a 0, proprio come un ritorno a capo reale. Alla fine l'interprete viene letto dall'interprete e il valore di 0 caratteri viene utilizzato per segnalare la fine dell'input e passare alle fasi di iterazione laser. Quando viene letto il carattere laser [<> ^ v], anche questo viene copiato nel repository di memoria (sopra il carattere 'a') e le sue coordinate vengono copiate nelle colonne a sinistra.

Il risultato finale di tutto ciò è che l'intero file viene sostanzialmente copiato nel codice Befunge, leggermente al di sotto del codice effettivo attraversato.

Successivamente, la posizione del raggio viene copiata nuovamente nelle posizioni del cursore e viene eseguita la seguente iterazione:

  • Verificare la direzione del raggio corrente e incrementare o decrementare le coordinate del cursore in modo appropriato. (Lo faccio per primo per evitare di dover affrontare il caso angolare del raggio laser proprio al primo movimento.)
  • Leggi il personaggio in quella posizione.
  • Se il personaggio è "#", metti newline e "false" nella pila, stampa e termina.
  • Confrontalo con tutti i caratteri del raggio [<> ^ v]; se c'è una corrispondenza, stampa anche "false \ n" e termina.
  • Se il personaggio è uno spazio, svuota la pila e continua.
  • Se il personaggio è una barra, prendi la direzione del raggio sulla pila e confrontala con ciascuno dei personaggi di direzione a turno. Quando ne viene trovata una, la nuova direzione viene memorizzata nello stesso punto nel codice e il ciclo si ripete.
  • Se il personaggio è una barra rovesciata, fai sostanzialmente la stessa cosa di cui sopra (tranne che con la mappatura corretta per la barra rovesciata).
  • Se il personaggio è "x", abbiamo colpito il bersaglio. Stampa "true \ n" ed esce.
  • Se il carattere non è nessuno di questi, stampa "errore \ n" ed esce.

Se c'è abbastanza richiesta, cercherò di indicare esattamente dove nel codice tutto ciò è realizzato.


14
+1: solo perché potrebbe essere erroneamente interpretato come un file EXE aperto nel blocco note.
Kyle Rosendo,

1
Uhm ... santo ****. Ho rovinato Befunge, e questo è davvero, davvero impressionante.
Almo,

Codice golf in lingue offuscate ... come burro di arachidi e Cayenna!
wberry,

29

F #, 36 righe, molto leggibile

Ok, solo per avere una risposta là fuori:

let ReadInput() =
    let mutable line = System.Console.ReadLine()
    let X = line.Length 
    let mutable lines = []
    while line <> null do
        lines <- Seq.to_list line :: lines
        line <- System.Console.ReadLine()
    lines <- List.rev lines
    X, lines.Length, lines

let X,Y,a = ReadInput()
let mutable p = 0,0,'v'
for y in 0..Y-1 do
    for x in 0..X-1 do 
        printf "%c" a.[y].[x]
        match a.[y].[x] with 
        |'v'|'^'|'<'|'>' -> p <- x,y,a.[y].[x]
        |_ -> ()
    printfn ""

let NEXT = dict [ '>', (1,0,'^','v')
                  'v', (0,1,'<','>')
                  '<', (-1,0,'v','^')
                  '^', (0,-1,'>','<') ]
let next(x,y,d) =
    let dx, dy, s, b = NEXT.[d]
    x+dx,y+dy,(match a.[y+dy].[x+dx] with
               | '/' -> s
               | '\\'-> b
               | '#'|'v'|'^'|'>'|'<' -> printfn "false"; exit 0
               | 'x' -> printfn "true"; exit 0
               | ' ' -> d)

while true do
    p <- next p    

Campioni:

##########
#   / \  #
#        #
#   \   x#
# >   /  #
##########
true

##########
#   v x  #
# /      #
#       /#
#   \    #
##########
false

#############
#     #     #
# >   #     #
#     #     #
#     #   x #
#     #     #
#############
false

##########
#/\/\/\  #
#\\//\\\ #
#//\/\/\\#
#\/\/\/x^#
##########
true

##########
#   / \  #
#        #
#/    \ x#
#\>   /  #
##########
false

##########
#  /    \#
# / \    #
#/    \ x#
#\^/\ /  #
##########
false

54
POSSO LEGGERE QUESTO QUESTO! MIRACOLOSO!
Jeff Atwood,

17
Il codice Java / C # golf è contato da righe e non da caratteri. Questo è l'handicap.
Nathan Feger,

3
@strager non è deprimente in 3 anni quando sei assunto per mantenere il codice e lo sviluppatore originale se n'è andato da tempo.
Nathan Feger,

Ciò non riesce utilizzando F # in Visual Studio 2010. Seq.to_list non esiste (ok, lo ha cambiato in List), e quindi nella riga 25, corrispondenza del modello incompleta.
Russell,

2
Sì, modifica to_list in toList ora. L'avviso di corrispondenza incompleta va bene; è codice golf, quindi non ho fatto codice come: | _ -> failwith "impossibile"
Brian

29

Golfscript - 83 caratteri (mashup dei miei e degli strager)

La nuova riga è qui per il confezionamento

:|'v^><'.{|?}%{)}?:$@=?{.[10|?).~)1-1]=$+
:$|=' \/x'?\[.\2^.1^'true''false']=.4/!}do

Golfscript - 107 caratteri

La nuova riga è lì solo per chiarezza

10\:@?):&4:$;{0'>^<v'$(:$=@?:*>}do;
{[1 0&--1&]$=*+:*;[{$}{3$^}{1$^}{"true "}{"false"}]@*=' \/x'?=~5\:$>}do$

Come funziona.

La prima riga indica la posizione e la direzione iniziali.
La seconda riga passa attraverso la rotazione ogni volta che il laser colpisce uno specchio.


18

353 caratteri in Ruby:

314 277 caratteri adesso!

OK, 256 caratteri in Ruby e ora ho finito. Bel numero rotondo a cui fermarsi. :)

247 caratteri. Non riesco a smettere.

223 203 201 caratteri in Ruby

d=x=y=-1;b=readlines.each{|l|d<0&&(d="^>v<".index l[x]if x=l.index(/[>^v<]/)
y+=1)};loop{c=b[y+=[-1,0,1,0][d]][x+=[0,1,0,-1][d]]
c==47?d=[1,0,3,2][d]:c==92?d=3-d:c==35?(p !1;exit):c<?x?0:(p !!1;exit)}

Con spazi bianchi:

d = x = y = -1
b = readlines.each { |l|
  d < 0 && (d = "^>v<".index l[x] if x = l.index(/[>^v<]/); y += 1)
}

loop {
  c = b[y += [-1, 0, 1, 0][d]][x += [0, 1, 0, -1][d]]

  c == 47 ? d = [1, 0, 3, 2][d] :
  c == 92 ? d = 3 - d :
  c == 35 ? (p !1; exit) :
  c < ?x ? 0 : (p !!1; exit)
}

Leggermente refactored:

board = readlines

direction = x = y = -1
board.each do |line|
  if direction < 0
    x = line.index(/[>^v<]/)
    if x
      direction = "^>v<".index line[x]
    end
    y += 1
  end
end

loop do
  x += [0, 1, 0, -1][direction]
  y += [-1, 0, 1, 0][direction]

  ch = board[y][x].chr
  case ch
  when "/"
    direction = [1, 0, 3, 2][direction]
  when "\\"
    direction = 3 - direction
  when "x"
    puts "true"
    exit
  when "#"
    puts "false"
    exit
  end
end

Ma ... è possibile rinominare cha Co qualsiasi altra lettera 1 carattere per salvare 2 caratteri!
LiraNuna,

Ok ok, bene ... In realtà mi sono reso conto che l'intera variabile non è necessaria poiché la uso solo una volta. Questo e un paio di altri miglioramenti lo hanno ridotto a 247 caratteri.
Jeremy Ruten,

1
No i++(invece di i+=1)?
LiraNuna,

6
No. Puoi fare ++ i, ma lo rende davvero davvero così positivo come una volta.
DigitalRoss,

Mi piace la versione compressa: #; p
SeanJA,

17

Pitone

294 277 253 240 232 caratteri incluse le nuove righe:

(il primo carattere nelle righe 4 e 5 è una scheda, non spazi)

l='>v<^';x={'/':'^<v>','\\':'v>^<',' ':l};b=[1];r=p=0
while b[-1]:
 b+=[raw_input()];r+=1
 for g in l:
    c=b[r].find(g)
    if-1<c:p=c+1j*r;d=g
while' '<d:z=l.find(d);p+=1j**z;c=b[int(p.imag)][int(p.real)];d=x.get(c,' '*4)[z]
print'#'<c

Avevo dimenticato che Python aveva anche punti e virgola opzionali.

Come funziona

L'idea chiave dietro questo codice sta usando numeri complessi per rappresentare posizioni e direzioni. Le file sono l'asse immaginario, aumentando verso il basso. Le colonne sono l'asse reale, aumentando verso destra.

l='>v<^';un elenco dei simboli laser. L'ordine viene scelto in modo che l'indice di un carattere di direzione laser corrisponda a una potenza di sqrt (-1)

x={'/':'^<v>','\\':'v>^<',' ':l};una tabella di trasformazione che determina come cambia la direzione quando la trave lascia tessere diverse. Il riquadro è la chiave e le nuove direzioni sono i valori.

b=[1];tiene il tavolo. Il primo elemento è 1 (viene considerato vero) in modo che il ciclo while venga eseguito almeno una volta.

r=p=0 rè il numero di riga corrente dell'ingresso, pè la posizione corrente del raggio laser.

while b[-1]: interrompere il caricamento dei dati della scheda quando raw_input restituisce una stringa vuota

b+=[raw_input()];r+=1 aggiungere la riga successiva di input alla scheda e incrementare il contatore di righe

for g in l: indovina a turno ogni direzione del laser

c=b[r].find(g) imposta la colonna sulla posizione del laser o -1 se non è nella linea (o punta in una direzione diversa)

if-1<c:p=c+1j*r;d=gse abbiamo trovato un laser, quindi impostare la posizione pe la direzione correnti d. dè uno dei caratteri inl

Dopo aver caricato la scheda b, la posizione pe la direzione correnti dsono state impostate su quelle della sorgente laser.

while' '<d: lo spazio ha un valore ASCII più basso di qualsiasi altro simbolo di direzione, quindi lo usiamo come flag di stop.

z=l.find(d);indice del carattere di direzione corrente nella lstringa. zviene utilizzato in seguito sia per determinare la nuova direzione del raggio utilizzando la xtabella, sia per aumentare la posizione.

p+=1j**z;incrementare la posizione usando una potenza di i. Per esempio,l.find('<')==2 -> i ^ 2 = -1, che si sposterà a sinistra di una colonna.

c=b[int(p.imag)][int(p.real)]; leggi il carattere nella posizione corrente

d=x.get(c,' '*4)[z]cercare la nuova direzione per la trave nella tabella di trasformazione. Se il carattere corrente non esiste nella tabella, impostare dlo spazio.

print'#'<c print false se ci fermiamo su qualcosa di diverso dalla destinazione.


9
p+=1j**z: È dolce.
dmckee --- ex gattino moderatore,

16

Questa è stata una porta diretta della soluzione di Brian a C # 3, meno le interazioni della console. Questa non è una voce nella sfida poiché non è un programma completo, mi stavo solo chiedendo come alcuni dei costrutti F # che ha usato potessero essere rappresentati in C #.

bool Run(string input) {
    var a = input.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
    var p = a.SelectMany((line, y) => line.Select((d, x) => new {x, y, d}))
             .First(x => new[] {'v', '^', '<', '>'}.Contains(x.d));
    var NEXT = new[] {
            new {d = '>', dx = 1, dy = 0, s = '^', b = 'v'},
            new {d = 'v', dx = 0, dy = 1, s = '<', b = '>'},
            new {d = '<', dx = -1, dy = 0, s = 'v', b = '^'},
            new {d = '^', dx = 0, dy = -1, s = '>', b = '<'}
        }.ToDictionary(x => x.d);
    while (true) {
        var n = NEXT[p.d];
        int x = p.x + n.dx,
            y = p.y + n.dy;
        var d = a[y][x];
        switch (d) {
            case '/':  d = n.s; break;
            case '\\': d = n.b; break;
            case ' ':  d = p.d; break;
            default: return d == 'x';
        }
        p = new {x, y, d};
    }
}

Modifica: dopo alcuni esperimenti, il seguente codice di ricerca piuttosto dettagliato:

int X = a[0].Length, Y = a.Length;
var p = new {x = 0, y = 0, d = 'v'};
for (var y = 0; y < Y; y++) {
    for (var x = 0; x < X; x++) {
        var d = a[y][x];
        switch (d) {
            case 'v': case '^': case '<': case '>':
                p = new {x, y, d}; break;
        }
    }
}

è stato sostituito con un codice LINQ to Objects molto più compatto:

var p = a.SelectMany((line, y) => line.Select((d, x) => new {x, y, d}))
         .First(x => new[] {'v', '^', '<', '>'}.Contains(x.d));

8
Oh mio Dio. Che bell'esempio per dimostrare quanto sono diventati potenti linq e c #. 1+ perché sono un grande fan di c #. x)
Emiswelt,

16

F #, 255 caratteri (e ancora piuttosto leggibile!):

Ok, dopo una notte di riposo, ho migliorato molto questo:

let a=System.Console.In.ReadToEnd()
let w,c=a.IndexOf"\n"+1,a.IndexOfAny[|'^';'<';'>';'v'|]
let rec n(c,d)=
 let e,s=[|-w,2;-1,3;1,0;w,1|].[d]
 n(c+e,match a.[c+e]with|'/'->s|'\\'->3-s|' '->d|c->printfn"%A"(c='x');exit 0)
n(c,"^<>v".IndexOf a.[c])

Parliamone riga per riga.

Innanzitutto, assorbi tutto l'input in un grande array monodimensionale (gli array 2D possono essere dannosi per il golf del codice; basta usare un array 1D e aggiungere / sottrarre la larghezza di una linea all'indice per spostarsi su / giù).

Quindi calcoliamo 'w', la larghezza di una linea di input, e 'c', la posizione iniziale, indicizzando nel nostro array.

Ora definiamo la 'prossima' funzione 'n', che assume una posizione corrente 'c' e una direzione 'd' che è 0,1,2,3 per su, sinistra, destra, giù.

L'indice-epsilon 'e' e il what-new-direction-if-we-hit-a-slash 's' sono calcolati da una tabella. Ad esempio, se la direzione corrente 'd' è 0 (su), il primo elemento della tabella dice "-w, 2", il che significa che diminuiamo l'indice di w, e se colpiamo una barra la nuova direzione è 2 (giusto).

Ora rientriamo nella prossima funzione 'n' con (1) l'indice successivo ("c + e" - current plus epsilon) e (2) la nuova direzione, che calcoliamo guardando avanti per vedere cosa c'è nell'array in quella cella successiva. Se il carattere lookahead è una barra, la nuova direzione è 's'. Se si tratta di una barra rovesciata, la nuova direzione è 3-s (la nostra scelta della codifica 0123 fa sì che funzioni). Se è uno spazio, continuiamo semplicemente nella stessa direzione "d". E se è un altro personaggio 'c', il gioco finisce, stampa 'vero' se il carattere era 'x' e falso altrimenti.

Per dare il via alle cose, chiamiamo la funzione ricorsiva 'n' con la posizione iniziale 'c' e la direzione iniziale (che fa la codifica iniziale della direzione in 0123).

Penso che probabilmente potrò ancora radere qualche altro personaggio, ma sono abbastanza contento di questo (e 255 è un bel numero).


11

Con un peso di 18203 caratteri è una soluzione Python che può:

  • far fronte agli specchi fuori dalla "stanza"
  • calcola la traiettoria quando non c'è "spazio" sulla base di limitazioni 2D (la specifica dice molto su ciò che deve essere nella "stanza" ma non se la stanza deve esistere)
  • riferire sugli errori

Ha ancora bisogno di essere riordinato un po 'e non so se la fisica 2D imponga che il raggio non possa attraversare se stesso ...

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
The shortest code by character count to input a 2D representation of a board, 
and output 'true' or 'false' according to the input.

The board is made out of 4 types of tiles:

# - A solid wall
x - The target the laser has to hit
/ or \ - Mirrors pointing to a direction (depends on laser direction)
v, ^, > or < - The laser pointing to a direction (down, up, right and left
respectively)

There is only one laser and only one target. Walls must form a solid rectangle 
of any size, where the laser and target are placed inside. Walls inside the
'room' are possible.

Laser ray shots and travels from it's origin to the direction it's pointing. If
a laser ray hits the wall, it stops. If a laser ray hits a mirror, it is bounces
90 degrees to the direction the mirror points to. Mirrors are two sided, meaning
both sides are 'reflective' and may bounce a ray in two ways. If a laser ray
hits the laser (^v><) itself, it is treated as a wall (laser beam destroys the
beamer and so it'll never hit the target).
"""



SOLID_WALL, TARGET, MIRROR_NE_SW, MIRROR_NW_SE, LASER_DOWN, LASER_UP, \
LASER_RIGHT, LASER_LEFT = range(8)

MIRRORS = (MIRROR_NE_SW, MIRROR_NW_SE)

LASERS = (LASER_DOWN, LASER_UP, LASER_RIGHT, LASER_LEFT)

DOWN, UP, RIGHT, LEFT = range(4)

LASER_DIRECTIONS = {
    LASER_DOWN : DOWN,
    LASER_UP   : UP,
    LASER_RIGHT: RIGHT,
    LASER_LEFT : LEFT
}

ROW, COLUMN = range(2)

RELATIVE_POSITIONS = {
    DOWN : (ROW,     1),
    UP   : (ROW,    -1),
    RIGHT: (COLUMN,  1),
    LEFT : (COLUMN, -1)
}

TILES = {"#" : SOLID_WALL,
         "x" : TARGET,
         "/" : MIRROR_NE_SW,
         "\\": MIRROR_NW_SE,
         "v" : LASER_DOWN,
         "^" : LASER_UP,
         ">" : LASER_RIGHT,
         "<" : LASER_LEFT}

REFLECTIONS = {MIRROR_NE_SW: {DOWN : LEFT,
                              UP   : RIGHT,
                              RIGHT: UP,
                              LEFT : DOWN},
               MIRROR_NW_SE: {DOWN : RIGHT,
                              UP   : LEFT,
                              RIGHT: DOWN,
                              LEFT : UP}}



def does_laser_hit_target(tiles):
    """
        Follows a lasers trajectory around a grid of tiles determining if it
        will reach the target.

        Keyword arguments:
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
    """

    #Obtain the position of the laser
    laser_pos = get_laser_pos(tiles)

    #Retrieve the laser's tile
    laser = get_tile(tiles, laser_pos)

    #Create an editable starting point for the beam
    beam_pos = list(laser_pos)

    #Create an editable direction for the beam
    beam_dir = LASER_DIRECTIONS[laser]

    #Cache the number of rows
    number_of_rows = len(tiles)

    #Keep on looping until an ultimate conclusion
    while True:

        #Discover the axis and offset the beam is travelling to
        axis, offset = RELATIVE_POSITIONS[beam_dir]

        #Modify the beam's position
        beam_pos[axis] += offset

        #Allow for a wrap around in this 2D scenario
        try:

            #Get the beam's new tile
            tile = get_tile(tiles, beam_pos)

        #Perform wrapping
        except IndexError:

            #Obtain the row position
            row_pos = beam_pos[ROW]

            #Handle vertical wrapping
            if axis == ROW:

                #Handle going off the top
                if row_pos == -1:

                    #Move beam to the bottom
                    beam_pos[ROW] = number_of_rows - 1

                #Handle going off the bottom
                elif row_pos == number_of_rows:

                    #Move beam to the top
                    beam_pos[ROW] = 0

            #Handle horizontal wrapping
            elif axis == COLUMN:

                #Obtain the row
                row = tiles[row_pos]

                #Calculate the number of columns
                number_of_cols = len(row)

                #Obtain the column position
                col_pos = beam_pos[COLUMN]

                #Handle going off the left hand side
                if col_pos == -1:

                    #Move beam to the right hand side
                    beam_pos[COLUMN] = number_of_cols - 1

                #Handle going off the right hand side
                elif col_pos == number_of_cols:

                    #Move beam to the left hand side
                    beam_pos[COLUMN] = 0

            #Get the beam's new tile
            tile = get_tile(tiles, beam_pos)

        #Handle hitting a wall or the laser
        if tile in LASERS \
        or tile == SOLID_WALL:
            return False

        #Handle hitting the target
        if tile == TARGET:
            return True

        #Handle hitting a mirror
        if tile in MIRRORS:
            beam_dir = reflect(tile, beam_dir)

def get_laser_pos(tiles):
    """
        Returns the current laser position or an exception.

        Keyword arguments:
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
    """

    #Calculate the number of rows
    number_of_rows = len(tiles)

    #Loop through each row by index
    for row_pos in range(number_of_rows):

        #Obtain the current row
        row = tiles[row_pos]

        #Calculate the number of columns
        number_of_cols = len(row)

        #Loop through each column by index
        for col_pos in range(number_of_cols):

            #Obtain the current column
            tile = row[col_pos]

            #Handle finding a laser
            if tile in LASERS:

                #Return the laser's position
                return row_pos, col_pos

def get_tile(tiles, pos):
    """
        Retrieves a tile at the position specified.

        Keyword arguments:
        pos --- a row/column position of the tile
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
    """

    #Obtain the row position
    row_pos = pos[ROW]

    #Obtain the column position
    col_pos = pos[COLUMN]

    #Obtain the row
    row = tiles[row_pos]

    #Obtain the tile
    tile = row[col_pos]

    #Return the tile
    return tile

def get_wall_pos(tiles, reverse=False):
    """
        Keyword arguments:
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
        reverse --- whether to search in reverse order or not (defaults to no)
    """

    number_of_rows = len(tiles)

    row_iter = range(number_of_rows)

    if reverse:
        row_iter = reversed(row_iter)

    for row_pos in row_iter:
        row = tiles[row_pos]

        number_of_cols = len(row)

        col_iter = range(number_of_cols)

        if reverse:
            col_iter = reversed(col_iter)

        for col_pos in col_iter:
            tile = row[col_pos]

            if tile == SOLID_WALL:
                pos = row_pos, col_pos

                if reverse:
                    offset = -1
                else:
                    offset = 1

                for axis in ROW, COLUMN:
                    next_pos = list(pos)

                    next_pos[axis] += offset

                    try:
                        next_tile = get_tile(tiles, next_pos)
                    except IndexError:
                        next_tile = None

                    if next_tile != SOLID_WALL:
                        raise WallOutsideRoomError(row_pos, col_pos)

                return pos

def identify_tile(tile):
    """
        Returns a symbolic value for every identified tile or None.

        Keyword arguments:
        tile --- the tile to identify
    """

    #Safely lookup the tile
    try:

        #Return known tiles
        return TILES[tile]

    #Handle unknown tiles
    except KeyError:

        #Return a default value
        return

def main():
    """
        Takes a board from STDIN and either returns a result to STDOUT or an
        error to STDERR.

        Called when this file is run on the command line.
    """

    #As this function is the only one to use this module, and it can only be
    #called once in this configuration, it makes sense to only import it here.
    import sys

    #Reads the board from standard input.
    board = sys.stdin.read()

    #Safely handles outside input
    try:

        #Calculates the result of shooting the laser
        result = shoot_laser(board)

    #Handles multiple item errors
    except (MultipleLaserError, MultipleTargetError) as error:

        #Display the error
        sys.stderr.write("%s\n" % str(error))

        #Loop through all the duplicated item symbols
        for symbol in error.symbols:

            #Highlight each symbol in green
            board = board.replace(symbol, "\033[01;31m%s\033[m" % symbol)

        #Display the board
        sys.stderr.write("%s\n" % board)

        #Exit with an error signal
        sys.exit(1)

    #Handles item missing errors
    except (NoLaserError, NoTargetError) as error:

        #Display the error
        sys.stderr.write("%s\n" % str(error))

        #Display the board
        sys.stderr.write("%s\n" % board)

        #Exit with an error signal
        sys.exit(1)

    #Handles errors caused by symbols
    except (OutsideRoomError, WallNotRectangleError) as error:

        #Displays the error
        sys.stderr.write("%s\n" % str(error))

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

        line = "%s\033[01;31m%s\033[m%s" % (before, symbol, after)

        lines[error.row_pos] = line

        board = "\n".join(lines)

        #Display the board
        sys.stderr.write("%s\n" % board)

        #Exit with an error signal
        sys.exit(1)

    #Handles errors caused by non-solid walls
    except WallNotSolidError as error:

        #Displays the error
        sys.stderr.write("%s\n" % str(error))

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

        line = "%s\033[01;5;31m#\033[m%s" % (before, after)

        lines[error.row_pos] = line

        board = "\n".join(lines)

        #Display the board
        sys.stderr.write("%s\n" % board)

        #Exit with an error signal
        sys.exit(1)

    #If a result was returned
    else:

        #Converts the result into a string
        result_str = str(result)

        #Makes the string lowercase
        lower_result = result_str.lower()

        #Returns the result
        sys.stdout.write("%s\n" % lower_result)

def parse_board(board):
    """
        Interprets the raw board syntax and returns a grid of tiles.

        Keyword arguments:
        board --- the board containing the tiles (walls, laser, target, etc)
    """

    #Create a container for all the lines
    tiles = list()

    #Loop through all the lines of the board
    for line in board.split("\n"):

        #Identify all the tiles on the line 
        row = [identify_tile(tile) for tile in line]

        #Add the row to the container
        tiles.append(row)

    #Return the container
    return tiles

def reflect(mirror, direction):
    """
        Returns an updated laser direction after it has been reflected on a
        mirror.

        Keyword arguments:
        mirror --- the mirror to reflect the laser from
        direction --- the direction the laser is travelling in
    """

    try:
        direction_lookup = REFLECTIONS[mirror]
    except KeyError:
        raise TypeError("%s is not a mirror.", mirror)

    try:
        return direction_lookup[direction]
    except KeyError:
        raise TypeError("%s is not a direction.", direction)

def shoot_laser(board):
    """
        Shoots the boards laser and returns whether it will hit the target.

        Keyword arguments:
        board --- the board containing the tiles (walls, laser, target, etc)
    """

    tiles = parse_board(board)

    validate_board(tiles)

    return does_laser_hit_target(tiles)

def validate_board(tiles):
    """
        Checks an board to see if it is valid and raises an exception if not.

        Keyword arguments:
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
    """

    found_laser = False
    found_target = False

    try:
        n_wall, w_wall = get_wall_pos(tiles)
        s_wall, e_wall = get_wall_pos(tiles, reverse=True)
    except TypeError:
        n_wall = e_wall = s_wall = w_wall = None

    number_of_rows = len(tiles)

    for row_pos in range(number_of_rows):
        row = tiles[row_pos]

        number_of_cols = len(row)

        for col_pos in range(number_of_cols):

            tile = row[col_pos]

            if ((row_pos in (n_wall, s_wall) and
                 col_pos in range(w_wall, e_wall))
                or
                (col_pos in (e_wall, w_wall) and
                 row_pos in range(n_wall, s_wall))):
                if tile != SOLID_WALL:
                    raise WallNotSolidError(row_pos, col_pos)
            elif (n_wall != None and
                  (row_pos < n_wall or
                   col_pos > e_wall or
                   row_pos > s_wall or
                   col_pos < w_wall)):

                if tile in LASERS:
                    raise LaserOutsideRoomError(row_pos, col_pos)
                elif tile == TARGET:
                    raise TargetOutsideRoomError(row_pos, col_pos)
                elif tile == SOLID_WALL:
                    if not (row_pos >= n_wall and
                            col_pos <= e_wall and
                            row_pos <= s_wall and
                            col_pos >= w_wall):
                        raise WallOutsideRoomError(row_pos, col_pos)
            else:
                if tile in LASERS:
                    if not found_laser:
                        found_laser = True
                    else:
                        raise MultipleLaserError(row_pos, col_pos)
                elif tile == TARGET:
                    if not found_target:
                        found_target = True
                    else:
                        raise MultipleTargetError(row_pos, col_pos)

    if not found_laser:
        raise NoLaserError(tiles)

    if not found_target:
        raise NoTargetError(tiles)



class LasersError(Exception):
    """Parent Error Class for all errors raised."""

    pass

class NoLaserError(LasersError):
    """Indicates that there are no lasers on the board."""

    symbols = "^v><"

    def __str__ (self):
        return "No laser (%s) to fire." % ", ".join(self.symbols)

class NoTargetError(LasersError):
    """Indicates that there are no targets on the board."""

    symbols = "x"

    def __str__ (self):
        return "No target (%s) to hit." % ", ".join(self.symbols)

class MultipleLaserError(LasersError):
    """Indicates that there is more than one laser on the board."""

    symbols = "^v><"

    def __str__ (self):
        return "Too many lasers (%s) to fire, only one is allowed." % \
               ", ".join(self.symbols)

class MultipleTargetError(LasersError):
    """Indicates that there is more than one target on the board."""

    symbols = "x"

    def __str__ (self):
        return "Too many targets (%s) to hit, only one is allowed." % \
               ", ".join(self.symbols)

class WallNotSolidError(LasersError):
    """Indicates that the perimeter wall is not solid."""

    __slots__ = ("__row_pos", "__col_pos", "n_wall", "s_wall", "e_wall",
                 "w_wall")

    def __init__(self, row_pos, col_pos):
        self.__row_pos = row_pos
        self.__col_pos = col_pos

    def __str__ (self):
        return "Walls must form a solid rectangle."

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

    row_pos = property(__get_row_pos)
    col_pos = property(__get_col_pos)

class WallNotRectangleError(LasersError):
    """Indicates that the perimeter wall is not a rectangle."""

    __slots__ = ("__row_pos", "__col_pos")

    def __init__(self, row_pos, col_pos):
        self.__row_pos = row_pos
        self.__col_pos = col_pos

    def __str__ (self):
        return "Walls must form a rectangle."

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

    row_pos = property(__get_row_pos)
    col_pos = property(__get_col_pos)

class OutsideRoomError(LasersError):
    """Indicates an item is outside of the perimeter wall."""

    __slots__ = ("__row_pos", "__col_pos", "__name")

    def __init__(self, row_pos, col_pos, name):
        self.__row_pos = row_pos
        self.__col_pos = col_pos
        self.__name = name

    def __str__ (self):
        return "A %s was found outside of a 'room'." % self.__name

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

    row_pos = property(__get_row_pos)
    col_pos = property(__get_col_pos)

class LaserOutsideRoomError(OutsideRoomError):
    """Indicates the laser is outside of the perimeter wall."""

    def __init__ (self, row_pos, col_pos):
        OutsideRoomError.__init__(self, row_pos, col_pos, "laser")

class TargetOutsideRoomError(OutsideRoomError):
    """Indicates the target is outside of the perimeter wall."""

    def __init__ (self, row_pos, col_pos):
        OutsideRoomError.__init__(self, row_pos, col_pos, "target")

class WallOutsideRoomError(OutsideRoomError):
    """Indicates that there is a wall outside of the perimeter wall."""

    def __init__ (self, row_pos, col_pos):
        OutsideRoomError.__init__(self, row_pos, col_pos, "wall")



if __name__ == "__main__":
    main()

Uno script bash per mostrare la segnalazione degli errori di colore:

#!/bin/bash

declare -a TESTS

test() {
    echo -e "\033[1m$1\033[0m"
    tput sgr0
    echo "$2" | ./lasers.py
    echo
}

test \
"no laser" \
"    ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"multiple lasers" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\  ^ #
    ##########"

test \
"no target" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"multiple targets" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\  x #
    ##########"

test \
"wall not solid" \
"    ##### ####
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"laser_outside_room" \
"    ##########
 >  #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"laser before room" \
" >  ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"laser row before room" \
"   >
    ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"laser after room" \
"    ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########  >"

test \
"laser row after room" \
"    ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########
  > "

test \
"target outside room" \
"    ##########
 x  #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"target before room" \
" x  ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"target row before room" \
"   x
    ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"target after room" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########   x"

test \
"target row after room" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########
  x "

test \
"wall outside room" \
"    ##########
 #  #   v    #
    # /      #
    #       /#
    #   \\  x #
    ##########"

test \
"wall before room" \
" #  ##########
    #   v    #
    # /      #
    #       /#
    #   \\  x #
    ##########"

test \
"wall row before room" \
"    #
    ##########
    #   v    #
    # /      #
    #       /#
    #   \\  x #
    ##########"

test \
"wall after room" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\  x #
    ########## #"

test \
"wall row after room" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\  x #
    ##########
  #"

test \
"mirror outside room positive" \
"    ##########
 /  #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## "

test \
"mirrors outside room negative" \
"    ##########
 \\  #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"mirror before room positive" \
" \\  ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## "

test \
"mirrors before room negative" \
" /  ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"mirror row before room positive" \
"     \\
    ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## "

test \
"mirrors row before room negative" \
"     \\
    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"mirror after row positive" \
"    ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## /  "

test \
"mirrors after row negative" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########   /  "

test \
"mirror row after row positive" \
"    ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## 
 /  "

test \
"mirrors row after row negative" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ########## 
 /  "

test \
"laser hitting laser" \
"    ##########
    #   v   \\#
    #        #
    #        #
    #x  \\   /#
    ##########"

test \
"mirrors positive" \
"    ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## "

test \
"mirrors negative" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"wall collision" \
"    #############
    #     #     #
    # >   #     #
    #     #     #
    #     #   x #
    #     #     #
    #############"

test \
"extreme example" \
"    ##########
    #/\\/\\/\\  #
    #\\\\//\\\\\\ #
    #//\\/\\/\\\\#
    #\\/\\/\\/x^#
    ##########"

test \
"brian example 1" \
"##########
#   / \\  #
#        #
#/    \\ x#
#\\>   /  #
##########"

test \
"brian example 2" \
"##########
#  /    \\#
# / \\    #
#/    \\ x#
#\\^/\\ /  #
##########"

Gli unittest utilizzati nello sviluppo:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import unittest

from lasers import *

class TestTileRecognition(unittest.TestCase):
    def test_solid_wall(self):
        self.assertEqual(SOLID_WALL, identify_tile("#"))

    def test_target(self):
        self.assertEqual(TARGET, identify_tile("x"))

    def test_mirror_ne_sw(self):
        self.assertEqual(MIRROR_NE_SW, identify_tile("/"))

    def test_mirror_nw_se(self):
        self.assertEqual(MIRROR_NW_SE, identify_tile("\\"))

    def test_laser_down(self):
        self.assertEqual(LASER_DOWN, identify_tile("v"))

    def test_laser_up(self):
        self.assertEqual(LASER_UP, identify_tile("^"))

    def test_laser_right(self):
        self.assertEqual(LASER_RIGHT, identify_tile(">"))

    def test_laser_left(self):
        self.assertEqual(LASER_LEFT, identify_tile("<"))

    def test_other(self):
        self.assertEqual(None, identify_tile(" "))

class TestReflection(unittest.TestCase):
    def setUp(self):
        self.DIRECTION = LEFT
        self.NOT_DIRECTIO

6
La fisica del laser impone che il raggio possa attraversare se stesso. Il commento sopra è un importante riferimento culturale.
dmckee --- ex gattino moderatore,

5
Tortoise e la lepre si avvicinano al golf del codice. Fornisci qualcosa con ovviamente troppi personaggi (91 volte più dell'attuale vincitore) ma presta attenzione a ogni lettera delle specifiche. Comunque, lento e costante mi fa lavorare meno per contratto.
Metalshark,

Il tuo unittest sembra mancare una parte. Viene interrotto a "self.NOT_DIRECTIO"
BioGeek

@BioGeek - colpisci il limite per come post lunghezza;). Inoltre i test di stile BASH mettono in evidenza l'evidenziazione del colore.
Metalshark,

11

Rubino, 176 caratteri

x=!0;y=0;e="^v<>#x";b=readlines;b.map{|l|(x||=l=~/[v^<>]/)||y+=1};c=e.index(b[y][x])
loop{c<2&&y+=c*2-1;c>1&&x+=2*c-5;e.index(n=b[y][x])&&(p n==?x;exit);c^='  \/'.index(n)||0}

Ho usato una semplice macchina statale (come la maggior parte dei poster), niente di speciale. Ho continuato a sminuirlo usando ogni trucco che mi veniva in mente. Lo XOR bit a bit usato per cambiare direzione (memorizzato come intero nella variabile c) è stato un grande miglioramento rispetto ai condizionali che avevo nelle versioni precedenti.

Ho il sospetto che il codice aumenti xe ypotrebbe essere ridotto. Ecco la sezione del codice che esegue l'incremento:

c<2&&y+=c*2-1;c>1&&x+=(c-2)*2-1

Modifica : sono stato in grado di abbreviare leggermente quanto sopra:

c<2&&y+=c*2-1;c>1&&x+=2*c-5

La direzione corrente del laser c viene memorizzata come segue:

0 => su
1 => giù
2 => sinistra
3 => destra

Il codice si basa su questo fatto per incrementare xe yper la quantità corretta (0, 1 o -1). Ho provato a riorganizzare i numeri associati a ciascuna direzione, cercando un accordo che mi permettesse di fare qualche manipolazione bit per aumentare i valori, perché ho la sensazione assillante che sarebbe più breve della versione aritmetica.


9

C # 3.0

259 caratteri

bool S(char[]m){var w=Array.FindIndex(m,x=>x<11)+1;var s=Array.FindIndex(m,x=>x>50&x!=92&x<119);var t=m[s];var d=t<61?-1:t<63?1:t<95?-w:w;var u=0;while(0<1){s+=d;u=m[s];if(u>119)return 0<1;if(u==47|u==92)d+=d>0?-w-1:w+1;else if(u!=32)return 0>1;d=u>47?-d:d;}}

Leggermente più leggibile:

bool Simulate(char[] m)
{
    var w = Array.FindIndex(m, x => x < 11) + 1;
    var s = Array.FindIndex(m, x => x > 50 & x != 92 & x < 119);
    var t = m[s];
    var d = t < 61 ? -1 : t < 63 ? 1 : t < 95 ? -w : w;
    var u = 0;
    while (0 < 1)
    {
        s += d;
        u = m[s];
        if (u > 119)
            return 0 < 1;
        if (u == 47 | u == 92)
            d += d > 0 ? -w - 1 : w + 1;
        else if (u != 32)
            return 0 > 1;
        d = u > 47 ? -d : d;
    }
}

Il principale spreco di caratteri sembra essere nel trovare la larghezza della mappa e la posizione della sorgente laser. Qualche idea su come accorciare questo?


Non sono sicuro se questo è più corto ma è il mio tentativo di trovare il laser e trovare la larghezza: usando L = Elenco <stringa>; usando P = System.Drawing.Point; usando L = Elenco <stringa>; L r = nuova L () {"v", "<", ">", "^"}; P p = new P (); r.ForEach (a => {int c = 0; v.ForEach (s => {c ++ ; if (s.IndexOf (a)! = - 1) {pX = s.IndexOf (a); pY = c;}});}); int l = v [0] .Length; v è un Elenco <stringa> contenente la tabella e genera un Punto che rappresenta la posizione del laser + un int che rappresenta la larghezza
RCIX,

meglio: usando L = List <string>; L l = new L (4) {"v", "<", ">", "^"}; var point = new {x = 0, y = 0}; int c = 0; l.ForEach (a => {m.ForEach (s => {if (s.IndexOf (a)! = - 1) {point = new {x = s.IndexOf (a), y = c};}}); c ++;}); int w = m [0] .Length;
RCIX,

4
Problemi richiede un programma completo, non una funzione.
Strager,

che ne dici while(1)
SSpoke il

9

C + ASCII, 197 caratteri:

G[999],*p=G,w,z,t,*b;main(){for(;(*p++=t=getchar()^32)>=0;w=w|t-42?w:p-G)z=t^86?t^126?t^28?t^30?z:55:68:56:75,b=z?b:p;for(;t=z^55?z^68?z^56?z^75?0:w:-w:-1:1;z^=*b)b+=t;puts(*b^88?"false":"true");}

Questa soluzione C assume un set di caratteri ASCII, permettendoci di usare il trucco del mirror XOR. È anche incredibilmente fragile - tutte le linee di input devono avere la stessa lunghezza, ad esempio.

Si rompe sotto il segno di 200 caratteri - ma non farlo, non ho ancora battuto quelle soluzioni Perl!


= O! +1! Grats mi picchia. =]
strager

2
La maggior parte delle buone soluzioni qui fanno l'assunto "tutte le linee hanno la stessa lunghezza". Tutto è giusto nel golf e nella guerra.
Hobbs,

Se fosse necessario, le linee non avevano la stessa lunghezza, aggiungerei un caso di prova. ma ho detto chiaramente che era intenzionale :)
LiraNuna,

9

Golfscript (83 caratteri)

Ciao gnibbler!

:\'><v^'.{\?}%{)}?:P@=?{:O[1-1\10?).~)]=P+
:P\=' \/x'?[O.2^.1^'true''false']=.4/!}do

3
golfscript: perl ~ = 1: 1.7
John La Rooy,

9

Python - 152

Legge l'input da un file chiamato "L"

A=open("L").read()
W=A.find('\n')+1
D=P=-1
while P<0:D+=1;P=A.find(">^<v"[D])
while D<4:P+=[1,-W,-1,W][D];D=[D,D^3,D^1,4,5][' \/x'.find(A[P])]
print D<5

Per leggere da stdin sostituire la prima riga con questa

import os;A=os.read(0,1e9)

Se hai bisogno di minuscolo vero / falso cambia l'ultima riga in

print`D<5`.lower()

Quanti caratteri ci vogliono per cambiare Truein truee Falsein false? ;-)
mob

Non è stato possibile rimuovere 1 carattere modificando "stampa D<5" in "stampa D <5"? O c'è qualcosa che mi manca?
Ponkadoodle,

@wallacoloo, certo che puoi. È necessario solo per il minuscolo vero / falso
John La Rooy,

7

JavaScript - 265 caratteri

Aggiornamento IV - Le probabilità sono che questo sarà l'ultimo round di aggiornamenti, riuscito a salvare un paio di caratteri in più passando a un ciclo do-while e riscrivendo l'equazione del movimento.

Aggiornamento III - Grazie al suggerimento di strager per quanto riguarda la rimozione di Math.abs () e l'inserimento delle variabili nello spazio dei nomi globale, che combinato con qualche riorganizzazione delle assegnazioni delle variabili ha portato il codice a 282 caratteri.

Aggiornamento II - Altri aggiornamenti al codice per rimuovere l'uso di! = -1 e un uso migliore delle variabili per operazioni più lunghe.

Aggiornamento : quando completato e apportato alcune modifiche creando un riferimento alla funzione indexOf (grazie LiraNuna!) E rimuovendo le parentesi non necessarie.

Questa è la prima volta che faccio un golf di codice, quindi non sono sicuro di quanto possa essere migliore, qualsiasi feedback è apprezzato.

Versione completamente minimizzata:

a;b;c;d;e;function f(g){a=function(a){return g.indexOf(a)};b=a("\n")+1;a=g[c=e=a("v")>0?e:e=a("^")>0?e:e=a("<")>0?e:a(">")];d=a=="<"?-1:a==">"?1:a=="^"?-b:b;do{e=d==-1|d==1;a=g[c+=d=a=="\\"?e?b*d:d>0?1:-1:a=="/"?e?-b*d:d>0?1:-1:d];e=a=="x"}while(a!="#"^e);return e}

Versione originale con commenti:

character; length; loc; movement; temp;
function checkMaze(maze) {
        // Use a shorter indexOf function
        character = function(string) { return maze.indexOf(string); }
        // Get the length of the maze
        length = character("\n") + 1;
        // Get the location of the laser in the string
        character = maze[loc = temp = character("v") > 0 ? temp :
                               temp = character("^") > 0 ? temp :
                               temp = character("<") > 0 ? temp : character(">")];
        // Get the intial direction that we should travel
        movement = character == "<" ? -1 :
                   character == ">" ? 1 :
                   character == "^" ? -length : length;
        // Move along until we reach the end
        do {
            // Get the current character
            temp = movement == -1 | movement == 1;
            character = maze[loc += movement = character == "\\" ? temp ? length * movement : movement > 0 ? 1 : -1 :
                                               character == "/" ? temp ? -length * movement : movement > 0 ? 1 : -1 : movement];                                   
            // Have we hit a target?
            temp = character == "x";
            // Have we hit a wall?
        } while (character != "#" ^ temp);
        // temp will be false if we hit the target
        return temp;
    }

Pagina Web da testare con:

<html>
  <head>
    <title>Code Golf - Lasers</title>
    <script type="text/javascript">
    a;b;c;d;e;function f(g){a=function(a){return g.indexOf(a)};b=a("\n")+1;a=g[c=e=a("v")>0?e:e=a("^")>0?e:e=a("<")>0?e:a(">")];d=a=="<"?-1:a==">"?1:a=="^"?-b:b;do{e=d==-1|d==1;a=g[c+=d=a=="\\"?e?b*d:d>0?1:-1:a=="/"?e?-b*d:d>0?1:-1:d];e=a=="x"}while(a!="#"^e);return e}
    </script>
  </head>
  <body>
    <textarea id="maze" rows="10" cols="10"></textarea>
    <button id="checkMaze" onclick="alert(f(document.getElementById('maze').value))">Maze</button>
  </body>
</html>

come ci vuole input? Voglio testare e verificare questo. Inoltre, puoi salvare molti personaggi se salvi un riferimento a a.indexOf
LiraNuna,

Sostituisci index != -1con per index > 0favore! (Speriamo che nessuno metta il lazer nell'angolo in alto a sinistra in modo 0da non essere restituito. =]) Puoi concatenare le varistruzioni o eliminarle del tutto (mettendo le variabili nello spazio dei nomi globale). Penso che Math.abs(m)==1possa essere sostituito con m==-1|m==1. Può movement = ...; location += movementessere ottimizzato per location += movement =?
Strager,

@ strager- Ho appena visto il tuo commento, sembra che tu l'abbia pubblicato mentre stavo aggiornando il codice, fino a 300 caratteri. Vedrò cosa posso fare con l'eliminazione di Math.abs ().
rjzii,

function(a){return g.indexOf(a)}può essere sostituito con function(a)g.indexOf(a)nelle ultime versioni di JavaScript.
user1686

6

House of Mirrors

Non è un vero contributo alla sfida, ma ho scritto un gioco basato su questo concetto (non troppo tempo fa).

È scritto in Scala, open-source e disponibile qui :

Fa un po 'di più; si occupa di colori e vari tipi di specchi e dispositivi, ma la versione 0.00001 ha fatto esattamente ciò che questa sfida richiede. Ho perso quella versione però e non è mai stata ottimizzata per il conteggio dei personaggi.


Sarebbe possibile caricare una versione compilata che funziona su Windows senza installare Scala?
Milano

Esiste una versione con librerie Scala incluse. Guarda l'elenco dei download. Ma comunque, se hai già installato Scala, sono contento di averti fatto farlo :)
HRJ,

6

c (K&R) 339 caratteri necessari dopo ulteriori suggerimenti dello strager.

Il fisico in me ha notato che le operazioni di propagazione e riflessione sono invarianti di inversione temporale, quindi questa versione lancia i raggi dal bersaglio e controlla se arriva all'emettitore laser.

Il resto dell'implementazione è molto semplice ed è preso più o meno esattamente dal mio precedente impegno.

compressa:

#define R return
#define C case
#define Z x,y
int c,i,j,m[99][99],Z;s(d,e,Z){for(;;)switch(m[x+=d][y+=e]){C'^':R 1==e;
C'>':R-1==d;C'v':R-1==e;C'<':R 1==d;C'#':C'x':R 0;C 92:e=-e;d=-d;C'/':c=d;
d=-e;e=-c;}}main(){while((c=getchar())>0)c==10?i=0,j++:(c==120?x=i,y=j:
i,m[i++][j]=c);puts(s(1,0,Z)|s(0,1,Z)|s(-1,0,Z)|s(0,-1,Z)?"true":"false");}

Non compresso (ish):

#define R return
#define C case
#define Z x,y
int c,i,j,m[99][99],Z;
s(d,e,Z)
{
  for(;;)
    switch(m[x+=d][y+=e]){
    C'^': 
      R 1==e;
    C'>': 
      R-1==d;
    C'v': 
      R-1==e;
    C'<': 
      R 1==d;
    C'#':
    C'x':
      R 0;
    C 92:
      e=-e;
      d=-d;
    C'/':
      c=d;
      d=-e;
      e=-c;
    }
}
main(){
  while((c=getchar())>0)
    c==10?i=0,j++:
      (c==120?x=i,y=j:i,m[i++][j]=c);
  puts(s(1,0,Z)|s(0,1,Z)|s(-1,0,Z)|s(0,-1,Z)?"true":"false");
}

Non esiste una convalida dell'input e un input errato può inviarlo in un ciclo infinito. Funziona correttamente con input non più grandi di 99 per 99. Richiede un compilatore che collegherà la libreria standard senza includere nessuna delle intestazioni. E penso di aver finito, lo strager mi ha battuto per un notevole tratto, anche con il suo aiuto.

Spero piuttosto che qualcuno dimostrerà un modo più sottile di compiere il compito. Non c'è niente di sbagliato in questo, ma non è una magia profonda.


Non è necessario =0sui globali poiché sono inizializzati su 0 per impostazione predefinita. Sostituisci le costanti di carattere con il loro equivalente in decimale. Utilizzare >0invece di !=EOFverificare con EOF (e \0). Probabilmente puoi #defineeliminare un po 'del codice casecome ho fatto con if. Non è necessario alcun extra \nin putsquanto putsdeve comunque stampare una riga. for(;;)è più corto di while(1). Spero che questo ti aiuti. =]
strager

@strager: grazie. Vengo sempre a questi in modo iterativo, perché non la penso così ...
dmckee --- ex gattino moderatore,

2
"There is no input validation"- Non dovrebbe essercene nessuno. Per facilitare i giocatori di golf, si presume che l'input sia sempre "pulito", se non diversamente specificato.
LiraNuna,

@dmckee, non preoccuparti, anche noi professionisti del Code Golf lavoriamo in modo iterativo. Tuttavia, generalmente usiamo alcuni trucchi fin dall'inizio (come la metà di quelli che ho citato), ma questo viene fornito con esperienza. =]
strager

A meno che non stia contando male, il programma è di 390 caratteri, non di 380.
Strager,

6

Rubino - 146 caratteri

A=$<.read
W=A.index('
')+1
until
q=A.index(">^<v"[d=d ?d+1:0])
end
while d<4
d=[d,d^3,d^1,4,5][(' \/x'.index(A[q+=[1,-W,-1,W][d]])or 4)]
end
p 5>d

5

PostScript , 359 byte

Primo tentativo, molto margine di miglioramento ...

/a[{(%stdin)(r)file 99 string readline not{exit}if}loop]def a{{[(^)(>)(<)(v)]{2
copy search{stop}if pop pop}forall}forall}stopped/r count 7 sub def pop
length/c exch def[(>)0(^)1(<)2(v)3>>exch get/d exch def{/r r[0 -1 0 1]d get
add def/c c[1 0 -1 0]d get add def[32 0 47 1 92 3>>a r get c get .knownget
not{exit}if/d exch d xor def}loop a r get c get 120 eq =

4

Haskell, 395 391 383 361 339 caratteri (ottimizzata)

Utilizza ancora una macchina a stati generici, piuttosto che qualcosa di intelligente:

k="<>^v"
o(Just x)=x
s y(h:t)=case b of{[]->s(y+1)t;(c:_)->(c,length a,y)}where(a,b)=break(flip elem k)h
r a = f$s 0 a where f(c,x,y)=case i(a!!v!!u)"x /\\"["true",g k,g"v^><",g"^v<>"]of{Just r->r;_->"false"}where{i x y=lookup x.zip y;j=o.i c k;u=j[x-1,x+1,x,x];v=j[y,y,y-1,y+1];g t=f(j t,u,v)}
main=do{z<-getContents;putStrLn$r$lines z}

Una versione leggibile:

k="<>^v"    -- "key" for direction
o(Just x)=x -- "only" handle successful search
s y(h:t)=case b of  -- find "start" state
  []->s(y+1)t
  (c:_)->(c,length a,y)
 where (a,b)=break(flip elem k)h
r a = f$s 0 a where -- "run" the state machine (iterate with f)
 f(c,x,y)=case i(a!!v!!u)"x /\\"["true",g k,g"v^><",g"^v<>"] of
   Just r->r
   _->"false"
  where
   i x y=lookup x.zip y -- "index" with x using y as key
   j=o.i c k -- use c as index k as key; assume success
   u=j[x-1,x+1,x,x] -- new x coord
   v=j[y,y,y-1,y+1] -- new y coord
   g t=f(j t,u,v) -- recurse; use t for new direction
main=do
 z<-getContents
 putStrLn$r$lines z

3

Credo nel riutilizzo del codice, utilizzerei uno dei tuoi codici come API :).

  mette Board.new.validate (input)

32 caratteri \ o / ... wohoooo


6
è un doppio bogey!
Jeff Atwood,

3
Beat it to it: p Board.new.validate input 26 caratteri \ o /
Alessandra Pereyra

3

C ++: 388 caratteri

#include<iostream>
#include<string>
#include<deque>
#include<cstring>
#define w v[y][x]
using namespace std;size_t y,x,*z[]={&y,&x};int main(){string p="^v<>",s;deque<string>v;
while(getline(cin,s))v.push_back(s);while(x=v[++y].find_first_of(p),!(x+1));int 
i=p.find(w),d=i%2*2-1,r=i/2;do while(*z[r]+=d,w=='/'?d=-d,0:w==' ');while(r=!r,
!strchr("#x<^v>",w));cout<<(w=='x'?"true":"false");}

( 318 senza intestazioni)


Come funziona:

Innanzitutto, vengono lette tutte le righe, quindi viene trovato il laser. Quanto segue valuterà fino 0a quando non è stata ancora trovata alcuna freccia laser e allo stesso tempo assegnare alla xposizione orizzontale.

x=v[++y].find_first_of(p),!(x+1)

Quindi guardiamo in quale direzione abbiamo trovato e lo memorizziamo i. I valori pari di isono in alto / a sinistra ("decrescente") e i valori dispari in basso / a destra ("crescente"). Secondo tale nozione, vengono impostati d("direzione") e r("orientamento"). Indicizziamo l'array di puntatori zcon orientamento e aggiungiamo la direzione all'intero che otteniamo. La direzione cambia solo se colpiamo una barra, mentre rimane la stessa quando colpiamo una barra. Naturalmente, quando colpiamo uno specchio, cambiamo sempre orientamento ( r = !r).


Mi stai facendo fare la mia soluzione C ++. =]
strager

2
@strager, questo sta diventando noioso. Facciamo una soluzione che visualizzi "vero" o "falso" al momento della compilazione xD
Johannes Schaub - litb,

aggiunta spiegazione poiché penso che lo terrò a questo :)
Johannes Schaub - litb,

2

Groovy @ 279 caratteri

m=/[<>^v]/
i={'><v^'.indexOf(it)}
n=['<':{y--},'>':{y++},'^':{x--},'v':{x++}]
a=['x':{1},'\\':{'v^><'[i(d)]},'/':{'^v<>'[i(d)]},'#':{},' ':{d}]
b=[]
System.in.eachLine {b<<it.inject([]) {r,c->if(c==~m){x=b.size;y=r.size;d=c};r<<c}}
while(d==~m){n[d]();d=a[b[x][y]]()}
println !!d

2

C #

1020 caratteri.
1088 caratteri (aggiunto input dalla console).
925 caratteri (variabili refactored).
875 caratteri (inizializzatore dizionario ridondante rimosso; modificato in binario e operatori)

Ha sottolineato di non guardare nessun altro prima di pubblicare. Sono sicuro che potrebbe essere un po 'LINQ. E l'intero metodo FindLaser nella versione leggibile mi sembra terribilmente sospetto. Ma funziona ed è tardi :)

Nota che la classe leggibile include un metodo aggiuntivo che stampa l'Arena corrente mentre il laser si muove.

class L{static void Main(){
A=new Dictionary<Point,string>();
var l=Console.ReadLine();int y=0;
while(l!=""){var a=l.ToCharArray();
for(int x=0;x<a.Count();x++)
A.Add(new Point(x,y),l[x].ToString());
y++;l=Console.ReadLine();}new L();}
static Dictionary<Point,string>A;Point P,O,N,S,W,E;
public L(){N=S=W=E=new Point(0,-1);S.Offset(0,2);
W.Offset(-1,1);E.Offset(1,1);D();
Console.WriteLine(F());}bool F(){
var l=A[P];int m=O.X,n=O.Y,o=P.X,p=P.Y;
bool x=o==m,y=p==n,a=x&p<n,b=x&p>n,c=y&o>m,d=y&o<m;
if(l=="\\"){if(a)T(W);if(b)T(E);if(c)T(S);
if(d)T(N);if(F())return true;}
if(l=="/"){if(a)T(E);if(b)T(W);if(c)T(N);
if(d)T(S);if(F())return true;}return l=="x";}
void T(Point p){O=P;do P.Offset(p);
while(!("\\,/,#,x".Split(',')).Contains(A[P]));}
void D(){P=A.Where(x=>("^,v,>,<".Split(',')).
Contains(x.Value)).First().Key;var c=A[P];
if(c=="^")T(N);if(c=="v")T(S);if(c=="<")T(W);
if(c==">")T(E);}}

Versione leggibile (non proprio la versione finale del golf, ma stessa premessa):

class Laser
{
    private Dictionary<Point, string> Arena;
    private readonly List<string> LaserChars;
    private readonly List<string> OtherChars;

    private Point Position;
    private Point OldPosition;
    private readonly Point North;
    private readonly Point South;
    private readonly Point West;
    private readonly Point East;

    public Laser( List<string> arena )
    {
        SplitArena( arena );
        LaserChars = new List<string> { "^", "v", ">", "<" };
        OtherChars = new List<string> { "\\", "/", "#", "x" };
        North = new Point( 0, -1 );
        South = new Point( 0, 1 );
        West = new Point( -1, 0 );
        East = new Point( 1, 0 );
        FindLaser();
        Console.WriteLine( FindTarget() );
    }

    private void SplitArena( List<string> arena )
    {
        Arena = new Dictionary<Point, string>();
        int y = 0;
        foreach( string str in arena )
        {
            var line = str.ToCharArray();
            for( int x = 0; x < line.Count(); x++ )
            {
                Arena.Add( new Point( x, y ), line[x].ToString() );
            }
            y++;
        }
    }

    private void DrawArena()
    {
        Console.Clear();
        var d = new Dictionary<Point, string>( Arena );

        d[Position] = "*";
        foreach( KeyValuePair<Point, string> p in d )
        {
            if( p.Key.X == 0 )
                Console.WriteLine();

            Console.Write( p.Value );
        }
        System.Threading.Thread.Sleep( 400 );
    }

    private bool FindTarget()
    {
        DrawArena();

        string chr = Arena[Position];

        switch( chr )
        {
            case "\\":
                if( ( Position.X == Position.X ) && ( Position.Y < OldPosition.Y ) )
                {
                    OffSet( West );
                }
                else if( ( Position.X == Position.X ) && ( Position.Y > OldPosition.Y ) )
                {
                    OffSet( East );
                }
                else if( ( Position.Y == Position.Y ) && ( Position.X > OldPosition.X ) )
                {
                    OffSet( South );
                }
                else
                {
                    OffSet( North );
                }
                if( FindTarget() )
                {
                    return true;
                }
                break;
            case "/":
                if( ( Position.X == Position.X ) && ( Position.Y < OldPosition.Y ) )
                {
                    OffSet( East );
                }
                else if( ( Position.X == Position.X ) && ( Position.Y > OldPosition.Y ) )
                {
                    OffSet( West );
                }
                else if( ( Position.Y == Position.Y ) && ( Position.X > OldPosition.X ) )
                {
                    OffSet( North );
                }
                else
                {
                    OffSet( South );
                }
                if( FindTarget() )
                {
                    return true;
                }
                break;
            case "x":
                return true;
            case "#":
                return false;
        }
        return false;
    }

    private void OffSet( Point p )
    {
        OldPosition = Position;
        do
        {
            Position.Offset( p );
        } while( !OtherChars.Contains( Arena[Position] ) );
    }

    private void FindLaser()
    {
        Position = Arena.Where( x => LaserChars.Contains( x.Value ) ).First().Key;

        switch( Arena[Position] )
        {
            case "^":
                OffSet( North );
                break;
            case "v":
                OffSet( South );
                break;
            case "<":
                OffSet( West );
                break;
            case ">":
                OffSet( East );
                break;
        }
    }
}

2
Il programma dovrebbe ricevere input. Più comunemente dallo stdin.
LiraNuna,

0

Perl 219
La mia versione di Perl è 392 342 caratteri (ho dovuto gestire il caso del fascio che colpisce il laser):
Aggiornamento , grazie Hobbs per avermi ricordato di tr//, è ora di 250 caratteri:
aggiornamento , la rimozione del min m//, cambiando i due whilecicli portati qualche risparmio; ora è richiesto solo uno spazio.
( L:it;goto Lè della stessa lunghezza di do{it;redo}):

@b=map{($y,$x,$s)=($a,$-[0],$&)if/[<>^v]/;$a++;[split//]}<>;L:$_=$s;$x++if/>/;
$x--if/</;$y++if/v/;$y--if/\^/;$_=$b[$y][$x];die"true\n"if/x/;die"false\n"if
/[<>^v#]/;$s=~tr/<>^v/^v<>/if/\\/;$s=~tr/<>^v/v^></if/\//;goto L

Ne ho rasato alcuni, ma a malapena compete con alcuni di questi, anche se in ritardo.
Sembra un po 'meglio come:

#!/usr/bin/perl
@b = map {
    ($y, $x, $s) = ($a, $-[0], $&) if /[<>^v]/;
    $a++;
    [split//]
} <>;
L:
    $_ = $s;
    $x++ if />/;
    $x-- if /</;
    $y++ if /v/;
    $y-- if /\^/;
    $_ = $b[$y][$x];
    die "true\n"  if /x/;
    die "false\n" if /[<>^v#]/;
    $s =~ tr/<>^v/^v<>/ if /\\/;
    $s =~ tr/<>^v/v^></ if /\//;
goto L

Bene ... Onestamente questo dovrebbe essere autoesplicativo se capisci che si @btratta di una matrice di caratteri in ogni riga e puoi leggere la semplice regexp e le trdichiarazioni.


Suggerimento: è possibile abbreviare il codice mirror verso l'alto. $_=$s;tr/^v<>/<>^v/e $_=$s;tr/v^<>/<>^v/rispettivamente. Inoltre, non è necessario il min m//.
Hobbs,

Scusa, $_=$s;tr/v^></<>^v/;
falla

Ne hai ancora diversi if m/.../che potrebbero if/.../salvare due personaggi al pop.
Hobbs,

Puoi usare y///invece di tr///salvare due personaggi.
Platinum Azure,

0

F # - 454 (o successivi)

Un po 'in ritardo al gioco, ma non posso resistere a pubblicare il mio secondo tentativo.

Aggiornamento leggermente modificato. Ora si interrompe correttamente se il trasmettitore viene colpito. Pizzicato l'idea di Brian per IndexOfAny (peccato che la linea sia così dettagliata). In realtà non sono riuscito a capire come ottenere ReadToEnd per tornare dalla console, quindi mi sto prendendo un po 'di fiducia ...

Sono contento di questa risposta, come se fosse piuttosto breve, è ancora abbastanza leggibile.

let s=System.Console.In.ReadToEnd()       //(Not sure how to get this to work!)
let w=s.IndexOf('\n')+1                   //width
let h=(s.Length+1)/w                      //height
//wodge into a 2d array
let a=Microsoft.FSharp.Collections.Array2D.init h (w-1)(fun y x -> s.[y*w+x])
let p=s.IndexOfAny[|'^';'<';'>';'v'|]     //get start pos
let (dx,dy)=                              //get initial direction
 match "^<>v".IndexOf(s.[p]) with
 |0->(0,-1)
 |1->(-1,0)
 |2->(1,0)
 |_->(0,1)
let mutable(x,y)=(p%w,p/w)                //translate into x,y coords
let rec f(dx,dy)=
 x<-x+dx;y<-y+dy                          //mutate coords on each call
 match a.[y,x] with
 |' '->f(dx,dy)                           //keep going same direction
 |'/'->f(-dy,-dx)                         //switch dx/dy and change sign
 |'\\'->f(dy,dx)                          //switch dx/dy and keep sign
 |'x'->"true"
 |_->"false"
System.Console.Write(f(dx,dy))

Sono decorazioni. Controlla le mie altre sfide, è solo una cosa di formattazione.
LiraNuna,

@LiraNuna, ok a quanto pare, questa iterazione li mangia comunque comunque :)
Benjol,

Sarebbe bello confrontarlo con un'implementazione 1-d. Basta aggiungere / sottrarre 1 per sinistra e destra e aggiungere / sottrarre w per su e giù. Mi aspetto che risparmi un bel po 'di caratteri
John La Rooy,

@gnibbler, Brian l'ha già fatto, non sono sicuro di poterlo battere, ma potrei provare.
Benjol,
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.