HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Triangle Tessellation Project

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
triangletessellationproject

Problem

I have this Python project to draw tessellated triangles on the screen. It takes the height to form the size of the triangle, cols to specify how many triangles on a line, and rows which is how many lines it outputs.
This program has taken me some time to put together and I'm not sure if this is the best way to do this. The first line is just the normal triangle, the second line and every other line after however only should show half of the triangle on the first and last column.

Here's my .py file:

import sys

print("make sure shell in full screen so the triangles are viewed properly... or disable word wrap :)")
height          = int(input("height"))
cols            = int(input("cols"))
rows            = int(input("rows"))

MAX_PAGE_WIDTH = 19 * 8

width = height * 2 - 1
if((width * cols) > MAX_PAGE_WIDTH):
    print("Triangles not gonna fit on page, please enter smaller params... :/")
    sys.exit()

def get_even_number(num):
    return num % 2 == 0

triangle        = ""

for column_row in range(rows):
    half_space      = height - 1
    stars           = 1

    for row_of_triangle in range(height):
        if(get_even_number(column_row)):
            for column in range(cols):
                triangle += " " * (half_space + 1) + "*" * stars + " " * half_space
        else:
            for column in range(cols + 1):
                if(not(column == 0)):
                    triangle += " " * (half_space + 1)

                if(column == 0 or column >= cols):
                    sub = row_of_triangle
                    if(column >= cols):
                        sub += 1
                    triangle += "*" * (stars - sub)
                else:
                    triangle += "*" * stars

                if(column < cols):
                    triangle += " " * half_space

        half_space      -= 1
        stars           += 2
        triangle        += "\n"

print(triangle)


Here is some sample output:

input: height: 6 cols: 6 rows: 4


```
*

Solution

Using the * operator to repeat strings is smart, but there are still a lot of nested ifs and and fors. In Python, excessive looping can often be remedied using list comprehensions and itertools.

It would definitely be a good idea to split the work into functions. The input validation code is unrelated to the output routine. The output routine, in turn, can be decomposed into smaller reusable units. In particular, it is helpful to observe that the odd rows are like the even rows, but upside-down and colour-inverted.

from itertools import chain, cycle, islice

def tesselated_triangles(height, cols, rows):
    def triangle_row(height, cols, space=' ', fill='*'):
        return [
            (
                space * (height - i) +
                fill * (2 * i + 1) +
                space * (height - i - 1)
            ) * cols
            for i in range(height)
        ]

    def alt_triangle_row(height, cols, space=' ', fill='*'):
        return reversed(triangle_row(height, cols, space=fill, fill=space))

    return '\n'.join(chain.from_iterable(
        row(height, cols)
        for row in islice(cycle([triangle_row, alt_triangle_row]), rows)
    ))

print(tesselated_triangles(6, 6, 4))


Additional remarks:

  • Since strings in Python are immutable, repeated string concatenation should be avoided. Appending just a single character using += involves allocating and copying the entire string. For this application, you should use '\n'.join(…). (Doing '\n'.join(…) would also avoid printing two newlines at the end of the output, which is wrong in my opinion.)



  • If the program failed, it would be a good idea to call sys.exit() with a non-zero status code.



  • It is uncommon in Python to write if(…): using parentheses.



-
Using extra spaces to align equals signs is discouraged in PEP 8, the official Python style guide. In this case, I really think you have overdone it.

half_space      -= 1
stars           += 2
triangle        += "\n"


  • get_even_number() is poorly named. You're not retrieving anything; you're testing something. An appropriate name would be is_even_number() or simply is_even(). You could just eliminate the function, though, since it's so simple.

Code Snippets

from itertools import chain, cycle, islice

def tesselated_triangles(height, cols, rows):
    def triangle_row(height, cols, space=' ', fill='*'):
        return [
            (
                space * (height - i) +
                fill * (2 * i + 1) +
                space * (height - i - 1)
            ) * cols
            for i in range(height)
        ]

    def alt_triangle_row(height, cols, space=' ', fill='*'):
        return reversed(triangle_row(height, cols, space=fill, fill=space))

    return '\n'.join(chain.from_iterable(
        row(height, cols)
        for row in islice(cycle([triangle_row, alt_triangle_row]), rows)
    ))

print(tesselated_triangles(6, 6, 4))
half_space      -= 1
stars           += 2
triangle        += "\n"

Context

StackExchange Code Review Q#145364, answer score: 5

Revisions (0)

No revisions yet.