diff options
author | Timotej Lazar <timotej.lazar@fri.uni-lj.si> | 2016-02-28 19:32:04 +0100 |
---|---|---|
committer | Timotej Lazar <timotej.lazar@fri.uni-lj.si> | 2016-02-28 19:32:04 +0100 |
commit | 7335a43bbbb82de66132f12e504f2fbea736a45c (patch) | |
tree | ff08317c712353c58c9630ad7f6e94caebbc8798 | |
parent | e756acb31c54558ee16a0bbcda13f991b7d4f714 (diff) |
Prolog: add general and family relations intro
-rw-r--r-- | prolog/intro_sl.html | 135 | ||||
-rw-r--r-- | prolog/problems/family_relations/intro_sl.html | 378 | ||||
-rw-r--r-- | prolog/problems/family_relations/sl.py | 9 | ||||
-rw-r--r-- | prolog/sl.py | 5 | ||||
-rw-r--r-- | prolog/style.css | 60 |
5 files changed, 583 insertions, 4 deletions
diff --git a/prolog/intro_sl.html b/prolog/intro_sl.html new file mode 100644 index 0000000..e56e079 --- /dev/null +++ b/prolog/intro_sl.html @@ -0,0 +1,135 @@ +<!DOCTYPE html> +<html lang="sl"> + <head> + <meta charset="utf-8" /> + <title>CodeQ: Prolog</title> + <link rel="stylesheet" type="text/css" href="style.css" /> +</head> +<body> + +<h1><span class="codeq">CodeQ</span>: Prolog</h1> +<p> +V oknu, ki ga sedaj bereš, je nekaj praktičnih napotkov in teorije za vsak učni +sklop. Ob tem je tudi seznam nalog tega sklopa. Naloge lahko načeloma rešuješ v +poljubnem vrstnem redu, so pa tipično urejene po naraščajoči težavnosti. +Nekatere naloge tudi lažje rešiš z uporabo rešitev predhodnih nalog. Teh +rešitev ne potrebuješ prepisovati, sistem si jih zapomni sam od sebe in jih +lahko takoj uporabljaš, če želiš. +</p> + +<h2>Kako rešujem naloge?</h2> +<p> +Nalogo začneš reševati s klikom nanjo. S tem se odpre spletna stran, v kateri +programiraš rešitev. Vsaka stran je povezana s konkretno nalogo in vsebuje +štiri razdelke. +Razpored razdelkov lahko spremeniš v nastavitvah. +</p> +<ul> + <li> + <p> +Navodila, ki na kratko opišejo nalogo. Posebej bodi pozoren na ime predikata, +ki ga moraš sprogramirati – poimenovati ga moraš točno tako, kot je navedeno, +da bo sistem razpoznal tvojo rešitev. +Seveda pa lahko sprogramiraš več pomožnih predikatov; tu ni nobenih omejitev. + </p> + <p> +Poleg tega bodi pozoren tudi na število argumentov, ki jih ciljni predikat +zahteva. Npr. predikat <code>mother(?X, ?Y)</code> zahteva dva argumenta, +<code>X</code> in <code>Y</code>. Vprašaj pred imenom argumenta pomeni, da ta +argument lahko predstavlja tako vhod kot izhod. Argumenti, ki delujejo le kot +vhod, so označeni s <code>+</code>, argumenti, ki delujejo le kot izhod, pa z +<code>-</code>. +Na začetku se ne obremenjuj s tem, ampak preprosto programiraj, vhod/izhod se +bo večinoma pravilno uredil sam od sebe. Prolog je pameten. 😉 + </p> + </li> + + <li> + <p> +V levem razdelku, ti bo aplikacija dajala povratne informacije. Te so lahko v +obliki splošnega plana (kako se neke naloge lotiti), ali pa specifični nasveti, +kaj je morda narobe s tvojo <em>trenutno</em> rešitvijo. +Namigi so različni, včasih bodo tudi v obliki protiprimera – konkretnega vhoda, +na katerem tvoj program deluje narobe. Tukaj bodo tudi prologova opozorila in +obvestila o napakah v programu. + </p> + <p> +Če se ti kakšen namig zdi napačen, najprej dobro poglej svoj program. +Če se ti še vedno zdi napačen, nas obvesti. +Če bo res napačen, plačamo kavo mi, sicer jo plačaš ti! 😉 + </p> + <p> +(<em>Disclaimer</em>: včasih ni možno z gotovostjo ugotoviti, ali je neka +napaka prisotna; takrat sistem uporabi besede, kot so <em>mogoče</em>, +<em>morda</em> in <em>verjetno</em> – tega ne štejemo kot napačno.) + </p> + </li> + + <li> + <p> +Konzola, tipično črne barve in kjer te čaka prologov poziv <code>?-</code>, je +namenjena tvojemu pogovoru s prologom. V ozadju teče minimalno okrnjen +<a target="_blank" href="http://www.swi-prolog.org">SWI Prolog</a>, +ki mu lahko zastavljaš vprašanja. +Vse potrebne podatke za posamezno nalogo (npr. bazo znanja) ima sistem že +naložene. Prav tako vedno samodejni naloži trenutno različico tvojega programa. +Prologu lahko zastavljaš poljubna vprašanja, ne le ta, povezana s tvojim +programom. + </p> + </li> + + <li> + <p> +Nazadnje je tu še osrednji del: urejevalnik besedila, v katerem pišeš svojo +rešitev. Na prvi pogled morda res manjkajo reči, kot je npr. „autocomplete“, a +boš hitro ugotovil, da so programi v prologu kratki in ne zahtevajo veliko +tipkanja. + </p> + <p> +Če tvoj program prerase 8‒10 vrstic, si ga verjetno preveč zakompliciral! 😉 +Najdaljši program v vseh sklopih nalog ne potrebuje več kot kakšnih 12 vrstic +(in takšne naloge so redke). Prej omenjeni gumbi pa so opisani spodaj. + </p> + </li> +</ul> + +<p> +Osrednji programerski del vsebuje tudi gumba „Plan“ in „Testiraj“. +Najpogosteje boš uporabljal slednjega, ki sproži samodejno preverjanje tvoje +rešitve. +Gumb „Plan“ ti da splošen nasvet, kako se lotiti dane naloge; včasih ga lahko +pritisneš večkrat, za zmeraj bolj „izdajalske“ nasvete. +Seveda pa poskusi vsako nalogo najprej rešiti brez uporabe namigov. +</p> + +<p> +Če program ni pravilen, ti bo <span class="codeq">CodeQ</span> poleg sporočila +o opravljenih testih včasih ponudil gumb „Namig“. +Ta gumb ti poda namig, kaj je morda narobe s tvojim programom. +Nekateri namigi so pripravljeni ročno s strani avtorjev aplikacije, včasih bo +na delu umetna inteligenca, včasih boš dobil protiprimer, na katerem program ne +deluje, včasih pa namiga sploh ne bo. +V tem primeru je program najbrž grozen! Malce se hecam… morda. 😉 +</p> + +<h2>Kako shranim rešitve?</h2> +<p> +Sistem <span class="codeq">CodeQ</span> avtomatsko shranjuje tvoje rešitve na +strežnik, seveda pa moraš biti povezan na internet. +Vse spremembe se beležijo v realnem času, zato ne potrebuješ skrbeti za +shranjevanje kode ali se obremenjavati s tem kdaj ti bo potekla seja. +Trajanje seje je načeloma 60 minut, prekine pa se tudi, če se na drugem +računalniku ali v drugem zavihku prijaviš z istim uporabniškim imenom. +</p> +<p> +Opozorilo: glede na to, da sistem v realnem času shranjuje vse, kar v njem +pišeš (tako je, keylogger je!), priporočamo, da se zaupnih sporočil ne piše +vanj. Sicer jih bomo prebrali, obljubimo! 😊 +</p> +<p> +Vse svoje rešitve za posamezni sklop si lahko ogledaš s klikom na povezavo ob +naslovu. +</p> + +</body> +</html> diff --git a/prolog/problems/family_relations/intro_sl.html b/prolog/problems/family_relations/intro_sl.html new file mode 100644 index 0000000..0e1147b --- /dev/null +++ b/prolog/problems/family_relations/intro_sl.html @@ -0,0 +1,378 @@ +<!DOCTYPE html> +<html lang="sl"> + <head> + <meta charset="utf-8" /> + <title>Prolog: družinske relacije</title> + <link rel="stylesheet" type="text/css" href="../style.css" /> + </style> +</head> +<body> + +<h1>Prolog: družinske relacije</h1> +<p> +Prvi sklop je seveda namenjen spoznavanju prologa, obenem pa bomo obnovili naše +poznavanje družinskih relacij – tako je, ukvarjali se bomo s tetami, strici, +dedki, predniki in potomci. +</p> + +<h2>Baza znanja</h2> +<p> +Načeloma je vse, kar prolog ve, zapisano v njegovi bazi znanja. Ta se tipično +naloži v sistem iz ene ali več datotek, <span class="codeq">CodeQ</span> to +bazo naloži samodejno. Baza pravzaprav ni nič drugega kot (preprost) prologov +program. Spodnja slika prikazuje bazo za ta sklop nalog. +</p> + +<figure> + <a href="famrel.svg" target="_blank"> + <img src="famrel.svg" /> + </a> + <figcaption>Graf (gozd) družinskih relacij</figcaption> +</figure> + +<p> +Baza seveda ni v grafični obliki – to je za nas, ljudi. Za prolog pa (njen +izsek) izgleda takole: +</p> +<pre> +parent(tina, william). +parent(thomas, william). +parent(thomas, sally). +parent(thomas, jeffrey). +parent(william, vanessa). +… +female(tina). +female(sally). +female(vanessa). +… +male(william). +male(thomas). +male(jeffrey). +… +</pre> + +<p> +Kot vidiš, ni težko razbrati formata. In res je, to je povsem legalen prologov +program. Formalno bomo taki obliki stavka (v vsaki vrstici zgoraj je en stavek) +rekli dejstvo. V naši bazi imamo definirane tri relacije: +</p> +<ol> + <li>kdo je komu starš: relacija <code>parent/2</code>,</li> + <li>kdo je ženskega spola: relacija <code>female/1</code> in</li> + <li>kdo je moškega spola: relacija <code>male/1</code>.</li> +</ol> +<p> +Zadnji dve bi lahko definirali seveda tudi drugače, npr. kot +<code>gender(tina, female)</code>; to je povsem stvar sloga. +</p><p> +Ko je prolog bazo prebral, ve vse, kar je v njej zapisano. Obenem ve samo to, +kar je v njej zapisano, in nič drugega! Pozna torej relacije <code>parent/2</code>, <code>female/1</code> +in <code>male/1</code>. Zakaj jih pišem na tak način? Pred poševnico je ime relacije (kot +npr. ime funkcije ali procedure v kakšnem drugem jeziku), za poševnico pa +število argumentov. To je standarden zapis, ki ga boš videl v literaturi. +</p><p> +Opazil si, da se je zgoraj vsak stavek končal s piko. Pika seveda označuje +konec stavka, tako kot v slovenščini. Vsi stavki, ne glede na tip (trije tipi +so, jih bomo spoznali v kratkem) se končajo s piko! (Klicaj pomeni nekaj +drugega in tega si danes še ne želiš vedeti, verjemi mi.) Verjetno bo danes +tvoja najpogostejša napaka, da boš pozabil na piko (navada iz drugih jezikov). +Še posebej pa bodi pozoren, da stavka ne končaš s podpičjem, to pomeni nekaj +povsem drugega! 😉 +</p> + +<h2>Prvi koraki</h2> +<p> +Baza je torej naložena, tako da lahko začnemo z delom v prologu. Navadno to +poteka tako, da sistemu postavljamo vprašanja. Če odpreš stran s poljubno +nalogo, lahko v konzolo pišeš primere, ki so opisani v nadaljevanju. +</p><p> +Za začetek lahko prologu zastavimo preprosto vprašanje: +</p> +<pre> +?- parent(tina, william). +yes. +</pre> +<p> +To vprašanje bi se v slovenščini glasilo: je Tina starš od Williama? Prolog iz +baze znanja ve, da je Tina res starš od Williama, zato odgovori s +<code>true</code> ali <code>yes</code> (odvisno od dialekta prologa). Gotovo si +opazil tudi piko na koncu vprašanja. Tako je, čeprav gre za vprašalni tip +stavka (drugi tip, ki smo ga pravkar spoznali), je na koncu pika. Vprašaj je na +začetku, skoraj kot v španščini. 😊 +</p><p> +Vprašajmo ga kaj bolj zapletenega. Na primer: kdo so Thomasovi otroci? +</p> +<pre> +?- parent(thomas, X). +X = william ; +X = sally ; +X = jeffrey ; +no. +</pre> +<p> +Aha! Kaj je tisto podpičje na koncu in zakaj je rešitev več? Podpičje v resnici +pomeni logični „ali“, po vsakem prologovem odgovoru (en odgovor, ena vrstica) +pa nas (če ve, da je rešitev več) prolog počaka, da mu lahko rečemo, da želimo +več odgovorov. S podpičjem (ali črno „n“ kot „next“) zahtevamo morebitne +dodatne rešitve, s pritiskom na tipko „Enter“ pa poizvedbo končamo. +</p> +<p> +Kot vidiš, so rešitve tri. Odgovor „no“ na koncu pa samo pomeni, da po tretji +rešitvi ni nobene rešitve več. +</p><p> +Zakaj so imena ljudi v bazi pisana z malo začetnico in zakaj je tisti <code>X</code> zgoraj +z veliko? Je to pomembno? Seveda je pomembno! Prolog avtomatsko ve, kakšnega +tipa je določen stavčni element: v splošnem vse, kar je pisano z veliko +začetnico, smatra za spremenljivke, vse z malo pa za konstante (tehnično za +atome, ampak za zdaj se ne vtikajmo v to). V večini drugih jezikov bi ljudi v +bazi verjetno pisali kot nize, jih obdali z narekovaji ali čim podobnim, v +prologu pa je to bolj preprosto. Skratka, zato so vsa imena ljudi z malo +začetnico – ne zaradi sloga, pač pa, ker tako mora biti. Sicer bi bil pomen +drugačen. +</p><p> +No, kaj pa tole vprašanje? +</p> +<pre> +?- parent(X, william). +X = tina ; +X = thomas. +</pre> +<p> +Čakaj, čakaj, kaj so tu vhodi in kaj izhodi? Tako je, kar navadi se: večinoma +so vsi argumenti lahko vhodi in izhodi hkrati. Nič ni strogo definirano. Temu +bomo pogovorno rekli, da prolog deluje v vse (več) smeri. Vprašali smo seveda, +kdo je starš od Williama. +</p><p> +Privoščimo silahko še več. +</p> +<pre> +?- parent(X, Y). +X = tina, Y = william ; +X = thomas, Y = william ; +… +</pre> +<p> +Kako pa to ve? Seveda, saj je zapisano v bazi. Prolog nam je lepo začel +naštevati, kdo vse je komu starš. Pametno, pametno. To je navsezadnje tudi +pomen našega vprašanja. +</p><p> +Kaj pa je bila tista vejica med obema spremenljivkama zgoraj? Medtem ko +podpičje pomeni logični „ali“, vejica pomeni logični „in“. Izkoristimo to novo +znanje in vprašajmo prolog še nekaj malce bolj zapletenega, kdo vse so +<em>sinovi</em> od Thomasa? Sinovi so seveda osebe moškega spola, ki jim je +Thomas starš. +</p> +<pre> +?- parent(thomas, X), male(X). +X = william ; +X = jeffrey ; +no. +</pre> +<p> +Vejico ali podpičje lahko torej uporabimo tudi v vprašanju. Seveda! Če bi +želeli našteti npr. vse osebe v bazi, tako moške kot ženske, bi zapisali +naslednje vprašanje: +</p> +<pre> +?- male(X) ; female(X). +… +</pre> + +<h2>Moj prvi program v prologu</h2> +<p> +Ne bo „Hello, world“, ker je prelahek in nesmiselen za logični jezik, kot je +prolog. Bo pa zato tisto, kar nas je večina spoznala kot svojo prvo besedo v +življenju – relacija mama. Skratka, <code>mother/2</code> bo naš ciljni +predikat, definiran takole: <code>mother(X, Y)</code> naj pomeni, da je +<code>X</code> mama od <code>Y</code>. +</p><p> +S tem, kar smo spoznali do sedaj, bi se tega lahko lotili tako, da pogledamo +osebe v bazi, kje relacija velja in te primere zapišemo, nekako takole: +</p> +<pre> +mother(tina, william). +mother(sally, andrew). +mother(sally, melanie). +mother(vanessa, susan). +… +</pre> +<p> +S tem pravzaprav ni nič narobe in bi povsem lepo delovalo. Problem je le, da je +zamudno, zelo zamudno. Seveda v nadaljevanju ne bomo popisovali relacij dejstvo +za dejstvom, ampak bomo stvari poskusili avtomatizirati oz. definirati. +Avtomatizacija je navsezadnje bistvena lastnost računalnikov. +</p><p> +Spoznali bomo še zadnji, tretji (poleg dejstva in vprašalnega stavka) tip +stavka: pravilo. +</p><p> +Kaj mora torej veljati, da je <code>X</code> mama od <code>Y</code>? Dve +stvari: da je <code>X</code> starš od <code>Y</code> in da je <code>X</code> +ženskega spola. S tem zadnjim ločimo mame od očetov. Pa zapišimo to s +prologovim pravilom: +</p> +<pre> +mother(X, Y) :- + parent(X, Y), + female(X). +</pre> +<p> +Poglejmo sestavne dele zapisanega. Piko na koncu že poznamo, ravno tako že +vemo, da vejica pomeni logični „in“. Torej je <code>X</code> starš <em>in</em> +ženska hkrati. +Kaj pa pomeni nenavadni operator <code>:-</code>, ki je tako značilen za +prolog? Ta operator nam definira pravilo, loči pa ga na dva dela: tisto pred :- +imenujemo glava stavka, tisto za njim pa telo stavka. Bere pa se zelo preprosto +takole: če logično velja telo stavka, potem iz tega sledi, da velja tudi glava +stavka. +</p><p> +Za naš primer to pomeni naslednje. <em>Če</em> velja, da je <code>X</code> starš +od <code>Y</code> in <em>hkrati</em> (vejica!) velja, da je <code>X</code> +ženskega spola, <em>potem</em> velja, da je <code>X</code> mama od +<code>Y</code>. Pravzaprav je kot pogojni stavek, kajne? +</p><p> +Še nekaj zelo pomembnega. Vsakič, ko sprogramiraš kakšno pravilo – in večina +programov bo preprosto množica enega ali več pravil – ga preberi tako, kot smo +ga prebrali zgoraj. To je najboljši način razhroščevanja v prologu! Če se ti +pravilo ob branju ne zdi smiselno, potem skoraj gotovo ni pravilno; kar zaupaj +svojemu občutku za logiko. +</p><p> +Za konec nekaj besed o slogu programiranja. Kot vidiš, sem pisal posamezne +konjunkte v svojo vrstico, celotno telo stavka pa sem tudi nekoliko zamaknil. +Vse to ni nujno potrebno, se pa tako veliko lažje bere in posledično lažje +najde morebitno napako. +</p><p> +Tako, sedaj si nared, da kaj tudi samostojno sprogramiraš. Vse relacije +(naloge) v tem sklopu so definirane tako, da je <code>X</code> v relaciji z +<code>Y</code> in ne obratno. Tako <code>father(X, Y)</code> pomeni, da je +<code>X</code> oče od <code>Y</code> in ne, da je <code>Y</code> oče od +<code>X</code>. +Naloge rešuj povsem naravno, ne obremenjuj se s tem, da morajo delovati v „vse +mogoče smeri“, kot je delovala relacija <code>parent/2</code>. Boš videl, da bo +to večinoma prišlo kar samo od sebe kot bonus. Sem se vrni, ko naletiš na prvo +rekurzijo, to je relacijo <code>ancestor/2</code>. +</p> +<!-- +Tipično smo se prej ustavili že pri brother/sister zaradi potrebe po operatorju +\==, ampak sedaj to uredijo namigi. Poleg tega za konec (je to implementirano, +najbrž ni?) tam povemo kot zanimivost kaj bi bilo, če je \== prvi cilj v +telesu. --> + +<h2>Prva rekurzija</h2> +<p> +Prolog načeloma ne uporablja standardnih kontrolnih struktur, kot so npr. +while ali for zanke, zamišljen je povsem drugače. Saj to si do sedaj že opazil. +Zato je rekurzija glavno orodje „avtomatizacije“ oz. nadomešča zanke. +</p><p> +Kako se je lotimo? Načeloma ima vsaka rekurzivna definicija robni primer in +splošni primer. Obojih je lahko tudi več. Tipično (to je seveda odvisno od +tvojega sloga) za vsak primer napišeš svoje pravilo. +</p><p> +Robni primer tipično predstavlja najbolj enostaven primer, ko relacija velja. +Spomnimo se matematične indukcije, rekurzija ji je zelo podobna! Tipično +najprej dokažeš, da relacija velja za n=1 (robni primer), potem pa se lotiš +težjega, splošnega primera takole: <em>predpostaviš</em>, da relacija velja za +nek n in poskusiš pokazati, da če je to res, da potem relacija velja tudi za +n+1. Pri rekurziji v splošnem primeru razmišljaš takole: kako lahko primer +preveden na enak, le kanček bolj enostaven primer? Najbolje je to videti na +primeru, definirajmo relacijo prednik, torej <code>ancestor/2</code>. +</p><p> +Začnimo takole: vprašajmo se, kdaj je nek <code>X</code> prednik od +<code>Y</code> na najbolj enostaven način? Predniki od <code>Y</code> so +njegovi starši, pa dedki in babice, pa pradedki in prababice, pa…. Naštevamo +(dodajamo predpono pra‐) lahko v nedogled. Ampak najbolj enostaven (najkrajši, +če relacije gledamo kot družinsko drevo) primer je? Starši, seveda! Robni +primer je torej: +</p> +<pre> +ancestor(X, Y) :- + parent(X, Y). +</pre> +<p> +Spomni se, da se to pravilo prebere kot: če je <code>X</code> starš od +<code>Y</code>, potem je <code>X</code> prednik od <code>Y</code>. Sliši se +smiselno, zato gremo naprej. +</p><p> +Kako bi se lotili splošnega primera? Kaj, če predpostavimo, da poznamo nekega +prednika od <code>Y</code>? Recimo mu <code>Z</code>. Potem so tudi +<code>Z</code>-jevi starši predniki od <code>Y</code>, kajne? +Znamo to izkoristititi? Seveda! +</p> +<pre> +ancestor(X, Y) :- + parent(X, Z), + ancestor(Z, Y). +</pre> +<p> +Zanimivo pravilo! Pravi naslednje: če (predpostavka!) je <code>Z</code> prednik +od <code>Y</code> in hkrati (vejica) je <code>X</code> starš od <code>Z</code>, +potem je <code>X</code> tudi prednik od <code>Y</code>. Logično, kajne? +</p><p> +Pomembno: doseg spremenljivk, kot so zgoraj <code>X</code>, <code>Y</code> in +<code>Z</code>, je omejen na trenutni stavek! +Globalnih spremeljivk ni – tehnično to ni čisto res, ampak za zdaj to ni +pomembo. 😊 +Tako sta <code>X</code> in <code>Y</code> v prvem stavku (robni primer) druga +kot <code>X</code> in <code>Y</code> v drugem stavku (splošni primer). +</p><p> +Vidiš, kako smo relacijo prednik definirali s pomočjo same sebe? To lahko +storimo, če problem „zmanjšamo“. Če pogledamo družinsko drevo, je +<code>Z</code> en korak bližji prednik od <code>Y</code>, kot je to +<code>X</code>. +Tako je, ko smo postavili zahtevo <code>parent(X, Z)</code>, smo problem +„zmanjšali“ za en korak. Splošni primer se tako korak za korakom bliža robnemu +primeru, ki rekurzijo konča. +</p><p> +Brez skrbi, s precej vaje, ki jo omogačajo naloge v naslednjih sklopih, ti bo +rekurzija postala zelo domača. Spoznal jo boš do obisti, obljubim! +</p> + +<h2>Slog programiranja</h2> +<p> +Kot si opazil, smo prejšni primer (prednik) rešili z dvema praviloma. Tukaj je +celotna rešitev: +</p> +<pre> +ancestor(X, Y) :- + parent(X, Y). +ancestor(X, Y) :- + parent(X, Z), + ancestor(Z, Y). +</pre> +<p> +Rešitev bi lahko zapisali tudi takole: +</p> +<pre> +ancestor(X, Y) :- + parent(X, Y) + ; + parent(X, Z), +ancestor(Z, Y). +</pre> +<p> +Uporabili smo podpičje, logični „ali“. Preberimo pravilo: <em>če</em> je +<code>X</code> starš od <code>Y</code> <em>ali</em> če je <code>X</code> starš od +<code>Z</code> <em>in</em> je hkrati <code>Z</code> prednik od <code>Y</code>, +<em>potem</em> je <code>X</code> prednik od <code>Y</code>. +</p><p> +Tudi ta rešitev je pravilna. Pravzaprav boš kasneje videl, da je povsem enaka, +le zapisana je drugače. Katero verzijo uporabiš, je bolj ali manj stvar tvojega +sloga. Kasneje boš opazil, da je včasih ena verzija bolj primerna (krajša), +včasih pa druga. +</p><p> +Še dve pomembni opazki za konec: +</p> +<ul> + <li> +Spremenljivke imajo pravzaprav doseg ene veje (konjunkcije). Tako sta v drugem +primeru <code>X</code> in <code>Y</code> v cilju <code>parent(X, Y)</code> +druga kot za podpičjem. + </li> + <li> +Logični „in“ (vejica) ima prednost pred logičnim „ali“ (podpičje), točno tako, +kot si vajen iz logike. Če želiš spremeniti, kako so cilji povezani, lahko za +to seveda uporabiš navadne oklepaje – spet tako kot v logiki. + </li> +</ul> + + </body> +</html> diff --git a/prolog/problems/family_relations/sl.py b/prolog/problems/family_relations/sl.py index 81242ed..a808947 100644 --- a/prolog/problems/family_relations/sl.py +++ b/prolog/problems/family_relations/sl.py @@ -1,8 +1,11 @@ name = 'Družinske relacije' description = '''\ -<p>Prvi koraki v prologu – pisanje pravil za različne družinske relacije. -Za naloge v tem sklopu je že definirana baza podatkov o +<p> +<a target="_blank" href="[%@resource intro_sl.html%]">Prvi koraki v prologu</a> +– pisanje pravil za različne družinske relacije. Za naloge v tem sklopu je že +definirana baza podatkov o <a target="_blank" href="[%@resource famrel.svg%]">družinskih drevesih</a>. V prologu so te informacije predstavljene s predikati <code>parent/2</code>, -<code>male/1</code> in <code>female/1</code>.</p> +<code>male/1</code> in <code>female/1</code>. +</p> ''' diff --git a/prolog/sl.py b/prolog/sl.py index 5a408a7..095d253 100644 --- a/prolog/sl.py +++ b/prolog/sl.py @@ -1,7 +1,10 @@ # coding=utf-8 name = 'Prolog' -description = 'Uvodni tečaj prologa.' +description = '''\ +Uvodni tečaj prologa. +<a target="_blank" href="[%@resource intro_sl.html%]">Napotki za uporabo aplikacije.</a> +''' hint = { 'no_hint': '''\ diff --git a/prolog/style.css b/prolog/style.css new file mode 100644 index 0000000..2000a50 --- /dev/null +++ b/prolog/style.css @@ -0,0 +1,60 @@ +body { + max-width: 60em; + margin: 0 auto; + padding: 1em; + hyphens: auto; + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; +} + +figure { + margin: 0 auto; +} +figure > figcaption { + text-align: center; + width: 100%; +} +figure img { + display: block; + margin: 0.25em auto; + max-width: 80%; +} + +li > p { + margin: 0; +} +li > p:last-child { + margin-bottom: 0.5em; +} + +p { + text-align: justify; +} + +/* code snippets */ +code, pre { + font-size: 0.95em; +} + +code { + background-color: #f4f2f9; + color: #1525c6; + padding: 0.1em 0.2em; +} + +pre { + padding: 0.5em 1em; + margin: 0 0 10px; + color: #333; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #ccc; + border-radius: 4px; +} + +/* CodeQ name in small caps */ +span.codeq { + font-variant: small-caps; +} |