Program, that creates triangle and square - python

I've started learning programming and I need to create program, where user can enter amount of rows wanted and then program has to print two different shapes according to the info given by user. Shapes have to be like
Blockquote
# # # # # *
# # * *
# # AND * * *
# # * * * *
# # # # # * * * * *
I managed to do the triangle, but I can't figure out, how to create square that is empty inside. I have only done it filled inside.
Can anyone help me to modify my code?
userInput = input("Enter amount of row's wanted: ")
def shape(userInput, drawCharacter):
n = 0
while n < int(userInput):
n += 1
if drawCharacter == "*":
print(n*drawCharacter.rjust(3))
elif drawCharacter == "#":
print(int(userInput)*drawCharacter.rjust(3))
shape(userInput, "*")
print("|__________________|\n")
shape(userInput, "#")

A method using numpy array to avoid loops when generating the matrix:
import numpy
n = 5 # or userinput, has to be >= 2
mat = np.full((n,n), '#') # a matrix of #s
mat[1:-1, 1:-1] = np.full((n-2, n-2), ' ') # make the center of the matrix ' '
print('\n'.join([' '.join(e) for e in mat]))
result:
# # # # #
# #
# #
# #
# # # # #

Your box consists of basically following parts:
Top and bottom rows: print (width * '#')
And center rows: print ('#{}#'.format(' ' * (width - 2)))
And as an exercise you just need to figure out the loop.. ;)

If this is your first encounter with programming(any language), what I would recommend you to do is to try to implement this problem with nested for loops (which will simulate a 2d-array, or basically a matrix), try to figure out what index-es of the matrix not to print out and print out only the edges.
By doing this approach you will get a much better in-depth understanding of the problem that this task presents and how to solve it. Good luck!

Related

python: Nesting

I am trying to write code that will display a shape with an odd width. Once the shape is completed it is placed inside an outer shape. The user will be able to input the characters used for the shape and the number of rows.
I am hoping to produce a shape and, with a for loop, produce an outer shape.
***** .
*** ...
* .....
.*****.
...***...
.....*.....
this is my current code. I only know how to create a shape.
char = (input("Enter first charactrer"))
rows = int(input("enter the number of rows"))
for m in range(rows, 0, -1):
for n in range(0, rows-m):
print(end=" ")
for n in range(0,m):
print(char,end=" ")
print()
There is no need for some of the for-loops:
A useful feature in python is the way you can multiply a char by an int to get a string of that repeated char.
For example, if you do:
'c' * 10
you get:
'cccccccccc'
The reason this will be useful in your case is that you can use it to print the spaces and chars. This will be neater than for-loops as instead of printing a single chars over and over with no line breaks, you can instead print the full number of spaces as a string with one call.
To see what I mean, I wrote your original code using this:
char = input("enter the char ")
rows = int(input("enter the number of inner rows "))
for r in range(rows, 0, -1):
print(' ' * 2 * (rows-r), end='')
print((char+' ') * (2*r+1))
see how much neater it is? Also, you can notice that in the second print of each row for the chars, I used the calculation: 2*r +1. This is what you need to convert this pattern:
3. * * * *
2. * * *
1. * *
0. *
to this one (as you requested):
3. *******
2. *****
1. ***
0. *
you can see that for each row of the second one, the number of chars is 2 * the row +1. So row 3 has 7 chars, row 2 has 5 etc.
If you wanted to, as you have gotten rid of the unnecessary for-loops now, you could put both of the prints in one statement:
print(' ' * 2 * (rows-r) + (char+' ') * (2*r+1))
however, the first may be considered neater and clearer so you might want to stick with the separate statements.
Embedding the inner triangle in an outer one
First off for this, we will need to input two different chars for the inner and outer triangles. This will allow us to differentiate which is which.
I think that the best way to do this would be to keep the print statement which creates the spaces before the triangles as before, but modify how we draw the chars and their pattern.
This is what we want for an input of 4 rows:
0. .
1. ...
2. .....
3. .......
4. .*******.
5. ...*****...
6. .....***.....
7. .......*.......
notice how it would be simplest to split the printing process in half. So for the top half just print a regular triangle, but for the bottom print one regular, one flipped and another regular.
To do this, we want to loop through each of the 8 rows and check when we are half way through. If past halfway, we want the calculations for each smaller triangle to think they are at the top of the triangle, i.e. reset the row count for them so when printing row 4, we calculate as if printing on row 0. To achieve this, once past halfway, we need to modulo the row variable by half of the total rows (the total rows now being not what is entered, but double the entered amount as you can see we have a triangle with 8 rows but an inputted row value of 4). This will give the intended effect of the triangles being half size of the total triangle.
Finally, one last thing to consider is that the center/inner triangle needs to be flipped as we have done before. As our row count is now going from 0 at the top downwards rather than the other way around, we need to change the calculation for that row to be rows - r so it is flipped.
Taking all this into account, the final code may look something like:
innerChar = input("enter the inner char ")
outerChar = input("enter the outer char ")
rows = int(input("enter the number of inner rows "))
for r in range(2 * rows):
#print the white space on the left
print(' ' * 2 * (2 * rows-r), end='')
if r < rows:
#top triangle
print((outerChar+' ') * (2*r + 1))
else:
#working with the row modulo 2
r %= rows
#bottom three triangles
print((outerChar+' ') * (2*r + 1), end='')
print((innerChar+' ') * (2*(rows-r) - 1), end='')
print((outerChar+' ') * (2*r + 1))
One way to make this easier is to not worry about the spaces at first. Just generate the non-space symbols of each row, and save them into a list. Then at the end, determine the width of the biggest row, and use the str.center method to print each row with the correct amount of space.
def tri(n, chars='*.'):
ic, oc = chars
outer = range(1, 2*n, 2)
# top triangle chars
rows = []
for w in outer:
rows.append(w * oc)
# lower triangles chars
inner = reversed(outer)
for u, v in zip(outer, inner):
a, b = u * oc, v * ic
rows.append(a + b + a)
# Get maximum row size
width = len(rows[-1])
#Print all the rows
for row in rows:
print(row.center(width))
# test
tri(5)
output
.
...
.....
.......
.*******.
...*****...
.....***.....
.......*.......
The characters to use are passed to tri as a two character string, with a default of '*' for the inner char (ic) and '.' for the outer char (oc). But if you want to use other chars you can pass them, like this:
tri(4, '#o')

Finding the largest square in an n * n grid

I have a problem where I have to find the largest square in an n * n grid.
e.g.
. . . . .
. # . # .
. # . . .
. # . # .
. # . . .
where the biggest square would be 3 by 3 in the bottom corner.
I am supposed to return the most steps someone could take before turning right so that they can repeat this infinitely without hitting a wall "#" or going outside the n * n square which is why the output is one less that the width/length of the square.
My code loops through the grid left to right, top to bottom looking for vertices that face down and to the right. Once it finds one it then looks for the biggest possible vertex facing up and to the right and when it finds that checks all four sides to see whether or not they are made up or .. This code works in under 1 second for me on anything around n = 100, however I need it to run at 1 second for n = 500. Any tips on how I can speed this up?
import sys
input = sys.stdin.readline
n = int(input())
maze = [list(input()) for _ in range(n)]
squares = 0
for r in range(n - 1):
for c in range(n - 1):
if maze[r][c] == '.' and maze[r][c + 1] == '.' and maze[r + 1] [c] == '.':
sides = []
for i in range(min(n - r - 1, n - c - 1), -1, -1):
if maze[r + i][c + i] == '.' and maze[r + i][c + i - 1] == '.' and maze[r + i - 1][c + i] == '.':
sides = i
if maze[r][c : c + sides] == ['.'] * sides and maze[r + sides][c : c + sides] == ['.'] * sides:
a = True
for j in range(sides):
if maze[r + j][c] != '.' or maze[r + j][c + sides] != '.':
a = False
if a and sides > squares:
squares = sides
break
if squares == n - 1:
break
print(squares)
I can think of a O(n^3) algorithm as follows:
Precompute 4 arrays: top[][], bottom[][], left[][], right[][], each stores the maximum length of a direction that you can go from (i,j)
For each (i,j) , use it as a square's bottom left corner, for each its diagonal points (i-1, j+1), (i-2, j+2)...etc., test if those points can be used as the square's top right corner. Store the maximum square side in the process
For step 1, all 4 arrays can be precomputed in O(n^2)
For step 2, as we loop through all (i,j), and for each (i,j) we have to see at most all diagonal points which is at most n of them, total we get O(n^3)
The test in step 2 can be done in O(1) using the 4 precomputed arrays, simply check if the 4 corners of the "possible squares" can be joined by checking the corresponding directions (top, bottom, left, right)
Of course, there are many minor things which can be done to speed up, for example:
In step 2, for each (i,j), only check for diagonal points which is in the range [current_maximum_diagonal_found ... max(right[i][j], top[i][j])]
Update current_maximum_diagonal_found along the whole algorithm, so that we hope for some (i,j), we do not need to check whole n diagonal points.
But strictly speaking, it is still O(n^3), but as far as I know it should be able to run in 1 second for n~500
that's an interesting problem. I tried out some things and ended up with this implementation which is O(n^3). I commented the code so that you can follow the idea hopefully. There's still room for speed improvements, but this version already does the job (e.g. with maze size 500x500):
Finished after 0.708 seconds.
Result: 112581 squares found, maximum square (x=13, y=270, size=18).
This is the source code (Python 3):
import random
import pprint
import time
# small sample maze
maze = ['.....',
'...#.',
'.#...',
'.#.#.',
'.#...']
# convert to boolean maze
maze_bin = [[True if cell == '.' else False for cell in line] for line in maze]
# uncomment to generate a random maze
# maze_size = 500
# threshold = 0.2
# maze_bin = [[1 if random.random() >= threshold else 0 for _ in range(maze_size)] for _ in range(maze_size)]
# take start time
t1 = time.time()
# rotate the maze (first column becomes first row, first row becomes first column)
maze_bin_rot = [[maze_bin[i][j] for i in range(len(maze_bin))] for j in range(len(maze_bin[0]))]
# horizontal_lengths is a two-dimensional list that contains the number of possible steps to the right for every cell.
horizontal_lengths = []
for line in maze_bin:
num = 0
line_lengths = []
for i in reversed(line):
line_lengths.append(i*num)
num = i * (num + i)
horizontal_lengths.append(tuple(reversed(line_lengths)))
# vertical_lengths is a two-dimensional list that contains the number of possible steps to the bottom for every cell.
vertical_lengths_rot = []
for line in maze_bin_rot:
num = 0
line_lengths = []
for i in reversed(line):
line_lengths.append(i*num)
num = i * (num + i)
vertical_lengths_rot.append(tuple(reversed(line_lengths)))
# do the rotation again to be back in normal coordinates
vertical_lengths = [[vertical_lengths_rot[i][j] for i in range(len(vertical_lengths_rot))] for j in range(len(vertical_lengths_rot[0]))]
# calculate the maximum size of a square that has it's upper left corner at (x, y).
# this is the minimum of the possible steps to the right and to the bottom.
max_possible_square = []
for y in range(len(maze_bin)):
line = []
for x in range(len(maze_bin[0])):
line.append(min(horizontal_lengths[y][x], vertical_lengths[y][x]))
max_possible_square.append(line)
# search for squares
results = []
max_size_square = (-1, -1, -1)
for y in range(len(max_possible_square)):
for x in range(len(max_possible_square[0])):
# start with maximum possible size and decrease size until a square is found.
for size in reversed(range(1, max_possible_square[y][x]+1)):
# look at the upper right (x+size,y) and bottom left corner (x,y+size).
# if it's possible to make at least size steps to the right from the bottom left corner
# and at least size steps to the bottom from the upper right corner, this is a valid square.
if horizontal_lengths[y+size][x] >= size and vertical_lengths[y][x+size] >= size:
results.append((x, y, size+1))
if size+1 > max_size_square[2]:
max_size_square = (x, y, size+1)
# break after the the largest square with upper left corner (x,y) has been found.
break
t2 = time.time()
# comment this print section if you use larger grids
print('Maze:')
pprint.pprint(maze_bin)
print('\n')
print('Horizontal possible steps:')
pprint.pprint(horizontal_lengths)
print('\n')
print('Vertical possible steps:')
pprint.pprint(vertical_lengths)
print('\n')
print('Maximum possible size of square:')
pprint.pprint(max_possible_square)
print('\n')
print('Results:')
for square in results:
print('Square: x={}, y={}, size={}'.format(*square))
print('\n')
# final results
print('Finished after {:.3f} seconds.'.format(t2-t1))
print('Result: {} squares found, maximum square (x={}, y={}, size={}).'.format(len(results), *max_size_square))
I hope this is what you were looking for. If you have any questions, just leave a comment below ;)
If we do not want to enumerate all results, one optimization that may be worth considering is the following. It's based on the strategy - "do not proceed further with this cell if it can not lead to the optimal solution"
for y in range(possible_y_value):
for x in range(possible_x_value):
# We are ready to process cell identified by (x,y).
# Check if max_possible_square_length at this cell is greater than size of best_result seen so far. If so, proceed further, otherwise skip this cell
if max_possible_square[y][x]+1 > best_result.size:
# proceed further with the inner most for loop
....
Even from within the inner most for loop, we can break out of the loop at the iteration when it falls below the best_result's size seen so far

Creating a Diagonal Line in Python/only using Nested Loops

Alright, so I've been staring at my screen for the past few hours trying to solve this problem. I have to create a diagonal line that which could have any character.
Needs to look like something like this:
*
*
*
This is my code that I have right now.
# Draw a Diagonal
row = 1
while row <= size:
# Output a single row
col = 1
while col <= row:
# Output the drawing character
print()
# The next column number
col = col + 1
# Output a newline to end the row
print(end=drawingChar)
# The next row number
row = row + 1
print()
and it doesn't come out close to anything like a diagonal line! Could use some insight, thank you for the help. I have to use nested loops. I saw a couple other questions like this on the search, but they don't work for my assignment.
you can do this with a simple for loop:
>>> for i in range(5):
print(' '*i, end = '*\n')
*
*
*
*
*

python nested loop print spaces between two characters every repeat

this is the question i am trying to solve
i have tried everything to get the spaces to appear between the hashtags but have failed. i don't know what else to do
this is what i have done so far, i found a few ways to get only 1 space between the hashtags, but to have them repeat every time is what i have not been able to do
star = 6
for r in range(star):
for c in range(r - 5):
print ' ',
print '##',
print
this is the output i get
any help is appreciated.
def hashes(n):
for i in range(n):
print '#' + ' '*i + '#'
Testing
>>> hashes(1)
##
>>> hashes(4)
##
# #
# #
# #
Obviously, there are more succinct ways of doing this, but the original question called for nested loops:
import sys
inner = 1
for x in range(6):
sys.stdout.write('#')
for y in range(inner):
if y == inner - 1:
sys.stdout.write('#')
else:
sys.stdout.write(' ')
sys.stdout.write('\n')
inner += 1
Output:
$ python loops.py
##
# #
# #
# #
# #
# #

Draw inverted triangle of asterisk by using nested loops in Python

I've to write a program that get a series of valid inputs from user and then uses the nested loops to draw the inverted triangle.
I've managed to work out the triangle but I struggling on inverted triangle. Can anyone give me some hint on how to draw the inverted triangle by only print a single charater of * and without using * * rowlength?
Global constant
L = 10
Get rows number
rows = int(input ( 'Enter a number of rows: ' ) )
Rows cannot less than 10 or greater than 100
while rows < 10 or rows > 100:
if rows < L:
print( 'The number is too Low.' )
else:
print( 'The number is too high.' )
rows = int(input ( 'Enter the correct value: ' ) )
Display the triangle
for r in range(rows):
for c in range(r + 1):
print('*', end='')
print()
This is very similar to a question I had to do for class once, but we were implementing it in C. Actually, quite cool to go back now, reimplement it in python and look at the difference.
The problem we had in class was very similar. My python code to make this work is:
while True:
rows = input('Enter the number of rows: ')
if 3 <= rows <= 33:
break
else:
continue
padding = ' '*rows
while rows > 0:
print(padding[rows:] + '*'*rows)
rows = rows - 1
-- modified below, to print outline of inverted triangle:
# print the outline of an inverted triangle:
height = rows
# inner padding for min height (3)
inner_buffer = [0, 1, 3]
while len(inner_buffer) <= rows:
inner_buffer.append(inner_buffer[-1]+2)
while height > 0:
outer_padding = ' '*(rows - height)
if height == 1:
print(outer_padding + '*')
else:
inner_padding = ' '*(inner_buffer.pop()-2)
print(outer_padding + '*' + inner_padding + '*')
height = height - 1
There has got to be a more elegant want to code this, but simply a working hack to see if we are on the right track.
New revision below:
-- function that will produce a regular triangle, or inverted triangle as defined
def get_rows():
while True:
rows = input('Enter the number of rows: ')
if 3 <= rows <= 33:
return rows
def triangle(rows, regular=False, invert=True):
if invert:
height = -1 * rows
else:
height = 0
# inner padding for min height (3)
inner_buffer = [0, 1, 3]
while len(inner_buffer) <= rows:
inner_buffer.append(inner_buffer[-1]+2)
level = 0
while level <= rows:
outer_padding = ' '*(rows - abs(height))
if height == 0:
print(outer_padding + '*')
else:
inner_padding = ' '*( inner_buffer[ abs(height) ] )
print(outer_padding + '*' + inner_padding + '*')
height += 1
level += 1
Let me know :)

Categories

Resources