Python: Loop Practice, Building Patterns, Games, and Visual Output

Build python pattern programs the hands-on way: python star patterns, number pyramids, a dice roller, rock-paper-scissors, and a progress bar. 10+ tested loop programs from beginner triangles to visual output.

“The only way to learn a new programming language is by writing programs in it.”

Dennis Ritchie

Last Updated: July 2026 | Tested on: Python 3.14.6 | Difficulty: Beginner | Reading Time: 13 minutes

You know for loops, while loops, break, and continue. Theory is done. Now we build things. Think of these python pattern programs like learning to drive: you can read the manual all day, but you only really get it once your hands are on the wheel. This post is that practice lot. Ten small programs that put your loops to work, starting with classic star patterns and working up to a playable rock-paper-scissors game, a live progress bar, and a text bar chart.

Here’s what you’ll build by the end:

Right Triangle

Progress bar[████░░░░]Bar chartfrom dataAnimationspinnerDice rollerRock paperscissorsWordscrambleMultiplicationtableFibonaccisequenceNumberpyramidRight triangle******Pyramid  * ********Diamond  * ***  *Loop Pattern Building BlocksStar PatternsNested loops +print() controlNumber PatternsArithmetic insideloopsMini Gameswhile True +input() + randomVisual OutputProgress bars,ASCII artPython Pattern Programs: Loop Building Blocks for Stars, Numbers, and Games

Tip: click the diagram to open it full screen, then use the zoom and pan controls for a closer look.

The diagram lays out the building blocks of nested-loop pattern programs. The outer loop picks the row, the inner loop decides what goes on that row, and the two loop variables together shape the result. Here is the part worth remembering: almost every star, number, or character pattern, however fancy it looks, is just this same two-loop skeleton with a different thing being printed inside. It is like a printer feeding paper. The outer loop pulls down a fresh line, the inner loop fills that line left to right.

Once that clicks, you build any new pattern just by changing the inner loop’s range. One note on the map: it shows the whole loop-skills landscape, not a strict section list. The word scramble is saved for the closing challenge, and the diamond and animation spinner are stretch ideas you can build with the exact same tricks once you finish the ten programs.

📄 right_triangle.py: the classic starter pattern

rows = 5
for i in range(1, rows + 1):
    print("*" * i)

▶ Output

*
**
***
****
*****

What happened here: "*" * i is string multiplication. When i is 3, "*" * 3 gives you "***", the same way 3 * 4 gives 12. So each trip through the loop prints one more star than the last, and the triangle grows on its own. No inner loop needed here, Python builds the row string for you in one step.

Inverted Triangle

📄 inverted.py: count backwards

rows = 5
for i in range(rows, 0, -1):
    print("*" * i)

▶ Output

*****
****
***
**
*

What happened here: Same idea as the right triangle, just counting down instead of up. The range(rows, 0, -1) starts at 5 and steps back by one each time, so i goes 5, 4, 3, 2, 1 and the rows shrink. It is the first program played in reverse, like rewinding a video.

Centered Pyramid

📄 pyramid.py: spaces create the centering effect

rows = 5
for i in range(1, rows + 1):
    spaces = " " * (rows - i)
    stars = "*" * (2 * i - 1)
    print(spaces + stars)

▶ Output

    *
   ***
  *****
 *******
*********

What happened here: The trick to centering is the spaces in front. Each row gets rows - i spaces pushing the stars to the right, then 2 * i - 1 stars (1, 3, 5, 7, 9, always odd so there is a clean middle). Picture players lining up for a team photo: the back rows take a step in from each side so the shape stays a neat triangle.

Number Pyramid

📄 number_pyramid.py: numbers instead of stars

rows = 5
for i in range(1, rows + 1):
    for j in range(1, i + 1):
        print(j, end=" ")
    print()

▶ Output

1
1 2
1 2 3
1 2 3 4
1 2 3 4 5

What happened here: This is your first real nested loop. The outer loop sets the row number i, and the inner loop prints 1 up to i on that row. The end=" " keeps the numbers on one line with a space between them, and the bare print() after the inner loop drops to the next line. It is like writing a list on a notepad: you jot items across one line, then hit Enter to start the next. Strictly speaking this shape is a number triangle, not a pyramid: add the same leading-space trick from the previous section and it centers into a true pyramid.

Multiplication Table

📄 multiplication.py: nested loops with formatted output

size = 5
# Header
print("  ×  |", end="")
for j in range(1, size + 1):
    print(f"{j:4}", end="")
print(f"\n{'─' * (size * 4 + 6)}")

# Body
for i in range(1, size + 1):
    print(f"  {i}  |", end="")
    for j in range(1, size + 1):
        print(f"{i*j:4}", end="")
    print()

▶ Output

  ×  |   1   2   3   4   5
──────────────────────────
  1  |   1   2   3   4   5
  2  |   2   4   6   8  10
  3  |   3   6   9  12  15
  4  |   4   8  12  16  20
  5  |   5  10  15  20  25

What happened here: The f"{i*j:4}" part pads every number to four spaces wide, so the columns line up like a spreadsheet no matter how many digits a number has. Think of it as reserving four parking spaces for each car: a small car (the number 6) and a big one (the number 25) both sit neatly in their slot. The outer loop walks down the rows, the inner loop fills each row across.

Heads up on Windows: this program prints special characters (the × sign and the line). On a default Windows terminal those can trigger a UnicodeEncodeError because the old console code page cannot draw them. The quick fix is to tell Python to use UTF-8: run py -X utf8 multiplication.py, or set PYTHONUTF8=1 once in your environment. On macOS and Linux it just works. The same tip applies to the progress bar and bar chart further down, since they use block characters too.

Fibonacci Sequence

📄 fibonacci.py: each number is the sum of the two before it

n = 15
a, b = 0, 1
print("Fibonacci sequence:")
for _ in range(n):
    print(a, end=" ")
    a, b = b, a + b
print()

▶ Output

Fibonacci sequence:
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

What happened here: Each new number is the sum of the two before it, and a, b = b, a + b slides the window forward in a single line. Python works out the whole right side first, so you do not need a temporary variable to hold the old value. Picture two people leapfrogging down a path: every step, the back person jumps to the front, and the new front is the sum of where both just were.

Dice Roller

📄 dice_roller.py: while True + random + break

import random

print("🎲 Dice Roller (type 'quit' to stop)\n")
total_rolls = 0

while True:
    command = input("Press Enter to roll (or 'quit'): ").strip().lower()
    if command == "quit":
        break

    die1 = random.randint(1, 6)
    die2 = random.randint(1, 6)
    total_rolls += 1

    print(f"  Roll #{total_rolls}: [{die1}] [{die2}] = {die1 + die2}")

    if die1 == die2:
        print("  🎉 Doubles!")

print(f"\nYou rolled {total_rolls} times. Thanks for playing!")

▶ Output (user presses Enter 3 times then types quit)

🎲 Dice Roller (type 'quit' to stop)

Press Enter to roll (or 'quit'):
  Roll #1: [3] [5] = 8
Press Enter to roll (or 'quit'):
  Roll #2: [4] [4] = 8
  🎉 Doubles!
Press Enter to roll (or 'quit'):
  Roll #3: [1] [6] = 7
Press Enter to roll (or 'quit'): quit

You rolled 3 times. Thanks for playing!

What happened here: while True keeps the dice rolling forever until break stops it, which is exactly what you want for a menu that runs “until the user is done.” It is like a carrom night with friends: nobody decides upfront how many rounds you will play, the game just keeps going until someone says “I’m done” and you pack up the board. Each loop reads a line, checks for quit, then rolls two dice with random.randint(1, 6). Because the rolls are random, your numbers will be different every run, so treat the output above as one sample game, not a fixed result. The doubles check is just if die1 == die2.

Rock Paper Scissors

📄 rps.py: a complete game using everything we’ve learned

import random

choices = ["rock", "paper", "scissors"]
wins = losses = ties = 0

print("✊✋✌️ Rock Paper Scissors (best of 5)\n")

for round_num in range(1, 6):
    while True:
        player = input(f"Round {round_num}: rock/paper/scissors? ").strip().lower()
        if player in choices:
            break
        print("Invalid choice. Try again.")

    computer = random.choice(choices)
    print(f"  You: {player} vs Computer: {computer}")

    if player == computer:
        print("  → Tie!")
        ties += 1
    elif (player == "rock" and computer == "scissors" or
          player == "paper" and computer == "rock" or
          player == "scissors" and computer == "paper"):
        print("  → You win! 🎉")
        wins += 1
    else:
        print("  → Computer wins!")
        losses += 1

print(f"\nFinal: {wins}W - {losses}L - {ties}T")
print("🏆 You win!" if wins > losses else "💻 Computer wins!" if losses > wins else "🤝 It's a draw!")

▶ Output (sample game)

✊✋✌️ Rock Paper Scissors (best of 5)

Round 1: rock/paper/scissors? rock
  You: rock vs Computer: scissors
  → You win! 🎉
Round 2: rock/paper/scissors? paper
  You: paper vs Computer: paper
  → Tie!
Round 3: rock/paper/scissors? scissors
  You: scissors vs Computer: rock
  → Computer wins!
Round 4: rock/paper/scissors? rock
  You: rock vs Computer: scissors
  → You win! 🎉
Round 5: rock/paper/scissors? paper
  You: paper vs Computer: rock
  → You win! 🎉

Final: 3W - 1L - 1T
🏆 You win!

What happened here: This one ties everything together. The for loop runs five rounds, the inner while True keeps asking until you type a valid move (so a typo like “rok” just gets a polite retry), and random.choice picks the computer’s move. That inner loop works like an ATM keypad: it simply refuses to move forward until you enter something it accepts, no crash, just another chance. The win logic lists the three ways you beat the computer; anything else that is not a tie is a loss. The computer plays at random, so your run will look different. The scoreboard above is just one possible game.

Progress Bar

📄 progress_bar.py: visual feedback using loops and string math

import time

total = 20
for i in range(total + 1):
    percent = i * 100 // total
    filled = "█" * i
    empty = "░" * (total - i)
    print(f"\r[{filled}{empty}] {percent}%", end="", flush=True)
    time.sleep(0.1)
print(" Done!")

▶ Output (final state)

[████████████████████] 100% Done!

What happened here: The key is \r, the carriage return. It moves the cursor back to the start of the line without going down, so each new bar prints right on top of the old one. That is why you see one bar smoothly filling up instead of twenty separate lines. It works like a typewriter sliding the carriage back to the left margin to overwrite the same row. The flush=True forces Python to show each frame right away, and time.sleep(0.1) just slows it down enough for your eyes to follow.

Bar Chart from Data

Say five students named Anvi, Anvay, Aviraj, Aditi, and Rahul just got their test scores back. A list of raw numbers takes effort to compare, but one small loop can turn the whole class into a chart you can scan in a second.

📄 bar_chart.py: visualize data in the terminal

scores = {"Anvi": 95, "Anvay": 88, "Aviraj": 72, "Aditi": 91, "Rahul": 65}

print("Student Scores\n")
for name, score in scores.items():
    bar = "▓" * (score // 5)
    print(f"{name:<10} {bar} {score}")

▶ Output

Student Scores

Anvi       ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 95
Anvay      ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 88
Aviraj     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 72
Aditi      ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 91
Rahul      ▓▓▓▓▓▓▓▓▓▓▓▓▓ 65

What happened here: Each score becomes a bar by repeating a block character score // 5 times, so 95 gives 19 blocks and 65 gives 13. The {name:<10} pads every name to ten characters and lines them up on the left, which keeps the bars in a tidy column. It is the same idea as a horizontal chart in a spreadsheet, only drawn with text. Floor division // keeps the block count a whole number, since you cannot print half a block.

Try It Yourself

Challenge: Build a word scramble game. Pick a random word from a list, scramble its letters using random.sample(), and let the player guess the original word. Give them 3 attempts. Track wins and losses across rounds.

Conclusion

Patterns teach you nested loop mechanics. Games teach you while True + break + input validation. Visual output teaches you string formatting and end/flush tricks. Every program here combined concepts from the earlier posts in this series. If you built all ten, your loop skills are solid.

Next up: Lists, Python’s most-used data structure, covering creation, indexing, slicing, and the memory model behind it. And if you want the full roadmap from basics to AI/ML in one place, browse the Python + AI/ML tutorial series home.

Frequently Asked Questions

How do I print a star pattern in Python?

Most python pattern programs use nested for loops: the outer loop controls rows, the inner loop controls columns. For a right triangle: for i in range(1, n+1): print('*' * i). For a pyramid, add spaces before the stars to center them.

How does the progress bar work in Python?

Use \r (carriage return) to overwrite the same line, end='' to prevent newlines, and flush=True to force output. Build the bar string with filled/empty characters and update it in a loop with time.sleep() for the animation effect.

How do I generate Fibonacci numbers in Python?

Use two variables a, b = 0, 1 and swap them in a loop: a, b = b, a + b. This uses Python’s simultaneous assignment to compute the next number without a temporary variable.

How do I make a simple game in Python?

Combine while True for the game loop, input() for player actions, random module for computer choices, and if/elif/else for game logic. Use break to exit when the game ends. The rock-paper-scissors example in this post is a complete template.

What is the underscore variable _ in for loops?

The underscore _ is a convention for a loop variable you don’t need. for _ in range(5): means ‘repeat 5 times, I don’t care about the index.’ It’s not special syntax, just a naming convention that tells other developers the variable is intentionally unused.

Interview Questions on Python Pattern Programs

These come from real screens and onsites. Practice answering before you read each answer.

Q: What does end=" " do in print(), and why do pattern programs rely on it?

By default print() ends every call with a newline (\n). Passing end=" " replaces that newline with a space, so repeated prints inside an inner loop stay on the same line. Pattern programs use it to build a row piece by piece, then call a bare print() to move to the next row. Without it, every star or number would land on its own line.

Q: You wrote a pyramid program but the stars come out left-aligned as a right triangle instead of centered. What did you miss?

The leading spaces. A centered pyramid needs rows - i spaces printed before the stars on each row so the shape gets pushed toward the middle. You also need an odd star count per row, typically 2 * i - 1, so every row has a clean center column. If you only print stars, you get the right triangle by default.

Q: What is the difference between print("*" * i) and an inner loop that prints one star at a time?

The result on screen is identical. "*" * i uses string multiplication to build the whole row as one string and prints it in a single call, so you do not need an inner loop at all. The inner-loop version prints character by character with end="" and needs an extra print() for the line break. String multiplication is shorter and more Pythonic for simple rows; the nested loop becomes necessary when each column needs its own logic, like the multiplication table.

Q: Your while True menu never exits, even though the user typed “QUIT” or “quit ” with a trailing space. What do you check first?

Check how the input is normalized before the comparison. input() returns exactly what was typed, so "QUIT" == "quit" and "quit " == "quit" are both False and break never runs. The fix is input().strip().lower(): strip() removes surrounding whitespace and lower() makes the match case-insensitive. That is exactly why the dice roller in this post chains both calls.

Q: Why do these programs use range(1, rows + 1) instead of range(rows)?

Because the loop variable doubles as the row number in the math. range(rows) gives 0 to 4, and row 0 would print zero stars, an empty first line. range(1, rows + 1) gives 1 to 5, so row 1 prints one star. Remember that range() excludes its stop value, which is why the + 1 is needed to include the last row.

Q: Your progress bar shows nothing while running, then the finished bar appears all at once at the end. What is going on?

That is output buffering. Python holds printed text in a buffer and normally flushes it on a newline, but the progress bar uses end="" so no newline ever arrives until the loop finishes. The fix is flush=True in the print() call, which forces each frame onto the screen immediately. This is a common catch whenever you animate a single line in the terminal.

Want more? the official Python documentation documents everything this post could not fit.

Previous: Python Loop Control: break, continue, pass, else on Loops

Next: Python: Lists, Creation, Indexing, Slicing Complete Guide

Series Home: Python + AI/ML Tutorial Series

RahulAuthor posts

Avatar for Rahul

Rahul is a passionate IT professional who loves to sharing his knowledge with others and inspiring them to expand their technical knowledge. Rahul's current objective is to write informative and easy-to-understand articles to help people avoid day-to-day technical issues altogether. Follow Rahul's blog to stay informed on the latest trends in IT and gain insights into how to tackle complex technical issues. Whether you're a beginner or an expert in the field, Rahul's articles are sure to leave you feeling inspired and informed.

No comment

Leave a Reply

Your email address will not be published. Required fields are marked *