Code Golf: Laser

152

Die Herausforderung

Der kürzeste Code nach Zeichenanzahl, um eine 2D-Darstellung einer Karte einzugeben und je nach Eingabe 'true' oder 'false' auszugeben .

Das Brett besteht aus 4 Arten von Fliesen:

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

Es gibt nur einen Laser und nur ein Ziel . Wände müssen ein festes Rechteck beliebiger Größe bilden, in dem sich Laser und Ziel befinden. Wände im 'Raum' sind möglich.

Laserstrahl schießt und wandert von seinem Ursprung in die Richtung, in die er zeigt. Wenn ein Laserstrahl auf die Wand trifft, stoppt er. Wenn ein Laserstrahl auf einen Spiegel trifft, springt er um 90 Grad in die Richtung, in die der Spiegel zeigt. Spiegel sind zweiseitig, was bedeutet, dass beide Seiten "reflektierend" sind und einen Strahl auf zwei Arten reflektieren können. Wenn ein Laserstrahl auf den Laser ( ^v><) selbst trifft , wird er als Wand behandelt (Laserstrahl zerstört den Beamer und trifft daher niemals das Ziel).

Testfälle

Eingang:
    ##########
    # / \ #
    # #
    # \ x #
    #> / #
    ########## 
Ausgabe:
    wahr

Eingang:
    ##########
    # vx #
    # / #
    # / #
    # \ #
    ##########
Ausgabe:    
    falsch

Eingang:
    ##############
    # # #
    #> # #
    # # #
    # # x #
    # # #
    ##############
Ausgabe:
    falsch

Eingang:
    ##########
    # / \ / \ / \ #
    # \\ // \\\ #
    # // \ / \ / \\ #
    # \ / \ / \ / x ^ #
    ##########
Ausgabe:
    wahr

Die Codeanzahl umfasst die Eingabe / Ausgabe (dh das vollständige Programm).

LiraNuna
quelle
84
IMMA CHARGIN 'MAH LAZER!
Ólafur Waage
37
Das ist großartig .
GManNickG
33
Überqueren
Sie nicht die
49
@GameFreak: Das wird wirklich alt.
Artelius
24
Ist das eigentlich ein Hai mit einem verdammten Faulpelz auf dem Kopf?
Nathan Feger

Antworten:

78

Perl, 166 160 Zeichen

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

Die Lösung hatte 166 Schläge, als dieser Wettbewerb endete, aber A. Rex hat ein paar Möglichkeiten gefunden, um 6 weitere Charaktere zu rasieren:

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,$/

Die erste Zeile lädt die Eingabe in %teine Tabelle der Karte, in $t{99*i+j}der das Zeichen in Zeile i , Spalte j enthalten ist . Dann,

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

Es durchsucht die Elemente von %tnach einem Zeichen, das mit > ^ <oder übereinstimmt v, und setzt gleichzeitig $deinen Wert zwischen 0 und 3, der die Anfangsrichtung des Laserstrahls angibt.

Zu Beginn jeder Iteration in der Hauptschleife aktualisieren wir, $dob sich der Strahl derzeit auf einem Spiegel befindet. XOR'ing um 3 ergibt das richtige Verhalten für einen \Spiegel und XOR'ing um 1 ergibt das richtige Verhalten für einen /Spiegel.

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

Als nächstes wird die aktuelle Position $rentsprechend der aktuellen Richtung aktualisiert.

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

Wir weisen das Zeichen an der aktuellen Position zu $_, um die Match-Operatoren bequem zu nutzen.

/[\/\\ ]/ && redo

Fahren Sie fort, wenn sich eine Leerstelle oder ein Spiegelzeichen befindet. Andernfalls beenden wir, truewenn wir uns auf dem Ziel befinden ( $_ =~ /x/) und falseansonsten.

Einschränkung: Funktioniert möglicherweise nicht bei Problemen mit mehr als 99 Spalten. Diese Einschränkung könnte auf Kosten von 3 weiteren Zeichen aufgehoben werden.

Mob
quelle
Okay, ich habe 323 Zeichen. = D
Strager
5
Ich kann 99 in 1E5 ändern, um es auf Kosten von 3 Zeichen sehr robust zu machen.
Mob
2
Ihre beste Lösung würde sich am oberen Rand des Beitrags besser bemerkbar machen.
Strager
13
Aber mit regulären Ausdrücken das Board drehen? Das war krank. Das ist wie ein automatischer 20-Takt-Bonus.
Mob
1
@mobrule: Speichern Sie sechs Striche: Ordnen Sie die erste Zeile neu an s!.!$t{$s++}=$&!ge,$s=$r+=99for<>;und ändern Sie %d=split//,.." to % d = .. = ~ /./ g , and change grep {..}% t` ingrep..,%t
A. Rex
75

Perl, 177 Zeichen

Der erste Zeilenumbruch kann entfernt werden. Die anderen beiden sind obligatorisch.

$/=%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}

Erläuterung:

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

Wenn ein sich nach rechts bewegender Strahl in einen {leeren Raum, einen nach oben abgewinkelten Spiegel, einen nach unten abgewinkelten Spiegel} läuft, wird er zu einem {nach rechts bewegten Strahl, einem sich nach oben bewegenden Strahl, einem sich nach unten bewegenden Strahl}. $/Auf dem Weg initialisieren - zum Glück ist "6" kein gültiges Eingabezeichen.

$_ = <>;

Lesen Sie die Tafel in $_.

$s="#";

$sist das Symbol für alles, worauf der Strahl jetzt sitzt. Da der Laseremitter wie eine Wand behandelt werden soll, stellen Sie dies zunächst als Wand ein.

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

Wenn der Laserstrahl nur nach rechts zeigt, drehen Sie das Symbol und dann die gesamte Platine an Ort und Stelle (drehen Sie auch die Symbole für die Spiegel). Es handelt sich um eine 90-Grad-Drehung nach links, die effektiv durch Umkehren der Zeilen beim Transponieren von Zeilen und Spalten in einer leicht teuflischen s///eNebenwirkung erreicht wird. Im Golfcode ist das tr in der Form geschrieben, y'''die es mir ermöglicht, einen Backslashing einen Backslash zu überspringen.

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

Beenden Sie mit der richtigen Nachricht, wenn wir das Ziel oder eine Wand treffen.

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

Wenn sich vor dem Laser ein leerer Raum befindet, gehen Sie vorwärts. Wenn sich vor dem Laser ein Spiegel befindet, bewegen Sie sich vorwärts und drehen Sie den Strahl. In beiden Fällen setzen Sie das "gespeicherte Symbol" wieder an die alte Position des Strahls und setzen Sie das, was wir gerade überschrieben haben, in das gespeicherte Symbol.

redo;

Wiederholen Sie bis zur Beendigung. {...;redo}ist zwei Zeichen kleiner als for(;;){...}und drei Zeichen kleiner als while(1){...}.

Hobbs
quelle
4
Dreh das Brett ... Verrückt. Regexp ... Verrückter. O_o
Strager
39
Du ... du Monster!
LiraNuna
4
LiraNuna: Ich nehme das als Kompliment.
Hobbs
21
Der Golf ist vorbei. Wie kann man das Drehen eines 2D-Boards mit regulären Ausdrücken schlagen?!
Konrad Rudolph
13
wtf? Perl-Programmierer sind Assistenten.
Johannes Schaub - litb
39

C89 (209 Zeichen)

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

Erläuterung

Diese Monstrosität wird wahrscheinlich schwer zu verfolgen sein, wenn Sie C nicht verstehen. Nur eine Warnung.

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

Dieses kleine Makro prüft, ob das aktuelle Zeichen ( *p) dem entspricht, was ain Zeichenform ( *#a) vorliegt . Wenn sie gleich sind, setzen Sie den Bewegungsvektor auf b( m=b), markieren Sie dieses Zeichen als Wand ( *p=1) und setzen Sie den Startpunkt auf die aktuelle Position ( q=p). Dieses Makro enthält den Teil "else".

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

Deklarieren Sie einige Variablen. * qist der aktuelle Standort des Lichts. * Gist das Spielbrett als 1D-Array. * pist der aktuelle Leseort beim Auffüllen G. * wist die Breite des Boards.

main(m){

Offensichtlich main. mist eine Variable, die den Bewegungsvektor speichert. (Es ist ein Parameter mainals Optimierung.)

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

Durchlaufen Sie alle Zeichen und füllen Sie sie Gmit p. G[0]Als Optimierung überspringen ( pim dritten Teil von muss kein Zeichen erneut geschrieben werden for).

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

Verwenden Sie nach Möglichkeit das oben genannte Makro, um den Lazer zu definieren. -1und 1entsprechen links bzw. rechts und -wund wauf und ab.

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

Wenn das aktuelle Zeichen eine Zeilenende-Markierung (ASCII 10) ist, legen Sie die Breite fest, falls diese noch nicht festgelegt wurde. Das übersprungene G[0]erlaubt uns zu schreiben w=p-Gstatt w=p-G+1. Auch dies beendet die ?:Kette von den M's.

    for(;
        q+=m,

Bewegen Sie das Licht um den Bewegungsvektor.

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

Reflektieren Sie den Bewegungsvektor.

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

Wenn dies eine Wand ist oder xbeenden Sie mit der entsprechenden Nachricht ( m=0beendet die Schleife). Ansonsten nichts tun (noop; m=m)

    );
}
strager
quelle
8
Pfui! Ich arbeitete an einer C-Lösung, als in meinem Apartmentkomplex der Feueralarm ertönte. Jetzt wurde ich geschlagen. Gute Lösung.
Rlbond
Wenn Sie eine temporäre Variable für Ihre Swap- und Swap- / Negationsschritte verwenden, sparen Sie ein paar Zeichen.
Artelius
@Artelius, Ja, das habe ich gemerkt und ein paar andere Dinge. Vielen Dank.
Strager
1
TCC mag die untypisierten Erklärungen und Fehler nicht mit g.c:3: declaration expected:(
Mark Rushakoff
2
Das Entfernen putsder Erklärung hat geholfen, aber nicht genug, um sie unter 170 zu bringen. 209 ist jedoch ziemlich gut, also denke ich, dass ich es dabei belassen werde. Danke für deine Hilfe, Leute. Ich weiß das wirklich zu schätzen. =] (Alles, um diese Perl-Hexen zu entthronen!)
Strager
36

Ich würde wetten, dass die Leute eine LOOOOONG-Zeit auf diesen gewartet haben. (Was meinst du damit, die Herausforderung ist vorbei und niemand kümmert sich mehr darum?)

Siehe ... ich präsentiere hier eine Lösung in

Befunge-93!

Es wiegt satte 973 Zeichen (oder 688, wenn Sie gemeinnützig genug sind, um Leerzeichen zu ignorieren, die nur zum Formatieren verwendet werden und im eigentlichen Code nichts bewirken ).

Vorsichtsmaßnahme : Ich habe vor kurzem meinen eigenen Befunge-93-Interpreter in Perl geschrieben, und leider ist dies alles, womit ich wirklich Zeit hatte, ihn zu testen. Ich bin ziemlich zuversichtlich, dass es im Allgemeinen <>korrekt ist , aber es kann eine merkwürdige Einschränkung in Bezug auf EOF geben: Da Perls Operator am Ende der Datei undef zurückgibt, wird dies im numerischen Kontext als 0 verarbeitet. Bei C-basierten Implementierungen, bei denen EOF einen anderen Wert hat (z. B. -1), funktioniert dieser Code möglicherweise nicht.

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"\:"<"\: "^"   -!#^_-!#^_-!      ^
               >                       ^

Erläuterung

Wenn Sie mit der Befunge-Syntax und -Operation nicht vertraut sind, klicken Sie hier .

Befunge ist eine stapelbasierte Sprache, aber es gibt Befehle, mit denen man Zeichen in den Befunge-Code schreiben kann. Ich nutze das an zwei Stellen. Zuerst kopiere ich die gesamte Eingabe auf das Befunge-Board, aber ein paar Zeilen unter dem tatsächlich geschriebenen Code. (Dies ist natürlich nie sichtbar, wenn der Code ausgeführt wird.)

Der andere Ort befindet sich oben links:

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

In diesem Fall speichere ich in dem oben hervorgehobenen Bereich einige Koordinaten. In der ersten Spalte in der mittleren Zeile speichere ich die x-Koordinate für die aktuelle "Cursorposition". In der zweiten Spalte speichere ich die y-Koordinate. Die nächsten beiden Spalten dienen zum Speichern der x- und y-Koordinate der Laserstrahlquelle, wenn diese gefunden wird. und die letzte Spalte (mit dem 'a'-Zeichen) wird schließlich überschrieben, um die aktuelle Strahlrichtung zu enthalten, die sich offensichtlich ändert, wenn der Strahlengang verfolgt wird.

Das Programm beginnt mit der Platzierung von (0,27) als anfängliche Cursorposition. Anschließend wird die Eingabe zeichenweise gelesen und an der Cursorposition platziert. Zeilenumbrüche bewirken lediglich, dass die y-Koordinate zunimmt und die x-Koordinate auf 0 zurückkehrt, genau wie bei einem echten Wagenrücklauf. Schließlich wird undef vom Interpreter gelesen und dieser 0-Zeichen-Wert wird verwendet, um das Ende der Eingabe zu signalisieren und mit den Laseriterationsschritten fortzufahren. Wenn das Laserzeichen [<> ^ v] gelesen wird, wird es auch in das Speicher-Repository kopiert (über das 'a'-Zeichen) und seine Koordinaten werden in die Spalten links kopiert.

Das Endergebnis all dessen ist, dass die gesamte Datei im Grunde genommen in den Befunge-Code kopiert wird, ein wenig unterhalb des tatsächlich durchquerten Codes.

Anschließend wird die Strahlposition zurück in die Cursorpositionen kopiert und die folgende Iteration durchgeführt:

  • Überprüfen Sie die aktuelle Strahlrichtung und erhöhen oder verringern Sie die Cursorkoordinaten entsprechend. (Ich mache das zuerst, um zu vermeiden, dass ich mich gleich beim ersten Zug mit dem Eckfall des Laserstrahls befassen muss.)
  • Lesen Sie das Zeichen an dieser Stelle.
  • Wenn das Zeichen "#" ist, setzen Sie Newline und "false" auf den Stapel, drucken Sie und beenden Sie.
  • Vergleichen Sie es mit allen Balkenzeichen [<> ^ v]; Wenn es eine Übereinstimmung gibt, drucken Sie auch "false \ n" und beenden Sie.
  • Wenn das Zeichen ein Leerzeichen ist, leeren Sie den Stapel und fahren Sie fort.
  • Wenn es sich bei dem Zeichen um einen Schrägstrich handelt, legen Sie die Strahlrichtung auf den Stapel und vergleichen Sie sie nacheinander mit den einzelnen Richtungszeichen. Wenn eine gefunden wird, wird die neue Richtung an derselben Stelle im Code gespeichert und die Schleife wiederholt sich.
  • Wenn das Zeichen ein Backslash ist, machen Sie im Grunde das Gleiche wie oben (außer mit der richtigen Zuordnung für Backslash).
  • Wenn der Charakter 'x' ist, haben wir das Ziel getroffen. Drucken Sie "true \ n" und beenden Sie das Programm.
  • Wenn das Zeichen keines davon ist, drucken Sie "error \ n" und beenden Sie das Programm.

Wenn es genügend Nachfrage gibt, werde ich versuchen, genau darauf hinzuweisen, wo im Code all dies erreicht wird.

Platinum Azure
quelle
14
+1 - Nur weil es falsch interpretiert werden könnte, eine im Editor geöffnete EXE zu sein.
Kyle Rosendo
1
Ähm ... heilig ****. Ich habe mich mit Befunge angelegt, und das ist wirklich sehr, sehr beeindruckend.
Almo
Code Golf in verschleierten Sprachen ... wie Erdnussbutter und Cayennepfeffer!
Wberry
29

F #, 36 Zeilen, sehr gut lesbar

Ok, nur um eine Antwort zu bekommen:

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    

Proben:

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

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

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

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

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

##########
#  /    \#
# / \    #
#/    \ x#
#\^/\ /  #
##########
false
Brian
quelle
54
Ich kann dieses tatsächlich lesen! WUNDER!
Jeff Atwood
17
Java / C # -Code Golf wird durch Zeilen und nicht durch Zeichen gezählt. Das ist das Handicap.
Nathan Feger
3
@strager ist in 3 Jahren nicht deprimierend, wenn Sie für die Pflege des Codes eingestellt werden und der ursprüngliche Entwickler längst abgereist ist.
Nathan Feger
Dies schlägt bei Verwendung von F # in Visual Studio 2010 fehl. Seq.to_list existiert nicht (ok, geändert in toList) und dann Zeile 25, unvollständiger Mustervergleich.
Russell
2
Ja, ändern Sie to_list jetzt in toList. Die unvollständige Übereinstimmungswarnung ist in Ordnung. Es ist Code Golf, also habe ich keinen Code wie: | gemacht _ -> scheitern mit "unmöglich"
Brian
29

Golfscript - 83 Zeichen (Mashup von mir und Strager)

Die Newline ist nur zum Einwickeln da

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

Golfscript - 107 Zeichen

Die Newline dient nur der Übersichtlichkeit

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

Wie es funktioniert.

In der ersten Zeile wird die ursprüngliche Position und Richtung ermittelt.
Die zweite Linie dreht sich immer dann, wenn der Laser auf einen Spiegel trifft.

Gnibbler
quelle
18

353 Zeichen in Ruby:

314 277 Zeichen jetzt!

OK, 256 Zeichen in Ruby und jetzt bin ich fertig. Schöne runde Nummer zum Anhalten. :) :)

247 Zeichen. Ich kann nicht aufhören

223 203 201 Zeichen 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)}

Mit Leerzeichen:

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

Leicht überarbeitet:

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
Jeremy Ruten
quelle
Aber ... Sie können chin Coder einen anderen Buchstaben mit 1 Zeichen umbenennen , um 2 Zeichen zu speichern!
LiraNuna
Ok ok, okay ... Ich habe tatsächlich festgestellt, dass diese ganze Variable unnötig ist, da ich sie nur einmal benutze. Diese und einige andere Verbesserungen haben es auf 247 Zeichen reduziert.
Jeremy Ruten
1
Nein i++(statt i+=1)?
LiraNuna
6
Nee. Sie können ++ i machen, aber es macht es wirklich so positiv wie früher.
DigitalRoss
Ich mag die komprimierte Version: #; p
SeanJA
17

Python

294 277 253 240 232 Zeichen einschließlich Zeilenumbrüche:

(Das erste Zeichen in den Zeilen 4 und 5 ist eine Registerkarte, keine Leerzeichen.)

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

Ich hatte vergessen, dass Python sogar optionale Semikolons hatte.

Wie es funktioniert

Die Schlüsselidee hinter diesem Code ist die Verwendung komplexer Zahlen zur Darstellung von Positionen und Richtungen. Die Reihen sind die imaginäre Achse und nehmen nach unten zu. Die Spalten sind die reale Achse und werden nach rechts vergrößert.

l='>v<^';eine Liste der Lasersymbole. Die Reihenfolge wird so gewählt, dass der Index eines Laserrichtungszeichens einer Potenz von sqrt (-1) entspricht.

x={'/':'^<v>','\\':'v>^<',' ':l};eine Transformationstabelle, die bestimmt, wie sich die Richtung ändert, wenn der Strahl verschiedene Kacheln verlässt. Die Kachel ist der Schlüssel und neue Richtungen sind die Werte.

b=[1];hält das Brett. Das erste Element ist 1 (wird als wahr ausgewertet), sodass die while-Schleife mindestens einmal ausgeführt wird.

r=p=0 rist die aktuelle Zeilennummer des Eingangs, pist die aktuelle Position des Laserstrahls.

while b[-1]: Beenden Sie das Laden von Board-Daten, wenn raw_input eine leere Zeichenfolge zurückgibt

b+=[raw_input()];r+=1 Hängen Sie die nächste Eingabezeile an die Karte an und erhöhen Sie den Zeilenzähler

for g in l: Errate nacheinander jede Laserrichtung

c=b[r].find(g) Stellen Sie die Spalte auf die Position des Lasers oder -1 ein, wenn sie nicht in der Linie liegt (oder in eine andere Richtung zeigt).

if-1<c:p=c+1j*r;d=gWenn wir einen Laser gefunden haben, stellen Sie die aktuelle Position pund Richtung ein d. dist einer der Zeichen inl

Nach dem Laden der Platine bwurden die aktuelle Position pund Richtung dauf die der Laserquelle eingestellt.

while' '<d: Leerzeichen hat einen niedrigeren ASCII-Wert als jedes der Richtungssymbole, daher verwenden wir ihn als Stopp-Flag.

z=l.find(d);Index der aktuellen Richtung char in der lZeichenfolge. zwird später verwendet, um sowohl die neue Strahlrichtung anhand der xTabelle zu bestimmen als auch die Position zu erhöhen.

p+=1j**z;Erhöhen Sie die Position mit einer Potenz von i. Zum Beispiel l.find('<')==2-> i ^ 2 = -1, wodurch eine Spalte nach links verschoben wird.

c=b[int(p.imag)][int(p.real)]; Lesen Sie das Zeichen an der aktuellen Position

d=x.get(c,' '*4)[z]Suchen Sie in der Transformationstabelle nach der neuen Richtung für den Strahl. Wenn das aktuelle Zeichen nicht in der Tabelle vorhanden ist, setzen Sie es dauf Leerzeichen.

print'#'<c print false, wenn wir auf etwas anderem als dem Ziel angehalten haben.

Theran
quelle
9
p+=1j**z: Das ist süß.
dmckee --- Ex-Moderator Kätzchen
16

Dies heißt war ein direkter Anschluss von Brians Lösung C # 3, abzüglich der Konsole Interaktionen. Dies ist kein Eintrag in der Herausforderung, da es sich nicht um ein vollständiges Programm handelt. Ich habe mich nur gefragt, wie einige der von ihm verwendeten F # -Konstrukte in C # dargestellt werden könnten.

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

Bearbeiten: Nach einigen Experimenten der folgende ziemlich ausführliche Suchcode:

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

wurde durch einen viel kompakteren LINQ to Objects-Code ersetzt:

var p = a.SelectMany((line, y) => line.Select((d, x) => new {x, y, d}))
         .First(x => new[] {'v', '^', '<', '>'}.Contains(x.d));
Nathan Baulch
quelle
8
Oh mein Gott. Was für ein schönes Beispiel, um zu demonstrieren, wie mächtig linq und c # geworden sind. 1+ denn ich bin ein großer C # -Fan. x)
Emiswelt
16

F #, 255 Zeichen (und immer noch ziemlich lesbar!):

Ok, nach einer Nachtruhe habe ich das sehr verbessert:

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

Lassen Sie uns Zeile für Zeile darüber sprechen.

Schlürfen Sie zunächst alle Eingaben in ein großes eindimensionales Array (2D-Arrays können für Code-Golf schlecht sein; verwenden Sie einfach ein 1D-Array und addieren / subtrahieren Sie die Breite einer Linie zum Index, um eine Linie nach oben / unten zu verschieben).

Als nächstes berechnen wir 'w', die Breite einer Eingabezeile, und 'c', die Startposition, indem wir in unser Array indizieren.

Definieren wir nun die 'nächste' Funktion 'n', die eine aktuelle Position 'c' und eine Richtung 'd' einnimmt, die 0,1,2,3 für oben, links, rechts, unten ist.

Das Index-Epsilon 'e' und das Was-neue-Richtung-wenn-wir-einen-Schrägstrich treffen 'werden von einer Tabelle berechnet. Wenn zum Beispiel die aktuelle Richtung 'd' 0 (aufwärts) ist, sagt das erste Element der Tabelle "-w, 2", was bedeutet, dass wir den Index um w dekrementieren, und wenn wir einen Schrägstrich treffen, ist die neue Richtung 2 (richtig).

Jetzt kehren wir mit (1) dem nächsten Index ("c + e" - aktuell plus epsilon) und (2) der neuen Richtung, die wir berechnen, indem wir nach vorne schauen, um zu sehen, in was sich das Array befindet, in die nächste Funktion 'n' zurück diese nächste Zelle. Wenn der Lookahead-Zeichen ein Schrägstrich ist, lautet die neue Richtung 's'. Wenn es sich um einen Backslash handelt, beträgt die neue Richtung 3 Sekunden (unsere Wahl der Codierung 0123 macht dies möglich). Wenn es ein Leerzeichen ist, gehen wir einfach weiter in die gleiche Richtung 'd'. Und wenn es sich um ein anderes Zeichen 'c' handelt, endet das Spiel und gibt 'true' aus, wenn das Zeichen 'x' war, andernfalls false.

Zum Auftakt rufen wir die rekursive Funktion 'n' mit der Anfangsposition 'c' und der Startrichtung auf (die die anfängliche Kodierung der Richtung in 0123 vornimmt).

Ich denke, ich kann wahrscheinlich noch ein paar Charaktere davon rasieren, aber ich bin ziemlich zufrieden damit (und 255 ist eine nette Zahl).

Brian
quelle
11

Das Wiegen von 18203 Zeichen ist eine Python-Lösung, die:

  • mit Spiegeln außerhalb des "Raumes" fertig werden
  • Berechnen Sie die Flugbahn, wenn es keinen "Raum" gibt, basierend auf 2D-Einschränkungen (die Spezifikation sagt viel darüber aus, was sich im "Raum" befinden muss, aber nicht, wenn der Raum existieren muss).
  • Fehler melden

Es muss noch etwas aufgeräumt werden und ich weiß nicht, ob die 2D-Physik vorschreibt, dass der Strahl sich nicht selbst kreuzen kann ...

#!/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()

Ein Bash-Skript zur Darstellung der Farbfehlerberichterstattung:

#!/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#
#\\^/\\ /  #
##########"

Die in der Entwicklung verwendeten Unittests:

#!/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
Metalshark
quelle
6
Die Laserphysik schreibt vor, dass sich der Strahl selbst kreuzen kann. Der obige Kommentar ist eine wichtige kulturelle Referenz.
dmckee --- Ex-Moderator Kätzchen
5
Schildkröte und der Hase Ansatz zum Code Golf. Liefern Sie etwas mit offensichtlich zu vielen Zeichen (91x mehr als der aktuelle Gewinner), aber achten Sie auf jeden Buchstaben der Spezifikation. Langsam und stetig bringt mir im Allgemeinen weniger Vertragsarbeit.
Metalshark
Ihrem Unittest scheint ein Teil zu fehlen. Es wird bei "self.NOT_DIRECTIO"
BioGeek
@BioGeek - das Limit für die Länge des Posts erreichen;). Neben den BASH-Stiltests wird die Farbhervorhebung deutlich.
Metalshark
11

Ruby, 176 Zeichen

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}

Ich habe eine einfache Zustandsmaschine verwendet (wie die meisten Poster), nichts Besonderes. Ich habe es einfach mit jedem Trick, den ich mir vorstellen konnte, runtergeschnitten. Das bitweise XOR, das zum Ändern der Richtung verwendet wurde (als Ganzzahl in der Variablen gespeichert c), war eine große Verbesserung gegenüber den Bedingungen, die ich in früheren Versionen hatte.

Ich habe den Verdacht, dass der Code, der inkrementiert xund yverkürzt werden könnte. Hier ist der Abschnitt des Codes, der das Inkrementieren ausführt:

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

Edit : Ich konnte das obige etwas kürzen:

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

Die aktuelle Richtung des Lasers cwird wie folgt gespeichert:

0 => auf
1 => runter
2 => links
3 => richtig

Der Code stützt sich auf diese Tatsache zu erhöhen xund ydurch die richtige Menge (0, 1 oder -1). Ich habe versucht, die Zahlen für jede Richtung neu anzuordnen, und nach einer Anordnung gesucht, mit der ich die Werte bitweise manipulieren kann, da ich das Gefühl habe, dass sie kürzer als die arithmetische Version ist.

Mike Spross
quelle
9

C # 3.0

259 Zeichen

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

Etwas besser lesbar:

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

Die Hauptverschwendung von Zeichen scheint darin zu liegen, die Breite der Karte und die Position der Laserquelle zu ermitteln. Irgendwelche Ideen, wie man das verkürzt?

Noldorin
quelle
Ich bin mir nicht sicher, ob dies kürzer ist, aber es ist mein Versuch, den Laser und die Breite zu finden: mit L = List <string>; mit P = System.Drawing.Point; mit L = List <string>; L r = new L. () {"v", "<", ">", "^"}; P p = neues 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 ist eine Liste <string>, die die Tabelle enthält, und sie gibt einen Punkt aus, der die
Laserposition darstellt
besser: mit 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
Probleme erfordert ein vollständiges Programm, keine Funktion.
Strager
wie wäre es while(1)
SSpoke
9

C + ASCII, 197 Zeichen:

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

Diese C-Lösung setzt einen ASCII-Zeichensatz voraus, sodass wir den XOR-Spiegeltrick verwenden können. Es ist auch unglaublich zerbrechlich - zum Beispiel müssen alle Eingabezeilen gleich lang sein.

Es unterschreitet die 200-Zeichen-Marke - aber verdammt noch mal, ich habe diese Perl-Lösungen immer noch nicht geschlagen!

caf
quelle
= O! +1! Danke, dass du mich geschlagen hast. =]
Strager
2
Bei den meisten guten Lösungen wird davon ausgegangen, dass alle Zeilen gleich lang sind. In Golf und Krieg ist alles fair.
Hobbs
Wenn es erforderlich wäre, dass die Zeilen nicht gleich lang sind, würde ich einen Testfall hinzufügen. aber ich habe klar gesagt, dass es beabsichtigt war :)
LiraNuna
9

Golfscript (83 Zeichen)

Hallo Gnibbler!

:\'><v^'.{\?}%{)}?:P@=?{:O[1-1\10?).~)]=P+
:P\=' \/x'?[O.2^.1^'true''false']=.4/!}do
Strager
quelle
3
Golfskript: Perl ~ = 1: 1,7
John La Rooy
9

Python - 152

Liest Eingaben aus einer Datei namens "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

Um von stdin zu lesen, ersetzen Sie die erste Zeile durch diese

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

Wenn Sie wahr / falsch in Kleinbuchstaben benötigen, ändern Sie die letzte Zeile in

print`D<5`.lower()
Gnibbler
quelle
Wie viele Zeichen braucht es, um Truezu trueund Falsezu zu wechseln false? ;-)
Mob
Könnten Sie nicht 1 Zeichen entfernen, indem Sie "print D<5" in "print D <5" ändern ? Oder fehlt mir etwas?
Ponkadoodle
@ Wallacoloo, sicher kann. Es wird nur für die Kleinbuchstaben wahr / falsch benötigt
John La Rooy
7

JavaScript - 265 Zeichen

Update IV - Es besteht die Möglichkeit, dass dies die letzte Runde von Updates ist, bei denen ein paar weitere Zeichen eingespart werden können, indem zu einer Do-While-Schleife gewechselt und die Bewegungsgleichung neu geschrieben wird.

Update III - Dank des Vorschlags von strager, Math.abs () zu entfernen und die Variablen in den globalen Namensraum zu stellen, wurde der Code in Verbindung mit einer Neuanordnung der Variablenzuweisungen auf 282 Zeichen reduziert.

Update II - Einige weitere Aktualisierungen des Codes, um die Verwendung von! = -1 zu entfernen, sowie einige bessere Verwendung von Variablen für längere Operationen.

Update - Wenn Sie fertig sind und einige Änderungen vorgenommen haben, indem Sie einen Verweis auf die Funktion indexOf erstellen (danke LiraNuna!) Und nicht benötigte Klammern entfernen.

Dies ist mein erstes Mal, dass ich Code Golf spiele, daher bin ich mir nicht sicher, wie viel besser dies sein könnte. Feedback wird geschätzt.

Vollständig minimierte Version:

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}

Originalversion mit Kommentaren:

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

Webseite zum Testen mit:

<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>
Rob Z.
quelle
Wie nimmt es Input? Ich möchte dies testen und verifizieren. Sie können auch viele Zeichen speichern, wenn Sie einen Verweis auf a.indexOf
LiraNuna
Ersetzen Sie index != -1mit index > 0bitte! (Hoffentlich setzt niemand den Lazer in die obere linke Ecke, damit er 0nicht zurückgegeben wird. =]) Sie können die varAnweisungen verketten oder ganz entfernen (indem Sie die Variablen in den globalen Namespace einfügen). Ich denke Math.abs(m)==1kann durch ersetzt werden m==-1|m==1. Kann movement = ...; location += movementoptimiert werden location += movement =?
Strager
@ strager- Hab gerade deinen Kommentar gesehen, sieht so aus, als hättest du ihn gepostet, während ich den Code aktualisiert habe, auf 300 Zeichen. Ich werde sehen, was ich mit der Eliminierung von Math.abs () tun kann.
rjzii
function(a){return g.indexOf(a)}kann durch function(a)g.indexOf(a)in neueren JavaScript-Versionen ersetzt werden.
user1686
6

Haus der Spiegel

Kein wirklicher Einstieg in die Herausforderung, aber ich habe ein Spiel geschrieben, das auf diesem Konzept basiert (nicht zu lange zurück).

Es ist in Scala geschrieben, Open Source und hier verfügbar :

Es macht ein bisschen mehr; befasst sich mit Farben und verschiedenen Arten von Spiegeln und Geräten, aber Version 0.00001 hat genau das getan, was diese Herausforderung verlangt. Ich habe diese Version jedoch verloren und sie wurde sowieso nie für die Anzahl der Zeichen optimiert.

HRJ
quelle
Wäre es Ihnen möglich, eine kompilierte Version hochzuladen, die unter Windows funktioniert, ohne scala installieren zu müssen?
Mailand
Es gibt eine Version mit Scala-Bibliotheken. Schauen Sie sich die Liste der Downloads an. Aber trotzdem, wenn Sie Scala jetzt installiert haben, bin ich froh, dass ich Sie dazu gebracht habe :)
HRJ
6

c (K & R) 339 notwendige Zeichen nach weiteren Vorschlägen von strager.

Der Physiker in mir bemerkte, dass die Ausbreitungs- und Reflexionsoperationen zeitumkehrinvariant sind, daher wirft diese Version Strahlen vom Ziel und prüft, ob sie am Laseremitter ankommen.

Der Rest der Implementierung ist sehr einfach und basiert mehr oder weniger genau auf meinen früheren Bemühungen.

Komprimiert:

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

Unkomprimiert (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");
}

Es gibt keine Eingabevalidierung, und eine schlechte Eingabe kann sie in eine Endlosschleife senden. Funktioniert ordnungsgemäß mit Eingaben, die nicht größer als 99 x 99 sind. Erfordert einen Compiler, der die Standardbibliothek ohne Einfügen eines der Header verknüpft. Und ich denke, ich bin fertig, Strager hat mich trotz seiner Hilfe um einiges geschlagen .

Ich hoffe eher, dass jemand einen subtileren Weg zeigt, um die Aufgabe zu erfüllen. Daran ist nichts auszusetzen, aber es ist keine tiefe Magie.

dmckee
quelle
Keine Notwendigkeit für =0die Globals, da sie standardmäßig auf 0 initialisiert sind. Ersetzen Sie Zeichenkonstanten durch ihre Dezimalstellen. Verwenden Sie >0anstelle von !=EOF, um mit EOF (und \0) zu vergleichen. Sie können wahrscheinlich einen #defineTeil des Codes so entfernen, casewie ich es mit ifs getan habe . Keine Notwendigkeit für die zusätzlichen \nim putsso putsmuss sowieso eine neue Zeile drucken. for(;;)ist kürzer als while(1). Hoffe das hilft. =]
Strager
@strager: Danke. Ich komme immer iterativ dazu, weil ich nicht so denke ...
dmckee --- Ex-Moderator Kätzchen
2
"There is no input validation"- Es sollte keine geben. Um es den Golfern zu erleichtern, wird davon ausgegangen, dass die Eingabe immer "sauber" ist, sofern nicht anders angegeben.
LiraNuna
@dmckee, keine Sorge, wir Code Golf-Profis arbeiten auch iterativ. Im Allgemeinen verwenden wir jedoch von Anfang an einige Tricks (wie die Hälfte der von mir erwähnten), aber das kommt mit Erfahrung. =]
Strager
Sofern ich nicht falsch zähle, besteht das Programm aus 390 Zeichen, nicht aus 380.
Strager
6

Rubin - 146 Zeichen

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
John La Rooy
quelle
5

PostScript , 359 Bytes

Erster Versuch, viel Raum für Verbesserungen ...

/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 =
KirarinSnow
quelle
4

Haskell, 395 391 383 361 339 Zeichen (optimiert)

Verwendet immer noch eine generische Zustandsmaschine und nichts Kluges:

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}

Eine lesbare Version:

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
Kommensturm
quelle
3

Ich glaube an die Wiederverwendung von Code, ich würde einen Ihrer Codes als API verwenden :).

  setzt Board.new.validate (Eingabe)

32 Zeichen \ o / ... wohoooo

Rishav Rastogi
quelle
6
Das ist ein Doppel-Bogey!
Jeff Atwood
3
Schlagen Sie es zu: p Board.new.validate Eingabe 26 Zeichen \ o /
Alessandra Pereyra
3

C ++: 388 Zeichen

#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 ohne Überschriften)


Wie es funktioniert:

Zuerst werden alle Zeilen eingelesen, dann wird der Laser gefunden. Im Folgenden wird ausgewertet, 0solange noch kein Laserpfeil gefunden wurde, und gleichzeitig xder horizontalen Position zugewiesen .

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

Dann schauen wir uns die Richtung an, in der wir sie gefunden haben, und speichern sie i. Gerade Werte von isind oben / links ("abnehmend") und ungerade Werte sind unten / rechts ("ansteigend"). Nach diesem Begriff werden d("Richtung") und r("Orientierung") eingestellt. Wir indizieren das Zeigerarray zmit Ausrichtung und fügen die Richtung der Ganzzahl hinzu, die wir erhalten. Die Richtung ändert sich nur, wenn wir einen Schrägstrich treffen, während sie gleich bleibt, wenn wir einen Schrägstrich treffen. Wenn wir auf einen Spiegel treffen, ändern wir natürlich immer die Ausrichtung ( r = !r).

Johannes Schaub - litb
quelle
Sie lassen mich meine eigene C ++ - Lösung machen. =]
Strager
2
@strager, das wird aber langweilig. Lassen Sie uns eine Lösung machen, die zur Kompilierungszeit "true" oder "false" anzeigt.
XD
Erklärung hinzugefügt, da ich denke, ich werde es dabei behalten :)
Johannes Schaub - litb
2

Groovy @ 279 Zeichen

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
Reverend Gonzo
quelle
2

C #

1020 Zeichen.
1088 Zeichen (Eingabe von der Konsole hinzugefügt).
925 Zeichen (überarbeitete Variablen).
875 Zeichen (redundanter Dictionary-Initialisierer entfernt; geändert in Binär & Operatoren)

Es wurde darauf hingewiesen, dass Sie sich vor dem Posten keine anderen ansehen sollten. Ich bin mir sicher, dass es ein bisschen LINQ sein könnte. Und die ganze FindLaser-Methode in der lesbaren Version scheint mir furchtbar faul zu sein. Aber es funktioniert und es ist spät :)

Beachten Sie, dass die lesbare Klasse eine zusätzliche Methode enthält, mit der die aktuelle Arena ausgedruckt wird, wenn sich der Laser bewegt.

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

Lesbare Version (nicht ganz die endgültige Golfversion, aber dieselbe Voraussetzung):

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;
        }
    }
}
Metro Schlumpf
quelle
2
Das Programm sollte Eingaben nehmen. Am häufigsten von stdin.
LiraNuna
0

Perl 219
Meine Perl-Version ist 392 342 Zeichen lang (ich musste den Fall behandeln, dass der Strahl auf den Laser trifft):
Update , danke Hobbs, dass er mich daran erinnert hat tr//, es sind jetzt 250 Zeichen:
Aktualisieren , Entfernen des mIn m//, Ändern der beiden whilemitgebrachten Schleifen ein paar Einsparungen; Es ist nur noch ein Platz erforderlich.
( L:it;goto List gleich lang wie 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

Ich habe einige rasiert, aber es konkurriert kaum mit einigen davon, wenn auch spät.
Es sieht ein bisschen besser aus als:

#!/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

Nun ... Ehrlich gesagt sollte dies selbsterklärend sein, wenn Sie verstehen, dass @bes sich um ein Array von Zeichen in jeder Zeile handelt und Sie den einfachen regulären Ausdruck und die trAnweisungen lesen können .

Dlamblin
quelle
Tipp: Sie können Ihren Spiegelcode ganz nach oben kürzen. $_=$s;tr/^v<>/<>^v/und $_=$s;tr/v^<>/<>^v/jeweils. Außerdem brauchen Sie das min nicht m//.
Hobbs
Sorry, mach das zweite$_=$s;tr/v^></<>^v/;
Hobbs
Sie haben noch mehrere if m/.../, die if/.../zwei Zeichen pro Pop speichern könnten .
Hobbs
Sie können y///statt tr///zwei Zeichen speichern.
Platinum Azure
0

F # - 454 (oder ungefähr)

Etwas spät zum Spiel, kann aber nicht widerstehen, meinen zweiten Versuch zu veröffentlichen.

Update leicht modifiziert. Stoppt jetzt korrekt, wenn der Sender getroffen wird. Gekniffen Brians Idee für IndexOfAny (schade, dass diese Zeile so ausführlich ist). Ich habe es nicht wirklich geschafft, herauszufinden, wie ReadToEnd von der Konsole zurückkehren kann, also vertraue ich darauf ...

Ich bin mit dieser Antwort zufrieden, als wäre sie ziemlich kurz, aber immer noch ziemlich lesbar.

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))
Benjol
quelle
Sie sind Dekoration. Überprüfen Sie meine anderen Herausforderungen, es ist nur eine Formatierungssache.
LiraNuna
@LiraNuna, ok wie sich herausstellt, diese Iteration frisst sie sowieso nur :)
Benjol
Wäre schön mit einer 1-d Implementierung zu vergleichen. Addiere / subtrahiere einfach 1 für links und rechts und addiere / subtrahiere w für oben und unten. Ich würde erwarten, dass Sie einige Zeichen sparen
John La Rooy
@gnibbler, Brian hat das schon getan, ich bin mir nicht sicher, ob ich ihn schlagen könnte, aber ich könnte es versuchen.
Benjol