Lua, 562 535 529 513 507 504 466 458 byte
Di gran lunga il mio golf più massiccio in questo momento, penso di poter ancora tagliare 100 byte, a cui lavorerò, ma pubblicandolo come una risposta in quanto ha già impiegato del tempo :). Avevo ragione, ho tagliato più di 100 byte! Non credo che ci sia molto margine di miglioramento.
questa funzione deve essere chiamata con un array 2D contenente un carattere per cella.
40 byte salvati lavorando con @KennyLau , grazie a lui!
Woohoo! Meno di 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
Ungolfed
Le spiegazioni arriveranno quando avrò finito di giocare a golf, per il momento, ti presterò una versione leggibile di questo codice sorgente: D Ecco le spiegazioni!
Modifica: non aggiornato con l'ultima modifica, continua a giocare a golf prima dell'aggiornamento. Lo stesso vale per le spiegazioni
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
Quindi ecco alcune spiegazioni dettagliate su come funziona questo programma.
Prima di tutto, consideriamo il ciclo etichettato a
, ci consente di trovare l'estremità più vicina all'angolo in alto a sinistra. Andrà in loop per sempre se non c'è fine, ma non è un problema: D.
Su una griglia 4x4, qui ci sono le distanze del serpente (a sinistra) e l'ordine in cui vengono guardate (a destra)
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
Per ognuno di questi personaggi, per essere alla fine, deve controllare due condizioni: - Non essere uno spazio - Essere circondato esattamente da 3 spazi (o esattamente 1 non-spazio)
Queste condizioni sono verificate nel codice seguente
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...
Controllare se il carattere non è uno spazio viene raggiunto dall'espressione m[i][j]~=s
.
Controllando se siamo circondati da solo 1 non-spazio viene raggiunto xorando le condizioni di cui sopra per l'ambiente circostante, questo potrebbe essere scritto come
m[i+1][j]~=" " ⊕ m[i][j+1]~=" " ⊕ m[i-1][j]~=" " ⊕ m[i][j-1]~=" "
E infine, se tutto quanto sopra è valutato come vero, il ternario restituirà ciò che è nell'ultimo and
-> m[i][j]
. Altrimenti, lasciamo r
deselezionare :)
Ora che abbiamo la testa del serpente, andiamo fino all'altra estremità! L'iterazione del serpente è ottenuta principalmente dai seguenti ternari nidificati:
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
Abbiamo reimpostato i
e j
allo stesso tempo per evitare la necessità dei manichini di memorizzare i vecchi valori Entrambi hanno la stessa identica struttura e usano condizioni semplici, quindi li presenterò sotto forma di nidificati if
, dovrebbe permetterti di leggerli più facilmente. :)
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
Può essere tradotto in:
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
Provalo!
Ecco il codice che uso per eseguirlo, puoi testarlo online copiandolo e incollandolo.
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)