Solution: Staircase#

Write a function that returns a staircase with n steps using the hash # and underscore _ symbols.

Rules#

  1. The number of steps are either positive or negative values.

  2. Function returns a string.

  3. The steps are adjoined with the newline character \n

  4. A positive number of step denotes the staircase’s upward direction.

  5. A negative number of step denotes the staircase’s downward direction.

Example#

Upward staircase#

staircase(3)

output: "__#\n_##\n###"

or

print(staircase(3))

output:

__#
_##
###

Downward staircase#

staircase(-5)

output: "#####\n_####\n__###\n___##\n____#"

or

print(staircase(-5))

output:

#####
_####
__###
___##
____#

Solution 1#

In this solution every step is created “manually” and stored in a list.

If it is a downward staircase, the list is reversed.

def staircase(n):
    stair = []
    for i in range(abs(n)):
        txt = '_'*(abs(n)-i-1)
        txt += '#'*(i+1)
        stair.append(txt)

    if n < 0:
        stair.reverse()

    return "\n".join(stair)

Solution 2#

Very similar to the previus solution, but the _ symbol is added into the string using the rjust() method.

Note that you also could do a similar solution adding the # symbol by using the ljust() method.

def staircase(n):
    stair = []
    for i in range(abs(n)):
        txt = '#'*(i+1)
        txt = txt.rjust(abs(n),'_')
        stair.append(txt)

    if n < 0:
        stair.reverse()

    return "\n".join(stair)

Solution 3#

In this solution, instead using the reverse() method when we have a downward staircase, the list is build in the right order in both cases.

To do this, instead using the append() method to add a new step to the list, we are using the insert() method (we can control where the new item is going to be inserted).

def staircase(n):
    m = n
    if n<0:
        m = 0

    stair = []
    for i in range(abs(n)):
        txt = '#'*(i+1)
        txt = txt.rjust(abs(n), '_')
        stair.insert(m, txt)

    return "\n".join(stair)

Solution 4#

Similar to the above, but instead control where the new item will be inserted, we are going to create the steps in different order.

def staircase(n):    
    stair = []

    i, j, k = 1, n+1, 1
    if n<0:
        i, j, k = abs(n), 0, -1

    for i in range(i,j,k):
        txt = '#'*(i)
        txt = txt.rjust(abs(n),'_')
        stair.append(txt)
    return "\n".join(stair)

Testing#

Check if your function returns the expected value using the cell below.

import unittest

class UnitTests(unittest.TestCase):

    def test_coin_type(self):
        self.assertTrue(isinstance(staircase(1), str), 'The function should return a string')

    def test_negative_even(self):
        self.assertEqual(staircase(-8), "########\n_#######\n__######\n___#####\n____####\n_____###\n______##\n_______#")

    def test_negative_odd(self):
        self.assertEqual(staircase(-5), "#####\n_####\n__###\n___##\n____#")

    def test_positive_even(self):
        self.assertEqual(staircase(4), "___#\n__##\n_###\n####")

    def test_positive_odd(self):
        self.assertEqual(staircase(7), "______#\n_____##\n____###\n___####\n__#####\n_######\n#######")

unittest.main(argv=[''], verbosity=2,exit=False)
test_coin_type (__main__.UnitTests) ... 
ok
test_negative_even (__main__.UnitTests) ... 
ok
test_negative_odd (__main__.UnitTests) ... 
ok
test_positive_even (__main__.UnitTests) ... 
ok
test_positive_odd (__main__.UnitTests) ... 
ok

----------------------------------------------------------------------
Ran 5 tests in 0.003s

OK
<unittest.main.TestProgram at 0x7f43b04c9110>