Blekinge Institude of Technology

Kmom01Kursmoment01: Get Started with Python

Introduction

You must now create a program that asks the user to enter one of the following values:

  • Speed (km/h)
  • Price

The program should then ask which value the user wants to convert to:

  • P: Price, where the value is adjusted with a fixed discount (10 SEK) and then increased by VAT (20%).
  • S: Speed, where the value is interpreted as km/h and converted to mph (miles per hour).

1 kilometer equals 0.62137 miles.
Finally, print the converted value with a maximum of two decimal places.

It is important that your program follows the instructions in the requirements; otherwise, the tests will not work and your submission will not be graded.

                    
value_str = input().strip()

if not value_str.replace(".", "", 1).lstrip("-").isdigit():
    print("Invalid value")
    exit()

value = float(value_str)

converter = input().strip().upper()

# Skriv ut det ursprungliga värdet formaterat
print(f"{value:.1f} ")

if converter == "S":
    mph = value * 0.62137
    print(f"{mph:.2f} ")

elif converter == "P":
    discount = 10
    tax = 0.2
    price_after_discount = value - discount
    final_price = price_after_discount * (1 + tax)
    print(f"{final_price:.1f} ")

# felaktig konvertering
else:
    print("Invalid converter")
    exit()
                    
                

Kmom02Kursmoment02: Loop

Marvin - steg 1

Programming and problem-solving in Python, where you will build a chatbot called Marvin that can answer “all” your questions.

                    
from collections import Counter

"""
Marvin, vännen i terminal
"""

print(r"""
.<'"'=,,_ //__ -_"(XX, (y") \_ ) "X ( \ r )_| X______ ) | (_//"/\__ \ Y_<_ /_/ /\ \ \ |__\ \/ x\ \ \ /_--\ \x / \ \ ( \ \ \/ | \_ |\ \ "' \ fu''_] | \ \ | | r"" \__\ | \ || ,x"| | ',"' x" | |\_.-"_>-. x' | |[_.-" \ |\ | |/ | _|_| | | fl"Ol] _/ / |,U""-. / \_.-"| || /" | | "' / | | / / | | / / | /_ | .' \ \ | \ \ | | | '._-\ | | ". \ | / \ \ |__| _\ \ f""l ( _ ] I | "" "" I | __l | ( _ ] """ ""
""") print("Hej, Här har du Marvin, hjälpsamma robot som hjälper dig 🦾") while True: # main loop som visar upp menyn å kontrollerar user's val print("\nMeny") print("1. Skriv ditt namn") print("2. Change Temperature Celsius → Fahrenheit") print("3. Poäng till betyg") print("4. Jämför tal: ") print("5. Skriv in personnummer") print("6. Rovarspråket") print("q. Avsluta") val = input("Välja ett alternativ: ") if val == "q": print(f"{GREEN}Hejdå från roboten 👋{RESET}") break # avslutar programmet -------------------------------------------------------------------------------- elif val == "1": print(f"{GREEN}Hej Ali heter jag, å Robot hälsar dig tillbaka 🤚{RESET}") -------------------------------------------------------------------------------- elif val == "2": celcius = float(input(f"{GREEN}Skriv temperaturen i Celcius: {RESET}")) fahrenheit = round((celcius * 9 / 5) + 32, 2) # runda decimalen till 2 print(f"{celcius} °C Celcius motsvarar {fahrenheit: 2} °F Fahrenheit") -------------------------------------------------------------------------------- elif val == "3": max_poang = float(input("Ange Max poang: ")) # example 169 din_poang = float(input("Ange dina poang: ")) # example 59 procent = (din_poang / max_poang) * 100 # 59/169 = 0.349 * 100 = 34.9 GRADE_A = 90 GRADE_B = 80 GRADE_C = 70 GRADE_D = 60 GRADE_E = 50 if procent >= GRADE_A: betyg = "A" elif procent >= GRADE_B: betyg = "B" elif procent >= GRADE_C: betyg = "C" elif procent >= GRADE_D: betyg = "D" elif procent >= GRADE_E: betyg = "E" else: betyg = "F" print(f"{GREEN}score: {betyg}{RESET}") -------------------------------------------------------------------------------- elif val == "4": old_value = None while True: # tar en input från användaren value = input( f"{GREEN}skriv ett tal eller (skriv done för att avsluta): {RESET}" ) if value == "done": break; try: # Konvertera till int för strikt jämförelse tal = int(value) if old_value is None: old_value = tal continue # försätt if tal > old_value: print("larger!") elif tal < old_value: print("smaller!") else: print("same!") old_value = tal except ValueError: # s124❌ dfhdf❌ 4124✅ print("not a number!") -------------------------------------------------------------------------------- elif val == "5": personnummer = input(f"{GREEN}Skriv in personnummer: {RESET}").replace("-", "") LENGHT_PERSONNUMMER = 10 if not personnummer.isdigit() or len(personnummer) != LENGHT_PERSONNUMMER: RED = "\033[31m" RESET = "\033[0m" print(f"{RED}Not valid{RESET}") continue # försätt till nästa iteration total = 0 # summering variabel enligt Luhn algorithm # gå genom varje siffra i personnummer i å värdet är digit for i, digit in enumerate(personnummer): tal_n = int(digit) # omvandla siffran från sträng till heltal if i % 2 == 0: # varje siffra som är jämna index bearbetas tal_n = tal_n * 2 # multipliceras siffran med 2 LUHN = 9 # if result greater than 9, addera ihop siffror if tal_n > LUHN: tal_n = tal_n // 10 + tal_n % 10 total = total + tal_n # lägger siffran till den totala summan if total % 10 == 0: # kontroll om siffran är modulus 10 print(f"{GREEN}Valid{RESET}") else: print(f"{RED}Not valid{RESET}") -------------------------------------------------------------------------------- elif val == "6": word = input("Skriv ett ord: ") # ber skriva skrva nåt vowels = "AEIOUÅÄÖaeiouyåäö" resultat = "" for s in word: if s.isalpha() and s not in vowels: resultat += s + "o" + s else: resultat += s print(f"{GREEN}{resultat}{RESET}") -------------------------------------------------------------------------------- elif val == "7": # nytt alternativ: jämför två strängar, för extra uppgifter string_one = input("Skriv din första strängen: ").lower() string_two = input("Skriv din andra strängen: ").lower() count_str_one = Counter(string_one) count_str_two = Counter(string_two) match = True for letter, antal in count_str_two.items(): if count_str_one[letter] < antal: match = False break if match: print(f"{GREEN}Matching ...{letter} finns med i första strängen{RESET}") else: print(f"{RED}Not Matching.{RESET}") -------------------------------------------------------------------------------- else: RED = "\033[31m" RESET = "\033[0m" print(f"{RED}Alternativet {val} finns ej med i listen..!{RESET}")

Kmom03Kursmoment03: Functions & Modules

Marvin - steg 2

Programming and problem-solving in Python. Structure the code using your own functions.

main.py

                    
import marvin1
import marvin2

def main():
    """Startar Marvin och visar menyn."""
    while True:
        print("\n==== Marvin Menu ====")
        print("1. Greet")
        print("2. Celsius to Fahrenheit")
        print("3. Points to Grade")
        print("4. Compare Numbers")
        print("5. Validate SSN")
        print("6. Robber Language")
        print("7. Create SSN")
        print("8. Randomize String")
        print("q. Quit")

        choice = input("Your choice: ")

        if choice == "q":
            print("Goodbye!")
            break

        if choice == "1":
            marvin1.greet()

        elif choice == "2":
            marvin1.celsius_to_fahrenheit()

        elif choice == "3":
            marvin1.points_to_grade()

        elif choice == "4":
            marvin1.compare_numbers()

        elif choice == "5":
            marvin1.validate_ssn()

        elif choice == "6":
            marvin1.robber_language()

        elif choice == "7":
            birth = input("Enter birth date (YYMMDD): ")
            print(marvin2.create_ssn(birth))

        elif choice == "8":
            text = input("Enter a string to randomize: ")
            print(f"{text} --> {marvin2.randomize_string(text)}")

        else:
            print("Invalid choice.")


if __name__ == "__main__":
    main()
                    
                

marvin1.py

                    
VOWELS = "aeiouyåäöAEIOUYÅÄÖ"
GRADE_F_LIMIT = 50
GRADE_E_LIMIT = 60
GRADE_D_LIMIT = 70
GRADE_C_LIMIT = 80
GRADE_B_LIMIT = 90

SSN_LEN = 10
LUHN_NBR = 9


def greet():
    """Menyval 1: Hälsa på användaren."""
    name = input("What is your name? ")
    print("\nMarvin says:\n")
    print(f"Hello {name} - your awesomeness!")
    print("What can I do you for?!")
--------------------------------------------------------------------------------

def celsius_to_fahrenheit():
    """Menyval 2: Omvandla Celsius till Fahrenheit."""
    celsius = float(input("Enter temperature in Celsius: "))
    fahrenheit = celsius * 9 / 5 + 32
    print(f"{celsius}°C is {fahrenheit}°F")
--------------------------------------------------------------------------------

def get_grade(points):
    """Returnerar betyg beroende på poäng."""
    if points < GRADE_F_LIMIT:
        return "F"
    elif points < GRADE_E_LIMIT:
        return "E"
    elif points < GRADE_D_LIMIT:
        return "D"
    elif points < GRADE_C_LIMIT:
        return "C"
    elif points < GRADE_B_LIMIT:
        return "B"
    return "A"
--------------------------------------------------------------------------------

def points_to_grade():
    """Menyval 3: Räkna ut betyg från poäng."""
    while True:
        try:
            value = input("Enter your points (0–100 or 'done'): ")
        except (EOFError, StopIteration):
            break

        if value is None or value.lower() == "done":
            break

        try:
            points = int(value)
        except ValueError:
            continue

        grade = get_grade(points)
        print(f"score: {grade}")
--------------------------------------------------------------------------------

def compare_numbers():
    """Menyval 4: Jämför flera tal tills 'done' skrivs."""
    prev = None
    while True:
        value = input("Enter a number (or 'done'): ")
        if value.lower() == "done":
            break

        num = float(value)
        if prev is not None:
            if num > prev:
                print("larger!")
            elif num < prev:
                print("smaller!")
            else:
                print("same!")
        prev = num
--------------------------------------------------------------------------------

def validate_ssn():
    """Menyval 5: Kontrollera giltigt personnummer."""
    ssn = input("Enter a full SSN (YYMMDD-NNNN): ")

    # Ta bara siffror
    digits = ""
    for ch in ssn:
        if ch.isdigit():
            digits += ch

    if len(digits) != SSN_LEN:
        print("Invalid SSN (must have 10 digits)")
        return

    # Räkna ut Luhn-summan
    total = calculate_luhn_sum(digits)

    # Om summan är delbar med 10 → giltigt SSN
    if total % 10 == 0:
        print("Valid SSN")
    else:
        print("Invalid SSN")
--------------------------------------------------------------------------------

def calculate_luhn_sum(digits):
    """Räknar ut Luhn-summan (för svenska personnummer, från vänster)."""
    total = 0
    for i, ch in enumerate(digits):
        n = int(ch)
        if i % 2 == 0:  # varannan siffra från vänster
            n *= 2
            if n > LUHN_NBR:
                n -= LUHN_NBR
        total += n
    return total
--------------------------------------------------------------------------------

def robber_language():
    """Menyval 6: Översätt till rövarspråket."""
    text = input("Enter text: ")
    result = ""

    for ch in text:
        if ch.lower() not in VOWELS and ch.isalpha():
            result += ch + "o" + ch.lower()
        else:
            result += ch

    print(result)
                    
                

marvin2.py

                    
import random
from marvin1 import calculate_luhn_sum

# Konstant för antal slumpade siffror i personnummer
RANDOM_DIGIT_COUNT = 3

def calculate_luhna_sum(ssn):
    """Wrapper för testet som använder felstavat funktionsnamn."""
    return calculate_luhn_sum(ssn)
--------------------------------------------------------------------------------

def create_ssn(birth):
    """Menyval 7: Skapa ett giltigt personnummer med slumpade siffror."""
    random_digits = ""
    count = 0
    while count < RANDOM_DIGIT_COUNT:
        random_digits += str(random.randint(0, 9))
        count += 1

    digits = birth + random_digits  # utan bindestreck!
    total = calculate_luhn_sum(digits)
    last_digit = (10 - (total % 10)) % 10

    ssn = f"{birth}-{random_digits}{last_digit}"
    return ssn
--------------------------------------------------------------------------------

def randomize_string(text):
    """Menyval 8: Slumpa om bokstäver i en text (utan listor)."""
    result = ""
    original = text

    # Slumpa bort bokstäver en i taget
    while len(text) > 0:
        index = random.randint(0, len(text) - 1)
        result += text[index]
        text = text[:index] + text[index + 1 :]

    # Om slumpningen blev identisk, kör om
    if result == original and len(original) > 1:
        return randomize_string(original)

    return result
                    
                

Kmom04Kursmoment04: Lists

Marvin - steg 3

Programming and problem-solving in Python. Continue working with Marvin and implement new functionality using lists.

inventory.py

                    
# Funktion för att lägga till föremål i ryggsäcken
def pick(bagpack, item, position=None):
    try:
        # Om ingen position anges, lägg sist
        if position is None:
            bagpack.append(item)
            print(f"Du lade till '{item}' i ryggsäcken (sist).")
--------------------------------------------------------------------------------
        else:
            position = int(position)  # Gör om till heltal
            if position < 0 or position > len(bagpack):
                print(f"Error: position {position} finns inte.")
                return bagpack

            # Lägg till på specifik position
            bagpack.insert(position, item)
            print(f"Du lade till '{item}' på position {position}.")

    # Fel om position inte är ett nummer
    except ValueError:
        print(f"Error ogiltig position '{position}'.")
    return bagpack
--------------------------------------------------------------------------------

# Funktion för att slänga föremål från ryggsäcken
def drop(bagpack, item):
    try:
        # Försök ta bort föremålet
        bagpack.remove(item)
        print(f"Du slängde '{item}'.")

    except ValueError:
        print(f"Error '{item}' finns inte i ryggsäcken.")
    return bagpack

def swap(bagpack, first, second):
    if len(bagpack) == 0:
        # Lägg till första föremålet om ryggsäcken är tom
        print(f"Error: föremålen '{first}' och '{second}' finns inte i ryggsäcken.")
        return bagpack
    try:
        i1 = bagpack.index(first)
        i2 = bagpack.index(second)
        bagpack[i1], bagpack[i2] = bagpack[i2], bagpack[i1]
        print(f"Bytte plats på '{first}' och '{second}'.")
    except ValueError:
        missing_items = []
        if first not in bagpack:
            missing_items.append(first)
        if second not in bagpack:
            missing_items.append(second)
        print(f"Error: föremålen {', '.join(missing_items)} finns inte i ryggsäcken.")
    return bagpack
--------------------------------------------------------------------------------

# Funktion för att visa innehåll i ryggsäcken
def inventory(bagpack):
    # Om ryggsäcken är tom
    if not bagpack:
        print("Ryggsäcken är tom.")
        print("0")
        return
    # Visa alla föremål i ryggsäcken
    print(f"Ryggsäcken innehåller {len(bagpack)} saker:")
    for i, thing in enumerate(bagpack):
        print(f"{i}: {thing}")
                    
                

main.py

                    
# Importera funktioner från inventory-filen
from inventory import pick, drop, swap, inventory

# Konstant för kommandon
INV = "inv"
INV_PICK = "inv pick"
INV_DROP = "inv drop"
INV_SWAP = "inv swap"

# Antal ord för varje kommando
PICK_WORDS = 3
PICK_POSITION = 4
DROP_WORDS = 3
SWAP_WORDS = 4
INV_DROP_ARGS = 2
--------------------------------------------------------------------------------

def main():
    bagpack = []  # Tom ryggsäck från början

    # Visa instruktioner
    print("Hej! Jag är Marvin3 här 🤖.")
    print("Skriv kommandon (q för att avsluta).")

    print(" inv         - Visa innehållet i ryggsäcken")
    print(" inv pick    - plocka ett föremål och lägg det sist")
    print(" inv pick    - plocka ett föremål på specifik position")
    print(" inv drop    - Visa innehållet i ryggsäcken")
    print(" inv drop    - släng ut ett föremål")
    print(" inv swap    - bytar plats på två föremål")

    while True:
        User_input = input("> ").strip()

        if User_input == "":
            continue
--------------------------------------------------------------------------------
        if User_input == "q":
            print("Hejdå 👋")
            break
--------------------------------------------------------------------------------
        if User_input == INV:
            inventory(bagpack)
--------------------------------------------------------------------------------
        elif User_input.startswith(INV_PICK):
            parts = User_input.split()

            if len(parts) == PICK_WORDS:
                bagpack = pick(bagpack, parts[2])

            elif len(parts) == PICK_POSITION:
                bagpack = pick(bagpack, parts[2], parts[3])
            else:
                print("Error: inv pick kräver ett föremål och valfritt en position.")
--------------------------------------------------------------------------------
        # Släng föremål eller visa innehåll
        elif User_input.startswith(INV_DROP):
            parts = User_input.split()

            if len(parts) == INV_DROP_ARGS:
                inventory(bagpack)

            elif len(parts) == DROP_WORDS:
                bagpack = drop(bagpack, parts[2])
            else:
                print("Error: inv drop kräver ett föremål.")
--------------------------------------------------------------------------------
        # Byt plats på två föremål
        elif User_input.startswith(INV_SWAP):
            parts = User_input.split()
            # Byt plats om två föremål angivna
            if len(parts) == SWAP_WORDS:
                bagpack = swap(bagpack, parts[2], parts[3])
            else:
                print("Error: inv swap kräver två föremål.")
--------------------------------------------------------------------------------
        else:
            print(f"Error: Okänt kommando '{User_input}'")


if __name__ == "__main__":
    main()
                    
                

Kmom05Kursmoment05: Dictionary & Tuple

Carbon Emissions for Students

You will develop a program that can analyze students' carbon emissions. The program should handle multiple emission categories, such as transportation, food, and energy, and allow the user to:

  • Display the total emissions per student
  • Show the “greenest” student
  • Display emissions per category
  • Rank students by category
  • Add or update students' emissions
  • Remove students from the system

The program should work in a similar way to Marvin, using a menu loop.

emissions.py

                    
def print_menu():  # skriver ut meny med olika val
    print("\n--- Välkommen till klimat program ---")
    print("1. Visa totalutsläpp per student")
    print("2. Visa den grönaste studenten")
    print("3. Visa utsläpp per kategori")
    print("4. Rangordna studenter per kategori")
    print("5. Lägg till eller uppdatera student")
    print("6. Ta bort student")
    print("q. Avsluta programmet")
    print(".................................")

def display_total_emission_per_student(data):
    if not data:
        print("Ingen studentdata tillgänglig.")
        return 

    for student, categories in data.items(): 
        total = total_emission(categories)
        print(
            f"{student[0]} ({student[1]}): {total} kg CO2") 
--------------------------------------------------------------------------------

def display_the_greenest_student(data):
    if not data:
        print("Ingen studentdata tillgänglig.")
        return
    green = None 
    lowest = None 

    for (student,categories,) in data.items(): 
        total = total_emission(categories)

        if lowest is None or total < lowest:
            lowest = total 
            green = student 

    print(f"{green[0]} ({green[1]}): {lowest} kg CO2")
--------------------------------------------------------------------------------

def show_emission_per_category(data):
    if not data:
        print("Ingen studentdata tillgänglig.")
        return

    category_summa = {} 
    for categories in data.values():
        for (category,value,) in categories.items():
            if (category not in category_summa):
                category_summa[category] = 0
            category_summa[category] += (value)

    for cat, total in category_summa.items():
        print(f"{cat}: {total} kg CO2")
--------------------------------------------------------------------------------

def display_students_ranking(data, category):
    if not data:
        print("Ingen studentdata tillgänglig.")
        return

    rank = [] 
    for student, categories in data.items():
        value = categories.get(category, 0) 
        rank.append((student[0], student[1], value))

    swapp = True
    while swapp:
        swapp = False
        i = 0
        while i < len(rank) - 1: 
            first = rank[i]
            second = rank[i + 1]

            if first[2] < second[2] or (first[2] == second[2] and first[0] > second[0]):
                rank[i], rank[i + 1] = rank[i + 1], rank[i]
                swapp = True 
            i = i + 1  

    index = 1 
    for namn, student_id, value in rank:
        print(f"{index}. {namn} ({student_id}): {value} kg CO2 från {category}")
        index = index + 1
--------------------------------------------------------------------------------

def add_update(data, namn, student_id, category, value):
    key = (namn, student_id)  
    if key not in data:
        data[key] = {} 

    data[key][category] = value 
    print(f"Data uppdaterad för {namn} ({student_id}).")
--------------------------------------------------------------------------------

def delete_student(data, namn, student_id):
    key = (namn, student_id) 
    if key in data:
        del data[key] 
        print(f"{namn} ({student_id}) har tagits bort.")
    else:
        print(f"Student {namn} ({student_id}) hittades inte.")
--------------------------------------------------------------------------------

def total_emission(categories):
    total = 0 
    for value in categories.values():
        total = total + value 
    return total 
                    
                

main.py

                    
import emissions  # här importerar jag filen emissions där alla funktioner finns


def main():
    students_data = {
        ("Bob", 102): {"transport": 5, "food": 15, "energy": 20},
        ("Dana", 104): {"transport": 40, "food": 10, "energy": 15},
        ("Alice", 101): {"transport": 15, "food": 25, "energy": 30},
        ("Charlie", 103): {"transport": 10, "food": 13, "energy": 25, "waste": 5},
    }

    while True:
        emissions.print_menu()
        val = input("\nVälja ett alternativ: ").strip().lower()  # user väljer sitt val

        if val == "1":
            emissions.display_total_emission_per_student(students_data)
--------------------------------------------------------------------------------
        elif val == "2":
            emissions.display_the_greenest_student(students_data)
--------------------------------------------------------------------------------
        elif (val == "3"):
            emissions.show_emission_per_category(students_data)
--------------------------------------------------------------------------------
        elif val == "4": 
            category = input("Ange kategori: ").strip().lower()  # undrar vilken kategory
            emissions.display_students_ranking(students_data, category)
--------------------------------------------------------------------------------
        elif val == "5": 
            namn = input("student name: ").strip() 
            try:
                student_id = int(input("Student-ID: ")) 

            except ValueError:
                print("Invalid, ID måste va ett heltal")
                print("Enter för att försätta")
                continue  
            category = input("Kategori: ").strip().lower()

            try:
                value = int(input("Utsläppsvärde kg CO2: ")) 
            except ValueError:
                print("Invalid, ID måste va ett heltal")
                print("Enter för att försätta")
                continue

            emissions.add_update(students_data, namn, student_id, category, value)
--------------------------------------------------------------------------------
        elif val == "6":
            namn = input("student name: ").strip()
            try:
                student_id = int(input("Student-ID: ")) 
            except ValueError:
                print("Invalid, ID måste vara ett heltal.")
                input("Enter för att fortsätta...")
                continue  

            emissions.delete_student(students_data, namn, student_id)
--------------------------------------------------------------------------------
        elif val == "q":
            print("programmet avslutas")
            break
--------------------------------------------------------------------------------
        else:
            print("valet är ogiltig, försök igen!")

        print("Tryck Enter för att försätta....")  # pausa mellan varje val


if __name__ == "__main__":
    main()
                    
                

Kmom06Kursmoment06: File Handling

Analyze Text and Words

In Marvin, we have built a program consisting of two modules and several functions that work together so that Marvin can answer questions. We have also become familiar with dictionaries, where we can store key-value pairs. In this task, we will create a Marvin-like program that takes input and can analyze a text.

analyzer.py

                    
import os
import string

# Läser in textfilen från samma mapp som main.py
def _read_file(filename):
    """Läser textfilen säkert från samma mapp som main.py."""
    base_dir = os.path.dirname(__file__)
    file_path = os.path.join(base_dir, filename)

    try:
        with open(file_path, encoding="utf-8") as f:
            # returnerar all text i filen som en sträng
            return f.read()
    except FileNotFoundError:
        print(f"Filen '{filename}' hittades inte.")
        return ""
--------------------------------------------------------------------------------

# Denna funktion kan main.py och testerna anropa
def read_file(filename):
    """Publik funktion som anropar den privata _read_file."""
    return _read_file(filename)
--------------------------------------------------------------------------------

# Hjälpfunktion för sortering
def sortering_nyckel(item):
    return (item[1], item[0])
--------------------------------------------------------------------------------

# Räknar hur många rader som inte är tomma
def line_counter(text):
    count = 0  # börjar räkna från noll
    for line in text.splitlines():  # går igenom varje rad i texten
        if line.strip():  # om raden inte tom
            count += 1  # ökar räknaren
    return count
--------------------------------------------------------------------------------

# Gör texten enklare att räkna (tar bort skiljetecken)
def _clean_text(text):
    text = text.lower()  # gör om allt till små bokstäver
    for p in string.punctuation:  # går igenom varje skiljetecken
        text = text.replace(p, "")  # tar bort det från texten
    return text
--------------------------------------------------------------------------------

# Räknar antal ord i texten
def word_counter(text):
    clean = _clean_text(text)
    words = clean.split()  # delar texten i ord
    return len(words)  # räknar hur många ord det finns
--------------------------------------------------------------------------------

# Räknar antal bokstäver a z
def letter_counter(text):
    count = 0
    # går igenom varje tecken i texten, omvandlar till små bokstäver
    for c in text.lower():
        # kontrollerar om tecknet är en bokstav a till z
        if c.isalpha():
            count += 1  # ökar räknaren med 1 för varje bokstav
    return count  # return det totala antalet bokstäver i texten
--------------------------------------------------------------------------------

def frequency_count(items):
    """
    beräknar hur ofta varje element förekommer i en lista
    och beräknar procentandel för varje element.
    returnerar en sorterad lista med > element, antal, procent
    """
    count = {}  # Tom ordbok för att spara antalet förekomster
    # räknar hur många gngr varje element finns i listan
    for it in items:
        if it in count:
            count[it] += 1
        else:
            count[it] = 1

    # räknar totala antalet element
    total = 0
    for _ in items:
        total += 1
    result = []  

    for key, value in count.items():
        procent = round(value / total * 100, 1)
        result.append((key, value, procent))

    result.sort(key=sortering_nyckel, reverse=True)
    return result

MAX_ITEMS = 7  # antal toppresultat att visa
def simple_word(text):
    """
    Skriver ut de 7 mest frekventa orden i texten
    med deras antal och procentandel.
    """
    # tar bort onödiga tecken och formaterar texten
    clean = _clean_text(text)
    word_list = clean.split()  # delar upp texten i en lista av ord

    if not word_list:
        return  # avbryter om texten är tom

    items = frequency_count(word_list)  # hämtar statistik över orden

    for i, entry in enumerate(items):
        if i >= MAX_ITEMS:
            break
        word, cnt, pct = entry
        print(f"{word}: {cnt} | {pct}%")
--------------------------------------------------------------------------------
def simple_letter(text):
    """
    Skriver ut de 7 mest frekventa bokstäverna i texten
    med deras antal och procentandel.
    """
    letters = [] 

    for c in text.lower():
        if c.isalpha():
            letters.append(c)

    if not letters:
        return 

    items = frequency_count(letters) 

    for i, entry in enumerate(items):
        if i >= MAX_ITEMS:
            break
        letter, cnt, pct = entry
        print(f"{letter}: {cnt} | {pct}%")
--------------------------------------------------------------------------------

# Visar alla resultat
def display_all(text):
    """Visar alla analyser i rätt ordning."""
    print(line_counter(text))  # antal rader
    print(word_counter(text))  # antal ord
    print(letter_counter(text))  # antal bokstäver
    print()
    simple_word(text)  # vanligaste orden
    print()
    simple_letter(text)  # vanligaste bokstäverna
                    
                

lorum.txt

                    
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vitae aliquet dolor.
Vivamus neque dui, varius in iaculis a, imperdiet at ligula.
Donec dapibus urna.
                    
                

main.py

                    
import os
import analyzer  # importerar analyzer.py där funktionerna finns


def main():
    """Huvudprogram som visar meny och kör valda analyser."""
    base_dir = os.path.dirname(__file__)  # sökväg till mappen
    filename = "phil.txt"  # startfil

    while True:
        print("\n--- Text Analyzer ---")
        print(f"Nuvarande fil: {filename}")
        print("========================")
        print("lines  -> beräkna antal rader")
        print("words  -> beräkna antal ord")
        print("letters -> beräkna antal bokstäver")
        print("word_frequency -> Vanliga orden")
        print("letter_frequency -> Vanliga bokstäver")
        print("all -> Visa alla analyser")
        print("change -> Byt fil")
        print("q -> Avsluta programmet")
        print("========================")

        val = input("Välj ett alternativ: ").strip().lower()  # användarval

        # Hantera byte av fil först
        if val == "change":
            new_file = input("Ange nytt filnamn (t.ex. lorum.txt): ").strip()
            # Lägger till sökvägen till filen för att hantera den korrekt i testmiljöer
            new_path = os.path.join(base_dir, new_file)
            if os.path.exists(new_path):  # om filen finns
                filename = new_file
            else:
                print(f"Filen '{new_file}' finns inte i mappen.")
            continue  # gå tillbaka till meny

        # Åtgärda filinläsningen i main.py:
        text = analyzer.read_file(filename)

        if not text and val not in {"change", "q"}:  # om filen inte hittas
            continue

        if val == "lines":
            print(analyzer.line_counter(text))

        elif val == "words":
            print(analyzer.word_counter(text))

        elif val == "letters":
            print(analyzer.letter_counter(text))

        elif val == "word_frequency":
            analyzer.simple_word(text)

        elif val == "letter_frequency":
            analyzer.simple_letter(text)

        elif val == "all":
            analyzer.display_all(text)

        elif val == "q":  # avslutar programmet
            print("Programmet avslutas...")
            break

        else:  # ogiltigt val
            print("Ogiltigt val, försök igen.")

        # input("Tryck Enter för att fortsätta...")

if __name__ == "__main__":
    main()
                    
                

phil.txt

                    
Phil was quick to take a hint. He saw the menace in the shopkeepers
eyes, and, stopping abruptly, ran farther down the street, hugging his
fiddle, which he was afraid the angry tobacconist might seize and break.
This, to him, would be an irreparable misfortune and subject him to a
severe punishment, though the fault would not be his.
Next he strolled into a side street, and began to play in front of some
dwelling-houses. Two or three young children, who had been playing in
the street, gathered about him, and one of them gave him a penny. They
were clamorous for another tune, but Phil could not afford to work for
nothing, and, seeing no prospects of additional pay, took his violin,
and walked away, much to the regret of his young auditors, who, though
not rich, were appreciative. They followed him to the end of the block,
hoping that he would play again, but they were disappointed.
Phil played two or three times more, managing to obtain in all
twenty-five cents additional. He reached the corner of Thirteenth Street
just as the large public school, known as the Thirteenth Street School,
was dismissed for its noon intermission.
                    
                

Kmom10Kursmoment10: Project & Examination

Project Specification

You will implement a program for keyboard training. The program displays one line at a time for the user to type as quickly as possible. After the user has typed all the lines, the program should calculate how well they performed and display the results.

The basic requirements include 5 menu options:

  • 1. Start the typing test using the file easy.txt.
  • 2. Start the typing test using the file medium.txt.
  • 3. Start the typing test using the file hard.txt.
  • 4. Print the results list saved in scores.txt.
  • q. Exit the program.

Easy.txt

Medium.txt

Hard.txt

functions.py

                    
import os
import time

# grundläggande filvägar och konstanter
BASE_DIR = os.path.dirname(__file__)
TEXTS_DIR = os.path.join(BASE_DIR, "texts")
SCORES_FILE = os.path.join(BASE_DIR, "scores.txt")
EXPECTED_PARTS = 3

# wpm gränser och motsvarande djurkategorier
WPM_CATEGORIES = [
    (5, "Sloth 🦥"),
    (15, "Snail 🐌"),
    (30, "Manatee 🐋"),
    (40, "Human 🧑"),
    (50, "Gazelle 🦌"),
    (60, "Ostrich 🦩"),
    (70, "Cheetah 🐆"),
    (80, "Swordfish 🐟"),
    (90, "Spur-winged goose 🦢"),
    (100, "White-throated needletail 🐦"),
    (120, "Golden eagle 🦅"),
]

def get_animal_category(net_wpm):
    """
    tar ett värde (net_wpm) och returnerar en sträng med ett
    djurnamn och emoji som representerar användarens skrivhastighet.
    """
    for limit, category in WPM_CATEGORIES:
        if net_wpm <= limit:
            return category
    return "Peregrine falcon 🦅"
--------------------------------------------------------------------------------

def _compare_words(typed_words, original_words):
    """
    jämför användarens ord med originalord, räknar korrekta ord och bygger
    ett histogram över felstavade eller saknade ord.
    """
    correct_words = 0
    wrong_word_histogram = {}
    total_original_words = len(original_words)
    typed_word_count = len(typed_words)

    for i, original_word in enumerate(original_words):

        if i < typed_word_count:
            if typed_words[i] == original_word:
                correct_words += 1
            else:
                wrong_word_histogram[original_word] = (
                    wrong_word_histogram.get(original_word, 0) + 1
                )
        else:
            wrong_word_histogram[original_word] = (
                wrong_word_histogram.get(original_word, 0) + 1
            )

    extra_words = max(0, typed_word_count - total_original_words)
    return correct_words, extra_words, wrong_word_histogram
--------------------------------------------------------------------------------

def _process_results(results_data, filename):
    """
    beräknar wpm och noggrannhet, skriver ut resultaten och sparar poängen i filen.
        # hämtar tiden som user använde hur länge testet tog
        # hur många ord användaren skrev totalt
        # hur många ord det fanns i originaltexten
        # hur många ord användaren skrev korrekt (rätt stavade och på rätt plats)
        # hur många extra ord användaren skrev utöver originaltexten
        # en ordbok (dictionary) som visar vilka ord som var fel
        # och hur många gånger varje ord blev fel

    """
    time_used = results_data["time_used"]
    typed_words_count = results_data["typed_word_count"]
    total_words = results_data["total_words"]
    correct_words = results_data["correct_words"]
    extra_words = results_data["extra_words"]
    wrong_word_histogram = results_data["wrong_word_histogram"]

    print(f"\nTid det tog: {time_used:.2f} sekunder ({time_used / 60:.2f} minuter)")
    minutes = time_used / 60 if time_used > 0 else 1
    gross_wpm = typed_words_count / minutes
    wrong_total = total_words - correct_words
    net_wpm = gross_wpm - ((wrong_total + extra_words) / minutes)
    net_wpm = max(net_wpm, 0)
    accuracy = (net_wpm / gross_wpm) * 100 if gross_wpm > 0 else 0

    animal = get_animal_category(net_wpm)

    print("\n--- det totala resultatet ---")
    final_accuracy = (correct_words - extra_words) / total_words * 100
    print(f"ordprecision: {final_accuracy:.2f}%")

    print("\nfelstavade ord:")
    for wrong, count in wrong_word_histogram.items():
        print(f"{wrong:<20}: {'#' * count}")

    print(f"brutto wpm: {gross_wpm:.2f}")
    print(f"netto wpm: {net_wpm:.2f}")
    print(f"noggrannhet: {accuracy:.2f}%")
    print(f"du skriver snabbt som en {animal}")

    name = input("\nskriv in ditt namn: ")
    level = filename.replace(".txt", "")
    try:
        with open(SCORES_FILE, "a", encoding="utf-8") as f:
            f.write(f"{name},{final_accuracy:.2f},{level}\n")
    except OSError:
        print("kunde inte spara poängen: filåtkomst nekad.")
--------------------------------------------------------------------------------

def starting_test(filename):
    """
    huvudfunktionen som hanterar hela skrivtestet: ladda text, tidtagning,
    samla input och visa resultat.
    """
    file_path = os.path.join(TEXTS_DIR, filename)
    try:
        with open(file_path, encoding="utf-8") as f:
            text_lines = f.read().splitlines()
    except FileNotFoundError:
        print(f"filen hittades inte: {file_path}")
        return

    print("\n--- här är texten du ska skriva ---\n")
    for line in text_lines:
        print(line)
    input("\ntryck enter när du är redo att börja skriva...")

    start_time = time.time()
    typed_text = input("\nbörja skriva här:\n")
    end_time = time.time()
    time_used = end_time - start_time

    full_text = " ".join(text_lines)
    typed_words = typed_text.split()
    original_words = full_text.split()
    total_words = len(original_words)

    correct_words, extra_words, wrong_word_histogram = _compare_words(
        typed_words, original_words
    )
    # data för resultat, tex hur lång tid user tod på sig osv..
    results_data = {
        "time_used": time_used,
        "typed_word_count": len(typed_words),
        "total_words": total_words,
        "correct_words": correct_words,
        "extra_words": extra_words,
        "wrong_word_histogram": wrong_word_histogram,
    }
    _process_results(results_data, filename)
--------------------------------------------------------------------------------

def sorterings_nyckel(result_row):
    """
    tar ut vilken nivå testet var på
    tar ut noggrannheten i procent
    tar ut spelarens namn
    returnerar en sorteringsnyckel
    """
    level = result_row[2]
    precision = result_row[1]
    name = result_row[0]
    return (level, -precision, name)
--------------------------------------------------------------------------------

def show_scores():
    """
    Försöker läsa in alla poäng från filen:
    # 1. Skapar en tom lista
    # 2. Öppnar poängfilen i läsläge
    # 3. Läser in alla rader i listan 'lines'
    # 4. Om filen inte finns, fel meddela och funktionen avslutas
    """
    print("\n--- poänglista ---")
    lines = []
    try:
        with open(SCORES_FILE, encoding="utf-8") as f:
            lines = f.readlines()
    except FileNotFoundError:
        print("ingen poängfil hittades.")
        return

    results = []  # lista för att spara resultat
    for line in lines:  # looper varje rad i filen
        parts = line.strip().split(",") 
        if len(parts) == EXPECTED_PARTS:
            name = parts[0]  # namn på spelaren
            try:
                precision = float(parts[1])  # försöker omvandla precision till ett tal
            except ValueError:
                precision = 0
            level = parts[2]
            results.append([name, precision, level])

    results.sort(key=sorterings_nyckel)
    print(f"{'namn':<15}{'precision (%)':<15}{'nivå'}")
    print("-" * 40)
    for r in results:
        print(f"{r[0]:<15}{r[1]:<15.2f}{r[2]}")
                    
                

main.py

                    
from menu import show_menu, menu_choice

def main():
    """
    Kör huvudloopen för programmet Typing.
    """
    running = True
    while running:
        show_menu()
        choice = input("Choose an option: ").strip().lower()
        running = menu_choice(choice)


if __name__ == "__main__":
    main()
                    
                

menu.py

                    
from functions import starting_test, show_scores

def show_menu():
    print("\n=== Typing Test Menu ===")
    print("1. Starta skrivtest `Easy txt`")
    print("2. Starta skrivtest `Medium txt`")
    print("3. Starta skrivtest `Hard txt`")
    print("4. Skriv ut resultat som finns sparad i `scores.txt`")
    print("q. Avsluta programmet")

def menu_choice(choice):
    if choice == "1":
        starting_test("easy.txt")
    elif choice == "2":
        starting_test("medium.txt")
    elif choice == "3":
        starting_test("hard.txt")
    elif choice == "4":
        show_scores()
    elif choice == "q":
        print("Avslutar programmet. Goodbye!")
        return False
    else:
        print("Invalid choice. Please try again.")
    return True