Lua, 562 535 529 513 507 504 466 458 bajtów
Zdecydowanie najbardziej masywny golf w tej chwili, myślę, że wciąż mogę odciąć 100 bajtów, nad którymi będę pracował, ale opublikowałem to jako odpowiedź, ponieważ zajęło to już trochę czasu :). Miałem rację, skróciłem ponad 100 bajtów! Nie sądzę, żeby było dużo miejsca na ulepszenia.
tę funkcję należy wywołać za pomocą tablicy 2D zawierającej jeden znak na komórkę.
Dzięki niemu zaoszczędziłem 40 bajtów podczas pracy z @KennyLau !
Łał! Poniżej 500!
function f(m)t=2u=1i=1j=1s=" "::a::if s~=m[i][j]and(i<#m and m[i+1][j]~=s)~=(j<#m[i]and m[i][j+1]~=s)~=(i>1 and m[i-1][j]~=s)~=(j>1 and m[i][j-1]~=s)then goto b end
i,t=i%t+1,#m>t and t==i and t+1or t j=j>1 and j-1or u u=u<#m[1]and j==1 and u+1or u goto a::b::io.write(m[i][j])m[i][j]=s
i,j=i<#m and s~=m[i+1][j]and i+1or i>1 and s~=m[i-1][j]and i-1or i,j<#m[i]and s~=m[i][j+1]and j+1or j>1 and s~=m[i][j-1]and j-1or j
if s==m[i][j]then return end goto b end
Nie golfił
Wyjaśnienia nadejdą, kiedy skończę grać w golfa, na razie pożyczę ci czytelną wersję tego kodu źródłowego: D Oto wyjaśnienia!
Edycja: nie zaktualizowano o najnowszą modyfikację, nadal gra w golfa przed aktualizacją. To samo dotyczy wyjaśnień
function f(m) -- declare the function f which takes a matrix of characters
t=2 -- initialise the treshold for i
-- when looking for the first end of the snake
u=1 -- same thing for j
i,j=1,1 -- initialise i and j,our position in the matrix
s=" " -- shorthand for a space
::a:: -- label a, start of an infinite loop
if m[i][j]~=s -- check if the current character isn't a space
and(i<#m -- and weither it is surrounded by exactly
and m[i+1][j]~=s) -- 3 spaces or not
~=(j<#m[i]
and m[i][j+1]~=s) -- (more explanations below)
~=(i>1
and m[i-1][j]~=s)
~=(j>1
and m[i][j-1]~=s)
then goto b end -- if it is, go to the label b, we found the head
i,t= -- at the same time
i%t+1, -- increment i
#m>t and t==i and t+1or t -- if we checked all chars in the current range, t++
j=j>1 and j-1or u -- decrement j
u=u>#m[1]and j==1 and u+1or u-- if we checked all chars in the current range, u++
goto a -- loop back to label a
::b:: -- label b, start of infinite loop
io.write(m[i][j]) -- output the current char
m[i][j]=s -- and set it to a space
i,j=i<#m -- change i and j to find the next character in the snake
and m[i+1][j]~=s -- this nested ternary is also explained below
and i+1 -- as it takes a lot of lines in comment ^^'
or i>1
and m[i-1][j]~=s
and i-1
or i,
j<#m[i]
and m[i][j+1]~=s
and j+1
or j>1
and m[i][j-1]~=s
and j-1
or j
if m[i][j]==s -- if the new char is a space
then -- it means we finished
return -- exit properly to avoid infinite
end -- printing of spaces
goto b -- else, loop back to label b
end
Oto kilka szczegółowych wyjaśnień na temat działania tego programu.
Po pierwsze, rozważmy pętlę oznaczoną etykietą a
, która pozwala nam znaleźć najbliższy koniec lewego górnego rogu. Zapętli się na zawsze, jeśli nie będzie końca, ale to nie jest problem: D.
Na siatce 4x4 są to odległości węża (po lewej) i kolejność, w jakiej są oglądane (po prawej)
1 2 3 4 | 1 2 4 7
2 3 4 5 | 3 5 8 11
3 4 5 6 | 6 9 12 14
4 5 6 7 | 10 13 15 16
Dla każdej z tych postaci musi być koniec dwóch warunków: - Nie bycie spacją - Otoczenie dokładnie 3 spacjami (lub dokładnie 1 spacją)
Warunki te są sprawdzane przez następujący fragment kodu
r=m[i][j]~=s
and(i<#m and m[i+1][j]~=s)
==not(j<#m[i] and m[i][j+1]~=s)
==not(i-1>0 and m[i-1][j]~=s)
==not(j-1>0 and m[i][j-1]~=s)
and m[i][j]
or r
-- special note: "==not" is used as an equivalent to xor
-- as Lua doesn't know what is a xor...
Wyrażenie sprawdza, czy char nie jest spacją m[i][j]~=s
.
Sprawdzając, czy otaczają nas tylko 1 spacje, uzyskujemy xor powyższe warunki dla naszego otoczenia, można to zapisać jako
m[i+1][j]~=" " ⊕ m[i][j+1]~=" " ⊕ m[i-1][j]~=" " ⊕ m[i][j-1]~=" "
I wreszcie, jeśli wszystko powyższe zostanie ocenione jako prawdziwe, trójka zwróci to, co jest w ostatnim and
-> m[i][j]
. W przeciwnym razie pozwalamy r
rozbroić :)
Teraz, gdy mamy już głowę węża, przejdźmy do drugiego końca! Iteracja węża jest osiągana głównie przez następujące trójskładniki zagnieżdżone:
i,j=i<#m and m[i+1][j]~=s and i+1or i-1>0 and m[i-1][j]~=s and i-1or i,
j<#m[i]and m[i][j+1]~=s and j+1or j-1>0 and m[i][j-1]~=s and j-1or j
Zresetujemy się, i
a j
jednocześnie unikamy konieczności używania manekinów do przechowywania starych wartości. Obie mają dokładnie taką samą strukturę i używają prostych warunków, więc przedstawię je w formie zagnieżdżonej if
, co powinno umożliwić ich odczytanie łatwiejsze. :)
i=i<#m and m[i+1][j]~=s and i+1or i-1>0 and m[i-1][j]~=s and i-1or i
Można przetłumaczyć na:
if(i<#m)
then
if(m[i+1][j]~=" ")
then
i=i+1
end
elseif(i-1>0)
then
if(m[i-1][j]~=" ")
then
i=i-1
end
end
Sprawdź to!
Oto kod, którego używam do uruchomienia tego. Możesz go przetestować online , kopiując i wklejając.
function f(m)t=2u=1i=1j=1s=" "::a::if s~=m[i][j]and(i<#m and m[i+1][j]~=s)~=(j<#m[i]and m[i][j+1]~=s)~=(i>1 and m[i-1][j]~=s)~=(j>1 and m[i][j-1]~=s)then goto b end
i,t=i%t+1,#m>t and t==i and t+1or t j=j>1 and j-1or u u=u<#m[1]and j==1 and u+1or u goto a::b::io.write(m[i][j])m[i][j]=s
i,j=i<#m and s~=m[i+1][j]and i+1or i>1 and s~=m[i-1][j]and i-1or i,j<#m[i]and s~=m[i][j+1]and j+1or j>1 and s~=m[i][j-1]and j-1or j
if s==m[i][j]then return end goto b end
test1={}
s1={
" tSyrep ",
" r p ",
" in Sli ",
" g Sile",
" Snakes n",
"Ser ylt",
"a eh ilS ",
"fe w t ",
" emo h ",
" Sre ",
}
for i=1,#s1
do
test1[i]={}
s1[i]:gsub(".",function(c)test1[i][#test1[i]+1]=c end)
end
f(test1)