Wordle was zonder twijfel het populairste spelletje van 2022. Elke dag komt er een nieuwe opgave online en moeten alle spelers hetzelfde woord proberen te raden. Bij elke poging krijgen de spelers feedback onder de vorm van gekleurde tegels die aangeven welke letters op de juiste plaats staan en welke letters wel in het woord voorkomen maar op de verkeerde plaats staan.

wordle
Bij dit spelletje Wordle werd het gezochte woord RADAR in zes pogingen gevonden. Voor elke poging worden alle letters van het gegeven woord in groene, gele of grijze tegels weergegeven. Groen betekent dat de letter op de corresponderende plaats in het gezochte woord staat, geel dat de letter op een andere plaats in het gezochte woord staat, en grijs dat de letter niet in het gezochte woord voorkomt.

Een speler moet het woord van de dag in zo weinig mogelijk pogingen proberen te raden. Daarvoor moet bij elke poging een woord gegeven worden dat evenveel letters telt als het gezochte woord. Na elke poging worden alle letters van het gegeven woord in groene, gele of grijze tegels weergegeven. Groen betekent dat de letter op de corresponderende plaats in het gezochte woord staat, geel dat de letter op een andere plaats in het gezochte woord staat, en grijs dat de letter niet in het gezochte woord voorkomt. Meerdere exemplaren van dezelfde letter in het gegeven woord — zoals de drie exemplaren van de letter A in KABAA — worden enkel groen of geel gekleurd als de letter ook meerdere keren in het gezochte woord voorkomt. Overtollige exemplaren van de letter worden grijs gekleurd. Daarbij worden eerst de groene exemplaren (die op de juiste plaats staan) ingekleurd. Daarna worden de gele exemplaren van links naar rechts ingekleurd.

De Welshe softwareontwikkelaar Josh Wardle maakte het spelletje zodat hij en zijn vrouw het tegen elkaar konden spelen. Iedereen kon beginnen meespelen nadat Warlde het in oktober 2021 online gezet had. Het spel won snel aan populariteit toen spelers in december 2021 de mogelijkheid kregen om hun dagelijkse resultaten als emoji-vierkanten te kopiëren, en ze die massaal op Twitter begonnen te delen.

wordle (emoji)
Het spelletje Wordle won snel aan populariteit toen spelers in december 2021 de mogelijkheid kregen om hun dagelijkse resultaten als emoji-vierkanten te kopiëren, en ze die massaal op Twitter begonnen te delen.

Naast een donker thema waarbij enkel de achtergrondkleur verandert, heeft het spelletje ook een thema met hoog contrast dat toegankelijker is voor kleurenblinden. Bij dit laatste thema verandert het kleurenschema van groen en geel naar oranje en blauw.

wordle (contrast)
Naast een donker thema waarbij enkel de achtergrondkleur verandert, heeft het spelletje Wordle ook een thema met hoog contrast dat toegankelijker is voor kleurenblinden. Bij dit laatste thema verandert het kleurenschema van groen en geel naar oranje en blauw.

In januari 2022 kocht The New York Times Company het spel voor een niet nader genoemd bedrag van zeven cijfers, met plannen om het gratis te houden voor alle spelers. In februari 2022 werd het spel verplaatst naar de website van het bedrijf.

Opgave

Schrijf een bash shell script wordle waaraan twee argumenten moeten doorgegeven worden: i) een woord $$w$$ dat uit één of meer letters bestaat en ii) de padnaam van een tekstbestand met op elke regel een woord dat uit evenveel letters moet bestaan als woord $$w$$. Daarbij stelt woord $$w$$ het gezochte woord uit een spelletje Wordle voor en bevat het tekstbestand de woorden die een speler bij opeenvolgende pogingen heeft gegeven.

Het script moet een afbeelding in SVG-formaat uitschrijven naar stdout. Die afbeelding stelt een rooster met gekleurde velden voor, die corresponderen met de letters van de woorden die gegeven werden in de opeenvolgende pogingen. Elke rij van het rooster correspondeert met het gegeven woord op de overeenkomstige regel in het tekstbestand. Elk gekleurd veld in een rij correspondeert met de letter op de overeenkomstige plaats in het gegeven woord. De kleuren van de velden moeten volgens de regels van het spelletje Wordle aangeven welke letters op de juiste plaats staan en welke letters wel in het gezochte woord voorkomen maar op de verkeerde plaats staan. Verderop1 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 eerste afbeelding werd bijvoorbeeld gegenereerd met het gezochte woord RADAR en dit tekstbestand met gegeven woorden:

AUDIO
EARTH
KAABA
BRAND
ARRAY
RADAR

Het shell script schrijft dan de volgende SVG-afbeelding uit naar stdout (wordle.svg2):

<svg xmlns="http://www.w3.org/2000/svg" width="196" height="236" version="1.1">
<style>text{font-weight:bold;text-anchor:middle;dominant-baseline:middle;fill:white}</style>
<rect y="0" x="0" width="36" height="36" fill="#c9b458" />
<text y="18" x="18" font-family="monospace" font-size="24">A</text>
<rect y="0" x="40" width="36" height="36" fill="#777777" />
<text y="18" x="58" font-family="monospace" font-size="24">U</text>
<rect y="0" x="80" width="36" height="36" fill="#6aaa64" />
<text y="18" x="98" font-family="monospace" font-size="24">D</text>
<rect y="0" x="120" width="36" height="36" fill="#777777" />
<text y="18" x="138" font-family="monospace" font-size="24">I</text>
<rect y="0" x="160" width="36" height="36" fill="#777777" />
<text y="18" x="178" font-family="monospace" font-size="24">O</text>
…
</svg>

Om plaatst te sparen werd de inhoud van het SVG-bestand weggelaten dat de velden en de letters vanaf de twee rij weergeeft. Het script moet de volgende opties ondersteunen:

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:

In al deze gevallen moet de volgende boodschap uitgeschreven worden naar stderr:

Usage: wordle [-c] [-l] [-d <int>] [-s <int>] <word> <file>

Opbouw van de SVG-afbeelding

Scalable Vector Graphics (SVG) is een op XML3 gebaseerd bestandsformaat dat vectorafbeeldingen4 tekstueel beschrijft aan de hand van eenvoudige meetkundige bouwstenen zoals punten, lijnen, cirkels en veelhoeken. Het shell script wordle moet een SVG-afbeelding genereren die als volgt opgbouwd wordt.

SVG-structuur
Het shell script wordle genereert een SVG-afbeelding dat een rooster voorstelt met gekleurde velden voor alle letters van de woorden in de opeenvolgende pogingen. De velden hebben dimensie $$d$$ (breedte en hoogte) en onderlinge afstand $$s$$ (horizontaal en verticaal). De SVG-afbeelding heeft een coördinatenstelsel waarvan de oorsprong $$(0, 0)$$ samenvalt met de linkerbovenhoek van het eerste veld op de bovenste rij. Een veld op rij $$r$$ en kolom $$c$$ wordt getekend met linkerbovenhoek $$\left(r(d + s), c(d + s)\right)$$ (groen). De letter in dit veld wordt getekend op positie $$\left(r(d + s) + \left\lfloor{\frac{d}{2}}\right\rfloor, c(d + s) + \left\lfloor{\frac{d}{2}}\right\rfloor\right)$$ (oranje).

Je moet geen SVG of XML kennen om deze opgave op te lossen. We bespreken stap voor stap hoe de grafische voorstelling van het Wordle rooster in SVG-formaat opgebouwd wordt aan de hand van vier sjablonen: hoofding5, veld6, tekst7 en voettekst8. 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.

Hoofding
<svg xmlns="http://www.w3.org/2000/svg" width="196" height="236" version="1.1">
<style>text{font-weight:bold;text-anchor:middle;dominant-baseline:middle;fill:white}</style>

Op de eerste regel worden de breedte (width) en de hoogte (height) van de afbeelding ingesteld (in pixels). Deze afmetingen hangen af van het aantal kolommen $$n$$ en rijen $$m$$ van het rooster. Het aantal kolommen $$n$$ correspondeert met de lengte van het gezochte woord $$w$$. Het aantal rijen $$m$$ correspondeert met het aantal pogingen (het aantal regels in het tekstbestand). De breedte van de afbeelding kan dan berekend worden als $$n(d +s) - s$$ en de hoogte als $$m(d +s) - s$$. Daarbij is $$d$$ de dimensie van de gekleurde velden en $$s$$ de afstand tussen de velden. De waarden die in het sjabloon weergegeven worden, corresponderen bijvoorbeeld met een rooster met $$m = 6$$ rijen en $$n = 5$$ kolommen, en de standaardwaarden voor de dimensie ($$d = 36$$) en de afstand ($$s = 4$$).

Veld
<rect y="0" x="0" width="36" height="36" fill="#c9b458" />

Dit tekent een gekleurd veld met gegeven afmetingen en linkerbovenhoek op positie $$(y, x)$$. Als we de rijen van het rooster van boven naar onder nummeren en de kolommen van links naar rechts, telkens vanaf 0, dan ligt de linkerbovenhoek van een veld op rij $$r$$ en kolom $$c$$ op positie $$\left(r(d + s), c(d + s)\right)$$. Daarmee kunnen de parameters y en x van het sjabloon ingevuld worden. De breedte (width) en hoogte (height) van het veld worden ingevuld met dimensie $$d$$. De kleur wordt bepaald volgens de regels van het spelletje Wordle en hangt ook af van het gekozen kleurenschema:

betekenis standaardkleuren hoog contrast
letter op juiste plaats #6aaa64 (groen) #f7773c (oranje)
letter op verkeerde plaats #c9b458 (geel) #82c0fe (blauw)
letter komt niet voor #777777 (grijs) #777777 (grijs)

Bij het bepalen van de kleur mag geen onderscheid gemaakt worden tussen hoofdletters en kleine letters, zowel in het gezochte woord als in het gegeven woord.

De velden moeten rij per rij getekend worden (van boven naar onder) en voor elke rij moeten de velden van links naar rechts getekend worden. Het sjabloon van elk veld staat op een afzonderlijke regel.

Tekst
<text y="18" x="18" font-family="monospace" font-size="24">A</text>

Dit tekent een letter met gegeven grootte op positie $$(y, x)$$. De letter in het veld op rij $$r$$ en kolom $$c$$ staat op positie $$\left(r(d + s) + \left\lfloor{\frac{d}{2}}\right\rfloor, c(d + s) + \left\lfloor{\frac{d}{2}}\right\rfloor\right)$$. Daarbij staat $$\left\lfloor{x}\right\rfloor$$ voor het grootste natuurlijk getal dat kleiner of gelijk is aan $$x \in \mathbb{R}$$. Daarmee kunnen de parameters y en x van het sjabloon ingevuld worden. De grootte (font-size) van de letter wordt ingevuld met $$\left\lfloor{\frac{2}{3}d}\right\rfloor$$. De letter zelf komt op de plaats waar de A staat in het sjabloon en moet altijd als hoofdletter weergegeven worden in de SVG-afbeelding.

De regel die een letter tekent, volgt in de SVG-afbeelding onmiddellijk na de regel die het gekleurd veld tekent waarin de letter staat.

Voettekst
</svg>

Dit laatste sjabloon sluit de SVG-afbeelding af met een SVG stop-tag.

Voorbeeld

Onderstaande voorbeeldsessie toont hoe het shell script wordle moet kunnen gebruikt worden. Hierbij gaan we ervan uit dat de huidige directory enkel de bestanden uit het ZIP-bestand wordle.zip9 bevat.

$ wordle "RADAR" day01.txt10 > day01.svg11
$ cat day01.svg12
<svg xmlns="http://www.w3.org/2000/svg" width="196" height="236" version="1.1">
<style>text{font-weight:bold;text-anchor:middle;dominant-baseline:middle;fill:white}</style>
<rect y="0" x="0" width="36" height="36" fill="#c9b458" />
<rect y="0" x="40" width="36" height="36" fill="#777777" />
<rect y="0" x="80" width="36" height="36" fill="#6aaa64" />
<rect y="0" x="120" width="36" height="36" fill="#777777" />
<rect y="0" x="160" width="36" height="36" fill="#777777" />
<rect y="40" x="0" width="36" height="36" fill="#777777" />
<rect y="40" x="40" width="36" height="36" fill="#6aaa64" />
<rect y="40" x="80" width="36" height="36" fill="#c9b458" />
<rect y="40" x="120" width="36" height="36" fill="#777777" />
<rect y="40" x="160" width="36" height="36" fill="#777777" />
<rect y="80" x="0" width="36" height="36" fill="#777777" />
<rect y="80" x="40" width="36" height="36" fill="#6aaa64" />
<rect y="80" x="80" width="36" height="36" fill="#c9b458" />
<rect y="80" x="120" width="36" height="36" fill="#777777" />
<rect y="80" x="160" width="36" height="36" fill="#777777" />
<rect y="120" x="0" width="36" height="36" fill="#777777" />
<rect y="120" x="40" width="36" height="36" fill="#c9b458" />
<rect y="120" x="80" width="36" height="36" fill="#c9b458" />
<rect y="120" x="120" width="36" height="36" fill="#777777" />
<rect y="120" x="160" width="36" height="36" fill="#c9b458" />
<rect y="160" x="0" width="36" height="36" fill="#c9b458" />
<rect y="160" x="40" width="36" height="36" fill="#c9b458" />
<rect y="160" x="80" width="36" height="36" fill="#c9b458" />
<rect y="160" x="120" width="36" height="36" fill="#6aaa64" />
<rect y="160" x="160" width="36" height="36" fill="#777777" />
<rect y="200" x="0" width="36" height="36" fill="#6aaa64" />
<rect y="200" x="40" width="36" height="36" fill="#6aaa64" />
<rect y="200" x="80" width="36" height="36" fill="#6aaa64" />
<rect y="200" x="120" width="36" height="36" fill="#6aaa64" />
<rect y="200" x="160" width="36" height="36" fill="#6aaa64" />
</svg>
$ wordle -l "REBUS" day02.txt13 > day02.svg14
$ wordle -cl "QUACK" day03.txt15 > day03.svg16
$ wordle -l -d72 -s8 "SUGAR" day04.txt17 > day04.svg18
$ wordle -cld 50 -s 10 "METHANOL" day05.txt19 > day05.svg20

$ wordle "RADAR"
Usage: wordle [-c] [-l] [-d <int>] [-s <int>] <word> <file>
$ echo $?
1
$ wordle -x "RADAR" day01.txt21
Usage: wordle [-c] [-l] [-d <int>] [-s <int>] <word> <file>
$ echo $?
1
$ wordle -d -5 "RADAR" day01.txt22
Usage: wordle [-c] [-l] [-d <int>] [-s <int>] <word> <file>
$ echo $?
2
$ wordle -s "SPAM" "RADAR" day01.txt23
Usage: wordle [-c] [-l] [-d <int>] [-s <int>] <word> <file>
$ echo $?
3
$ wordle "R4D4R" day01.txt24
Usage: wordle [-c] [-l] [-d <int>] [-s <int>] <word> <file>
$ echo $?
4
$ wordle "RADAR" dayXX.txt
Usage: wordle [-c] [-l] [-d <int>] [-s <int>] <word> <file>
$ echo $?
5
$ wordle "RADAR" day05.txt25
Usage: wordle [-c] [-l] [-d <int>] [-s <int>] <word> <file>
$ echo $?
5