Lua, 562 535 529 513 507 504 466 458 Bytes
De longe, o meu golfe mais massivo no momento, acho que ainda posso cortar 100 bytes, nos quais trabalharei, mas publicá-lo como resposta, pois já levou algum tempo :). Eu estava certo, reduzi mais de 100 bytes! Não acho que haja muito espaço para melhorias.
essa função deve ser chamada com uma matriz 2D contendo um caractere por célula.
Economizou 40 bytes ao trabalhar com @KennyLau , graças a ele!
Woohoo! Menos de 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
As explicações virão assim que eu terminar de jogar isso, por enquanto, emprestarei uma versão legível deste código-fonte: D A seguir, as explicações!
Editar: não atualizado com a modificação mais recente, ainda jogando golfe antes da atualização. O mesmo vale para as explicações
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
Então, aqui estão algumas explicações detalhadas sobre como este programa funciona.
Primeiro de tudo, vamos considerar o loop rotulado a
, que permite encontrar o final mais próximo do canto superior esquerdo. Ele funcionará para sempre se não houver fim, mas isso não é um problema: D.
Em uma grade 4x4, aqui estão as distâncias das cobras (esquerda) e a ordem em que elas são vistas (direita)
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
Para cada personagem, para ser o fim, é necessário verificar duas condições: - Não ser um espaço - Estar cercado por exatamente 3 espaços (ou exatamente 1 não espaço)
Essas condições são verificadas no seguinte trecho de código
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...
Verificar se o char não é um espaço é alcançado pela expressão m[i][j]~=s
.
Verificando se você está cercado por apenas 1 não espaço, obtém-se as seguintes condições para o ambiente, isso pode ser escrito como
m[i+1][j]~=" " ⊕ m[i][j+1]~=" " ⊕ m[i-1][j]~=" " ⊕ m[i][j-1]~=" "
E finalmente, se todas as opções acima forem avaliadas como verdadeiras, o ternário retornará o que está no último and
-> m[i][j]
. Senão, deixamos por r
definir :)
Agora que temos a cabeça da cobra, vamos até o outro extremo! A iteração da cobra é alcançada principalmente pelos seguintes ternários aninhados:
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
Nós redefinimos i
e j
, ao mesmo tempo, para evitar a necessidade de manequins para armazenar os valores antigos. Ambos têm exatamente a mesma estrutura e usam condições simples; portanto, eu os apresentarei na forma de aninhados if
, deve permitir que você os leia mais 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
Pode ser traduzido para:
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
Teste-o!
Aqui está o código que eu uso para executar isso, você pode testá-lo online copiando e colando.
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)