diff --git a/frontend/src/tests/example_assignments/28-Z1-1.html b/frontend/src/tests/example_assignments/28-Z1-1.html new file mode 100644 index 0000000..084c34d --- /dev/null +++ b/frontend/src/tests/example_assignments/28-Z1-1.html @@ -0,0 +1,36 @@ +

+Kevin otevřel obálku (kterou našel ve schránce) a vyndal z ní všechny papíry. Jeden +ho obzvláště zaujal (ten od KSP). Ihned si všiml, že (na začátku) obsahuje nějak +mnoho závorek. Tak by ho zajímalo, jestli tam (autoři zadání) neudělali nějakou +chybu. Pomůžete mu (s ověřením)?

+

+Pro danou posloupnost symbolů ( a ), tedy otevíracích +a zavíracích závorek, najděte od začátku co nejdelší úsek, který je platným +uzávorkováním – tedy každá závorka má svoji do páru.

+

+Tvar vstupu: +Na prvním řádku dostanete číslo N. Na dalších N řádcích budou jednotlivé +testovací případy.

+

+Tvar výstupu: +Pro každý testovací případ vypište na řádek délku nalezeného uzávorkování.

+

+Slibujeme, že N bude nejvýše 1 000, a každý řádek bude mít nejvýše 105 symbolů.

+
+Ukázkový vstup: +
3
+(()())())()
+((()())())()
+(()()))()()()()()
+
+
+
+Ukázkový výstup: +
8
+12
+6
+
+
+
+

+Uzavírající závorka na deváté pozici nemá svůj protějšek. Druhý řádek je celý platné uzávorkování.

diff --git a/frontend/src/tests/example_assignments/31-3-3.html b/frontend/src/tests/example_assignments/31-3-3.html new file mode 100644 index 0000000..bad1e26 --- /dev/null +++ b/frontend/src/tests/example_assignments/31-3-3.html @@ -0,0 +1,51 @@ +

+Na podlaze se nachází sesypaný hrách s popelem a mezi tím poskakuje několik +holoubků a vrabčáků. Chtějí Popelce pomoct vysbírat všechen hrách. Pro každou +kuličku hrachu chceme zjistit, zda ji nějaký ptáček dokáže sezobnout a přenést +do ošatky. Holoubci i vrabčáci se však pohybují každý jinak. Vrabčáci poskakují +rovně dopředu, dozadu, doleva i doprava, zato holoubci chodí šikmo do všech +čtyř stran.

+

+Celou situaci si lze představit jako rozmístění figurek na šachovnici. +Holoubci představují černé střelce, vrabčáci černé věže a kuličky hrachu pak +bílé pěšáky. Pro každou bílou figurku chceme zjistit, zda ji dokážeme v jednom +tahu nějakou černou figurkou vyhodit.

+

+Formát vstupu: Na prvním řádku vstupu se nachází dvě čísla B a C, a to +počet kuliček hrachu (neboli bílých figurek) a počet ptáčků (neboli černých +figurek). Na dalších B řádcích se nachází souřadnice kuliček hrachu jako +dvojice čísel oddělených mezerou, číslo řádku a číslo sloupce udávajících, kde +se kulička nachází. Na dalších C řádcích se pak nachází pozice ptáčků – každý +takový řádek obsahuje znak H nebo V a dvojici čísel udávajících +řádek a sloupec, kde ptáček stojí (opět vše oddělené mezerami). Znak H +značí holoubka (pohybuje se jako střelec) a znak V vrabčáka (pohybuje se +jako věž). Figurky na vstupu mohou být seřazené náhodně.

+

+Formát výstupu: Na B řádků výstupu vypište (ve stejném pořadí, jako na +vstupu) pro každou kuličku hrachu ANO nebo NE podle toho, jestli +existuje nějaký holoubek nebo vrabčák, který může tuto kuličku hrachu jedním +tahem sezobnout.

+
+Ukázkový vstup: +
4 3
+0 1
+0 2
+0 3
+2 2
+V 0 0
+H 1 3
+V 3 3
+
+
+
+Ukázkový výstup: +
ANO
+ANO
+NE
+ANO
+
+Šachovnice s příkladem +
+
+Poznámka: +BUG diff --git a/frontend/src/tests/example_assignments/32-Z1-1.html b/frontend/src/tests/example_assignments/32-Z1-1.html new file mode 100644 index 0000000..c2660be --- /dev/null +++ b/frontend/src/tests/example_assignments/32-Z1-1.html @@ -0,0 +1,28 @@ +

+Kevin se po prázdninách zase vrací do školy. Jako obvykle dostal seznam pomůcek, +které si má obstarat. Malé sešity, velké sešity, pravítko, pastelky, barvy na +výtvarku, učebnice na češtinu a dějepis a možná i novou aktovku. To vypadá na +velký nákup!

+

+Kevin se tedy vydal do obchodu. Jak dává věci do košíku, píše si i seznam cen. V +tom si ale uvědomí, že má jen P korun. Kolik nejméně z N věcí v košíku musí +Kevin vyhodit, aby mu P korun stačilo?

+

+Tvar vstupu: Na prvním řádku se nachází počet věcí v košíku N a počet korun P, které Kevin může +utratit. Na druhém řádku je pak seznam cen věcí v košíku, tedy N kladných čísel +oddělených mezerami.

+

+Tvar výstupu: Vypište jedním číslem nejmenší počet věcí, které musí Kevin +z košíku vyhodit.

+
+Ukázkový vstup: +
5 59
+8 20 30 1999 40
+
+
+
+Ukázkový výstup: +
2
+
+
+
diff --git a/frontend/src/tests/example_solutions/28-Z1-1.html b/frontend/src/tests/example_solutions/28-Z1-1.html new file mode 100644 index 0000000..76bdd0b --- /dev/null +++ b/frontend/src/tests/example_solutions/28-Z1-1.html @@ -0,0 +1,65 @@ +

+Nejprve si vyřešme jednodušší úlohu: jak o nějaké posloupnosti závorek +poznáme, jestli je (celá) správně uzávorkovaná? Určitě musí obsahovat +stejný počet levých a pravých závorek – jinak těžko mohou tvořit páry.

+

+Ovšem to nestačí. Uvažte třeba posloupnost ())(. Ta obsahuje dvě +levé a dvě pravé závorky, ale korektním uzávorkováním určitě není. +Na třetí pozici se pokoušíme ukončit závorku „dřív, než začala“.

+

+Jak takovou situaci poznáme? Podíváme-li se na první tři znaky naší +posloupnosti, vidíme, že obsahují jednu levou závorku a dvě pravé. +Obecně problém nastane, pokud existuje v posloupnosti nějaké místo +takové, že v úseku od začátku po toto místo je více pravých závorek +než levých. Pak alespoň jedna z těch pravých nemá před sebou žádnou +levou, se kterou bychom ji mohli spárovat.

+

+Pokud posloupnost obsahuje stejně levých a pravých závorek a nenastane +problém popsaný výše, pak už si snadno rozmyslíte, že je vždy jde +správně spárovat, a tedy uzávorkování je korektní.

+
Ilustrace: Hroší pilot
+

+Nyní k původní úloze. Představme si, že si chceme označit všechna +místa v posloupnosti, kde může končit korektní uzávorkování (začínající +na začátku). Třeba pro příklad ze zadání to budou následující místa +(označena hvězdičkou): (()())*()*)().

+

+Jak je najdeme? Budeme postupně procházet posloupnost od začátku a průběžně +si počítat, kolik levých a pravých závorek už jsme viděli. Pokud narazíme +na místo, kde jsme napočítali víc pravých než levých, můžeme rovnou skončit. +Už víme, že takové uzávorkování korektní není, a přidáním libovolných dalších +závorek na konec už nemůžeme napravit chybějící závorky nalevo od aktuální +pozice.

+

+Pokud tato situace ještě nenastala a objevíme místo, před kterým je počet +levých a pravých závorek stejný, označíme si jej. Podle toho, co jsme si +řekli výše, uzávorkování končící na tomto místě je korektní.

+

+Ukažme si průběh algoritmu na předchozím příkladu:

+
+ + + + + + + +
( ( ) ( ) ) ( ) ) ( )
Pozice 1 2 3 4 5 6 7 8 9 10 11
Počet levých 1 2 2 3 3 3 4 4 4 - -
Počet pravých 0 0 1 1 2 3 3 4 5 - -
Rozdíl 1 2 1 2 1 0 1 0 -1 - -
Akce * * X
+
+

+Hvězdička znamená označení místa s korektním uzávorkováním +a X konec prohledávání, když žádné další uzávorkování korektní být +nemůže.

+

+Na konci jen vypíšeme nejpravější označené místo. Všimněme si, že +si nemusíme ukládat všechna označená místa, stačí si vždy pamatovat +poslední dosud nalezené. Další drobné zjednodušení je místo dvou +počítadel použít jen jedno, uchovávající rozdíl počtu dosud načtených +levých a pravých závorek (řádek „rozdíl“ v tabulce výše). Pak označujeme, +když je toto počítadlo rovné nule, a končíme, pokud klesne pod nulu.

+

Program (Python 3) – počítání obou druhů závorek

+

Program (Python 3) – stačí nám počítat jen levé

+

Filip Štědronský

+

+Pokud máte pocit, že jste zde dříve viděli něco jiného, nemýlíte se. Věříme, že toto řešení pro vás bude stravitelnější.

+
diff --git a/frontend/src/tests/example_solutions/31-3-3.html b/frontend/src/tests/example_solutions/31-3-3.html new file mode 100644 index 0000000..8ca6722 --- /dev/null +++ b/frontend/src/tests/example_solutions/31-3-3.html @@ -0,0 +1,50 @@ +

+Pro každou z bílých figurek chceme zjistit, zda je ohrožována aspoň jednou +černou. Můžeme zkusit vyzkoušet pro každou dvojici bílé a černé figurky, zda se +ohrožují. Těchto dvojic je ovšem až kvadraticky mnoho a navíc se nám může stát, že +i když by se dvojice ohrožovala, tak se mezi nimi nachází další figurka, která +černé figurce z naší dvojice překáží ve výhledu a znemožňuje jí bílou figurku +sebrat. Protože ověřit, zda dvojici nepřekáží ve výhledu další figurka, trvá +lineárně dlouho, toto řešení je O(n3).

+

+Jelikož černé figurky jsou pouze věže a střelci, bílé figurky mohou být +ohroženy pouze z dohromady osmi směrů, kterými se černé dokážou pohybovat. +Řešení můžeme vylepšit tím, že budeme zjišťovat, zda je bílá figurka ohrožena, +pro každý směr zvlášť. Například pokud chceme pro každou bílou figurku zjistit, +zda je ohrožena zleva nebo zprava, stačí nám uvažovat pouze ty figurky, které +leží na stejném řádku. Navíc každá figurka má na svém řádku nejvýše dva +sousedy, jednoho zleva, druhého zprava. Stačí nám uvažovat jen tyto +sousedy, protože budou všem ostatním figurkám na řádku překážet ve výhledu. Pro +každou z lineárně mnoho bílých figurek tedy v lineárním čase najdeme ty +figurky, které s nimi sdílí řádek (pro ostatní směry ty, které sdílí sloupec či +diagonálu), v lineárním čase najdeme mezi nimi dva nejbližší sousedy bílé +figurky a pro ty vyzkoušíme, zda figurku neohrožují, to jest zda se jedná o černé figurky a jestli jsou typu, který se umí v tomto směru pohybovat. Celkově je toto řešení +O(n · (n + n)), tedy O(n2).

+

+Abychom uměli rychle zjistit, které figurky leží na stejném řádku, můžeme si +nejprve všechny figurky seřadit podle jejich souřadnice řádku. V seřazeném seznamu figurek +leží figurky na stejném řádku vedle sebe. Pokud bychom navíc vzali +všechny figurky na stejném řádku a seřadili je podle souřadnice sloupce a +uložili do nějakého pole, budeme je mít uspořádané v tom pořadí, v jakém leží +na řádku za sebou. Pro libovolnou figurku na řádku tedy umíme najít její +sousedy prostě tak, že se podíváme v tomto uspořádaném poli na index o jedna +nižší a o jedna vyšší.

+

+Tato dvě setřídění můžeme provést zároveň. Primárně figurky setřídíme podle +souřadnice řádku, sekundárně pak podle souřadnice sloupce. Takové uspořádání, +kde třídíme primárně podle jednoho kritéria a sekundárně podle jiného, se +nazývá lexikografické. Nyní nám stačí projít setříděné pole a pro každou +bílou figurku se podívat na její dva sousedy a rozhodnout, zda ji neohrožují. +Také musíme dát pozor na to, že sousední figurky v setříděném poli figurek se +nemusí nacházet na stejném řádku. Pokud je soused bíle figurky na jiném řádku, +znamená to, že v daném směru se už na stejném řádku nenachází žádné figurky. +Také si všimněme, že tímto uspořádáním najdeme všechny takové figurky, které +bíle ohrožují ne jen z jednoho směru z osmi, ale ze dvou (zprava i zleva).

+

+Kompletní řešení pro každou ze čtyř „os“ (doleva-doprava, nahoru-dolů, +diagonálně doprava nahoru, diagonálně doprava dolů) lexikograficky figurky +uspořádá, uspořádané pole v lineárním čase projde a pro každou bílou figurku určí, zda +je ohrožována. Toto řešení má tedy časovou složitost O(n log n).

+

Program (C)

+

Kuba Pelc

+
diff --git a/frontend/src/tests/example_solutions/32-Z1-1.html b/frontend/src/tests/example_solutions/32-Z1-1.html new file mode 100644 index 0000000..8807a0e --- /dev/null +++ b/frontend/src/tests/example_solutions/32-Z1-1.html @@ -0,0 +1,27 @@ +

+K tomu, abychom za věci utratili co možná nejméně, potřebujeme do košíku +postupně vybírat věci od té nejlevnější po tu nejdražší.

+

+Pole cen tedy vzestupně setřídíme a budeme jej postupně procházet, přičemž +si budeme pamatovat součet cen věcí, které při průchodu potkáme. Jakmile +při procházení přesáhne tento součet koruny vyhrazené na nákup, tak podle +pozice v poli víme, kolik věcí si můžeme koupit.

+

+Jelikož se však zadání ptá na počet věcí, které si koupit nemůžeme, tak jako +řešení vypíšeme počet věcí od pozice, kde jsme skončili s procházením, do konce +pole cen.

+

+Řešení je jistě správné, určitě se totiž nemůže stát, že bychom si mohli koupit +víc věcí, než nám vypíše algoritmus. Vyhodili jsme z košíku ty nejdražší věci, +které jsme mohli, takže nám jich určitě nestačilo vyhodit méně.

+

+Rychlost řešení ovlivní hlavně to, jak rychle dokážeme ceny setřídit. Existují +různé třídící algoritmy a pokud použijete nějaký algoritmus zabudovaný přímo +v programovacím jazyce, běží většinou v čase O(n log n). Pokud jste si +implementovali vlastní jednoduché třídění, pravděpodobně bude mít časovou +složitost O(n2). O třídících algoritmech si můžete přečíst +v naší kuchařce o třídění.

+

Program (Python 3)

+

Program (C++)

+

Tom Sláma

+
diff --git a/frontend/src/tests/grabber.test.ts b/frontend/src/tests/grabber.test.ts index 06b36e1..663b0c0 100644 --- a/frontend/src/tests/grabber.test.ts +++ b/frontend/src/tests/grabber.test.ts @@ -1,7 +1,8 @@ import * as g from '../ksp-task-grabber' -import { readFileSync } from 'fs'; +import { readFileSync, readdirSync } from 'fs'; import { resolve } from 'path'; import type { TaskDescriptor, TasksFile } from '../tasks'; +import { action_destroyer } from 'svelte/internal'; const node_fetch: any = require('node-fetch') @@ -41,9 +42,9 @@ describe('tasks assignment', () => { for (const t of tasks.tasks) { if (t.type != "open-data") continue; - test(`${t.id}`, async () => { - const assignment = await g.grabAssignment((t as any).taskReference) - expect((t as any).taskReference).toEqual(assignment.id) + test.concurrent(`${t.id}`, async () => { + const assignment = await g.grabAssignment(t.taskReference) + expect(t.taskReference).toEqual(assignment.id) expect(assignment.points).toBeGreaterThanOrEqual(1) expect(assignment.description.trim()).toBeTruthy() expect(assignment.name.trim()).toBeTruthy() @@ -66,7 +67,7 @@ describe('tasks solutions', () => { continue } - test(`${t.id}`, async () => { + test.concurrent(`${t.id}`, async () => { const sol = await g.grabSolution(t.taskReference) expect(t.taskReference).toEqual(sol.id) expect(sol.description.trim()).toBeTruthy() @@ -74,3 +75,38 @@ describe('tasks solutions', () => { }) } }) + +describe('task assignment (exact match)', () => { + const assignmentDir = resolve(__dirname, "example_assignments") + const assignmentFiles = readdirSync(assignmentDir) + for (const a of assignmentFiles) { + const [_, id] = /(.*?)\.html/.exec(a)! + test(id, async () => { + const assignment = await g.grabAssignment(id) + const expected = readFileSync(resolve(assignmentDir, a)).toString() + try { + expect(assignment.description.trim()).toEqual(expected.trim()) + } catch(e) { + console.warn(assignment.description) + throw e + } + }) + } +}) +describe('task solution (exact match)', () => { + const assignmentDir = resolve(__dirname, "example_solutions") + const assignmentFiles = readdirSync(assignmentDir) + for (const a of assignmentFiles) { + const [_, id] = /(.*?)\.html/.exec(a)! + test(id, async () => { + const solution = await g.grabSolution(id) + const expected = readFileSync(resolve(assignmentDir, a)).toString() + try { + expect(solution.description.trim()).toEqual(expected.trim()) + } catch(e) { + console.log(solution.description) + throw e + } + }) + } +})