Луа, 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
Безумовно
Пояснення прийдуть, як тільки я закінчу це з гольфу, на даний момент я вам позичу читабельну версію цього вихідного коду: 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.
На сітці 4х4 тут розташовані відстані змій (зліва) та порядок їх перегляду (праворуч)
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...
Перевірка, чи знак char не є пробілом, досягається виразом m[i][j]~=s
.
Перевіряючи, чи оточено вас лише 1 непробілом, досягається встановлення вищезазначених умов для оточуючих, це може бути записано як
m[i+1][j]~=" " ⊕ m[i][j+1]~=" " ⊕ m[i-1][j]~=" " ⊕ m[i][j-1]~=" "
І нарешті, якщо все вищезазначене буде оцінено як істинне, термінал поверне те, що в останньому 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)