Tip of the day: testiranje zadataka sa HSIN-a

Mnogi od mojih postova sadrže poveznice na zadatke sa HSIN-a koji (barem zasad) ne postoje ni na kakvom evaluatoru. Zato je smanjena motivacija za njihovo rješavanje: nije moguće jednostavno submitati rješenje i odmah dobiti povratnu informaciju, nego je nužno pronaći i skinuti zipane testne primjere sa hsin.hr i lokalno ih isprobati.

Ovo “isprobati”, naravno, ima svoje nijanse. Mnogi znaju samo kopipejstati primjer u program, što je zbilja odvratno. Određen broj natjecatelja zna prosljeđivati jedan po jedan primjer u program koristeći komandnu liniju, te naredbom (diff ili fc) provjeriti podudaranje izlaza. Tek manji broj njih zna to učiniti za sve primjere odjednom, koristeći skriptu. Pokažimo kako se to radi!

Naprije na sporiji način. Dakle, nakon što smo zipane primjere pronašli negdje na https://hsin.hr/natjecanja.html ili na https://hsin.hr/honi/arhiva/ te ih otpakirali, potrebno je u terminalu navigirati do tog direktorija (npr. cd kodovi/herman ako se zadatak zove Herman). Ako smo rješenje kompajlirali tako da se program zove herman.exe, u terminalu ga pokrećemo na sljedeći način:

./herman.exe

(na Windowsu mislim da je bez ovoga ./). Sada bi se primjer unio “s tipkovnice” ili kopipejstao, što ne želimo. Prosljeđivanje primjera (npr. herman.in.1) izravno u program činimo na sljedeći način:

./herman.exe < herman.in.1

… i odmah vidimo što nam program ispisuje. Želimo li ispis u datoteku, pišemo npr. ovako:

./herman.exe < herman.in.1 > izlaz.txt

Tu će datoteka izlaz.txt biti stvorena ako ne postoji, ili prepisana ako postoji. Usporedbu tog našeg ispisa sa službenim izlazom činimo na sljedeći način:

diff izlaz.txt herman.out.1

(Mislim da je na Windowsu fc umjesto diff). Želimo li zanemariti whitespace, dodajemo opciju -w. Ako diff ne ispiše ništa, znači da su datoteke jednake (rješenje je točno), a inače se ispiše razlika.

To bi valjalo ponoviti za svaki primjer, npr. za peti primjer:

./herman.exe < herman.in.5 > izlaz.txt
diff -w izlaz.txt herman.out.5

Mnogo bolje od kopipejstanja, ali i dalje naporno, pogotovo ako postoji 30 primjera ili ako imamo clustere pa primjeri imaju nastavke 1a, 1b, 1c, 2a… No evo skripte koja to radi sve odjednom, nazovimo je npr. test.sh:

for input in herman.in.*; do
    extension="${input##*.}"
    output=herman.out.${extension}
    ./herman.exe < $input > izlaz.txt
    diff -w izlaz.txt $output
done

(Za Windows nemam pojma.) Da bismo je mogli pokrenuti, treba joj dodati executable flag:

chmod +x test.sh

… i potom je pokrećemo kao što bismo pokrenuli i program:

./test.sh

Riječ je o ružnom jeziku Bash koji je dobar za jednostavno Unix/Linux skriptiranje i ni za što drugo. U njemu i razmaci rade probleme.

Unaprijedimo našu Bash skriptu s još nekoliko stvari. Recimo, želimo da nam ista skripta može poslužiti za svaki zadatak, a ne da svaki put moramo mijenjati ime zadatka u skripti (u ovom slučaju Herman). Rješenje je uvesti varijablu umjesto tog imena, a tu varijablu pišemo kao $1 jer je riječ o prvom argumentu koji ćemo napisati desno od imena skripte pri njezinom pokretanju:

./test.sh herman

A skripta onda izgleda ovako:

for input in $1.in.*; do
    extension="${input##*.}"
    output=$1.out.${extension}
    ./$1.exe < $input > izlaz.txt
    diff -w izlaz.txt $output
done

Ako želimo “customizirati” i naziv rješenja, za koji smo dosad pretpostavljali da je oblika imeZadatka.exe, možemo dodati još jedan argument $2:

for input in $1.in.*; do
    extension="${input##*.}"
    output=$1.out.${extension}
    ./$2 < $input > izlaz.txt
    diff -w izlaz.txt $output
done

… nakon čega je pokrećemo npr. ovako:

./test.sh herman herman.exe

Možemo napisati i varijantu s trećim argumentom – rednim brojem primjera – ako želimo testirati samo određeni primjer. Evo i varijante koja ispisuje koji su primjeri prošli te se zaustavlja na prvom primjeru koji je pao:

for input in $1.in.*; do
    extension="${input##*.}"
    output=$1.out.${extension}
    ./$2 < $input > izlaz.txt
    if diff -w izlaz.txt $output; then
        echo $input 'prosao'
    else
        echo $input 'pao'
        exit 0
    fi
done

Primjer outputa:

herman.in.1 prosao
herman.in.2 prosao
herman.in.3 prosao
1c1
< 0
---
> 565315
herman.in.4 pao

Ni ja ne znam Bash, većinu ovoga sam izguglao. Ako netko ima primjedbi ili prijedloga poboljšanja, neka napiše u komentarima. Za neki od idućih postova nastojat ću napisati Python skriptu koja radi isto, a i više od ovoga.

2 misli o “Tip of the day: testiranje zadataka sa HSIN-a

  1. Povratni ping: Tip of the day: testiranje na pythonovski | Blogaritam

  2. Povratni ping: Tip of the day: testiranje | Blogaritam

Komentiraj

Popunite niže tražene podatke ili kliknite na neku od ikona za prijavu:

WordPress.com Logo

Ovaj komentar pišete koristeći vaš WordPress.com račun. Odjava /  Izmijeni )

Google photo

Ovaj komentar pišete koristeći vaš Google račun. Odjava /  Izmijeni )

Twitter picture

Ovaj komentar pišete koristeći vaš Twitter račun. Odjava /  Izmijeni )

Facebook slika

Ovaj komentar pišete koristeći vaš Facebook račun. Odjava /  Izmijeni )

Spajanje na %s