Bookmarks

🟢 Easy

Password Generator

What: A password generator builds a secure string by guaranteeing at least one character from each required set — one uppercase, one lowercase, one digit, one special — filling the rest from the combined pool, then shuffling so the pattern is not predictable. Why it matters: It is the canonical example of "constraint satisfaction": you enforce business rules (complexity requirements) before randomisation, just like you enforce schema constraints before writing to a Delta table. How to remember: Pick the mandatory four first, fill to length, shuffle last — if you shuffle before filling, the guarantee is lost.

Recipe — guarantee → fill → shuffle
A upper+ a lower+ 7 digit+ @ special fill to length
random from pool
shuffle() A7@kQ9pL2!x
Pool = upper + lower + digits + special  |  Without shuffle the first 4 chars would always be Upper-lower-special-digit (predictable!)
Python
import random, string
def gen_password(length=10):
    upper = string.ascii_uppercase
    lower = string.ascii_lowercase
    digits = '0123456789'
    special = '!@#$%^&*'
    pwd = [random.choice(upper), random.choice(lower), random.choice(special), random.choice(digits)]
    pool = upper + lower + digits + special
    pwd += [random.choice(pool) for _ in range(length - len(pwd))]
    random.shuffle(pwd)
    return ''.join(pwd)

print(gen_password(10))
print(gen_password(12))
# Example outputs (random, yours will differ):
# A7@kQ9pL2!x  /  Z3^mPq8&bL1!
Output
A7@kQ9pL2!x
Z3^mPq8&bL1!
🟡 Intermediate

Banking CLI — 7 operations (bug fixed)

What: The banking CLI is a miniature core-banking system built on a dictionary — bankaccount = {accNo: {name, balance}} — exposing seven operations: create, view, deposit, withdraw, transfer, list, and number generation. Why it matters: It forces you to handle the classic distributed-systems bug: transfer must debit one account and credit another atomically, with balance checks before mutation, otherwise a concurrent transfer can leave money duplicated or lost. How to remember: The fixed transfer bug is the lesson — check existence of both accounts, check sufficient funds on the sender, then mutate both in one step.

Architecture — 7 ops on one dict + the bug fix
create
rand 100000-999999
unique check
view
read balance
or "not exist"
deposit
balance += amt
withdraw
check ≥ amt
then -=
transfer ★ fixed
both exist? →
sender ≥ amt? →
sender-=, receiver+=
list
all accounts
or "none yet"
bankaccount = { 443402: {name:'praveen', balance:10000}, 499572: {name:'kumar', balance:3000} } — dict of dicts, like Spark JSON rows.
🐛 Bug that was fixed
Old transfer deducted from sender even if receiver did not exist. Fix: early-return if fr not in bankaccount or to not in bankaccount before touching balances.
Python
import random
bankaccount = {}
def generateaccountnumber():
    while True:
        n = random.randint(100000,999999)
        if n not in bankaccount: return n
def createaccount(name, initialbalance=0):
    n = generateaccountnumber()
    bankaccount[n] = {'name': name, 'balance': initialbalance}
    print(f'account created, your number is {n}')
    return n
def viewbalance(n):
    print(f'balance is {bankaccount[n]["balance"]}' if n in bankaccount else 'account does not exist')
def depositmoney(n, amt):
    if n in bankaccount:
        bankaccount[n]['balance']+=amt; print('deposited')
    else: print('account does not exist')
def withdrawmoney(n, amt):
    if n not in bankaccount: print('account does not exist')
    elif bankaccount[n]['balance'] < amt: print('insufficient funds')
    else: bankaccount[n]['balance']-=amt; print('withdrawn')
def transfermoney(fr,to,amt):
    if fr not in bankaccount or to not in bankaccount:
        print('account does not exist'); return
    if bankaccount[fr]['balance'] < amt:
        print(f'insufficient funds, balance is {bankaccount[fr]["balance"]}'); return
    bankaccount[fr]['balance']-=amt; bankaccount[to]['balance']+=amt
    print(f'funds transferred, your balance is {bankaccount[fr]["balance"]}')
def listaccounts():
    print(list(bankaccount.items()) if bankaccount else 'No account yet')

# Demo (numbers random)
# a = createaccount('praveen', 10000)  # 443402
# b = createaccount('kumar', 1000) # 499572
# viewbalance(a)        # balance is 10000
# depositmoney(a, 5000) # deposited → 15000
# withdrawmoney(a,3000) # withdrawn → 12000
# transfermoney(a,b,2000) # funds transferred → a:10000 b:3000
Output
account created, your number is 443402
account created, your number is 499572
balance is 10000
deposited
withdrawn
funds transferred, your balance is 10000
🟡 Intermediate

Bubble Sort

What: Bubble sort repeatedly walks the list, comparing each adjacent pair and swapping if they are out of order — the largest element "bubbles" to the end each pass, so the next pass can ignore the last sorted element. Why it matters: You will rarely sort in Python (use sorted() or Spark's orderBy), but bubble sort is the interview standard for proving you understand nested loops, the shrinking window range(n-i-1), and in-place swapping a,b = b,a. How to remember: Outer loop = number of passes, inner loop = window that shrinks by i each time because the last i elements are already sorted.

Bubble sort — largest bubbles right, window shrinks
Pass 1: window 0 → 6  |  Pass 2: window 0 → 5  |  Pass 3: window 0 → 4 …
10032→ swap 321005→ swap …
569123260100 ✓ sorted
for i in range(n): for j in range(n-i-1): if x[j] > x[j+1]: x[j],x[j+1]=x[j+1],x[j]n-i-1 is the shrinking window

palindrome

s == s[::-1] — reverse and compare. 'mom' → True.

count chars

out[c] = out.get(c,0)+1 — same pattern as word count in Spark.

fibonacci

a,b = b,a+b — parallel assignment generates sequence iteratively.
Python
xlist = [100,32,5,6,12,9,60]
n = len(xlist)
for i in range(n):
    for j in range(n-i-1):  # shrinks — last i elements already sorted
        if xlist[j] > xlist[j+1]:
            xlist[j], xlist[j+1] = xlist[j+1], xlist[j]
print(xlist)  # [5, 6, 9, 12, 32, 60, 100]

def countofoccurence(s):
    out={}
    for c in s:
        out[c] = out.get(c,0)+1
    return out
print(countofoccurence('aaabbaccddeeef'))
# {'a':4,'b':2,'c':2,'d':2,'e':3,'f':1}

def ispalindrome(s): return s == s[::-1]
print(ispalindrome('mom'))   # True
print(ispalindrome('praveen')) # False
def fibonacci(n):
    a,b, fib = 0,1,[]
    for _ in range(n): fib.append(a); a,b = b, a+b
    return fib
print(fibonacci(8))  # [0, 1, 1, 2, 3, 5, 8, 13]
Output
[5, 6, 9, 12, 32, 60, 100]
{'a': 4, 'b': 2, 'c': 2, 'd': 2, 'e': 3, 'f': 1}
True
False
[0, 1, 1, 2, 3, 5, 8, 13]
🟢 Easy

Turtle Race — GUI

What: The turtle race is a playful GUI simulation — six turtles (red, orange, yellow, green, blue, purple) start at x=-230 on six lanes, then each step moves a random 0-10 forward until one crosses x ≥ 230. Why it matters: It is not a PySpark project but a teachable event loop: while is_race_on: with random progress and a single winner — the same pattern as polling a queue until a job finishes. How to remember: It needs a display (Screen + Turtle), so it only runs locally; on a headless cluster the loop still illustrates non-deterministic racing and bet comparison.

Track — 6 lanes, random steps, first to 230 wins
red
🏁 230
y=-70
orange
y=-40
yellow
y=-10
green
y=20
blue
y=50
purple
y=80
Each loop: t.forward(random.randint(0,10))  |  Winner: first with t.xcor() >= 230 → compare to user_bet
Python
from turtle import Turtle, Screen
import random
screen = Screen(); screen.setup(width=500, height=400)
user_bet = screen.textinput(title="make your bet", prompt="Which turtle will win? Enter a colour: ")
colors = ["red","orange","yellow","green","blue","purple"]
y_positions = [-70,-40,-10,20,50,80]
all_turtles = []
for i in range(6):
    t = Turtle(shape="turtle"); t.color(colors[i]); t.penup()
    t.goto(x=-230, y=y_positions[i]); all_turtles.append(t)
is_race_on = bool(user_bet)
while is_race_on:
    for t in all_turtles:
        if t.xcor() >= 230:
            winning = t.pencolor()
            print("You've won!" if winning==user_bet else f"winning is {winning}, you lost")
            is_race_on=False; break
        t.forward(random.randint(0,10))
screen.exitonclick()
# → (GUI) prints: You've won!  or: winning is blue, you lost
Output
(GUI — run locally)
You've won!  # if bet matched winner
winning is blue, you lost