Tilbake
6.4

6.4 Terminal-interaksjon i klasser

Lese fra brukeren med `input()` og løkke som spør på nytt til en gyldig verdi gis — sjanger H, som oftest ligger inne i den store oppgaven.

45 min
7 oppgaver
Terminal-interaksjon i klasser
Din fremgang i kapitlet
0 / 7 oppgaver

Forkunnskaper — sist du var her

Kapitlet bygger på kap. 6.2 — Samarbeidende klasser og
kap. 1.3 — Løkker, og bruker
int(...) fra kap. 1.1.

De to tingene du trenger, friskes opp med kjørt kode.

1. while gjentar så lenge betingelsen er sann:

svar = "x" gyldige = ["ja", "nei"]
forsok = 0 while svar not in gyldige:
    forsok = forsok + 1 if forsok == 1:
        svar = "kanskje" else:
        svar = "ja" print(svar, forsok)

Utskrift:

ja 2

Her står to «svar» i koden i stedet for at noen skriver dem. Det er nøyaktig det grepet vi bruker for å kunne kjøre eksemplene i dette kapitlet.

2. Tekst må konverteres før den kan regnes med:

tekst = "12" print(tekst + tekst)
print(int(tekst) + int(tekst))

Utskrift:

1212
24

Alt brukeren skriver, er tekst. Det er hele grunnen til at int(...) er så sentralt her.

Løkke 1 — input gir alltid tekst (~11 min)

Et treningssenter skal spørre hvilken sal medlemmet vil melde seg på. Programmet må da stoppe opp, vente på at noen skriver noe, og fortsette med det som ble skrevet.

Det er input sin eneste jobb — og den ene tingen alle bommer på første gang, er at svaret alltid er en tekst.

`input(melding)`

Skriver ut meldingen, venter på at brukeren skriver en linje og trykker enter, og gir linja tilbake som en tekst.

navn = input("Hva heter du? ")
print("Hei,", navn)

Blokken er merket som ikke-kjørbar fordi den venter på at noen skriver noe.

Terminaldialog (det brukeren skriver, står etter spørsmålet):

Hva heter du? Ada
Hei, Ada

To detaljer er verdt å merke seg. Meldingen skrives uten linjeskift, så brukeren skriver på samme linje — derfor slutter meldingen som regel med et mellomrom.

Og linjeskiftet brukeren trykker, er ikke med i teksten du får. input renser det bort selv, i motsetning til readline fra
kap. 7.1.

`int(input(...))`

Skal svaret brukes som tall, må det konverteres:

alder = int(input("Hvor gammel er du? "))
print("Om ti aar er du", alder + 10)

Blokken er merket som ikke-kjørbar.

Terminaldialog:

Hvor gammel er du? 24
Om ti aar er du 34

Uten int(...) ville alder + 10 stoppet programmet med
TypeError: can only concatenate str (not "int") to str. Det er feilkode #4, glemt konvertering — den samme som ved filinnlesing.

Skriver brukeren noe som ikke er et tall, stopper int(...) programmet med
ValueError: invalid literal for int() with base 10: 'nei'. Å håndtere det krever konstruksjoner utenfor pensum her; oppgavene i denne boka forutsetter at brukeren skriver et tall når det er tall det spørres om.

✏️Eksempel 1: Ett spørsmål, ett svar

Vis den enkleste formen for terminal-interaksjon, og hva som skiller et tekstsvar fra et tallsvar.

Programmet spør om to ting, og bare den ene konverteres:

navn = input("Navn: ")
antall = int(input("Antall okter denne uka: "))
print(navn, "har trent", antall, "ganger")
print("Neste uke blir det", antall + 1)

Blokken er merket som ikke-kjørbar fordi den venter på inndata.

Terminaldialog:

Navn: Ada
Antall okter denne uka: 3
Ada har trent 3 ganger
Neste uke blir det 4

Legg merke til hva som skjer uten int(...). Da ville antall vært teksten
"3", og antall + 1 ville stoppet programmet. Hadde du i stedet skrevet
antall + "1", ville svaret blitt 31 — skjøting i stedet for addisjon, som er feilkode #3.

Navnet skal derimot ikke konverteres. Det er en merkelapp, ikke et tall. Samme
regel som ved filinnlesing: konverter bare det du faktisk skal regne med.

Slik ville sensor sett på det: tre ting gir uttelling — input med en
forståelig melding, int(...) på tallet, og at teksten ikke konverteres.

Merk mellomrommet på slutten av meldingene. Uten det ville brukeren skrevet
rett inntil kolonet. Det er en liten detalj, men den gjør dialogen lesbar.

📝Oppgave 1

(Innstegsoppgave — gjengivelse.) Se på de to linjene:

a = input("Tall: ")
b = int(input("Tall: "))

Blokken er merket som ikke-kjørbar fordi den venter på inndata. Brukeren skriver
5 begge ganger.

a) Hvilken type har a, og hvilken har b?

b) Hva skriver print(a + a) ut, og hva skriver print(b + b) ut?

c) Hva må du gjøre for at a skal kunne brukes i et regnestykke?

Løkke 2 — Spør til svaret er gyldig (~12 min)

Nå kommer selve eksamensmønsteret.

Brukeren skriver noe som ikke finnes. Programmet skal ikke gi opp, og det skal ikke gå videre med et ugyldig svar. Det skal spørre på nytt — og på nytt
— til svaret er gyldig.

📜Input-løkke-malen

Bokas nittende kodemønster. Fire linjer, og de er hele sjanger H:

    svar = input("Velg: ")
    while svar not in gyldige:
        svar = input("Ugyldig, prov igjen: ")
    return svar

Blokken er merket som ikke-kjørbar fordi den venter på inndata.

Fire regler:

1. Første input står FØR løkka — ellers har while ingenting å teste.
2. while, ikke if. En if spør bare én gang til. Det er feilkode #9,
og det er den vanligste feilen i hele sjangeren.
3. Nytt input INNE i løkka. Glemmer du det, henger programmet: betingelsen
endrer seg aldri.
4. Løkka avsluttes av seg selv når svaret er gyldig, og svar inneholder da
den gyldige verdien.

Formen er nøyaktig den samme som filinnlesing-løkka fra
kap. 7.1: ett kall før løkka, ett inne i den.

✏️Eksempel 2: Input-løkka, med kjørbar variant

Vis input-løkka slik den skrives på eksamen, og en variant som kan kjøres, der
«brukerens» svar kommer fra en liste.

Slik den skrives på eksamen:

gyldige = ["ja", "nei"]
svar = input("Vil du melde deg paa? (ja/nei) ")
while svar not in gyldige:
    svar = input("Svar ja eller nei: ")
print("Du svarte", svar)

Blokken er merket som ikke-kjørbar fordi den venter på inndata.

Terminaldialog:

Vil du melde deg paa? (ja/nei) kanskje
Svar ja eller nei: tja
Svar ja eller nei: ja
Du svarte ja

Og slik den kan kjøres, med «brukerens» svar hentet fra en liste i stedet for
fra tastaturet. Løkkestrukturen er nøyaktig den samme:

def les_svar(svarene, i):
    print("(bruker skriver)", svarene[i])
    return svarene[i]

svarene = ["kanskje", "tja", "ja"]
gyldige = ["ja", "nei"]
i = 0 svar = les_svar(svarene, i)
while svar not in gyldige:
    i = i + 1 svar = les_svar(svarene, i)
print("Du svarte", svar)

Utskrift:

(bruker skriver) kanskje
(bruker skriver) tja
(bruker skriver) ja
Du svarte ja

Sammenlign de to. les_svar(svarene, i) står nøyaktig der input(...) sto:
én gang før løkka, én gang inne i den. Det er den plasseringen som er hele mønsteret, og den er lik uansett hvor svaret kommer fra.

På eksamen skriver du selvsagt input. Erstatningen finnes bare i denne boka,
så eksemplene kan kjøres og utskriften kan verifiseres.

Slik ville sensor sett på det: fire ting gir uttelling — første input før
løkka, while og ikke if, nytt input inne i løkka, og at gyldighetstesten faktisk er riktig.

📝Oppgave 2
Eksamensnivå, sjanger H

En medstudent har skrevet:

svar = input("Velg dag: ")
if svar not in dagene:
    svar = input("Ugyldig, prov igjen: ")
print("Valgt:", svar)

Blokken er merket som ikke-kjørbar fordi den venter på inndata.

a) Hvilken feilkode er dette, og hva er problemet?

b) Gi et konkret eksempel på en dialog der koden går galt.

c) Skriv den rettede koden.

📝Oppgave 3
Eksamensnivå, sjanger A

Her er «brukerens» svar hentet fra en liste, slik at koden kan kjøres. Hva skriver programmet ut?

def les(svarene, i):
    print(">", svarene[i])
    return svarene[i]

svarene = ["5", "12", "8"]
grense = 10 i = 0 tall = int(les(svarene, i))
while tall < grense:
    i = i + 1 tall = int(les(svarene, i))
print("Godkjent:", tall)

Løkke 3 — Hva «gyldig» betyr (~11 min)

Betingelsen i input-løkka er der oppgaven varierer. Tre former dekker nesten alt som kommer.

Validere mot en samling
while svar not in gyldige: — der gyldige er en liste, eller en ordbok du skal slå opp i.

Er samlingen en ordbok, er dette dobbelt nyttig: løkka sikrer at nøkkelen finnes, og da kan du slå opp rett etterpå uten en ekstra if-sjekk.

    navn = input("Velg sal: ")
    while navn not in self._saler:
        navn = input("Finnes ikke, prov igjen: ")
    return self._saler[navn]

Blokken er merket som ikke-kjørbar fordi den venter på inndata.

Legg merke til at metoden returnerer objektet, ikke navnet. Den som kaller, kan da spørre videre.

Validere mot et indeksområde
while indeks < 0 or indeks >= len(liste): — når brukeren skal velge nummeret på noe i en liste.

Begge grensene må med. Den øvre er >= len(liste), ikke > len(liste): en liste med tre elementer har lovlige indekser 0, 1 og 2.

Skriver oppgaven at valgene skal vises som 1, 2, 3 i stedet, må du trekke fra én etterpå: indeks = valgt - 1. Skriv da en kommentar om det, så leseren ser at forskyvningen er bevisst.

Feilen her er feilkode #5, av-med-én, og den er lett å gjøre i begge retninger.

Validere mot et tallområde
while tall < min or tall > maks: — når svaret skal ligge mellom to grenser.

Les oppgaveteksten sakte: «minst 1» betyr < 1, «under 100» betyr >= 100. Det er kantverdiene som avgjør, og de rettes strengt.

Husk int(...) rundt input, ellers sammenlignes en tekst med et tall og programmet stopper.

Er begge grensene med i det gyldige området — «mellom 1 og 10, begge inkludert» — er betingelsen tall < 1 or tall > 10.

✏️Eksempel 3: Tre gyldighetstester, kjørbart

Vis de tre valideringsformene med «brukerens» svar hentet fra en liste, slik at utskriften kan kjøres.

En hjelpefunksjon står i for tastaturet. Alt annet er nøyaktig som på eksamen:

def les(svarene, i):
    print(">", svarene[i])
    return svarene[i]

# 1) mot en samling
gyldige = ["mandag", "tirsdag", "onsdag"]
svarene = ["fredag", "mandag"]
i = 0 dag = les(svarene, i)
while dag not in gyldige:
    i = i + 1 dag = les(svarene, i)
print("Dag:", dag)

# 2) mot et indeksomraade
saler = ["Speilsal", "Spinning", "Yoga"]
svarene = ["7", "-1", "2"]
i = 0 indeks = int(les(svarene, i))
while indeks < 0 or indeks >= len(saler):
    i = i + 1 indeks = int(les(svarene, i))
print("Sal:", saler[indeks])

# 3) mot et tallomraade
svarene = ["0", "15", "8"]
i = 0 antall = int(les(svarene, i))
while antall < 1 or antall > 10:
    i = i + 1 antall = int(les(svarene, i))
print("Antall:", antall)

Utskrift:

> fredag
> mandag
Dag: mandag
> 7
> -1
> 2
Sal: Yoga
> 0
> 15
> 8
Antall: 8

De tre løkkene har identisk struktur. Bare betingelsen er ulik: not in mot
en samling, to grenser mot et indeksområde, to grenser mot et tallområde.

Legg merke til at indeks 2 er den siste lovlige når lista har tre elementer.
Betingelsen indeks >= len(saler) fanger 3 og oppover, og indeks < 0 fanger de negative. Skriver du > len(saler), slipper du gjennom indeks 3, og programmet stopper med IndexError.

Og legg merke til at 10 er lovlig i den tredje løkka: antall > 10 er usann
når tallet er nøyaktig 10. Sier oppgaven «høyst 10», er det riktig. Sier den
«under 10», skal betingelsen være antall >= 10.

På eksamen skriver du input(...) der les(svarene, i) står, og du trenger
verken lista eller telleren.

— naturlig pausepunkt —

📝Oppgave 4
Eksamensnivå, sjanger H

Skriv kode som ber brukeren om et tall mellom 1 og 5, begge inkludert, og gjentar spørsmålet til svaret er gyldig. Skriv den både i eksamensform og i den kjørbare formen.

a) Eksamensformen, med input.

b) Den kjørbare formen, der svarene er "0", "9" og "3".

c) Hva ville skjedd om betingelsen var tall < 1 and tall > 5?

📝Oppgave 5
Eksamensnivå, sjanger A

Hva skriver programmet ut?

def les(svarene, i):
    print(">", svarene[i])
    return svarene[i]

saler = ["Speilsal", "Spinning", "Yoga"]
svarene = ["3", "0"]
i = 0 indeks = int(les(svarene, i))
while indeks < 0 or indeks >= len(saler):
    i = i + 1 indeks = int(les(svarene, i))
print(saler[indeks], indeks)

Løkke 4 — Input inne i en klassemetode (~11 min)

I settene ligger input-løkka nesten alltid inne i en metode på en av klassene. Det er den formen du skal skrive.

Metoden gjør typisk tre ting: viser hva som er å velge mellom, spør til svaret er gyldig, og returnerer objektet som ble valgt.

Velg-metoden

Standardformen for sjanger H i en klasse, i tre steg:

    def velg_sal(self):
        for navn in self._saler:
            print(" -", navn)
        valgt = input("Velg sal: ")
        while valgt not in self._saler:
            valgt = input("Finnes ikke, prov igjen: ")
        return self._saler[valgt]

Blokken er merket som ikke-kjørbar fordi den venter på inndata.

Steg 1: vis alternativene. Uten det vet ikke brukeren hva som er lovlig, og
løkka kan gå evig.

Steg 2: input-løkka. Betingelsen er not in self._saler, altså mot ordboka
selv.

Steg 3: returner objektet, ikke navnet. Løkka har allerede sikret at nøkkelen
finnes, så oppslaget trenger ingen ekstra if-sjekk — og det er et poeng verdt å si i en kommentar.

✏️Eksempel 4: Full sjanger H-deloppgave

> Et treningssenter holder salene i en ordbok fra navn til Sal-objekt. Skriv en
> metode velg_sal(self) som skriver ut alle salnavnene, ber brukeren velge én, og
> gjentar spørsmålet til navnet finnes. Metoden skal returnere Sal-objektet.

Skriv metoden i eksamensform, og vis en kjørbar variant.

Eksamensformen, slik den skal se ut i besvarelsen:

    def velg_sal(self):
        print("Saler:")
        for navn in self._saler:
            print(" -", navn)
        valgt = input("Velg sal: ")
        while valgt not in self._saler:
            valgt = input("Finnes ikke, prov igjen: ")
        return self._saler[valgt]

Blokken er et utdrag som venter på inndata, og er derfor merket som ikke-kjørbar.

Terminaldialog:

Saler:
 - Speilsal
 - Spinning
Velg sal: Basseng
Finnes ikke, prov igjen: Spinning

Den kjørbare varianten, med hele modellen rundt og «brukerens» svar fra en
liste:

class Sal:
    def __init__(self, navn, kapasitet):
        self._navn = navn self._kapasitet = kapasitet self._paameldte = 0

    def hent_navn(self):
        return self._navn

    def meld_paa(self):
        self._paameldte = self._paameldte + 1

    def __str__(self):
        return self._navn + " (" + str(self._paameldte) + "/" + str(self._kapasitet) + ")"

class Senter:
    def __init__(self, svarene):
        self._saler = {}
        self._svarene = svarene self._i = 0

    def legg_til(self, sal):
        self._saler[sal.hent_navn()] = sal

    def les(self, melding):
        svar = self._svarene[self._i]
        self._i = self._i + 1 print(melding, svar)
        return svar

    def velg_sal(self):
        print("Saler:")
        for navn in self._saler:
            print(" -", navn)
        valgt = self.les("Velg sal:")
        while valgt not in self._saler:
            valgt = self.les("Finnes ikke, prov igjen:")
        return self._saler[valgt]

    def skriv_alle(self):
        for navn in self._saler:
            print(self._saler[navn])

s = Senter(["Basseng", "Yoga", "Spinning"])
s.legg_til(Sal("Speilsal", 20))
s.legg_til(Sal("Spinning", 14))

sal = s.velg_sal()
sal.meld_paa()
s.skriv_alle()

Utskrift:

Saler:
 - Speilsal
 - Spinning
Velg sal: Basseng
Finnes ikke, prov igjen: Yoga
Finnes ikke, prov igjen: Spinning
Speilsal (0/20)
Spinning (1/14)

Fire ting er verdt å merke seg.

velg_sal returnerer objektet, så den som kaller, kan gjøre noe med det med én gang: sal.meld_paa().

Løkka har allerede sikret at nøkkelen finnes, så return self._saler[valgt] trenger ingen if-sjekk. Det er et poeng verdt å nevne i en kommentar.

Alternativene skrives ut før spørsmålet. Uten det kan brukeren gjette i det uendelige.

Og metoden les finnes bare i denne boka. På eksamen skriver du input(...) der self.les(...) står — ingenting annet endres.

Slik ville sensor sett på det: dette er en typisk 5–7-poengs deloppgave.
Poengene ligger på utskriften av alternativene, første input før løkka,
while og ikke if, nytt input inne i løkka, og at objektet returneres.

📝Oppgave 6
Eksamensnivå, sjanger H

En brettspillklubb holder spillene i en ordbok fra tittel til Spill-objekt.

a) Skriv metoden velg_spill(self) i eksamensform: den skal skrive ut alle
titlene, spørre til brukeren skriver en som finnes, og returnere
Spill-objektet.

b) Hvorfor trenger ikke return self._spill[valgt] en if-sjekk foran seg?

c) Hva ville skjedd om metoden returnerte tittelen i stedet for objektet?

📝Oppgave 7
Eksamensnivå, sjanger H

En resirkuleringsstasjon holder containerne i en ordbok fra materiale til Container-objekt.

a) Skriv metoden lever(self) i eksamensform. Den skal vise alle
materialene, spørre til brukeren skriver et som finnes, deretter spørre om antall kilo til svaret er minst 1, og til slutt levere avfallet til containeren.

b) Skriv den kjørbare varianten med hele modellen, der «brukerens» svar er
"papp", "glass", "0" og "12".

c) Hvor mange input-kall står det i metoden, og hvorfor står to av dem inne
i en løkke?

API- og konstruksjonsliste

Begrepsbank

Begrepsbanken er flashcard- og repetisjonsstoff — den gjentar det du nettopp har lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder kjernestoffet.

`input` gir alltid tekst

Uansett hva brukeren skriver — 5, ja, 3.14 — er verdien du får tilbake, en
tekst.

Skal den brukes som tall, må den gjennom int(...) eller float(...).
Konverter så snart verdien er lest, ikke spredt utover i koden — da vet du alltid hvilken type en variabel har.

Navn, koder og valgalternativer skal derimot forbli tekst. Samme regel som ved filinnlesing.

Input-løkke-malen

Fire linjer, og de er hele sjanger H: input før løkka, while med gyldighetstesten, input inne i løkka, og verdien brukt etterpå.

input skal stå to steder. Glemmer du den første, har while ingenting å teste; glemmer du den andre, henger programmet.

Formen er identisk med filinnlesing-løkka fra
kap. 7.1: ett kall før, ett inne i.

Feilkode #9

Å spørre én gang til med en if, i stedet for å gjenta i en while-løkke til svaret er gyldig.

Koden virker helt til brukeren bommer to ganger. Da går programmet videre med et ugyldig svar, og neste oppslag stopper det med KeyError.

Ett tegn skiller de to i lesing, og de er helt ulike i oppførsel. Tell alltid: er det en while der, eller en if?

Den uendelige input-løkka

Symptomet på en glemt input inne i løkka: den samme oppfordringen skrives i det uendelige.

Grunnen er at svar aldri endrer seg, så betingelsen forblir sann.

Det er den mest synlige feilen i kapitlet, og den letteste å rette — og den er nøyaktig samme feil som en glemt readline nederst i filinnlesing-løkka.

Å validere mot en samling
while svar not in gyldige: — der gyldige er en liste av lovlige svar, eller ordboka du skal slå opp i.

Er det ordboka selv, er dette dobbelt nyttig: når løkka slutter, vet du at nøkkelen finnes, og oppslaget etterpå trenger ingen if-sjekk.

Skriv gjerne en kommentarlinje om det, så ser sensor at utelatelsen er bevisst.

Å validere et indeksområde
while indeks < 0 or indeks >= len(liste):.

Begge grensene må med, og den øvre er >=. En liste med tre elementer har lovlige indekser 0, 1 og 2 — indeks 3 finnes ikke, selv om lengden er 3.

Skal valgene vises som 1, 2, 3, trekker du fra én etterpå: indeks = valgt - 1.
Skriv en kommentar om forskyvningen. Feilen her er #5, av-med-én.

`or` mot `and` i en gyldighetstest

«Ugyldig» er som regel under grensen ELLER over grensen, altså or.

Med and blir betingelsen aldri sann — ingen verdi er samtidig under 1 og over
5 — og løkka kjører aldri. Alt godtas, også det ugyldige.

De to er hverandres speilbilder: gyldig er tall >= 1 and tall <= 5, ugyldig er
tall < 1 or tall > 5.

Velg-metoden

Standardformen for sjanger H i en klasse, i tre steg: vis alternativene, spør til svaret er gyldig, returner objektet.

Å vise alternativene først er ikke pynt — uten det kan brukeren gjette i det uendelige, og oppgaven ber som regel uttrykkelig om det.

Å returnere objektet og ikke navnet er et selvstendig poeng: objektet kan alltid gi fra seg navnet sitt, men ikke omvendt.

Metoden som endrer i stedet for å returnere

En input-metode returnerer ikke alltid noe. Den kan i stedet utføre
handlingen: levere avfallet, melde på medlemmet, registrere besøket.

Begge formene forekommer i settene, og oppgaveteksten sier hvilken som gjelder:
«returner objektet som ble valgt» mot «meld medlemmet på den valgte salen».

Les den setningen sakte før du skriver return — eller lar være.

To spørsmål, to løkker

Skal metoden spørre om to ting, skrives to input-løkker etter hverandre — ikke én løkke med to spørsmål.

Hver løkke har sitt eget par av kall og sin egen gyldighetstest. Til sammen blir det fire input-kall.

Det er lengre å skrive, men det er den formen fasiten bruker, og hver løkke gir uttelling for seg.

Meldingen i `input`

Teksten som skrives ut mens programmet venter. Den skrives uten linjeskift, så brukeren skriver på samme linje — derfor slutter den som regel med et mellomrom.

Den andre meldingen, den inne i løkka, bør si hvorfor svaret var ugyldig:
«Finnes ikke, prov igjen: » er bedre enn «Feil: ».

Meldingene skrives uten æ, ø og å, som all kode i denne boka.

Hva skjer ved et ikke-tall
int("nei") stopper programmet med
ValueError: invalid literal for int() with base 10: 'nei'.

Å håndtere det pent krever konstruksjoner som er utenfor pensum her, og eksamensoppgavene forutsetter som regel at brukeren skriver et tall når det er tall det spørres om.

Er du usikker, skriv en kommentar om forutsetningen. Det er den ene legitime bruken av kommentarer i en besvarelse.

Den kjørbare erstatningen

I denne boka står av og til en hjelpemetode les(...) der input(...) skulle stått, slik at eksemplene kan kjøres og utskriften kan verifiseres.

Den henter «brukerens» svar fra en liste, i rekkefølge. Løkkestrukturen er nøyaktig den samme.

På eksamen skriver du input(...). Erstatningen finnes bare for at du skal
kunne se den faktiske utskriften her i boka.

Terminaldialog

Måten boka viser hva som skjer når et input-program kjører: spørsmålene og det brukeren skriver, i den rekkefølgen de kommer.

Det brukeren skriver, står etter spørsmålet på samme linje — akkurat slik det ser ut i et terminalvindu.

Dialogen er ikke en «Utskrift:»-blokk, fordi den inneholder både programmets utskrift og brukerens tastetrykk.

Repetisjon — de seks setningene som må sitte

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.

Skolesaga er en uavhengig læringsressurs og er ikke tilknyttet eller godkjent av Universitetet i Oslo. Dette er ikke offisielt studiemateriell. Les mer.