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.