9

I have been given the task of creating a spiral in python where the user inputs a number e.g 3 and it will output a 3x3 spiral which looks like this:

- - \
/ \ |
\ - /

I am not looking for the full code I just have no idea how to do it, obviously printing out every possible solution using if statements isn't possible or logical. The real question here is what should i be looking to do, for loops, define my own function? are there any docs people can link me to that would help. The full task outline is as follows:

Your task here is to write a program to draw a spiral of a given size inside a box.

Your program should ask the user for a positive integer denoting the size of the box. Your program should then print out a spiral inside of a box of that size.

For example:

Enter size: 3
- - \
/ \ |
\ - /

and:

Enter size: 4
- - - \
/ - \ |
| \ / |
\ - - /

​and:

Enter size: 5     
- - - - \
/ - - \ |
| / \ | |
| \ - / |
\ - - - /

The input size will always be greater than 1.

Maroun
  • 94,125
  • 30
  • 188
  • 241
Nick Adams
  • 199
  • 2
  • 7
  • 4
    Try with at least something. Try to produce a line and a corner. Play around with params. – Andrey Aug 05 '15 at 13:12

5 Answers5

15

I respect you for not wanting the full code. This is intentionally only a partial answer.

Start by making a 2-dimensional array. Something like:

grid = [[None]*n for i in range(n)]

This allows you to write code like grid[i][j] = '\'.

Start with i,j = 0,0. In a loop spiral around the grid. It might help to have a variable direction which takes on values 'right', 'left', 'up', 'down' together with a corresponding delta taking on values like (0,1) (for moving to the right) to be added to (i,j) to implement the move.

Go along a line in a certain direction placing '-' or '|' until you hit a corner (check for None as well as the limits of the overall grid). When you get to a corner, place the appropriate corner marker and change directions.

Once the grid is filled, join each rows with an empty string delimiter and join the result with '\n' as the delimiter.

John Coleman
  • 51,337
  • 7
  • 54
  • 119
14

Things to note:

  • number of characters in rows/cols is n
  • first row will always have n - 1 -s and one \
  • last row will always have n - 2 -s, begin with \ and ends with /

For example, when n is 4:

First row: - - - \
Last row: \ - - /

Can be easily achieved using:

def get_first_raw(n):
    return '- ' * (n - 1) + '\\'

def get_last_raw(n):
    return '\\ ' + '- ' * (n - 2) + '/'

Now regarding the body of the spiral, note the following:

For n = 3:

- - \
/ \ |
\ - /

For n = 5:

enter image description here

For n = 6:

enter image description here

Note that the 4-spiral is contained inside it, and the red boxes are fixed. Only their length changes according to n.

It's contained inside it. And fore n = 7, the n = 5 is contained inside it. The same holds for n = 2k, each n will have n/2 spiral contained in it.

What I'm trying to say here that you manually draw n = 3 and n = 2. If the spiral should be made from an even number, you use the n = 2 pattern, construct the first and last rows, and using loops you can append the body of the spiral.

Example for n = 5:

def get_spiral(n):
    res = []
    res.append(get_first_raw(n))
    res.append('/ ' + spiral[0] + ' |')
    for line in spiral[1:]:
        res.append('| ' + line + ' |')

    res.append(get_last_raw(n))
    return res

print '\n'.join(get_spiral(5))

where spiral is an initial spiral of size 3:

spiral = ['- - \\', '/ \ |', '\ - /']

In order to generate 7-spiral, you do:

spiral = build_spiral(5)
print '\n'.join(build_spiral(7))

and you'll get:

- - - - - - \
/ - - - - \ |
| / - - \ | |
| | / \ | | |
| | \ - / | |
| \ - - - / |
\ - - - - - /

Of course this can be improved and you can make the program more efficient, I just wanted to give you a guideline and to share my thoughts..

Here's more spirals for fun:

- - - - - - - - - - \
/ - - - - - - - - \ |
| / - - - - - - \ | |
| | / - - - - \ | | |
| | | / - - \ | | | |
| | | | / \ | | | | |
| | | | \ - / | | | |
| | | \ - - - / | | |
| | \ - - - - - / | |
| \ - - - - - - - / |
\ - - - - - - - - - /

- - - - - - - - - - - - - - - - - - - - - - - - \
/ - - - - - - - - - - - - - - - - - - - - - - \ |
| / - - - - - - - - - - - - - - - - - - - - \ | |
| | / - - - - - - - - - - - - - - - - - - \ | | |
| | | / - - - - - - - - - - - - - - - - \ | | | |
| | | | / - - - - - - - - - - - - - - \ | | | | |
| | | | | / - - - - - - - - - - - - \ | | | | | |
| | | | | | / - - - - - - - - - - \ | | | | | | |
| | | | | | | / - - - - - - - - \ | | | | | | | |
| | | | | | | | / - - - - - - \ | | | | | | | | |
| | | | | | | | | / - - - - \ | | | | | | | | | |
| | | | | | | | | | / - - \ | | | | | | | | | | |
| | | | | | | | | | | / \ | | | | | | | | | | | |
| | | | | | | | | | | \ - / | | | | | | | | | | |
| | | | | | | | | | \ - - - / | | | | | | | | | |
| | | | | | | | | \ - - - - - / | | | | | | | | |
| | | | | | | | \ - - - - - - - / | | | | | | | |
| | | | | | | \ - - - - - - - - - / | | | | | | |
| | | | | | \ - - - - - - - - - - - / | | | | | |
| | | | | \ - - - - - - - - - - - - - / | | | | |
| | | | \ - - - - - - - - - - - - - - - / | | | |
| | | \ - - - - - - - - - - - - - - - - - / | | |
| | \ - - - - - - - - - - - - - - - - - - - / | |
| \ - - - - - - - - - - - - - - - - - - - - - / |
\ - - - - - - - - - - - - - - - - - - - - - - - /

You also got a top view for a pyramid for free

Maroun
  • 94,125
  • 30
  • 188
  • 241
1

code:

def rot_right(a):
    return zip(*a[::-1])


def spiral(m, n, start=1, is_rotate=False):
    if n < 1:
        return

    lst = ['|' if is_rotate else '-' for i in range(start, m + start - 1)]
    lst += ['/' if is_rotate and m > 0 else '\\']


    yield tuple(lst)
    for row in rot_right(list(spiral(n - 1, m, m + start, not is_rotate))):
        yield row

n = 7
for row in spiral(n, n):
    print(''.join('%s' % i for i in row))

result:

------\
/----\|
|/--\||
||/\|||
||\-/||
|\---/|
\-----/

-------\
/-----\|
|/---\||
||/-\|||
|||\/|||
||\--/||
|\----/|
\------/
viktor.svirskyy
  • 469
  • 2
  • 8
1

As there are already some good answers with how to do it, I went along with the way I like and made the code, which is travelling in the spiral order and go setting the characters along the way. Its a bit long but for understanding purposes, could be shortened down about half:

n = 3;

grid = [[None]*n for i in range(n)]


def move(pos, d, counter): # first paint, then move
    x = pos[0]
    y=pos[1]

    #uncomment this line to check how it moves
    #print (x,y)

    if d == "right":
        if x == n-y-1: # if we are going right and we reach the end(n-y) -1 because of indexes, change direction to down
            grid[y][x] = "\\"
            y+=1
            d = "down"
        else:
            grid[y][x] = "-"
            x+=1
    elif d == "down": # if we are going down and reach the end, which is the same as column number we are on, change direction to left
        if y == x:
            grid[y][x] = "/"
            x-=1
            d = "left"
        else:
            grid[y][x] = "|"
            y+=1
    elif d == "left": # if we are going left and reach the end, which is the same as in right, change directiont to up
        if x == n-y-1:
            grid[y][x] = "\\"
            y-=1
            d="up"
        else:
            grid[y][x] = "-"
            x-=1
    elif d == "up": # if we are going up and reach the end, which is x+1, change direction to right
        if y ==x+1:
            grid[y][x] = "/"
            x+=1
            d = "right"
        else:
            grid[y][x] = "|"
            y-=1

    counter+=1
    if counter != n*n: # if we painted n*n times, it means we finished with the spiral
        move((x,y),d,counter)


move((0,0),"right",0) # start in coords (0,0) with direction going right and counter in 0

for row in grid:
    print(''.join('%s' % i for i in row))
juvian
  • 15,875
  • 2
  • 37
  • 38
  • So in the spirals i'm meant to output there's a space between each one like shown above. This is achieved by putting a space next to each character, but say i put that space on the right then every single line will have a space on the right even if it is invisible, is there a way to maybe .rstrip() or something? – Nick Adams Aug 05 '15 at 22:36
  • 1
    Fixed! added a space to the right of each character (-, / , \\) and then on the print at the end make it .... print(''.join('%s' % i for i in row).rstrip(' ')) – Nick Adams Aug 05 '15 at 22:43
1

I don't know python, but as the larger values of n are used to create the spiral, it becomes apparent that the spiral is a system of 3 equations and their inequalities. There are three line equations that correspond to the usage of \ and /:

\ is y1 = -x + (n - 1)
/ is y2 = x + 1
     y3 = x

 0,0
  - - - - - - - \y1
y2/ - - - - - \ |
  | / - - - \ | |
  | | / - \ | | |
  | | | \ / | | |
  | | \ - - / | |
  | \ - - - - / |
  \ - - - - - - /y3

Then, going through all points in the grid, calculate y1, y2 and y3 for the given x. Output the correct character given the current value of y in comparison to y1, y2 and y3.

If it's on a line, then it's a \ or /. If it's below both y1 and y2 or above both y1 and y3, then it's -, otherwise it's a | (C# Example):

for (int y = 0; y < n; y++)
{
    for (int x = 0; x < n; x++)
    {
        string c = "  ";
        int y1 = (n - 1) + (-1 * x);
        int y2 = x + 1;
        int y3 = x; // Redundant

        if (y == y1)
            c = "\\ ";
        else if ((y <= n / 2 && y == y2) || (y >= n / 2 && y == y3))
            c = "/ ";
        else if (y < y1 && y < y2)
            c = "- ";
        else if (y > y1 && y > y3)
            c = "- ";
        else
            c = "| ";

        Console.Write(c);
    }
    Console.Write('\n');
}
XNargaHuntress
  • 751
  • 6
  • 11