Python 3, 371 274 bytes
def f(s,n):
for y in(a:=range(n)):
for x in a:r=min(x,y,n+~x,n+~y);i=4*r*(n-r)-2*r+x+y+2*(2*(n+~r)-x-y)*(y>x);H=max(n+~y,y)>x>min(y-2,n-y-2);b=x+1>n/2;D=(n+~x-x)*b+x==n+~y;print(s[i]if i<len(s)else".<.>"[D+n%2*2]if(n+2*~x)*b+x==y-1else"|'-'"[D+2*H],end=" -"[H])
print()
Minus 64 bytes thanks to @noodleman and another 11 bytes thanks to @Kevin Cruijssen! I then saved another 22 bytes.
Instead of most other solutions (as far as I can tell), I tried calculating the index into the string. I dug up a post on StackOverflow that helped with this, though a lot was just throwing random equations and seeing what they do. Maybe the indexing equation can be simplified with a bit more thought, but it's surprisingly short already.
There are lots of places where -x-1
is replaced with +~x
(or variants). Booleans are heavily used for indexing and cancelling parts of equations with multiplication.
Ungolfed:
def function(string: str, number: int):
for y in range(number):
for x in range(number):
rounds = min(x, y, number - x - 1, number - y - 1)
# total increments after `rounds` revolutions and fix for overcounting
index = 4 * rounds * (number - rounds) - 2 * rounds
index += x + y # east + south increment
index += 2 * (2 * (number - rounds - 1) - x - y) * (y > x) # west + north
is_horizontal = max(number - y + 1, y + 2) > x + 2 > min(y, number - y)
is_right = x + 1 > number / 2
is_up_corner = x + is_right * (number - 2 * (x + 1)) == y - 1 # inlined
is_down_corner = x + is_right * (number - 1 - 2 * x) == number - y - 1
# is_middle = x + 1 - number % 2 == y == number // 2
# is_middle = is_up_corner and is_down_corner
# is_down = y > number / 2
# is_left_corner = y + is_down * (number - 2 * y) == x + 1
# is_right_corner = y + is_down * (number - 1 - 2 * y) != number - x - 1
print(
string[index] if index < len(string) else
".<.>"[is_down_corner + 2 * (number % 2)] if is_up_corner else
"|'-'"[is_down_corner + 2 * is_horizontal],
end=" -"[is_horizontal]
)
print()
Explanation of is_horizontal
boolean:
There are effectively four quadrants in which we need to determine whether the coordinate is a horizontal part in the snake, we can do this for the upper right corner with number - y - 1 > x
. On its own this is not enough, because the lower part of the snake is now messed up. Taking y > x
works for the lower right quadrant, but messes up the snake above. Combining these two equations into max(number - y - 1, y) > x
leaves only the left part of the snake to fix. Creating conditions for the other corners you can combine x > min(y - 2, number - y - 2)
into one large expression.
------------. ------------. ------------.
.---------. | .---------. | .---------. |
--.-----. | | --.-----. | | | .-----. | |
----.-> | | | becomes ----.-> | | | becomes | | .-> | | |
----' | ' | | ----'---' | | | | '---' | |
--' | | | ' | --'-------' | | '-------' |
' | | | | | ' '-----------' '-----------'