Skip to main content
Add 253 bytes method that outputs differently, shorter than other python now!
Source Link
anderium
  • 613
  • 5
  • 9

Python 3, 371 274 255 and 253 bytes

253 bytes solution

This solution outputs not a string, but a nested array/matrix of characters. This might be allowed according to the meta post: Strings and arrays of characters are interchangeable.

It's effectively the same as the above, but also returns instead of prints. It unfortunately requires *''.join() in the inner loop, because you cannot populate an array with two items per iteration. (And by doubling the iterations I only managed to golf to 255.)

lambda s,n:[[*''.join((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,s[i:]and s[i]or"|-..''><"[H+2*((n+2*~x)*b-~x==y)+4*((n+~x-x)*b+x==n+~y)])[4]+" -"[H]for x in range(n))]for y in range(n)]

Try it online!

Python 3, 371 274 255 bytes

Python 3, 371 274 255 and 253 bytes

253 bytes solution

This solution outputs not a string, but a nested array/matrix of characters. This might be allowed according to the meta post: Strings and arrays of characters are interchangeable.

It's effectively the same as the above, but also returns instead of prints. It unfortunately requires *''.join() in the inner loop, because you cannot populate an array with two items per iteration. (And by doubling the iterations I only managed to golf to 255.)

lambda s,n:[[*''.join((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,s[i:]and s[i]or"|-..''><"[H+2*((n+2*~x)*b-~x==y)+4*((n+~x-x)*b+x==n+~y)])[4]+" -"[H]for x in range(n))]for y in range(n)]

Try it online!

Incorporate xnor's improvement, simplify even further and add additional explanation
Source Link
anderium
  • 613
  • 5
  • 9

Python 3, 371 274274 255 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;print2;print(s[i]ifs[i:]and i<len(s)else"s[i]or"|-.<.>"[D+n%2*2]if''><"[H+2*((n+2*~x)*b+x==y*b-1else"|'~x==y)+4*((n+~x-'"[D+2*H]x)*b+x==n+~y)],end=" -"[H])
  print()

Try it online!Try it online!

Minus 64 bytes thanks to @noodleman and another 11 bytes thanks to @Kevin Cruijssen! I then saved another 22 bytes. Most recent improvement of 6 bytes by @xnor and 13 bytes by me.

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

      # See below for explanation
      is_horizontal = max(number - y +- 1, y + 2) > x + 2 > min(y - 2, number - y - 2)
      is_right = x + 1 > number / 2
      # Both inlined
      is_up_corner = x + 1 + 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_cornerstring[index:] +and 2string[index] *or (number\
 % 2)] if is_up_corner else   # See below for explanation
        "|'"|-'"[is_down_corner..''><"[is_horizontal + 2 * is_horizontal]is_up_corner + 4 * is_down_corner],
        end=" -"[is_horizontal]
      )
    print()

Explanation of special character indexing into |-..''><: There are six special characters that we need to index into, which can be separated into three categories: Straight, corner and tail. By virtue of the equations, we can determine we need a tail if something is both an up- and down-corner. Obviously, if it is not a corner or tail, it should be a straight piece. Using the equation is_up_corner + 2 * is_down_corner we can differentiate the four cases straight, up-corner, down-corner, and tail. To select the correct straight and tail pieces we still need a more granular distinction. Using is_horizontal obviously works for straight pieces and additionally it works for the tail, because the left-pointing arrow has an appendage whereas the right-pointing does not. This can be combined with the previous equation by doubling the corners.

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()

Try it online!

Minus 64 bytes thanks to @noodleman and another 11 bytes thanks to @Kevin Cruijssen! I then saved another 22 bytes.

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()

Python 3, 371 274 255 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;print(s[i:]and s[i]or"|-..''><"[H+2*((n+2*~x)*b-~x==y)+4*((n+~x-x)*b+x==n+~y)],end=" -"[H])
  print()

Try it online!

Minus 64 bytes thanks to @noodleman and another 11 bytes thanks to @Kevin Cruijssen! I then saved another 22 bytes. Most recent improvement of 6 bytes by @xnor and 13 bytes by me.

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

      # See below for explanation
      is_horizontal = max(number - y - 1, y) > x > min(y - 2, number - y - 2)
      is_right = x + 1 > number / 2
      # Both inlined
      is_up_corner = x + 1 + is_right * (number - 2 * (x + 1)) == y
      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
        string[index:] and string[index] or \
        # See below for explanation
        "|-..''><"[is_horizontal + 2 * is_up_corner + 4 * is_down_corner],
        end=" -"[is_horizontal]
      )
    print()

Explanation of special character indexing into |-..''><: There are six special characters that we need to index into, which can be separated into three categories: Straight, corner and tail. By virtue of the equations, we can determine we need a tail if something is both an up- and down-corner. Obviously, if it is not a corner or tail, it should be a straight piece. Using the equation is_up_corner + 2 * is_down_corner we can differentiate the four cases straight, up-corner, down-corner, and tail. To select the correct straight and tail pieces we still need a more granular distinction. Using is_horizontal obviously works for straight pieces and additionally it works for the tail, because the left-pointing arrow has an appendage whereas the right-pointing does not. This can be combined with the previous equation by doubling the corners.

Golf more and add minor explanation
Source Link
anderium
  • 613
  • 5
  • 9

Python 3, 371371 274 bytes

def f(s,n):
 for y in range(a:=range(n)):
  for x in range(n)a:
   r=min(x,y,n-x-1n+~x,n-y-1n+~y);i=4*r*(n-r)-2*r+x+y+2*(2*(n-r-1-xn+~r)+(n-r-1x-y)*(y+x<n-1))*(y>x);H=;H=max(x<n-n+~y,y-1or x<y)and>x>min(x>yy-2or x>n2,n-y-2)
   if i<len(s):c=s[i]
   elif x+1-(n%2)==y==n/;b=x+1>n/2:c="<>"[n%2]
   elif2;D=(n-2n+~x-2*xx)**b+x==n+~y;print(x+1>n/2)+x==y-1:c="."
  s[i]if elifi<len(n-1-2*xs)*else".<.>"[D+n%2*2]if(x+1>n/2n+2*~x)+x==n-y*b+x==y-1:c="'"
   else:c="|1else"|'-"[H]
   print(c'"[D+2*H],end=" -"[H])
  print()

Try it online!Try it online!

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. I'm rather certain Maybe the equationsindexing equation can be golfed further if I'd actually think about what I'm doingsimplified with a bit more thought, but it's surprisingly short already.

The obvious next step is to replaceThere are lots of places where - x - 1 is replaced with +~x, (or variants). Booleans are heavily used for indexing and the similar trickscancelling parts of equations with inversemultiplication.

def function(string: str, number: int):
  for y in range(number):
    for x in range(number):
      is_up_cornerrounds = min(x, +y, (number - 2 - 2 * x) * (x +- 1 >, number / 2) ==- y - 1)
      is_down_corner = x + (number - 1 - 2 * x) * (x + 1 ># numbertotal /increments 2)after ==`rounds` numberrevolutions -and yfix -for 1overcounting
      is_middleindex = x4 +* 1rounds -* (number %- 2rounds) == y ==- number2 //* 2rounds
      # is_left_cornerindex =+= yx + (number - 2 * y) * (y > number / 2) ==# xeast + 1south increment
      #index is_right_corner+= =2 y* +(2 * (number - rounds - 1) - 2x *- y) * (y > number / 2x) != number -# xwest -+ 1north

      roundsis_horizontal = minmax(x, y, number - xy -+ 1, number - y -+ 12)
        # sum> ofx increments+ per2 round> andmin(y, fixnumber for- overcountingy)
      indexis_right = 4x *+ rounds1 *> (number - rounds) -/ 2 * rounds
      indexis_up_corner +== x  # east increment
      index += y  # south increment
      index +=+ 2is_right * (number - rounds2 -* 1(x -+ x1)) *== (y >- x)1  # westinlined
      indexis_down_corner +== 2x + is_right * (number - rounds - 1 - y)2 * (y + x) <== number - 1) * (y > x)  #- north1

      is_horizontal# is_middle = ((x < y or+ x1 <- number -% y2 -== 1)
y == number // 2
      # is_middle = is_up_corner and is_down_corner
      # is_down and= (xy > ynumber -/ 2 
 or x > number - y# -is_left_corner 2))
= y + is_down * (number if- index2 <* len(stringy):
 == x + 1
    character = string[index]
# is_right_corner = y + is_down elif* is_middle:
(number - 1 - 2 * y) != characternumber =- "<>"[numberx %- 2]1
  
     elif is_up_corner:print(
        character = "."
  string[index] if index < eliflen(string) is_down_corner:else
        character".<.>"[is_down_corner =+ "'"
2 * (number % 2)] if elifis_up_corner is_horizontal:else
        character = ""|'-"
  '"[is_down_corner + 2 * else:is_horizontal],
        character =end=" "|"-"[is_horizontal]
      print(character, end='-' if is_horizontal else ' ')
    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     | | .-> | | |
----' | ' | |                 ----'---' | |                 | | '---' | |
--' | | | ' |                 --'-------' |                 | '-------' |
' | | | | | '                 '-----------'                 '-----------'

Python 3, 371 bytes

def f(s,n):
 for y in range(n):
  for x in range(n):
   r=min(x,y,n-x-1,n-y-1);i=4*r*(n-r)-2*r+x+y+2*((n-r-1-x)+(n-r-1-y)*(y+x<n-1))*(y>x);H=(x<n-y-1or x<y)and(x>y-2or x>n-y-2)
   if i<len(s):c=s[i]
   elif x+1-(n%2)==y==n//2:c="<>"[n%2]
   elif(n-2-2*x)*(x+1>n/2)+x==y-1:c="."
   elif(n-1-2*x)*(x+1>n/2)+x==n-y-1:c="'"
   else:c="|-"[H]
   print(c,end=" -"[H])
  print()

Try it online!

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. I'm rather certain the equations can be golfed further if I'd actually think about what I'm doing.

The obvious next step is to replace - x - 1 with +~x, and the similar tricks with inverse.

def function(string: str, number: int):
  for y in range(number):
    for x in range(number):
      is_up_corner = x + (number - 2 - 2 * x) * (x + 1 > number / 2) == y - 1
      is_down_corner = x + (number - 1 - 2 * x) * (x + 1 > number / 2) == number - y - 1
      is_middle = x + 1 - (number % 2) == y == number // 2
      # is_left_corner = y + (number - 2 * y) * (y > number / 2) == x + 1
      # is_right_corner = y + (number - 1 - 2 * y) * (y > number / 2) != number - x - 1

      rounds = min(x, y, number - x - 1, number - y - 1)
        # sum of increments per round and fix for overcounting
      index = 4 * rounds * (number - rounds) - 2 * rounds
      index += x  # east increment
      index += y  # south increment
      index += 2 * (number - rounds - 1 - x) * (y > x)  # west
      index += 2 * (number - rounds - 1 - y) * (y + x < number - 1) * (y > x)  # north

      is_horizontal = ((x < y or x < number - y - 1)
                       and (x > y - 2 or x > number - y - 2))
      if index < len(string):
        character = string[index]
      elif is_middle:
        character = "<>"[number % 2]
      elif is_up_corner:
        character = "."
      elif is_down_corner:
        character = "'"
      elif is_horizontal:
        character = "-"
      else:
        character = "|"
      print(character, end='-' if is_horizontal else ' ')
    print()

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()

Try it online!

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.

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     | | .-> | | |
----' | ' | |                 ----'---' | |                 | | '---' | |
--' | | | ' |                 --'-------' |                 | '-------' |
' | | | | | '                 '-----------'                 '-----------'
Source Link
anderium
  • 613
  • 5
  • 9
Loading