How to make make spiral in python?

I want to make a function that I give it a number, and the function returns a spiral from 1 to that number (in a 2-dimensional array). For example, if I give the number 25 of the function, it will return something like this:
enter image description here
I tried different methods, but nothing worked. I just can't figure it out. I hope I have correctly explained.

+4
source share
4 answers

Basically the problem is listing the coordinates - matching numbers with coordinates, and then listing, however you want.

Start by noting two basic patterns:

  • (Direction) Move right, then down, then left, then up, then ... (this, hopefully, is obvious)
  • () , , , , ...

, , number, coordinates .

, ; :

def move_right(x,y):
    return x+1, y

def move_down(x,y):
    return x,y-1

def move_left(x,y):
    return x-1,y

def move_up(x,y):
    return x,y+1

moves = [move_right, move_down, move_left, move_up]

, :

def gen_points(end):
    from itertools import cycle
    _moves = cycle(moves)
    n = 1
    pos = 0,0
    times_to_move = 1

    yield n,pos

    while True:
        for _ in range(2):
            move = next(_moves)
            for _ in range(times_to_move):
                if n >= end:
                    return
                pos = move(*pos)
                n+=1
                yield n,pos

        times_to_move+=1

:

list(gen_points(25))
Out[59]: 
[(1, (0, 0)),
 (2, (1, 0)),
 (3, (1, -1)),
 (4, (0, -1)),
 (5, (-1, -1)),
 (6, (-1, 0)),
 (7, (-1, 1)),
 (8, (0, 1)),
 (9, (1, 1)),
 (10, (2, 1)),
 (11, (2, 0)),
 (12, (2, -1)),
 (13, (2, -2)),
 (14, (1, -2)),
 (15, (0, -2)),
 (16, (-1, -2)),
 (17, (-2, -2)),
 (18, (-2, -1)),
 (19, (-2, 0)),
 (20, (-2, 1)),
 (21, (-2, 2)),
 (22, (-1, 2)),
 (23, (0, 2)),
 (24, (1, 2)),
 (25, (2, 2))]
+8

, :

enter image description here

NxN (N + 1) x (N + 1):

if N is odd:
    move right one step
    move down N steps
    move left N steps
else:
    move left one step
    move up N steps
    move right N steps

.

@Milan, (.. 23). - , , , :

from itertools import count

def steps_from_center():
    for n in count(start=1):
        if n % 2:
            yield RIGHT
            for i in range(n):
                yield DOWN
            for i in range(n):
                yield LEFT
        else:
            yield LEFT
            for i in range(n):
                yield UP
            for i in range(n):
                yield RIGHT

, , , , UP, DOWN, LEFT RIGHT.

2d, Python - . , , my_array[y][x] x y, ( ).

:

from collections import namedtuple

Step  = namedtuple("Step", ["dx", "dy"])
RIGHT = Step( 1,  0)
DOWN  = Step( 0,  1)
LEFT  = Step(-1,  0)
UP    = Step( 0, -1)

, , :

from math import ceil, floor, log10, sqrt

max_i = int(input("What number do you want to display up to? "))

# how big does the square have to be?
max_n = int(ceil(sqrt(max_i)))

# here is our initialized data structure
square = [[EMPTY] * max_n for _ in range(max_n)]

# and we start by placing a 1 in the center:
x = y = max_n // 2
square[y][x] = output(1)

: , , . output() - , , EMPTY - :

# how many digits in the largest number?
max_i_width = int(floor(log10(max_i))) + 1

# custom output formatter - make every item the same width
def output(item, format_string="{{:>{}}}".format(max_i_width)):
    return format_string.format(item)

EMPTY = output("")

, :

for i, step in enumerate(steps_from_center(), start=2):
    if i > max_i:
        break
    else:
        x += step.dx
        y += step.dy
        square[y][x] = output(i)

:

print("\n".join(" ".join(row) for row in square))

:

What number do you want to display up to? 79
73 74 75 76 77 78 79      
72 43 44 45 46 47 48 49 50
71 42 21 22 23 24 25 26 51
70 41 20  7  8  9 10 27 52
69 40 19  6  1  2 11 28 53
68 39 18  5  4  3 12 29 54
67 38 17 16 15 14 13 30 55
66 37 36 35 34 33 32 31 56
65 64 63 62 61 60 59 58 57
+4

. . ; , 23, 5 ; 5 (25), 31, 6 ; 6 (36). " " (.. ). " " , , , ( , N, S, E, W). , .


: , . , Python, , .

from functools import partial
from math import ceil, sqrt

def gen_grid(n):
  grid_size = int(ceil(sqrt(n)))
  return [[None for _ in range(grid_size)] for _ in range(grid_size)]

def valid_coord(grid, coord):
  try:
    return grid[coord[0]][coord[1]] is None
  except:
    return False

def origin(size):
  adjustment = 1 if size % 2 == 0 else 0
  return (size / 2 - adjustment), (size / 2 - adjustment)

north = lambda y, x: (y - 1, x)
south = lambda y, x: (y + 1, x)
east = lambda y, x: (y, x + 1)
west = lambda y, x: (y, x - 1)

directions = lambda y, x: [east(y, x), south(y, x), west(y, x), north(y, x)]
distance = lambda c, nxt: sqrt((c[0] - nxt[0]) ** 2 + (c[1] - nxt[1]) ** 2)

def walk_grid(nums):
  grid = gen_grid(len(nums))
  center = origin(len(grid[0]))
  current_position = center
  center_distance = partial(distance, center)

  for n in nums:
    y, x = current_position
    grid[y][x] = n
    unseen_points = [c for c in directions(y, x) if valid_coord(grid, c)]
    if n != nums[-1]:
      current_position = sorted(unseen_points, key=center_distance)[0]

  return grid

def print_grid(highest):
  result = walk_grid(range(1, highest + 1))
  for row in result:
    for col in row:
      print "{:>4}".format(col if col is not None else ''),  
    print "\n"

:

In [2]: grid.print_grid(25)
  21   22   23   24   25 

  20    7    8    9   10 

  19    6    1    2   11 

  18    5    4    3   12 

  17   16   15   14   13 
+3

, - "". , .

def get_new_direction(direction):
  switch direction:
     case E: return S
     case S: return W
     case W: return N
     case N: return E

i,j = initial_coordinates_of_the_one
direction = right
steps = 1
next_number = 1

while not done:
  place(next_number, i, j)
  i,j = get_coordinates_after_move(direction, steps)
  direction = get_new_direction(direction)
  next_number++
  if iteration is even:
    steps++

. ( ):

  • ,
0

Source: https://habr.com/ru/post/1540925/


All Articles