Delo v sistemu

V sistem se prijavimo z uporabniškim imenom in geslom, ki nam je bilo dodeljeno, oziroma preko svojega Google, Facebook ali Twitter računa.

Po uspešni prijavi se nam pokaže seznam predmetov, ki so v sistemu. Na vrhu seznama vidimo predmete, ki smo jih že dodali med priljubljene. To pomeni, da je naše ime na seznamu udeležencev (učencev) in da učitelj predmeta lahko pregleduje naše rešitve nalog. Predmeti, ki smo jih dodali na seznam priljubljenih, so označeni z Ikona Sledimo predmetu.. Predmet dodamo med priljubljene s klikom na Ikona Ne sledimo predmetu.

Če hočemo postati učitelj v predmetu, se moramo vanj najprej vpisati. Status učitelja v določenem predmetu nam bo dodelil eden od učiteljev tega predmeta oziroma administrator storitve Tomo. Predmeti, v katerih imamo status učitelja, so označeni z Ikona Učitelj v predmetu..

Seznam predmetov, kot ga vidi učitelj.

Slika 1: Seznam predmetov, v katere smo vpisani in seznam predmetov, v katere nismo vpisani.

Predmeti

Predmet je sestavljen iz sklopov nalog. Na spodnji sliki vidimo predmet ‘Uvod v programiranje’ in seznam sklopov v njem.

Seznam sklopov, kot ga vidi učitelj.

Slika 2: Seznam sklopov v predmetu

Desno od seznama sklopov so našteta imena učiteljev v tem predmetu. Pod njimi je seznam učenecev - to so uporabniki, ki so predmet dodali med priljubljene. Poleg vsakega imena so (skriti) gumbi za spremembo statusa tega udeleženca - iz učitelja v učenca oziroma iz učenca v učitelja. Gumb se pokaže, ko miško postavimo na ime. Poleg učencev se pokaže Ikona Spremeni status v učitelja., poleg učiteljev pa Ikona Spremeni status v učenca..

Številka levo od imena sklopa predstavlja delež nalog v tem sklopu, ki so jih učenci do sedaj že uspešno rešili. Na traku nad imenom sklopa je grafično prikazano, koliko nalog v tem sklopu so učenci uspešno rešili (zelena barva), neuspešno reševali (rumena barva) oziroma sploh še niso poskušali reševati (rdeča barva). Prikaz uspešnosti reševanja je bolj podrobno opisan v poglavju Pregled učenčevega dela.

Sklopi

Sklopi ponavadi zajemajo naloge podobne sorte. Na začetku sklopa je prostor za uvodno besedilo, v katerem so običajno razloženi osnovni ukazi, obravnavani v sklopu, temu pa sledijo posamezne naloge.

Na sliki 3 je prikazana vsebina sklopa ‘Pogojni stavek’:

Stran posameznega sklopa, kot jo vidi učitelj.

Slika 3: Stran posameznega sklopa

Krogci poleg naslovov nalog na desni prikazujejo, kako uspešno so učenci reševali posamezno nalogo. Rdeča barva prikazuje tiste, ki naloge še niso začeli reševati, rumena barva tiste, ki so nalogo neuspešno rešili in zelena barva tiste, ki so nalogo uspešno rešili. Prikaz uspešnosti reševanja je bolj podrobno opisan v poglavju Pregled učenčevega dela.

S klikom na gumb Dodaj sklop odpremo obrazec, v katerega vpišemo lastnosti novega sklopa: naslov, uvodno besedilo, vidnost sklopa in vidnost rešitev. Gumb se nahaja na koncu seznama sklopov v predmetu.

Za urejanje sklopov imamo na voljo naslednja orodja (gumbi se nahajajo desno od imen sklopov na seznamu vseh sklopov v predmetu):

Gumb Pomen
gumb Uredi. Odpre meni za urejanje lastnosti sklopa (naslov, uvodno besedilo, vidnost sklopa in vidnost rešitev).
gumb Briši. Zbriše sklop in vse naloge v njem.
gumba za premikanje sklopa gor oziroma dol po seznamu Sklop premaknemo za eno mesto višje oziroma nižje na seznamu sklopov v predmetu.
gumb Sklop je viden. ali gumb Sklop je skrit. Ikona ikona Sklop je skrit. označuje, da uporabniki s statusom učenca tega sklopa ne vidijo. Uporabniki s statusom učitelja bodo sklop vseeno lahko videli in urejali. ikona Sklop je viden. označuje, da lahko sklop in vso njegovo vsebino vidijo tudi učenci.
gumb Rešitve nalog so vidne. ali gumb Rešitve nalog so pogojno vidne. ali gumb Rešitve nalog so skrite. Te ikone označujejo vidnost rešitev za vse naloge v sklopu:
  • ikona Rešitve nalog so vidne. pomeni, da bodo učenci učiteljevo rešitev podnaloge lahko videli takoj, ko bodo oddali svojo rešitev iste podnaloge - tudi, če njihova rešitev ne bo sprejeta.
  • ikona Rešitve nalog so pogojno vidne. označuje, da bo učiteljeva rešitev postala vidna po tem, ko bo učenčeva rešitev sprejeta.
  • ikona Rešitve nalog so skrite. pomeni, da učiteljeva rešitev ne bo vidna niti po tem, ko bo učenčeva rešitev sprejeta.
Vidnost rešitev lahko kadarkoli spremenimo s klikanjem na ta gumb.

Naloge

Naloge so med seboj neodvisne, vsaka pa je sestavljena iz ene ali več podnalog, ki običajno gradijo ena na drugi in so postopoma težje.

Naloga, kot jo vidi učitelj.

Slika 4: Primer naloge

Za urejanje nalog imamo na voljo naslednja orodja:

Gumb Pomen
gumba za premikanje naloge gor oziroma dol po seznamu Nalogo premaknemo za eno mesto višje oziroma nižje na seznamu nalog v sklopu.
gumb Uredi. Odpre meni za urejanje lastnosti naloge (naslov in uvodno besedilo).
gumb Briši. Zbriše nalogo in vse podnaloge v njej.
gumb Kopiraj. Odpre meni za kopiranje naloge v drug sklop. Izbiramo lahko med sklopi v predmetih, kjer imamo status učitelja.

Prikaz rešitev

S klikom na gumb gumb Prikaži rešitve odpremo stran, ki prikazuje rešitve dane naloge. Na strani so prikazane naše rešitve in rešitve tistega, ki je nalogo sestavil - uradne rešitve. Primer vidimo na spodnji sliki:

Primerjava naših in uradnih rešitev naloge.

Slika 5: Primerjava naših in uradnih rešitev naloge.

Dodajanje novih nalog

S klikom na gumb Dodaj nalogo (nahaja se na dnu seznama nalog) odpremo obrazec, v katerega vpišemo naslov in uvodno besedilo nove naloge. Ko vsebino obrazca shranimo, se na strežniku naredi nova datoteka, ki vsebuje naslov in uvodno besedilo nove naloge (v obliki komentarjev) ter vso podporno programsko kodo, ki skrbi za komunikacijo s strežnikom. Mi moramo dodati samo še besedilo podnalog ter njihove rešitve.

Besedilo in rešitve podnalog vpisujemo neposredno v datoteko. Zato datoteko najprej prenesemo s strežnika in sicer s klikom na gumb Gumb Prenesi datoteko. pri čemer izberemo možnost Datoteka za urejanje.

S klikom na možnost Datoteka za reševanje prenesemo datoteko, pripravljeno za reševanje. To pomeni, da datoteka ne vsebuje naših rešitev in testov, ampak samo besedilo naloge. Tako datoteko s strežnika prenesejo učenci in vanjo vpisujejo svoje rešitve.

Datoteka, ki jo prenesemo s klikom na Datoteka za urejanje, pa vsebuje tudi naše rešitve in teste. Pri novo ustvarjeni nalogi med obema tipoma datotek še ni razlik, ko pa bomo že dodali nekaj podnalog in testov in bomo kasneje želeli nalogo še dopolniti, moramo prenesti datoteko za urejanje.

Če želimo prenesti datoteke vseh nalog v sklopu hkrati, kliknemo na gumb Gumb Prenesi vse datoteke., ki se nahaja nad prvo nalogo v sklopu.

Na sliki 6 vidimo naslov in uvodno besedilo naloge ‘Ploščine likov’. Nad in pod besedilom je programska koda, ki skrbi za komunikacijo s strežnikom. Te kode ne spreminjamo.

Vsebina datoteke za urejanje.

Slika 6: Vsebina datoteke

Za oblikovanje besedila uporabimo jezik Markdown. Osnovne ukaze najdemo tukaj. Brskalnik bo na podlagi uporabljenih ukazov prikazal ustrezno oblikovano besedilo. **Krog** bo na primer videti kot Krog.

Za pisanje matematičnih formul uporabimo običajne LaTeX ukaze, ki jih bo brskalnik prikazal s pomočjo knjižnice MathJax. Več o knjižnici MathJax piše tukaj.

Besedilo podnaloge napišemo pod `#=====`..., kot je prikazano na sliki 8. Za navodili napišemo uradno rešitev, za uradno rešitvijo pa teste, ki jih mora oddana rešitev prestati. Rešitev od testov ločimo z ukazom `Check.part()`.

Besedilo prve podnaloge ter njena rešitev in testi.

Slika 7: Besedilo prve podnaloge ter njena rešitev in testi.

Ko napišemo vse, kar smo želeli, datoteko poženemo. S tem vsebino shranimo na strežnik in hkrati preverimo, ali smo vse pravilno zapisali. Ob zagonu se bo naša uradna rešitev preverila na napisanih testih, ki nam bodo javili morebitne napake.

Ko besedilo podnaloge prvič shranimo na strežnik, se bo podnaloga shranila v bazo in dobila svoj ID. Ta ID bo prikazan na koncu niza `#=====`..., pod katerim smo zapisali besedilo podnaloge. Tega ID-ja ne spreminjajmo in ne brišimo.

Testiranje oddanih rešitev

Za testiranje rešitev imamo na voljo funkcije, opisane v nadaljevanju.

Check.equal

S `Check.equal(''izraz'', pricakovani_rezultat)`, preverimo, ali je rezultat danega izraza enak pričakovanemu. Izraz je ponavadi kar klic funkcije, ki jo preverjamo, ni pa nujno - lahko je poljubno število, niz, izraz ... v jeziku Python. Izraz mora biti podan kot niz, torej zapisan med narekovaji. Pričakovani rezultat je lahko poljubno število, niz, izraz … v jeziku Python.

Oglejmo si spodnji primer:

# ====================================================    
# Napiši funkcijo 'razdalja(x1, y1, x2, y2)', ki vrne
# razdaljo med točkama (x1, y1) in (x2, y2).
# ====================================================
def razdalja(x1, y1, x2, y2):
return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** (1/2)

Check.part()
Check.equal('razdalja(0, 0, 3, 4)', 5)
Check.equal('razdalja(1, 2, 3, 4)**2', 8)

Zgoraj vidimo primer, ko prvi argument funkcije `Check.equal` ni samo klic funkcije, ki jo testiramo.

Če vrednost izraza ni enaka pričakovanemu rezultatu, se učencu na zaslon izpiše, za katere testne podatke je njegova funkcija vrnila napačen rezultat in kakšen je pričakovani rezultat. Na primer, če bi učenec pri računanju razdalje pozabil na koren, bi bila povratna informacija take oblike:

- Izraz razdalja(0, 0, 3, 4) vrne 25 namesto 5.
- Izraz razdalja(1, 2, 3, 4)**2 vrne 64 namesto 8.

Check.secret

Ker se testiranje rešitve izvrši na učenčevem računalniku, so vsi testi vsebovani v datoteki za reševanje. Učenci lahko teste najdejo in vidijo pričakovane rezultate. Nato napišejo rešitev, ki uspešno prestane vse teste in bo zato sprejeta, vendar ni pravilna:

def razdalja(x1, y1, x2, y2):
    if (x1, y1, x2, y2) == (0, 0, 3, 4):
        return 5
    if (x1, y1, x2, y2) == (1, 2, 3, 4):
        return math.sqrt(8)

Učenci bi teste lahko tudi pobrisali in s tem dosegli, da bo rešitev sprejeta, saj testi ne bi javili napak. Take goljufije preprečimo z uporabo funkcije `Check.secret(ime_funkcije(arg1, arg2 …))`. Funkcija določi vrednost izraza `ime_funkcije(arg1, arg2 …)` in jo pošlje na strežnik. Strežnik primerja dobljeno vrednost z rezultatom, ki ga na istih podatkih vrne učiteljeva rešitev (ti rezultati se samodejno izračunajo, ko učitelj shrani svojo rešitev na strežnik). Če bi učenec teste zbrisal, bi strežnik zaznal, da ni dobil vrednosti za primerjavo in rešitve ne bi sprejel.

Učenci v datoteki sicer vidijo, s na katerih testnih podatkih se bo rešitev preverjala, vendar ne vidijo pričakovanega rezultata. Tudi v povratni informaciji, ki se pokaže po oddaji neustrezne rešitve, ne bo zapisan. Povratna informacija bo oblike `Rešitev podnaloge 3 ni sprejeta.`

Goljufanje še dodatno otežimo, če rešitev preverjamo na stotinah na videz naključnih podatkov:

for i in range(100):
    Check.secret(razdalja(i - 50, i * 17, i + 13, i/2)

Koda v zgoraj zapisanem primeru bo izračunala razdaljo med pari točk (-50, 0) & (13, 0), (-49, 17) & (14, 0), (-48, 34) & (15, 1) ...

Funkcija `Check.secret` je zato najbolj primerna za preverjanje izpitnih nalog ali ko želimo zagotoviti, da učenci pri reševanju ne bodo ubirali bližnjic.

Check.run

Ko preverjamo programe, ki spreminjajo vrednost lokalnih spremenljivk (na primer seznamov ali slovarjev), moramo poleg rezultata programa preveriti tudi vrednosti spremenljivk. V ta namen uporabimo funkcijo `Check.run(izrazi, pricakovano_stanje)`. izrazi so izrazi v jeziku Python, zapisani kot niz (torej med narekovaji). `pricakovano_stanje` je slovar vrednosti, ki naj bi jih spremenljivke imele po izračunu podanih izrazov. Na primer:

# =========================================================
# Napiši funkcijo ’spremeni_predznak(stevila)’, ki spremeni
# predznak vsem elementom seznama ‘stevila’.
# =====================================================

def spremeni_predznak(stevila):
    for i in range(len(stevila)):
        stevila[i] = -stevila[i]

Check.part()
Check.run([
    'a = [1, 3, -5, 2, -6]',
    'spremeni_predznak(a)',
    'b = [1, -5, 2, 5]',
    'spremeni_predznak(b)',
    'spremeni_predznak(b)'
    ], {'a': [-1, -3, 5, -2, 6], 'b': [1, -5, 2, 5]})

Če stanje spremenljivk po izvedbi izrazov ni enako pričakovanemu, bo reševalec prejel povratno informacijo o tem, za katere izraze njegova rešitev ne vrne pričakovanih rezultatov. Na primer, če bi zgornjo nalogo reševalec rešil tako, da se seznam `a` ne bi spremenil, bi bila povratna informacija oblike:

- Po izvedbi izrazov
>>> a = [1, 3, -5, 2, -6]
>>> spremeni_predznak(a)
>>> b = [1, -5, 2, 5]
>>> spremeni_predznak(b)
>>> spremeni_predznak(b)
je vrednost spremenljivke a enaka [1, 3, -5, 2, -6] namesto [-1, -3, 5, -2, 6].

Check.out_file

Za preverjanje rešitev, ki vračajo datoteke, uporabljamo `Check.out_file(ime_datoteke, pricakovana_vsebina)`. Funkcija preveri, ali se vsebina datoteke `ime_datoteke` ujema s `pricakovana_vsebina`. `Pricakovana_vsebina` je seznam vrstic, ki naj bi jih datoteka vsebovala.

Če na primer naloga zahteva, da učenec napiše funkcijo `napisi_abecedo(n, abeceda.txt)`, ki v datoteko `abeceda.txt` zapiše prvih `n` črk abecede, bi test izgledal takole:

napisi_abecedo(3, 'abeceda.txt')
Check.out_file('abeceda.txt', [
    'a', 'b', 'c',
])

Če se vsebina datoteke razlikuje od pričakovane, bodo v povratni informaciji tiste vrstice označene z `*`:

- Izhodna datoteka abeceda.txt
     je enaka         namesto:
       e                *a
       d         * b
       c         | c

Check.in_file

Za testiranje programov, ki berejo iz podane datoteke, uporabljamo `Check.in_file(ime_datoteke, vsebina)`. Funkcija ustvari datoteko z danim imenom in vsebino.Delovanje si oglejmo na primeru `Napiši funkcijo prestej_vrstice(ime_datoteke), ki vrne število vrstic v podani datoteki.` Testi bi bili na primer takšni:

with Check.in_file('test_vhodna_1.txt', ['a', 'b', 'c',]):
    Check.equal('prestej_vrstice("test_vhodna_1.txt")', 3)
with Check.in_file('test_vhodna2.txt', []):
    Check.equal('prestej_vrstice("test_vhodna2.txt")', 0)

Kot lahko vidimo, funkcijo `Check.equal` kličemo v kontekstu, za katerega poskrbi funkcija `Check.in_file`. Če je potrebno, lahko v istem kontekstu kličemo več testnih funkcij (ne samo ene, kot v zgornjem primeru). Funkcijo `Check.in_file` lahko kličemo večkrat in na ta način rešitev preverimo pri različnih vhodnih datotekah.

`Check.in_file` poskrbi, da povratna informacija vsebuje tudi ime in vsebino datoteke, pri kateri oddana rešitev ne vrne pričakovanih rezultatov:

- Pri vhodni datoteki test_vhodna.txt z vsebino
    a
    b
    c
je prišlo do naslednjih napak:
- Izraz prestej_vrstice("test_vhodna1.txt") vrne 4 namesto 3.

Napredno testiranje

Testi so pisani v jeziku Python, zato lahko pri pisanju uporabimo vse funkcionalnosti, ki jih ta jezik ponuja: pogojni stavki, značke, knjižnice ...

Osnovni ukaz, ki ga pri teh testih uporabljamo, je `Check.error(message)`, ki vrne napako in njen opis.

if f(100) > 1000:
    Check.error("Vrednost f(100) je prevelika!")

Na voljo je tudi razširjena oblika ukaza: `Check.error(message, arg1, arg2, ...)`. V niz `message` lahko vključimo spremenljivke `arg1`, `arg2` itd. in sicer tako, da v niz med `{` in `}` napišemo zaporedno številko mesta, na katerem je spremenljivka pri klicu funkcije (šteti začnemo z 0). Na primer, v spodnjem primeru med zavite oklepaje zapišemo številko 0, ker je argument `i` na prvem mestu.

for x in [100, 200, 300, 400]:
    if f(i) > 10 * i:
        Check.error("Vrednost f({0}) je prevelika!", i)

Če želimo preverjati kodo učenčeve rešitve, to storimo preko `Check.current_part['solution']`. Preverimo lahko na primer, ali je učenec pri reševanju uporabil zanke namesto rekurzije, to je, ali koda vsebuje besedi `for` ali `while`.

Za bolj natančno analizo kode si pomagamo s knjižnico ast.

Ukazi `Check.equal`, `Check.run` in `Check.out_file` vrnejo `True` ali `False`. Zato z njimi lahko preverimo, ali je sploh smiselno, da oddano rešitev še dodatno testiramo. Če rešitev ne prestane prvega testa, potem je očitno ne moremo sprejeti, zato nadaljnji testi niso potrebni.

Če pa želimo učencem pokazati, za katere nabore testnih podatkov njihov program ne vrne pričakovanih rezultatov, lahko pripravimo poljubno mnogo testov.

Pregled učenčevega dela

Tudi mi potrebujemo povratne informacije o tem, kako hitro in uspešno so učenci reševali določeno nalogo ali kako napreduje posamezen učenec.

Tomo prikaže statistiko reševanja za posamezno nalogo in statistiko reševanja za posameznega učenca.

Statistika za posamezno nalogo

Splošna statistika za posamezno nalogo je prikazana s tortnimi grafikoni. Grafikoni se nahajajo poleg seznama vseh nalog v sklopu, kot prikazuje spodnja slika. Vsaka podnaloga dane naloge ima svoj grafikon. Rdeča barva prikazuje delež učencev, ki podnaloge še niso začeli reševati. Rumena barva prikazuje tiste, ki so nalogo rešili narobe in zelena barva tiste, katerih rešitev je sprejeta.

Prikaz uspešnosti pri posameznih nalogah.

Slika 8: Prikaz uspešnosti pri posameznih nalogah.

Če si želimo uspešnost reševanja ogledati bolj podrobno, kliknemo na ime naloge. Odpre se stran, kjer je prikazana uspešnost reševanja posameznih študentov pri posameznih podnalogah. Rdeče obarvan krogec pomeni, da učenec podnaloge še ni poskušal reševati. Rumen krogec pomeni, da je učenec podnalogo rešil napačno, zelen krogec pa, da je učenčeva rešitev sprejeta.

Prikaz uspešnosti učencev pri določeni nalogi.

Slika 9: Prikaz uspešnosti učencev pri določeni nalogi.

Če kliknemo na obarvani krogec, se nam odpre stran z rešitvami tega učenca. Poleg učenčevih rešitev vidimo še uradne rešitve podnalog.

Ogled rešitev določenega učenca.

Slika 10: Prikaz učenčevih in učiteljevih rešitev

Statistika za posameznega učenca

Na prvi strani predmeta je objavljen seznam vseh učencev v predmetu. S klikom na ime učenca odpremo stran, ki prikazuje, kako uspešno je ta učenec reševal naloge v celotnem predmetu. Tudi tukaj rdeča barva pomeni, da učenec podnaloge še ni poskušal reševati. Rumena barva pomeni, da njegova rešitev podnaloge ni bila sprejeta in zelena barva pomeni, da je podnalogo uspešno rešil.

Prikaz uspešnosti določenega učenca pri predmetu.

Slika 11: Napredek učenca pri predmetu.

Če kliknemo na obarvani krogec, se nam odpre stran z rešitvami tega učenca (glej sliko 10).