ASCII Python Art # 2 - python

You may have noticed my last query on a similar task.
I am trying to replicate this structure:
********************
********* *********
******** ********
******* *******
****** ******
***** *****
**** ****
*** ***
** **
* *
** **
*** ***
**** ****
***** *****
****** ******
******* *******
******** ********
********* *********
********************
If you think of it as composed of 4 triangles - I am able to produce each of the corners individually, then to put them under one another.
I do not know how I would go about putting them together in a larger construct though.
Would I attempt this, or would I approach the problem by tackling it as if were a single construct and work on it line by line as I did with the individual triangle parts? I just assumed that the triangles into a bigger thing might be a shortcut.

This worked for me
w = 20
lines = []
for y in xrange(w / 2, 0, -1):
lines.append("".join(("*" * y, " " * (w - (y * 2)), "*" * y))
lines += reversed(lines[:-1])
for l in lines:
print l
You could shrink it down more if you wanted to as well:
lines = ["".join(("*" * y, " " * (w - (y * 2)), "*" * y)) for y in xrange(w / 2, 0, -1)]
print "\n".join(lines + lines[-2::-1])
Output w = 20:
********************
********* *********
******** ********
******* *******
****** ******
***** *****
**** ****
*** ***
** **
* *
** **
*** ***
**** ****
***** *****
****** ******
******* *******
******** ********
********* *********
********************

print '\n'.join('*' * (20 - i) + ' ' * (i * 2) + '*' * (20 - i) for i in range(0, 20))
print '\n'.join('*' * i + ' ' * (40 - i * 2) + '*' * i for i in range(0, 20))
http://codepad.org/Z46ldEOG

I would treat it as a different problem. If you imagine an origin at the centre of the figure, then you only want to print a * where the "Manhattan distance" to that cell is greater than half the length of the edge. For example, you could do the following:
import sys
r = 5
for y in range(-r,r+1):
for x in range(-r,r+1):
c = ' ' if (abs(x) + abs(y)) < r else '*'
sys.stdout.write(c)
print
... which produces this:
***********
***** *****
**** ****
*** ***
** **
* *
** **
*** ***
**** ****
***** *****
***********

How about:
W = 10
for i in range(10):
this_str = "*"*(W-i)+" "*i
print this_str+this_str[::-1]
for i in range(9,-1,-1):
this_str = "*"*(W-i)+" "*i
print this_str+this_str[::-1]
Peer pressure at work. Here's a shorter version to keep up with all my compatriots:
W=10
lines = ["*"*(W-i)+" "*2*i+"*"*(W-i) for i in range(W)]
print "\n".join(lines + lines[-2::-1])

If your instructor was looking for simple loops, this may help (even though its probably too late, and it only really works with even "w" value's)
w = 20
for a in range (0,w/2):
print((w/2-a)*"*"+2*a*" "+(w/2-a)*"*")
for a in range (2,w/2+1):
print(a*"*"+(w-2*a)*" "+a*"*")
Or if you wanted to take out the variable "w" all together:
for a in range (0,10):
print((10-a)*"*"+2*a*" "+(10-a)*"*")
for a in range (2,11):
print(a*"*"+(20-2*a)*" "+a*"*")

Related

How can I resolve this whitespace issue in my recurssion question

LAB: Drawing a right side up triangle
Write a recursive function called draw_triangle() that outputs lines of * to form a right side up isosceles triangle. Function draw_triangle() has one parameter, an integer representing the base length of the triangle. Assume the base length is always odd and less than 20. Output 9 spaces before the first * on the first line for correct formatting.
Hint: The number of * increases by 2 for every line drawn.
Ex: If the input of the program is:
3
the function draw_triangle() outputs:
*
***
Ex: If the input of the program is:
19
the function draw_triangle() outputs:
*
***
*****
*******
*********
***********
*************
***************
*****************
*******************
Note: No space is output before the first * on the last line when the base length is 19.
I have been able to figure out the recursion part but I cant figure out getting the right white space to the left of the triangle
If I understand your problem correctly, you see that the "top" of the triangle, always has one * in it. Then if the base of the triangle is n, the "top" row should have n - 1 spaces in it.
Continuing the pattern you can see that with every row under the top, you add 2 *'s. Then any given row will have n - 2r - 1 spaces if r is the row (starting from the top, r = 0).
Here's the cool part, since you know n is odd (given in question) and 2r is definitely even, then n - 2r - 1 is always going to be even. Call half this number the "whitespace amount" and print out that amount of spaces for each row (and remember, the row r starts from 0).
Here's some pseudo code
def print_triangle(width, row):
if 2 * row + 1 == width: # if you are in the last row
for i < 2 * row + 1:
print("*") # print the *
return # break out of recursion
else:
for i < (width - 2 * row - 1) / 2:
print(" ") # print whitespace
for i < 2 * row + 1:
print("*") # print the *
return print_triangle(width, row + 1) # recursive call
of course there are many more ways to do this, some of which will have more concise code, but hopefully this pseudo code helps you understand the logic behind the program.
You can't just have a single variable for recursion:
This code would help you:
def draw_triangle(n,i):
if(n<=0):
return
print(" "*(n//2),end="")
print("*"*i)
draw_triangle(n-2,i+2)
draw_triangle(19,1)
Output:
*
***
*****
*******
*********
***********
*************
***************
*****************
*******************
Hope this helps you. Here i=1 since you need to print 1 star at the begining.
For your weird request to have 9 space for all input :))
def draw_triangle(n,i=1,s=9):
if(i>n):
return
print(" "*s+"*"*i)
draw_triangle(n,i+2,s-1)
draw_triangle(3)
Here i represents how many stars in first line and s represent space in first line.
Output:
*
***

how to make my horizontal histogram to vertical

this is a part of my program which generates * patterns from 4 user inputs
total= progresscount + trailercount + retrivercount + excludecount
print("....................................................")
print("Histogram")
print("Progress",progresscount,":" , "*" * progresscount)
print("Trailer",trailercount,":" , "*" * trailercount)
print("Retriver",retrivercount,":" , "*" * retrivercount)
print("Excluded",excludecount ,":" , "*" * excludecount )
print("....................................................")
if I run my whole program and enter 2 3 1 and 2 for each input requests, output looks like this
....................................................
Histogram
Progress 2 : **
Trailer 3 : ***
Retriver 1 : *
Excluded 2 : **
....................................................
and I want to make a vertical version like this
....................................................
Progress Trailing Retriever Excluded
* * * *
* * *
*
....................................................
help me to figure this out?
You can create a custom function like below:
def display_vhist(data):
cell_len = max([len(k) for k in data]) + 2
max_val = max(data.values())
# display header
print(*[h.center(cell_len) for h in data.keys()], sep='')
# display histogram
for i in range(1, max_val+1):
for v in data.values():
c = '*' if i <= v else ' '
print(c.center(cell_len), end='')
print()
Usage:
data = {'Progress': 2, 'Trailer': 3, 'Retriver': 1, 'Excluded': 1}
display_vhist(data)
# Output
Progress Trailer Retriver Excluded
* * * *
* *
*

How to create a recursive pyramid function?

I do need to create two recursive functions in Python. the first function should create a pyramid with a given parameter n. for example pyramid(3) should have the following output
*
***
*****
I came up with the following function:
def pyramid(n, i=0):
if n == 0:
return 0
else:
print(" "*(n-1) +"*"*(2*i+1)+ " "*(n-1))
return pyramid(n-1, i+1)
Now I do need to create a second recursive function pyramid_seq with 2 parameters n,k what prints a sequence of pyramids in with height of n. for example pyramid_seq(3,4) should have the following output:
* * * *
*** *** *** ***
********************
Add another parameter to your function (notice the changes in the recursive call) that determines how many times you should print every line. This will create the desired effect.
def pyramid(n, k, i=0):
if n == 0:
return 0
else:
print(k*(" "*(n-1) +"*"*(2*i+1)+ " "*(n-1)))
return pyramid(n-1, k, i+1)
Output for pyramid(4, 6):
* * * * * *
*** *** *** *** *** ***
***** ***** ***** ***** ***** *****
******************************************
If you want to properly leverage the power of recursion, your function should return their result as data and the printing part should be separate. This will allow you to reuse a previously defined function to produces new results from it:
def pyramid(h):
if h==1: return ["*"]
return [" "+p+" " for p in pyramid(h-1)]+["*"*(2*h-1)]
The function returns an array of lines (strings) that you can print or reuse for something else:
print(*pyramid(5),sep="\n")
*
***
*****
*******
*********
Because you now have a function that generates a pyramid as a list of lines, you can reuse it to concatenate its result to form a series of pyramids without reinventing the wheel:
def pyramids(h,w):
return [p*w for p in pyramid(h)]
print(*pyramids(4,6),sep="\n")
* * * * * *
*** *** *** *** *** ***
***** ***** ***** ***** ***** *****
******************************************
If your second function also needs to be recursive, you can still reuse the first one to build it:
def pyramids(h,w):
if w == 1: return pyramid(h)
return [ ps+p for ps,p in zip(pyramids(h,w-1),pyramid(h)) ]

Create a Bowtie Pattern with Python 3.0

Given a odd positive integer h, greater than or equal to 5, create a bowtie pattern with h rows and 2h columns.
input: 5
output:
* *
*** ***
**********
*** ***
* *
or
input: 7
output:
* *
*** ***
***** *****
**************
***** *****
*** ***
* *
I created code that only works for one given value of h but I'm not sure how to make it functional for any value of h. I also tried taking advantage of the symmetry so I made only half of the bowtie.
h = input()
n = int(h)
x = "*"
space = " "
print(x)
print(-(-n // 2)*x)
print(n*x)
print(-(-n // 2)*x)
print(x)
You can build up the top half by left and right justifying the * repeated as many times as necessary (we use range with a step for this as the first row will have 1 *, the next 2 more, the next 2 more again up until we reach N) padded left and right with width n, eg:
n = int(input())
top = [('*' * i).ljust(n) + ('*' * i).rjust(n) for i in range(1, n, 2)]
This gives you a top (for n=5) of:
['* *', '*** ***']
Then, we print the top, the middle (which is always * repeated N*2 times) and then top in reverse order for the bottom separated by newlines, eg:
print(*top, '*' * n * 2, *reversed(top), sep='\n')
Gives you (n=5):
* *
*** ***
**********
*** ***
* *
Or for (n=11):
* *
*** ***
***** *****
******* *******
********* *********
**********************
********* *********
******* *******
***** *****
*** ***
* *
Symmetry tells you that the left and the right have the same number of *. It also tells you that the middle row is all stars (n * 2), and that each row the same distance above and below the middle row has the same size. Further, as you move away from the center, you lose 4 stars total, 2 from each side.
The two secrets to coding this concise are to 1) number the rows symmetrical, not from 1 to n, but from -n//2 to n//2; and 2) to think of the rows as a number of spaces drawn on a background of *s, rather than a number of *s surrounding spaces.
Once you figure out how many spaces are in each row (call it f(i), based on the value of i in for i in range(-n//2, n//2+1): ..., you can draw that row with (" "*f(i)).center(2*n, "*").
it will work for any odd number
h = input()
n = int(h)
i = 1
if(n%2)!=0 and n > 4:
halfmark= n//2
str=""
while i <= n:
if(i<=halfmark):
blank = ' '* (4*(halfmark +1-i))
elif i > (halfmark+1):
blank = ' '*(4*(i-(halfmark+1)))
else:
blank = ''
star = '*'*((2*n-len(blank))//2)
str = star+blank+star
print(str)
i +=1

Backwards looping, creating a diamond pattern

I made a program that allows the user to type in the height of a diamond and it will print one out in asterisks using loops. My code now looks like this:
diamond = int(input("Height": )
for i in range(diamond-1):
print((diamond-i) * " " + (2*i+1) * "*")
for i in range(diamond-1, -1, -1):
print((diamond - i) * " " + (2 * i + 1) * "*")
And the diamond will look perfect like this (diamond == 6):
*
***
*****
*******
*********
***********
*********
*******
*****
***
*
Now if I make some changes and instead write the backwards loop like this:
for i in reversed(range(diamond-1)):
print((diamond - i) * " " + (2 * i + 1) * "*")
It will print out the diamond like this:
*
***
*****
*******
*********
*********
*******
*****
***
*
So my question is: what is the difference between the first backwards loop and the second one I wrote? Why do they turn out so different?
Because they are different ranges:
>>> diamond = 6
>>> range(diamond-1, -1, -1)
[5, 4, 3, 2, 1, 0]
>>> list(reversed(range(diamond-1)))
[4, 3, 2, 1, 0]
range includes the start point, but excludes the end point.

Categories