2

I am trying to make write a code that makes a graph of front and backward slashes based upon the values that user input

def setNums(num_filter):
    if num_filter[0] != 0:
        num_filter.insert(0,0)  
    else:
        pass
    arranged_values = [-value if counter%2 == 0 else value for counter,value in enumerate(num_filter)]
    return arranged_values

def printLines(num_filter, total_lines):
    su = 0
    sd = 0
    li = -1
    
    for counter,num in enumerate(num_filter):
        for z in range(num):
            if (counter%2 != 0):
                li +=  1
                total_lines[li] += (" "*su+"/")
                try:
                    su = len(total_lines[li])-len(total_lines[li+1])
                except IndexError:
                    pass
                sd = 0
                
            else:
                total_lines[li] = total_lines[li]+(" "*sd+"\\")
                sd = len(total_lines[li])-len(total_lines[li-1])
                li -= 1
                su = 0
    return '\n'.join(total_lines[::-1])

def main():
    numbers = input("Enter numbers (seperated by space): ")
    num_filter = [int(num) for num in numbers.split()]
    nums_arranged = setNums(num_filter)
    total_lines = ['']*max([sum(nums_arranged[0:num:1]) for num in range(0, len(nums_arranged)+1)][1:]
    output = printLines(num_filter, total_lines)
    print ("Printing graph... \n", output)

It works well when the graph is going up but when the graph is going down then it pastes downside slashes on the top of the graph.

This code basically takes user input of multiple numbers like 2 3 4 2 4 1 3 6 then seperates odd index values and even index values by putting negative sign.. then with the cumulative sum, it predicts the lines needed (thats where the problem is I think) then based on the values of numbers it prints slashes in arrangement.

The output I am expecting is like this:

The output I am expecting is like this

The output I am getting is like this:

The output I am getting

2
  • Could you explain what the input 2 3 4 2 4 1 3 6 is supposed to mean for the solution? Is it up 2, then down 3, then up 4, etc.? Commented Jun 12, 2021 at 12:07
  • exactly.. if 2 then two slashes up, if 3 then 3 slashes down @aneroid Commented Jun 12, 2021 at 13:12

2 Answers 2

3

You have only considered how high the graph can be but forget to measure how low the graph can go. When you try to find the row with negative index, rows below your starting point will be moved to the top and sometimes too low which makes the negative index exceed the length of the graph and raise IndexError.

Different from yours, I created a list of lists for rows and columns of the graph, then changed their values in each loop.

# find the highest and the lowest point of the graph
def height(nums):
    highest = 0
    lowest = 0
    current = 0
    step = 1
    for num in nums:
        current += num * step
        if current > highest:
            highest = current
        if current < lowest:
            lowest = current
        step = step * -1
    # highest - lowest is the height of the graph
    # highest - 1 is the index of the lowest row of the positive part
    return (highest - lowest, highest - 1)

def draw_graph(nums):
    h, base_row = height(nums)
    # create all rows and columns, sum(nums) is the width of the graph
    rows = [[" "] * sum(nums) for i in range(h)]
    row = base_row
    col = 0
    # -1 for go up, 1 for go down
    step = -1
    for num in nums:
        slash = "/" if step == -1 else "\\"
        for n in range(num):
            rows[row][col] = slash
            # move up or down based on step
            row += step
            # must move forward no matter step
            col += 1
        # turn around when finished a part
        step *= -1
        # adjustment as up and down slashes are on the same row when turn around
        row += step
    return "\n".join("".join(row) for row in rows)

def main():
    nums = [int(i) for i in input("Enter numbers (seperated by space): ").split()]
    graph = draw_graph(nums)
    print("Printing graph... ")
    print(graph)

if __name__ == '__main__':
    main()

Test run:

Enter numbers (seperated by space): 2 3 4 2 4 1 3 6
Printing graph...
                  /\
                 /  \
              /\/    \
             /        \
        /\  /          \
 /\    /  \/            \
/  \  /
    \/

Enter numbers (seperated by space): 6 6 3 2 1 4 7 2
Printing graph...
     /\
    /  \                    /\
   /    \                  /  \
  /      \    /\          /
 /        \  /  \/\      /
/          \/      \    /
                    \  /
                     \/
Sign up to request clarification or add additional context in comments.

1 Comment

This similar to the way I would have done it +1. Wrt the height calculation - instead of a multiplier step, I'd first use a list comprehension and checking the index like in OP's arranged_values , but without a leading 0. And then take a max of the positive numbers and the min of the minimum, defaulting both to 0.
3

1. The first change to make to understand your output is the final print. Change it to an f-string or print the message and the output using separate print's. When you do print('some text\n', output) the comma gets inserted as a space after the newline and skews the top row of your output. How it looks when correct:

print(f"Printing graph... \n{output}")
Printing graph...
    \/            /\
                 /  \
              /\/    \
             /        \
        /\  /          \
 /\    /  \/            \
/  \  /

This shows that you are getting the required output except for - negative row indexes are being put at the top. Taking us to the next point.

2. Remove the try: ... except IndexError: ... part. You shouldn't be assigning to invalid indexes and by having that, you're just skipping over the errors and assigning to row 0.

If you take the cumulative sum of the list you provided, you'd see this:

nums_arranged = [0, 2, -3, 4, -2, 4, -1, 3, -6]
cumsum = [0, 2, -1, 3, 1, 5, 4, 7, 1]

The slashes in that -1 row is what's getting moved over to the top. And you're still getting Index Error for other lines if the negative value is < -1. So if the input was "2 3 4 6 4 1 3 6" you get an error for the line sd = len(total_lines[li])-len(total_lines[li-1])

The root cause of this is your calculation for total_lines. It doesn't account for negative peaks:

total_lines = ['']*max([sum(nums_arranged[0:num:1]) for num in range(0, len(nums_arranged)+1)][1:]

So add the absolute value of the negative peak - which is still an incorrect forumla because there's an assumption of :

total_lines = ['']*(max([sum(nums_arranged[0:num:1]) for num in range(0, len(nums_arranged)+1)][1:])
                    -min([sum(nums_arranged[0:num:1]) for num in range(0, len(nums_arranged)+1)][1:]))

With an input of "2 3 4 6 4 1 3 6", your output would be:

Printing graph...
    \/      \    /        \
             \  /          \
              \/            \
        /\            /\
 /\    /  \          /  \
/  \  /    \      /\/    \

As you can see, anything that should have been "below 0" has wrapped to the top.

3. In printLines - even taking into account reversing the output at the end - you're always assuming that you start your graph at (0, 0). If you have a negative peak, then your starting point would be lower than (0, 0) (since you flip it after). You'll need to calculate your lowest negative peak and then always add that offset to your row. I'm not going to make all that change in all the places it's needed, along with the changes mentioned above, so you'll have to work that out. The part wrt the rows and offset is:

# in main():
rows = (max([sum(nums_arranged[0:num:1]) for num in range(0, len(nums_arranged)+1)][1:]),
        -min([sum(nums_arranged[0:num:1]) for num in range(0, len(nums_arranged)+1)][1:]))
total_lines = [''] * sum(rows)
output = printLines(num_filter, total_lines, rows[1])  # added a param

# need to add the offset `off` everywhere in this function
def printLines(num_filter, total_lines, off):  # `off` = row offset
    su = 0
    sd = 0
    li = -1

    for counter,num in enumerate(num_filter):
        for z in range(num):
            if (counter%2 != 0):
                li +=  1
                total_lines[li + off] += (" "*su+"/")
                su = len(total_lines[li + off])-len(total_lines[li+1 + off])
                sd = 0
            else:
                ...

That should be a better starting point to getting the correct results.

3 Comments

I edited your post - corrected formatting - you cannot make text in the code italic or bold - you can only make the whole code italic or bold - please see if it is still what you meant.
@Programmer Yeah, that's ok. I just wanted to bring attention to the 6 even though it would appear in the code, since that was the difference from the original string. Thanks, anyway.
Ok, but sadly, no formatting is possible in code :( !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.