Lua, 562 535 529 513 507 504 466 458 байт
Безусловно, мой самый большой гольф на данный момент, я думаю , что я все еще могу отрезать 100 байтов, к которым я буду стремиться, но разместив его как ответ, поскольку это уже заняло некоторое время :). Я был прав, я вырубил более 100 байтов! Я не думаю, что есть много возможностей для улучшения.
эта функция должна вызываться с двумерным массивом, содержащим один символ на ячейку.
Благодаря ему удалось сэкономить 40 байт при работе с @KennyLau !
Woohoo! До 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
Пояснения придут, как только я закончу играть в гольф, на данный момент я одолжу вам читаемую версию этого исходного кода: D Вот и объяснения!
Изменить: не обновляется с последней модификацией, все еще игра в гольф перед обновлением. То же самое касается объяснений
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
Итак, вот некоторые подробные объяснения о том, как работает эта программа.
Прежде всего, давайте рассмотрим цикл с меткой a
, он позволяет нам найти ближайший конец к верхнему левому углу. Это будет цикл навсегда, если нет конца, но это не проблема: D.
На сетке 4x4 здесь указаны расстояния между змеями (слева) и порядок их просмотра (справа)
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
Для каждого этого символа, чтобы быть в конце, он должен проверить два условия: - не быть пробелом - быть окруженным ровно 3 пробелами (или ровно 1 не пробел)
Эти условия проверяются следующим фрагментом кода
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...
Проверка, если символ не пробел, достигается выражением m[i][j]~=s
.
Проверка того, что мы окружены только одним незаполненным пространством, достигается путем изменения указанных выше условий для нашего окружения, это можно записать как
m[i+1][j]~=" " ⊕ m[i][j+1]~=" " ⊕ m[i-1][j]~=" " ⊕ m[i][j-1]~=" "
И, наконец, если все вышеперечисленное оценено как true, троичный вернет то, что в последнем and
-> m[i][j]
. Остальное мы дадим r
неустановленным :)
Теперь, когда у нас есть голова змеи, давайте пройдем весь путь до другого конца! Итерации змеи в основном достигаются следующими вложенными троицами:
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
Мы переустанавливаем i
и j
в то же время избегаем использования манекенов для хранения старых значений. Они оба имеют одинаковую структуру и используют простые условия, поэтому я представлю их в виде вложенных if
, это должно позволить вам прочитать их легче. :)
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
Можно перевести на:
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
Проверь это!
Вот код, который я использую для запуска, вы можете проверить его онлайн , скопировав его.
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)