1

Possible Duplicate:
ASCII Python Art # 2

i = 10
while i>0:
    print i*'*' + 2*(10-i)*' ' + i*'*'
    i -=1
for x in range(1,11):
    print x* '*' + 2*(10-x)*' '+ x*'*'
    x +=1

I am trying to make a asterisk diamond with 19 lines. I get 20 instead. This is what I want:

********************
*********  *********
********    ********
*******      *******
******        ******
*****          *****
****            ****
***              ***
**                **
*                  *
**                **
***              ***
****            ****
*****          *****
******        ******
*******      *******
********    ********
*********  *********
********************

How can I get rid of the doubling up in height in the middle of the asterix.

cheers.

Community
  • 1
  • 1
Elsavador
  • 17
  • 6
  • Hey, english speaking people: is _" doubling up in height "_ a correct expression ? – eyquem Oct 05 '11 at 09:47
  • Solutions to exactly the same problem have been proposed in [http://stackoverflow.com/questions/7310494/ascii-python-art-2](http://stackoverflow.com/questions/7310494/ascii-python-art-2) – Chaos Manor Oct 08 '11 at 20:42

5 Answers5

2

The basic idea is to decide which loop should print the line with just a single start on each side. Then modify the other loop not to print that line (i.e. end or start with the 2-star line).

Change

for x in range(1,11):

to

for x in range(2,11):

Also, you can get rid of the very last line, as the second loop does all the incrementing of x on its own.

For readabilities sake I'd also switch to just a single kind of loop.

For example you can write the first loop using (notice: this loop will not run the x=1 case, so you'd have to use the unmodified version of your second loop).

for x in range(10, 1, -1):
    print x* '*' + 2*(10-x)*' '+ x*'*'
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
2

You've already worked out how to print each line. Now the last part is to generate the correct sequence of number to drive the line printing.

l = range(10,1,-1)
l.extend(range(1,11))
for x in l:
  print x*'*' + 2*(10-x)*' ' + x*'*'


[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
********************
*********  *********
********    ********
*******      *******
******        ******
*****          *****
****            ****
***              ***
**                **
*                  *
**                **
***              ***
****            ****
*****          *****
******        ******
*******      *******
********    ********
*********  *********
********************
AutomatedMike
  • 1,454
  • 13
  • 27
  • This doesn't produces the diamond he wants: there are still 2 stars at the middle of first and last lines. In fact, what is needed is whitespaces having ODD numbers of blanks. However, I upvote because of the good idea **l.extend(range(1,11))** – eyquem Oct 05 '11 at 09:43
  • Ah good spot - I missunderstood the question - this makes the first and last lines a special case. Here's my soluiton but it's not as nice l = range(9,1,-1) l.extend(range(1,10)) print 19*'*' for x in l: print x*'*' + (2*(10-x) - 1)*' ' + x*'*' print 19*'*' Is there an important business requirement for this code? – AutomatedMike Oct 05 '11 at 10:11
  • What does _"business requirement"_ mean , please ? – eyquem Oct 05 '11 at 10:16
2

I had some difficulty to find the trick:

def diamond(ni):
    li = [ i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
           for i in xrange(ni,0,-1)]

    li.extend(i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
              for i in range(2,ni+1))

    return '\n'.join(li)


print diamond(7)

draws

*************
****** ******
*****   *****
****     ****
***       ***
**         **
*           *
**         **
***       ***
****     ****
*****   *****
****** ******
*************

Noticing that

li.extend(i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
                  for i in range(2,ni+1))

does the same (less one line) than

    li = [ i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
           for i in xrange(ni,0,-1)]

but in reverse order, we can simplify:

def symetric_diamond(ni):
    li = [i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
          for i in xrange(ni,0,-1)]
    li.extend(li[-2::-1])
    return '\n'.join(li)

Please, note that

print '\n'.join(str(i) for i in xrange(500))

is displayed instantly, because the program computes the string '\n'.join(str(i) for i in xrange(500)) before to print it in one shot, while

for i in xrange(500):
    print str(i)

is far longer to be displayed, because the computer prints 500 strings one after the other, and each call to print is long

.

There's another manner to print a diamond,I will write it now.

Plus

def format_diamond(nl):
    ni = (nl+1)/2
    li = ['{:{fill}{align}{width}}'.format((2*(ni-x) - 1)*' ',fill='*',align='^',width=2*ni-1)
          for x in xrange(ni,0,-1)]
    li.extend(li[-2::-1])
    return '\n'.join(li)

-> all these functions give a diamond of nl-1 lines when nl is even.

Edit

Finally, what I prefer is:

def symetric_diamond(nl):
    '''Returns a diamond of nl lines if nl is odd, 
       and nl-1 lines if nl is even'''
    ni = (nl+1)//2
    li = [ (2*ni-1) * '*' ]
    li.extend(i*'*' + (2*(ni-i) - 1)*' ' +i*'*' for i in xrange(ni-1,0,-1))
    li += reversed(li[0:-1])  # in-place extension
    return '\n'.join(li)

because of the in-place extensions (with extend and reversed) and the absence of the horrid (i - i//ni)*'*'

Community
  • 1
  • 1
eyquem
  • 26,771
  • 7
  • 38
  • 46
1
x = list(range(0, 20, 2))
x += reversed(x[:-1])

for _ in x:
    stars, spaces = "*" * ((20 - _) / 2), " " * _
    print stars + spaces + stars
Kimvais
  • 38,306
  • 16
  • 108
  • 142
  • You can write directly ``print '{0}{1}{0}'.format("*" * ((20 - _) / 2), " " * _)`` . Unfortunately, this doesn't gives the display that the OP wants. I upvote for the ``x += reversed(x[:-1])`` and ``x[:-1]`` instead of the ``x[-2::-1]`` I used – eyquem Oct 05 '11 at 09:56
0

As you are doubling code, you could rewrite your program to

def line(x): print x* '*' + 2*(10-x)*' '+ x*'*'
i = 10
while i>0:
    line(i)
    i -=1
for x in range(1,11):
    line(x)
    # x +=1 # unnecessary - happens already due to the for loop

And now, you can make one loop out of the two (removing the function again):

rg = list(range(10, 1, -1)) + list(range(1, 11))
for x in rg:
    print x* '*' + 2*(10-x)*' '+ x*'*'
glglgl
  • 89,107
  • 13
  • 149
  • 217