Galgje is een spel voor twee spelers. Daarbij moet één van de spelers een woord bedenken dat de andere speler moet raden. Bij de start van het spel krijgt de speler die het woord moet raden te zien hoe lang het woord is. Daarvoor worden blokjes gebruikt die de verborgen letters van het woord voorstellen. Hieronder geven de blokjes met vraagtekens bijvoorbeeld aan dat er een woord van negen letters moet geraden worden.
Nu kan de speler het woord beginnen raden door individuele letters te raden. De andere speler geeft bij elke geraden letter aan op welke plaatsen die letter in het woord voorkomt. Hij doet dit door de blokjes voor die letters om te draaien, waardoor de letter op de achterkant te zien is. Dit is bijvoorbeeld wat de speler te zien krijgt nadat hij achtereenvolgens de letters E, N, O, T en I geraden heeft. De letter E komt één keer in het woord voor als tweede letter, de letter O komt twee keer in het woord voor als zevende en als achtste letter, en de letter T komt één keer in het woord voor als vijfde letter. De letters N en I zijn fout geraden, omdat ze niet in het woord voorkomen.
De speler die het woord moet raden, mag hoogstens negen fouten maken. Hij wint het spel als hij alle letters van het woord kan raden voordat hij tien fouten gemaakt heeft. Anders wint de andere speler.
De fout geraden letters worden in alfabetische volgorde weergegeven onder de blokjes voor het te raden woord. Bovendien wordt er ook een tekening gemaakt van een stokmannetje1 dat aan een galg hangt. Per fout geraden letter wordt er een extra segment aan de tekening toegevoegd. Het aantal fouten wordt ook weergegeven in een zwarte cirkel in de rechterbovenhoek van de tekening.
In de tekening wordt de bodem altijd getekend (ook bij nul fouten). De galg wordt opgebouwd uit vier segmenten (verticale paal, horizontale paal, dwarsbalk en touw) en het mannetje uit zes segmenten (hoofd, lichaam, linkerarm, rechterarm, linkerbeen en rechterbeen). Hieronder zie je hoe de tekening stelsematig opgebouwd wordt vanaf nul fouten tot en met het maximaal aantal van tien fouten.
In de bovenstaande weergaven hebben we standaard een lichtgroene achtergrondkleur gebruikt. Van zodra het aantal fouten een bepaalde drempelwaarde bereikt heeft (hierboven vanaf 8 fouten), zijn we overgeschakeld naar een lichtrode achtergrondkleur om aan te geven dat de speler die het woord moet raden bijna verloren is.
Schrijf een bash shell script hangman waaraan twee argumenten moeten doorgegeven worden: i) een woord $$w$$ dat bestaat uit één of meer hoofdletters en ii) een reeks $$r$$ van nul of meer hoofdletters. Het script moet naar stdout een afbeelding in SVG-formaat uitschrijven die weergeeft waar de geraden letters uit $$r$$ in woord $$w$$ voorkomen en welke letters uit $$r$$ fout geraden werden. Verderop2 bespreken we stap voor stap hoe deze SVG-afbeelding opgebouwd wordt. Het script moet bijvoorbeeld kunnen gebruikt worden om alle afbeelding uit de inleiding van deze opgave te genereren. De SVG-afbeelding voor de tweede afbeelding uit de inleiding ziet er bijvoorbeeld als volgt uit, waarbij het woord KERSTMAN moet geraden worden en een speler reeds de letters E, N, O, T en I geraden heeft:
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="100" version="1.1"> <style>line,circle{stroke-width:3px;stroke:black;stroke-linecap:round}</style> <style>text{font-family:monospace;font-weight:bold;text-anchor:middle}</style> <rect width="300" height="100" fill="#90EE90" rx="3" /> <circle cx="92" cy="8" r="4" stroke="black" fill="black" /> <text x="92" y="10" font-size="8px" fill="white">2</text> <line x1="5" y1="90" x2="95" y2="90" /> <line x1="15" y1="10" x2="15" y2="90" /> <line x1="10" y1="10" x2="60" y2="10" /> <text x="200" y="45" font-size="24px" fill="black">?E??T?OO?</text> <text x="200" y="70" font-size="14px" fill="black">IN</text> </svg>
Het script moet de volgende opties ondersteunen:
optie -g: toon enkel de component met de tekening (toon dus de component met de tekst niet)
optie -t: toon enkel de component met de tekst (toon dus de component met de tekening niet)
optie -h <char>: gebruik het karakter dat aan deze optie doorgegeven wordt om aan te geven welke letters van het woord nog niet geraden werden (standaardwaarde: ?)
optie -d <int>: gebruik de waarde die aan deze optie doorgegeven wordt als drempelwaarde (standaardwaarde: 8)
Het script moet voor de verwerking van de opties de flexibiliteit aan de dag leggen die gebruikelijk is bij Unix commando's: volgorde van opties speelt geen rol, opties kunnen samengenomen worden, argument bij een optie moet niet noodzakelijk van de optieletter gescheiden worden door witruimte, …. Daarnaast moet het script de volgende foutafhandeling voorzien:
als niet de gepaste opties doorgegeven worden (enkel ondersteuning voor de opties -g, -t, -h en -d, waarbij aan de opties -h en -d verplicht een argument moet doorgegeven worden) of als er niet exact twee argumenten doorgegeven worden, dan moet het script een boodschap uitschrijven naar stderr en eindigen met exit status 1; het script mag ervan uitgaan dat de twee argumenten enkel uit hoofdletters bestaan, zonder dat dit expliciet moet gecontroleerd worden
de opties -g en -t mogen niet samen gebruikt worden: het script moet ofwel enkel de component met de tekening of de component met de tekst weergeven, of beide; als beide opties toch samen gebruikt worden dan moet het script een boodschap uitschrijven naar stderr en eindigen met exit status 2
het argument dat aan de optie -h wordt doorgegeven, moet één enkel karakter zijn en dat mag geen letter zijn; als het argument hier niet aan voldoet dan moet het script een boodschap uitschrijven naar stderr en eindigen met exit status 3
het argument dat aan de optie -d wordt doorgegeven, moet een natuurlijk getal zijn tussen 0 en 10 (grenzen inbegrepen); als het argument hier niet aan voldoet dan moet het script een boodschap uitschrijven naar stderr en eindigen met exit status 4
In al deze gevallen moet deze boodschap uitgeschreven worden naar stderr:
Usage: ${commando} [-[gt]] [-h <character>] [-d <threshold>] word letters
Scalable Vector Graphics (SVG) is een op XML3 gebaseerd bestandsformaat voor vectorafbeeldingen4, waarbij afbeeldingen tekstueel beschreven worden aan de hand van eenvoudige meetkundige bouwstenen zoals punten, lijnen, cirkels en veelhoeken. Het shell script hangman moet een SVG-afbeelding genereren die bestaat uit twee componenten: een tekening (aan de linkerkant; 100 pixels breed en 100 pixels hoog) en tekst die aangeeft waar de geraden letters in het woord voorkomen en welke letters fout geraden werden (aan de rechterkant; 200 pixels breed en 100 pixels hoog). Het is ook mogelijk om slechts één van beide componenten te laten genereren.
Je moet geen SVG of XML kennen om deze opgave op te lossen. We bespreken stap voor stap hoe de grafische voorstelling in SVG-formaat opgebouwd wordt aan de hand van vijf sjablonen: hoofding5, tekening (twee sjablonen voor het aantal fouten6 en voor de segmenten per fout7), tekst8 en voettekst9. Daarbij zullen we de variabele onderdelen van elk sjabloon in het groen weergeven. Daar moet het script de juiste waarden invullen. Het is belangrijk dat elk sjabloon exact overgenomen wordt, zodat het resultaat dat het script uitschrijft precies overeenkomt met de beschreven specificatie.
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="100" version="1.1">
<style>line,circle{stroke-width:3px;stroke:black;stroke-linecap:round}</style>
<style>text{font-family:monospace;font-weight:bold;text-anchor:middle}</style>
<rect width="300" height="100" fill="#90EE90" rx="3" />
Op de eerste regel worden de breedte (width) en de hoogte (height) van de afbeelding ingesteld. De afbeeldingen hebben altijd een vaste hoogte van 100 pixels. De breedte is afhankelijk van de opties -g en -t. Als zowel de tekening als de tekst moeten weergeven worden, is de breedte 300 pixels. Als enkel de tekening moet weergeven worden is de breedte 100 pixels. Als enkel de tekst moet weergeven worden, is de breedte 200 pixels. Op de tweede en derde regel wordt wat vaste opmaak van de afbeelding ingesteld. Op de laatste regel wordt een rechthoek getekend die de achtergrondkleur bepaalt. Hierin moet opnieuw de breedte (width) van de afbeelding ingevuld worden. Daarnaast moet ook de achtergrondkleur (fill) ingevuld worden: #90EE90 (lichtgroen) als de drempelwaarde voor het aantal fouten niet bereikt wordt en #FFCCCB (lichtrood) van zodra de drempelwaarde bereikt wordt.
<circle cx="92" cy="8" r="4" stroke="black" fill="black" /> <text x="92" y="10" font-size="8px" fill="white">2</text>
De eerste regel tekent een zwarte cirkel in de rechterbovenhoek van de tekening. Door de tweede regel wordt het aantal fouten (variabel onderdeel) in die cirkel weergegeven. De SVG-afbeelding mag enkel de regels uit dit sjabloon bevatten als de component met de tekeningen moet weergegeven worden.
<line x1="5" y1="90" x2="95" y2="90" /> <line x1="15" y1="10" x2="15" y2="90" /> <line x1="10" y1="10" x2="60" y2="10" /> <line x1="15" y1="30" x2="35" y2="10" /> <line x1="55" y1="10" x2="55" y2="30" /> <circle cx="55" cy="36" r="6" fill="none" /> <line x1="55" y1="42" x2="55" y2="62" /> <line x1="55" y1="42" x2="45" y2="52" /> <line x1="55" y1="42" x2="65" y2="52" /> <line x1="55" y1="62" x2="40" y2="77" /> <line x1="55" y1="62" x2="70" y2="77" />
Dit sjabloon van 11 regels tekent de rest van de tekening. De eerste regel tekent de bodem. De daaropvolgende regels tekenen de opeenvolgende segmenten van de galg en het stokmannetje. Die segmenten staan in de juiste volgorde gerangschikt per aantal fouten. Als er bijvoorbeeld twee fouten gemaakt werden, dan moeten de eerste drie regels van het sjabloon aan de SVG-afbeelding toegevoegd worden: 1 regel voor de bodem en 2 regels voor de 2 fouten. De SVG-afbeelding mag enkel regels uit dit sjabloon bevatten als de component met de tekeningen moet weergegeven worden.
<text x="200" y="45" font-size="24px" fill="black">?E??T?OO?</text>
<text x="200" y="70" font-size="14px" fill="black">IN</text>
De eerste regel plaatst de tekst die aangeeft welke geraden letters in het woord voorkomen (tweede variabel onderdeel op die regel). De tweede regel plaatst de tekst die aangeeft welke letters fout geraden werden (tweede variabel onderdeel op die regel). Op beide regels hangt de horizontale positie (x) van de tekst (eerste variabel onderdeel op die regels) af van het feit of de component met de tekening getoond wordt. Als de tekening getoond wordt dan is de horizontale positie 200, anders is de horizontale positie 100. De SVG-afbeelding mag enkel de regels uit dit sjabloon bevatten als de component met de tekst moet weergegeven worden.
</svg>
Dit laatste sjabloon sluit de SVG-afbeelding af met een SVG stop-tag.
Onderstaande voorbeeldsessie toont hoe het shell script hangman moet kunnen gebruikt worden.
$ hangman KERSTMAN ENOTI
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="100" version="1.1">
<style>line,circle{stroke-width:3px;stroke:black;stroke-linecap:round}</style>
<style>text{font-family:monospace;font-weight:bold;text-anchor:middle}</style>
<rect width="300" height="100" fill="#90EE90" rx="3" />
<circle cx="92" cy="8" r="4" stroke="black" fill="black" />
<text x="92" y="10" font-size="8px" fill="white">2</text>
<line x1="5" y1="90" x2="95" y2="90" />
<line x1="15" y1="10" x2="15" y2="90" />
<line x1="10" y1="10" x2="60" y2="10" />
<text x="200" y="45" font-size="24px" fill="black">?E??T??N</text>
<text x="200" y="70" font-size="14px" fill="black">IO</text>
</svg>
$ hangman
Usage: solution.sh [-[gt]] [-h <character>] [-d <threshold>] word letters
$ echo $?
1
$ hangman -x KERSTMAN ENOTI
Usage: solution.sh [-[gt]] [-h <character>] [-d <threshold>] word letters
$ echo $?
1
$ hangman -gt KERSTMAN ENOTI
Usage: solution.sh [-[gt]] [-h <character>] [-d <threshold>] word letters
$ echo $?
2
$ hangman -h 'X' KERSTMAN ENOTI
Usage: solution.sh [-[gt]] [-h <character>] [-d <threshold>] word letters
$ echo $?
3
$ hangman -d 11 KERSTMAN ENOTI
Usage: solution.sh [-[gt]] [-h <character>] [-d <threshold>] word letters
$ echo $?
4