2 input_validators
atli164 edited this page 2024-03-18 20:01:28 +00:00

Þegar búið er að skrifa lýsingu þar sem inntaksstærðir verkefnis hafa komið fram að þá er gott að skrifa forrit til að tryggja að gögnin uppfylli skilyrðin.

Kattis krefst þess að slíkt forrit fylgi með, og af góðri ástæðu. Í þessu forriti þarf að lesa inn inntaksskrárnar og tékkar á öllum skilyrðum í inntaki. Ef lofað er að tiltekið verkefni hafi lausn í inntaki þarf að gá á því. Passa þarf að allar tölur séu skrifaðar með sómasamlegum hætti, passa þarf að inntak sé af réttri stærð, noti þau tákn sem sagt er að notað sé, og svo framvegis.

Hér er annaðhvort hægt að nota .ctd skrár eða skrifa forrit sem les inn gögn og hættir keyrslu með exit code 42 ef allt er í góðu. Fyrir Forritunarkeppni Framhaldsskólanna notum við almennt python, þar sem .ctd skrár bjóða ekki upp á ólíka virkni eftir inntakshópum. Sjáum dæmi úr verkefninu "Bilað lyklaborð". Neðan við það dæmi er tekið dæmi um .ctd skrá.

Í því verkefni stendur

\section*{Inntak}
Inntak er ein lína sem samanstendur af $n$ enskum lágstöfum ásamt bilum.

Og neðar í hópalýsingu stendur

\section*{Stigagjöf}
\begin{tabular}{|l|l|l|}
\hline
Hópur & Stig & Takmarkanir \\ \hline
1     & 40   & $1 \leq n \leq 100$, sama tákn kemur aldrei oftar en tvisvar í röð. \\ \hline
2     & 40   & $1 \leq n \leq 100$. \\ \hline
3     & 10   & $1 \leq n \leq 100\,000$, sama tákn kemur aldrei oftar en tvisvar í röð. \\ \hline
4     & 10   & $1 \leq n \leq 100\,000$. \\ \hline
\end{tabular}

Forritið þarf því að tryggja að inntakið sé aðeins ein lína, og að lengd línunnar sé rétt í hverjum hópi. Enn fremur þarf að passa að í sumum hópum séu mest tveir eins stafir í röð. Í gögnum dæmisins eru skilgreindar tvær breytur, max_n og multirepeat, undir limit. Þær eru sendar inn í input validator sem argument. Svo ef við notum python forrit má lesa þær inn með

#!/usr/bin/env python3

import re
import sys

exec(sys.argv[1]) # max_n
exec(sys.argv[2]) # multirepeat

Vegna þess að sys.argv[0] er nafn skránnar, en hin gildin í argv eru limits gildin. Þá eru max_n og multirepeat skilgreind sem rétt gildi fyrir hvern hóp, ef þau eru stillt rétt í skránnum í data möppunni.

Til þess að tryggja að eitthvað gildi getum við notað assert þar sem öll exit code önnur en 42 eru túlkuð sem svo að inntakið sé ekki í lagi. Restin af skránni er sem fylgir

line = sys.stdin.readline()

assert 1 <= len(line) <= max_n

assert line[-1] == "\n"
line = line[:-1]

lst1, lst2 = -1, -2

for c in line:
    if c != ' ':
        assert ord('a') <= ord(c) <= ord('z')
    if not multirepeat:
        assert lst1 != lst2 or lst1 != c
    lst2 = lst1
    lst1 = c

assert not sys.stdin.read()

sys.exit(42)

Þar sem sys.exit(42) kemur því til skila allt sé í lagi.

Ef nota á checktestdata (.ctd skrár) eru hlutir einfaldari, en það dugar bara þegar gögn eru eins í öllum hópum eða það eru ekki ólíkir hópar af gögnum. Formlega skilgreiningin á .ctd skrám má finna hér. Þá eru notuð föll eins og INT, FLOATP, STRING og svo framvegis til að lesa eitt token í einu úr inntaki.

Þetta leyfir oft mjög stutt og þægileg forrit. Sjáum dæmi, verkefnið deildajöfnuður úr FKHI23 er með inntakslýsinguna

\section*{Inntak}
Fyrsta lína inntaksins inniheldur eina heiltölu $n$, fjölda styrkja, þar sem $1 \leq n \leq 200$.
Önnur lína inntaksins inniheldur $n$ enska lágstafi, einn fyrir hvern styrk, þar sem hver stafur táknar deildina sem styrkurinn er tileinkaður.

Þetta verður að

INT(1, 200, n) NEWLINE
REGEX("[a-z]*", s) NEWLINE
ASSERT(STRLEN(s) == n)
EOF

Þetta mál býður upp á einfaldar lykkjur, til dæmis er inntakslýsingin fyrir verkefnið spilahlustun úr FKHI23

\section*{Inntak}
Fyrsta lína inntaksins inniheldur tvær heiltölur $n$, fjölda spila, þar sem $1 \leq n \leq 5 \cdot 10^5$, og $q$, fjölda snúninga í stokkuninni, þar sem $1 \leq q \leq 5 \cdot 10^5$.
og $q$ er fjöldi snúninga í stokkuninni. Svo koma $q$ línur sem hver lýsa einni viðsnúningu í formi tveggja talna $1 \leq 
i \leq j \leq n$. Þetta merkir að frá og með $i$-ta efsta spilinu til og með $j$-ta efsta spilinu sé snúið sem einni heild. Snúningarnir
eru gefnir í þeirri röð sem vélin framkvæmir þá.

sem verður að

INT(1, 500000, n) SPACE INT(1, 500000, q) NEWLINE
REP(q)
    INT(1, n, i)
    SPACE
    INT(i, n, j)
    NEWLINE
END
EOF

Einnig má setja meir en eina skrá í input_validators. Til dæmis getur verið þægilegt að gá að inntakið sé á réttu formi fyrst með .ctd skrá, og svo láta python eða c++ skrá gá á flóknari hlutum eins og hvort engir þrír punktar í inntaki séu á sömu línu til dæmis.