KULTUROSFERA

Refactorizare: jocul tău, tăiat în funcții

LaboratorVS CodePython90 minD3.3Programare textuală

Lecția-suport: Subprograme și funcții

Jocul din laboratorul trecut funcționează, dar e un bloc de cod în care totul stă claie peste grămadă. Azi îl operezi: tai logica în funcții cu nume clare, adaugi un meniu de start și obții o versiune pe care o poți extinde fără frică. La finalul laboratorului vei avea ghiceste_v2.py — același joc la exterior, dar organizat înăuntru ca un program adevărat, plus un meniu cu cel puțin trei opțiuni funcționale.

Ce îți trebuie

  • Python 3 și VS Code, deja instalate din laboratorul 1 (dacă ai lipsit, întoarce-te la el pentru instalare — durează 15 minute).
  • Fișierul ghiceste.py din laboratorul trecut. Nu-l ai? Rescrii varianta de bază în 10 minute — o găsești în laboratorul 1, secțiunea „Bucla while".
  • Cont: niciunul. Timp: 20 minute pe funcții simple + 40 pe refactorizare + restul pe meniu și misiune.

Lecția „Subprograme și funcții" din modulul 5 ți-a dat ideea: o funcție e o bucată de program cu nume, pe care o definești o dată și o chemi de câte ori vrei. Acolo ai făcut-o pe blocuri; azi o faci în Python, pe cod care e deja al tău.

Încălzire: def, parametri, return

Creează ghiceste_v2.py în același folder și scrie doar atât:

def saluta(nume):
    print("Salut,", nume + "!")

def dubleaza(n):
    return n * 2

saluta("Maria")
rezultat = dubleaza(21)
print(rezultat)

Rulează. Două lucruri de fixat, pentru că pe ele se sprijină tot laboratorul:

  • Definiția nu execută nimic. Liniile cu def doar pregătesc funcția. Abia apelul — saluta("Maria") — o pune în mișcare. Șterge apelurile și rulează din nou: nu se întâmplă nimic, și e normal.
  • print arată, return dă înapoi. saluta afișează ceva și atât. dubleaza returnează o valoare, pe care o poți prinde într-o variabilă și folosi mai departe. Confuzia print/return e cea mai frecventă greșeală a începătorilor — ține-o sub observație.

Operația: jocul tăiat în trei funcții

Deschide ghiceste.py alături (în VS Code poți pune fișierele unul lângă altul: click dreapta pe tab → Split Right). Planul de tăiere:

FuncțiaCe facePrimeșteReturnează
citeste_numar(minim, maxim)cere un număr valid din interval, insistă până îl primeștelimitelenumărul
joaca_runda(minim, maxim)o rundă completă de joclimitelenumărul de încercări
afiseaza_scor(incercari)comentariul de final („Ca la carte!" etc.)încercărilenimic
  1. Începe cu citeste_numar — e cea mai mică:
def citeste_numar(minim, maxim):
    numar = int(input("Ghiceste: "))
    while numar < minim or numar > maxim:
        print("Am zis intre", minim, "si", maxim, "!")
        numar = int(input("Ghiceste: "))
    return numar
  1. Construiește joaca_runda mutând bucla principală din vechiul joc în interiorul ei. Acolo unde vechiul cod avea int(input(...)), noul cod cheamă citeste_numar(minim, maxim) — o funcție care folosește altă funcție, exact ca blocurile tale personalizate din Scratch care se apelau între ele.
import random

def joaca_runda(minim, maxim):
    secret = random.randint(minim, maxim)
    incercari = 0
    raspuns = minim - 1
    while raspuns != secret:
        raspuns = citeste_numar(minim, maxim)
        incercari = incercari + 1
        if raspuns < secret:
            print("Prea mic.")
        elif raspuns > secret:
            print("Prea mare.")
    print("Corect!")
    return incercari
  1. Scrie afiseaza_scor(incercari) singur — muți acolo comentariile despre performanță din laboratorul 1.
  2. La sfârșitul fișierului, programul principal devine trei linii:
print("M-am gandit la un numar intre 1 si 100.")
rezultat = joaca_runda(1, 100)
afiseaza_scor(rezultat)

Rulează și joacă o rundă completă. Jocul trebuie să se comporte identic cu versiunea veche — asta înseamnă refactorizare: schimbi organizarea, nu comportamentul.

Meniul: funcțiile devin opțiuni

Acum, recompensa pentru ordine. Pentru că jocul e o funcție, poți construi în jurul lui un meniu:

def meniu():
    print()
    print("=== GHICESTE NUMARUL ===")
    print("1. Joc usor (1-50)")
    print("2. Joc greu (1-1000)")
    print("3. Iesire")
    return citeste_numar(1, 3)

optiune = meniu()
while optiune != 3:
    if optiune == 1:
        afiseaza_scor(joaca_runda(1, 50))
    elif optiune == 2:
        afiseaza_scor(joaca_runda(1, 1000))
    optiune = meniu()
print("Pe curand!")

Observă recircularea: meniu() refolosește citeste_numar (validarea de interval face exact ce trebuie și aici), iar afiseaza_scor(joaca_runda(...)) înlănțuie două funcții — rezultatul uneia intră direct în cealaltă. Niciun rând de logică nou pentru „joc ușor" vs „joc greu": doar alți parametri.

Dacă nu merge

  • NameError: name 'citeste_numar' is not defined: Python citește fișierul de sus în jos — definițiile funcțiilor trebuie să stea înaintea primului apel. Mută toate blocurile def sus, programul principal jos.
  • Funcția „nu face nimic": ai definit-o, dar n-ai apelat-o — sau ai scris joaca_runda fără paranteze. Fără () nu există apel.
  • joaca_runda merge, dar scorul e mereu None: funcția ta nu are return incercari la final, iar afiseaza_scor primește nimicul. Orice funcție fără return returnează None pe tăcute.
  • Meniul afișează opțiunile dar acceptă 7: ai apelat citeste_numar(1, 3) sau ai lăsat un int(input(...)) gol, fără validare? Refolosește funcția — pentru asta ai scris-o.
  • Jocul greu se termină instant: verifică dacă random.randint primește minim, maxim (parametrii), nu 1, 100 scris cu mâna — altfel secreta e mereu în intervalul vechi.

Misiunea ta

Nivel de bază (obligatoriu): ghiceste_v2.py cu cele trei funcții din tabel + programul principal scurt; comportament identic cu jocul din laboratorul 1.

Extindere: meniul complet cu joc ușor, joc greu și ieșire, construit pe funcțiile existente.

Provocare: adaugă opțiunea „4. Rolurile se schimbă" — tu te gândești la un număr, iar calculatorul ghicește înjumătățind intervalul; tu îi răspunzi cu 1 (prea mic), 2 (prea mare), 3 (corect). Scrie-o, evident, ca funcție separată. Dacă totul e corect, calculatorul nu are nevoie niciodată de mai mult de 10 încercări pentru 1-1000 — verifică!

Ai terminat când:

  • fiecare funcție face un singur lucru, iar numele ei spune care;
  • schimbarea intervalului de joc se face modificând un singur apel, nu zece linii;
  • opțiunea 3 chiar iese din program, iar 1 și 2 revin la meniu după rundă;
  • colegul de bancă, citind doar programul principal (fără corpul funcțiilor), poate povesti ce face jocul.