I'm trying to write a christmas tree in Python, and I'm trying to make it mirror to another side, so the text is mirrored to itself on the left so instead of having one side of the tree i have both sides
tree = "I"
for i in range(12):
print(tree.ljust(2-i) * i)
There are better ways to do this, in fact you don't really need to mirror, you could just adapt the padding on the left, but let's assume that you want a real mirroring, so that each line has the same number of characters.
You should first multiply the string and then justify it. Then you can use a slice operator to reverse the halves ([::-1]).
size = 12
for i in range(1, size):
half = (tree * i).rjust(size - 1)
print half + half[::-1]
output
II
IIII
IIIIII
IIIIIIII
IIIIIIIIII
IIIIIIIIIIII
IIIIIIIIIIIIII
IIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIIIIII
And remember..
Merry Christmas Don!
You should use rjust instead of ljust since the spaces should be padded on the left. Also you need to double the count since 3 chars don't really align with 2 properly.
tree = "I"
for i in range(12):
print((tree*(2*i)).rjust(12 + i))
output:
II
IIII
IIIIII
IIIIIIII
IIIIIIIIII
IIIIIIIIIIII
IIIIIIIIIIIIII
IIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIIIIII
it's almost christmas, adding some ornaments?
import random
tree = "I"
for i in range(12):
row = list(tree*(2*i))
if( i > 2):
index = int(random.random() * len(row))
if( index < len(row) - 1):
row[index] = "["
row[index + 1] = "]"
index2 = int(random.random() * len(row))
if( index2 != index and index2 != (index + 1)):
row[index2] = "O"
print (("".join(row)).rjust(12 + i))
tada:
II
IIII
I[]III
IIII[]IO
IIIOIIII[]
IIIIIIIIO[]I
III[]IIIIIOIII
IIIIIOIIIIIIII[]
IIIIIIIIOIIII[]III
IIIIOIIIIIIIIIIIIIII
II[]IIIIIIIIIIOIIIIIII
Here's my take on it:
l = 13
for i in range(l):
print(' ' * int((l - i)/2) + ('#' * i))
I prefer pointy trees, and (just to be different) using str.center() over str.rjust():
def tree(height, symbol='I'):
width = height*2 - 1
for i in range(height):
print((symbol * ((i*2)+1)).center(width))
>>> tree(12)
I
III
IIIII
IIIIIII
IIIIIIIII
IIIIIIIIIII
IIIIIIIIIIIII
IIIIIIIIIIIIIII
IIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIIIIIII
Related
I am trying to merge two outputs together so that it appears something like this:
0 1 2
0 ? ? ?
1 ? ? ?
2 ? ? ?
But it ended up appearing like this instead:
0 1 2
0
1
? ? ?
? ? ?
I tried this to make the codes appear but i have no idea how to place their outputs together
import random
rows = [3]
columns = [4]
def rowscol():
for j in range(columns[0]):
print(" " * 1, end="")
print(j, end="")
print()
for i in range(rows[0]):
print(i)
rowscol()
def create_game_board(rows, columns):
board = [[random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ") for _ in range(columns[0])] for _ in range(rows[0])]
# If number of cells is odd, make the last cell an unused cell
if (rows[0] * columns[0]) % 2 != 0:
board[-1][-1] = "#"
return board
board = create_game_board(rows,columns)
# Function to display the game board
def display_board(board):
pad = " " * 30
for row in board:
line = pad + " ".join('?' if column != '#' else '#' for column in row)
print(line)
display_board(board)
Welcome to StackOverflow!
When using multidimensional arrays, like in your case a list of lists, I like to be able to index into them easily. Because of this I usually change it to a dict and use the coordiantes as keys. This way you can even store additional information about the board, like the dimension sizes or anything else.
I added a bunch of comments to explain how the code works but feel free to ask if anything isn't clear:
import random
import string
def create_game_board(rows, cols):
board = dict()
# save dimensions inside the dict itself
board['cols'] = cols
board['rows'] = rows
for y in range(rows):
for x in range(cols):
# add random letter to board at (x,y)
# x,y makes a tuple which can be a key in a dict
# changed to use string.ascii_uppercase so that you don't forget any letter
board[x, y] = random.choice(string.ascii_uppercase)
# change last element to # when both dimensions are odd
if (rows * cols) % 2 == 1:
board[rows-1, cols-1] = "#"
return board
def display_board(board):
# get dimensions
cols, rows = board['cols'], board['rows']
# print header
print(' '.join([' '] + [str(x) for x in range(cols)]))
for y in range(rows):
# print rows
#print(' '.join([str(y)] + [board[x, y] for x in range(cols)])) # to display the actual letter at this location
print(' '.join([str(y)] + ['?' if board[x, y] == '#' else '#' for x in range(cols)])) # using your display function
print() # separator empty line
board = create_game_board(3, 3)
display_board(board)
The output is nothing special when I'm using your method of printing, you might need to change that, I'm not sure how you wanted to display it. I added a line that allows you to print the values on those coordinates.
This is the output:
0 1 2
0 # # #
1 # # #
2 # # ?
Maybe something like?
def draw_board(board):
print(" " + " ".join([str(i) for i in range(len(board[0]))])) # print column numbers
for i in range(len(board)):
row = ""
for j in range(len(board[i])):
row += board[i][j] + " "
print(str(i) + " " + row)
draw_board(board)
How to insert ' # ' for each n index from backward?
ex) n=4
evil = '01234567891234oooooooooooooooo321'
to
stan = '0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321'
i tried using list with for,if statement, got stuck. something shameful like this
a = 1234567891234
b = [ a[-i] for i in range(1,len(a)+1)]
for i in range(len(b)):
c += b[i]
if i%4==0: #stuck
c += ','
c.reverse()
What is the optimum way?
You might use a pattern asserting optional repetitions of 4 characters to the right, and replace that position with #
import re
pattern = r"(?=(?:.{4})*$)"
s = "01234567891234oooooooooooooooo321"
print(re.sub(pattern, "#", s))
Output
0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321#
Python demo
cut the string into chunks (backwards) and then concat them using the seperator
evil = '01234567891234oooooooooooooooo321'
l = 4
sep = '#'
sep.join([evil[max(i-l,0):i] for i in range(len(evil), 0, -l)][::-1])
'0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321'
chunks function as in this answer
def chunks(lst, n):
"""Yield successive n-sized chunks from lst."""
for i in range(0, len(lst), n):
yield lst[i:i + n]
evil = '01234567891234oooooooooooooooo321'
n = 4
stan = "#".join(chunks(evil[::-1], n))[::-1]
print(stan) # Output: 0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321
Input string is reversed ([::-1]), split into chunks, joined by "#" and then reversed back again. (It's possible to skip reverses if you calculate how many characters there will be in the first set of characters)
A naive solution would be using parts of evil string:
evil = '01234567891234oooooooooooooooo321'
n = 4
start = len(evil) % n
insert = '#'
stan = evil[:start] + insert
for i in range(start, len(evil) - n, n):
stan += evil[i:i+n] + insert
stan += evil[-n:]
For this, I would go backwards through your string evil by reversing the string and iterating through it in a for loop. Then I set a count variable to keep track of how many loops it's done, and reset to 0 when it equals 4. All of this looks like the below:
count = 0
for char in evil[::-1]:
if count == 4:
count = 0
count += 1
You can then establish a new empty string (new_str), and append each character of evil to, each time checking if count is 4, and adding a # to the string as well before resetting the count. Full code:
count = 0
new_str = ''
for char in evil[::-1]:
if count == 4:
new_str += '#'
count = 0
count += 1
new_str += char
This will produce the new string reversed, so you need to reverse it again to get the desired result:
new_str = new_str[::-1]
Output:
'123o#oooo#oooo#oooo#ooo4#3219#8765#4321#0'
You can do it like this:
evil = '01234567891234oooooooooooooooo321'
''.join(j if i%4 else f'#{j}' for i, j in enumerate(evil[::-1]))[::-1][:-1]
Output:
'0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321'
An exact method: use divmod to get the reminder and quotient of the string when divided in "blocks" of size 4 then slice.
evil = '01234567891234oooooooooooooooo321'
size = 4
q, r = divmod(len(evil), size)
sep = '#'
stan = f"{evil[:r]}{sep}{sep.join(evil[r+i*size: r+(i+1)*size] for i in range(q))}"
print(stan)
Remark: if the length of the string is a multiple of the block's size the new string will start with sep. Assumed as default behavior since lake of explanation
By using end="-" I got this loop. I want to remove that '-' for the last element.
m=4
n=1
for i in range(1,4):
for x in range(5,n,-1):
print(" ",end="")
n+=2
for y in range(3,3-i,-1):
print(y,end="-")
for z in range(m,4):
print(z,end="-")
m-=1
print()
Output:
3-
3-2-3-
3-2-1-2-3-
Instead of using end, you can actually use sep, which only separates between elements which sounds like what you want. This will even reduce your loops a bit.
You will have to change the prints to be something like: print(*range(m, 4), sep='-').
The spaces (' ') loop is also not necessary and can be a single print, so your whole code can look like:
m = 4
n = 1
for i in range(1, 4):
print(" " * abs(5-n), end='')
n += 2
print(*range(3, 3-i, -1), *range(m, 4), sep='-')
m -= 1
It is also possible to only use the loop variable i and avoid maintaining m and n. So the code can be reduced to:
m = 4
for i in range(1, m):
print(" " * abs(5-i*2+1), end='')
print(*range(3, 3-i, -1), *range(m-i+1, m), sep='-')
which gives:
3
3-2-3
3-2-1-2-3
Finally, to make it more reasonable by m being the range being printed, and making it completely generic to allow any m you can do:
m = 4
for i in range(1, m+1):
print(" " * (m*2-i*2), end='')
print(*range(m, m-i, -1), *range(m-i+2, m+1), sep='-')
Which will now print up-to 4:
4
4-3-4
4-3-2-3-4
4-3-2-1-2-3-4
Welcome to SO!
Nice work progress! Here, in my solution I am trying to is to divide the responsibilities into smaller tasks.
To generate the number to print
To print these in design format
m=4
n=1
max_line_length = 20
def special_print(items):
# convert each number to string
str_items = [str(each) for each in items]
# prepare output string
output_string = '-'.join(str_items)
prefix = ' ' * (max_line_length - len(output_string))
print(prefix + output_string)
# try
# print(output_string.center(max_line_length))
for i in range(1,4):
items = []
n+=2
for y in range(3,3-i,-1):
items.append(y)
for z in range(m,4):
items.append(z)
m-=1
# print(items)
special_print(items)
Output
3
3-2-3
3-2-1-2-3
Note: This solution can be further simplified by Python Pros but I tried to keep simple enough for you to understand.
You can explore python string objects features like center, join and list-comprehension, len function to improve your Python skills.
I have a string:
a = babababbaaaaababbbab
And it needs to be shortened so it looks like this:
(ba)3(b)2(a)5ba(b)3ab
So basically it needs to take all repeating characters and write how many times they are repeating instead of printing them.
I managed to do half of this:
from itertools import groupby
a = 'babababbaaaaababbbab'
grouped = ["".join(grp) for patt,grp in groupby(a)]
solved = [str(len(i)) + i[0] for i in grouped if len(i) >= 2]
but this only does this for characters that are repeating but not patterns. I get it that I could do this by finding 'ab' pattern in string but this needs to be viable for every possible string. Has anyone encountered something similar?
You can easily do this with regex:
>>> repl= lambda match:'({}){}'.format(match.group(1), len(match.group())//len(match.group(1)))
>>> re.sub(r'(.+?)\1+', repl, 'babababbaaaaababbbab')
'(ba)3(b)2(a)5ba(b)3ab'
Not much to explain here. The pattern (.+?)\1+ matches repeating character sequences, and the lambda function rewrites them to the form (sequence)number.
This is what I came up with, the code is a mess, but I just wanted to have a quick fun, so I let it be like this
a = 'babababbaaaaababbbab'
def compress(text):
for i in range(1, len(text) // 2):
for j, c in enumerate(text[:-i if i > 0 else len(text)]):
pattern = text[j:i+j]
new_text = pattern_repeats_processor(pattern, text, j)
if new_text != text:
return compress(new_text)
return text
def pattern_repeats_processor(pattern, text, i):
chunk = pattern
count = 1
while chunk == pattern and i + (count + 1) * len(pattern) < len(text):
chunk = text[i + count * len(pattern): i + (count + 1) * len(pattern)]
if chunk == pattern:
count = count + 1
else:
break
if count > 1:
return text[:i] + '(' + pattern + ')' + str(count) + text[i + (count + 0) * len(pattern):]
return text
print(compress(a))
print(a)
It makes
babababbaaaaababbbab =>
(ba)3(b)2(a)5ba(b)3ab
P.S. Of course answer of Rowing is miles better, pretty impressive even
I'm not sure what exactly you're looking for but here hope this helps.
A=a.count('a')
B=a.count('b')
AB=a.count('ab')
BAB=a.count('bab')
BA=a.count('ba')
print(A,'(a)',B,'(b)',AB,'(ab)',BAB,'(bab)',BA,'(ba)')
I am trying to create this pattern in python:
*
* *
* * *
* *
*
This is my program so far that I've come up with:
ster = "*"
space = " "
lines = 0
n = 3
x = 1
while lines <= 5:
print space*n, ster*x
n-= 1
x+= 1
lines += 1
What am I doing wrong?
Okay, first of all you can create a list of numbers which represents the number of stars in each line.
number_of_stars = 5
i_list = list(range(number_of_stars))
# extend the list by its inverse i_list[::-1]
# but exclude the first item
i_list.extend(i_list[::-1][1:])
print(i_list) # prints: [0, 1, 2, 3, 4, 3, 2, 1, 0]
Now you can go thru the list and print a multiple of *
for i in i_list:
print('* ' * i)
But this is not aligned properly. By adding multiple empty spaces to the left one can archive a solution:
for i in i_list:
print(' ' * (number_of_stars - i) + '* ' * i)
Note that in python one can repeat a string by using the multiplication symbol:
print('a'*5) # prints: aaaaa
Thank you for the help, I wrote a functional code for the problem. It was supposed to made using while loop(s).
This is what I did:
width = int(input("Width: "))
i = 1
while i < width*2:
if i < width:
print " " * (width-i) + "* " * i
else:
print " " * (i-width) + "* " * (2*width-i)
i = i + 1
Notice you have
3 spaces for 1 star
2 spaces for 2 stars
1 space for 3 stars.
For the upright triangle part of your diamond (including the large part). Then you have
2 spaces for 2 stars
3 spaces for 1 star
Without throwing out the answer, try analysing a certain pattern in what i've just pointed out. It can be achieved with 2 loops ( for or while, depending on your preference).