Perl, 647
Ini adalah upaya pertama saya di kode-golf, dan saya agak malu saya bahkan tidak mengalahkan skor C #, tapi saya pikir itu akan menarik (atau menyenangkan, atau hanya masokis) untuk melakukan semuanya sebagai serangkaian penggantian regex. (Saya juga berpikir akan menyenangkan untuk memoles Perl saya, tetapi pada akhirnya saya sangat menyesal tidak menerapkannya dalam Ruby atau Python.)
Saya belum melakukan banyak pengujian, tetapi saya pikir itu harus menangani setiap kasus.
Grid adalah input melalui STDIN. Harus ada setidaknya satu baris baru di input (yaitu satu baris tanpa baris baru tidak akan berfungsi).
%s=(d,'[|+#$vk%ZX]',u,'[|+#$^W%KX]',r,'[-G+#>k%KX]',l,'[-G+#<W%ZX]');%o=(d,'[-.*G/k\\\\Z',u,'[-.*G/W\\\\K',r,'[|.*$\\\\/kK',l,'[|.*$\\\\/ZW');for$d(d,u,r,l){$o{$d}.='123456789qwertyuio]'}%u=(d,'.|-+*$G#/Wk%\KZX',u,'.|-+*$G#/kW%\ZKX',r,'.-|+*G$#/Wk%\ZKX',l,'.-|+*G$#/kW%\KZX');@q=split//,"qwertyuio";local$/;$_=<STDIN>;for$i(1..9){$m{$i}=$q[$i-1];$m{$m{$i}}=$i;s/$i/$m{$i}/e}/.*?\n/;$l='.'x((length$&)-1);do{$c=0;for$d(d,u,r,l){%p=(d,"(?<=$s{d}$l)$o{d}",u,"$o{u}(?=$l$s{u})",r,"(?<=$s{r})$o{r}",l,"$o{l}(?=$s{l})");%h=split//,$u{$d};$c+=s!$p{$d}!$h{$&}||($v=$&,($o{$d}=~s/$v// && $s{$d}=~s/]/$m{$v}]/),$v)!es}}while($c);print/\*/?"False\n":"True\n"
Penjelasan: kode secara iteratif memperbarui string grid ketika laser melewatinya. -
merupakan laser horisontal, |
laser vertikal, +
laser menyeberang, K
sebuah \
cermin dengan laser memantul dari atas, k
sebuah /
cermin dengan laser memantul dari bawah, Z
sebuah \
cermin dengan laser memantul dari bagian bawah, dan W
sebuah /
cermin dengan laser memantul atas. %
adalah /
cermin dengan laser di kedua sisi, sementara X
adalah \
cermin dengan laser di kedua sisi. (Ini peka huruf besar-kecil. Saya mencoba mengambil huruf yang terlihat agak sesuai - misalnya, k
danK
adalah pilihan yang agak jelas - tetapi sayangnya efeknya sebenarnya tidak terlalu membantu. Saya benar-benar harus memasukkan info ini ke dalam tabel, tapi saya kelelahan sekarang.)
Menangani portal dengan cara yang sama (yaitu menetapkan setiap digit satu set karakter tambahan berdasarkan kemungkinan posisi input / output laser) akan membutuhkan 144 karakter (termasuk yang asli 9), jadi sebagai gantinya, ketika laser menyentuh portal "input", Saya menambahkan "output" karakter portal ke set karakter yang memancarkan laser ke arah yang tepat. (Ini memang membutuhkan membedakan antara portal input dan output; saya menggunakan huruf qwertyuio
untuk ini.)
Agak un-golf, dengan pernyataan cetak sehingga Anda dapat melihat substitusi terjadi (setiap substitusi mewakili satu "putaran" perkembangan laser), dan dengan g
bendera ditambahkan ke utama s///
sehingga tidak mengambil begitu banyak iterasi:
# Throughout, d,u,r,l represents lasers going down, up, left, or right
# `sources` are the character classes representing laser "sources" (i.e. any
# character that can, on the next round, cause a laser to enter the space
# immediately adjacent to it in the proper direction)
%sources=(d,'[|+#$vk%ZX]',u,'[|+#$^W%KX]',r,'[-G+#>k%KX]',l,'[-G+#<W%ZX]');
# `open` characters will not block a laser
%open=(d,'[-.*G/k\\\\Z',u,'[-.*G/W\\\\K',r,'[|.*$\\\\/kK',l,'[|.*$\\\\/ZW');
# One of each portal is changed into the corresponding letter in `qwertyuio`.
# At the start, each portal is 'open' and none of them is a source.
for$d(d,u,r,l){$open{$d}.='123456789qwertyuio]'}
# A mapping of 'open' characters to the characters they become when a laser
# goes through them. (This is used like a hash of hashes; see the assignment
# of `%h` below.)
%update=(d,'.|-+*$G#/Wk%\KZX',
u,'.|-+*$G#/kW%\ZKX',
r,'.-|+*G$#/Wk%\ZKX',
l,'.-|+*G$#/kW%\KZX');
@q=split//,"qwertyuio";
local$/;$_=<STDIN>;
for$i(1..9){
$m{$i}=$q[$i-1];
$m{$m{$i}}=$i;
s/$i/$m{$i}/e}
print "After substituting portals:\n";
print;
print "\n";
# Find the number of characters in each line and create a string of `.`'s,
# which will be used to correlate characters above/below one another in the
# grid with each other.
/.*?\n/;
$l='.'x((length$&)-1);
do{
$changes=0;
for$d(d,u,r,l){
# `patterns` is a mapping from each direction to the regex representing
# an update that must occur (i.e. a place where a laser must progress).
# Each pattern is either a lookahead or lookbehind plus the necessary
# "open" character class.
%patterns=(d,"(?<=$sources{d}$l)$open{d}",
u,"$open{u}(?=$l$sources{u})",
r,"(?<=$sources{r})$open{r}",
l,"$open{l}(?=$sources{l})");
%h=split//,$update{$d};
# Match against the pattern for each direction. Note whether any
# matches were found.
$changes+=s!$patterns{$d}!
# If the "open" character for a map is in the `update` map, return
# the corresponding value. Otherwise, the "open" character is a
# portal.
$h{$&} || ($v=$&,
# For portals, remove the input portal from the
# proper "open" list and add the output portal to
# the proper "source" list.
($open{$d}=~s/$v// && $sources{$d}=~s/]/$m{$v}]/),
$v)
# This whole substitution should allow `.` to match
# newlines (see the definition of `$l` above), and the
# replacement must be an expression rather than a string
# to facilitate the portal logic. The `g` allows multiple
# updates per "frame"; it is left out of the golfed code.
!egs
}
# Print the next "frame".
print;
print "\n";
# Continue updating until no "open" spaces are found.
}while($changes);
# Print whether `*` is still present in the input.
print/\*/?"False\n":"True\n"