Programmeermethoden 2021
Vierde programmeeropgave: Koffiesweeper

De vierde programmeeropgave van het vak Programmeermethoden in het najaar van 2021 heet Koffiesweeper; zie ook het elfde werkcollege, en lees geregeld deze pagina op WWW.

De opgave

van wikipedia Voor deze programmeeropgave gaan we het eenpersoons spel Koffiesweeper programmeren, beter bekend als Minesweeper (zie minesweeper.online en Wikipedia). Het is de bedoeling een klasse koffiebord te maken, die onder meer memberfuncties heeft als drukaf, menszet en randomzet. Uiteraard heeft deze klasse ook een constructor en een destructor. Verder moeten gedane zetten met behulp van een stapel ongedaan gemaakt kunnen worden.

Maak vanaf het begin gebruik van een aantal voorbeeldfiles, van waaruit de opgave stap voor stap kan worden gedaan. De files zijn allereerst (zie verderop voor gebruik met Code::Blocks, op eigen risico):

van minesweeper.online Het spel Koffiesweeper, een getrouwe kopie van het welbekende Minesweeper, verloopt als volgt. De speler ziet een rechthoek met m (hoogte) bij n (breedte) vakjes, alle gesloten. Op een aantal vakjes staat (verborgen) een kop koffie of thee. De speler krijgt te horen hoeveel dat er in totaal zijn. De speler kan een vakje selecteren door de coordinaten te geven. Als hier een kop koffie staat heeft de speler onmiddellijk verloren: de koffie moet meteen worden opgedronken. Zo niet, dan ziet de speler een getal tussen 0 en 8: het aantal directe buurvakjes, horizontaal, verticaal en diagonaal, dat een kop koffie bevat.

We spelen het spel als volgt. Eerst mag de grootte van het bord gekozen worden: het aantal rijen m en het aantal kolommen n, en welk percentage van de vakjes (ongeveer) gevuld is met een kop koffie (gebruik random ( ) uit <cstdlib>; denk aan srand ( ); en gebruik de functie leesgetal van de derde opgave); het exacte aantal wordt aan de speler bekend gemaakt. De speler kan kiezen of hij/zij zelf één spelletje speelt, of dat er volledig random wordt gespeeld, waarbij het aantal spelletjes gekozen mag worden (steeds met een nieuwe beginconfiguratie). Het eerst geopende vakje bevat nooit een kop koffie.
Als de mens speelt wordt steeds de stand —in eenvoudig formaat— op het scherm getoond, en kan de speler zijn/haar zet doen (een vakje openen), of juist de laatste zet terugnemen (zie straks), of een random zet laten doen, of een vakje markeren met een 'K'. Als er een reeds eerder geopende plek wordt geselecteerd, moet de speler natuurlijk opnieuw kiezen. Het aantal gedane zetten wordt ook steeds getoond.
De menselijke speler kan een vakje markeren waarvan hij/zij denkt dat het een kop koffie bevat; deze vorm van selecteren telt niet mee voor het aantal zetten. Als een vakje met 0 koffie-buren wordt geopend, kunnen al diens buren veilig worden opgevraagd. Schrijf hiertoe een recursieve functie die dit automatisch doet. De speler wint als alle vakjes die geen kop koffie bevatten zijn geopend.

Als het programma volledig random speelt, wordt in een tweetal arrays, één voor de gewonnen en één voor de verloren spelletjes, bijgehouden hoeveel zetten het telkens duurde. Na afloop wordt dan geprint hoeveel spelletjes z zetten duurden (z = 0, 1, ...), ten behoeve van een grafiek, zie onder.

Schrijf een functie voor de klasse koffiebord die een pointerstructuur aanlegt, waarbij ieder vakje, naast bijvoorbeeld een int en enkele bool's als inhoud, tevens een array met 8 pointers naar de onmiddellijke buren heeft: middenboven (0), rechtsboven (1), rechts (2), rechtsonder (3), middenonder (4), linksonder (5), links (6) en linksboven (7). De vakjes aan de randen bevatten uiteraard diverse nullptr's. Het bord is dus niet een m bij n array, maar een zeer ingewikkelde pointerstructuur.

Bij de menselijke speler moeten alle complete borden op een stapel worden bijgehouden, en deze kunnen daarmee teruggenomen worden. Zodra een speler zet, wordt een kopie van het bord opgeslagen. Dit onderdeel is zeker niet eenvoudig; mocht het ontbreken, dan kost dat een punt.

Het is de bedoeling om een vijftal files te produceren: de eerste bevat main en het menutje, de tweede (zeg koffiebord.h, zie boven) bevat de klasse-definitie voor koffiebord, en de derde (zeg koffiebord.cc, zie boven) bevat de functies uit die klasse. Evenzo zijn er files stapel.h en stapel.cc, indien van toepassing. Maak als het kan ook een makefile.
Code::Blocks-gebruikers: doe deze opgave liever op een Linux-machine. Maar het kan wel: open een nieuw project via "File -- New project -- Empty project", vul wat in, en voeg de drie files toe via "Project -- Add files", en daarna het project compileren op de gebruikelijke manier. Of, op eigen risco, lees over projecten.

Opmerkingen
Gebruik geschikte (member)functies. Bij deze opgave mogen wederom bij elke functie tussen begin-{ en eind-} hooguit circa 30 niet al te volle of complexe regels staan! Elke functie dient van commentaar voorzien te zijn. Als uitzondering mag main langer zijn, als daarin met het menu gewerkt wordt. Let op goed parametergebruik: alle parameters, met uitzondering van membervariabelen, in de heading doorgeven, en de variabele-declaraties zowel bij main als bij de andere functies aan het begin. De enige te gebruiken headerfile is in principe iostream, en eventueel ctime en cstdlib (voor de random-generator). Zeer ruwe indicatie voor de lengte van de gezamenlijke C++-files: 600 regels. Denk aan het infoblokje.

Uiterste inleverdatum: maandag 13 december 2021, 17:00 uur.
Manier van inleveren:

  1. Digitaal de C++-code inleveren: stuur een email naar pm@liacs.leidenuniv.nl.
    Stuur geen executable's, lever alleen de vijf (of drie) C++-files en eventueel de makefile digitaal in! Noem de file koffiebord.cc hier bij voorkeur zoiets als garfunkelsimongobord4.cc, dit voor de opdracht van het duo Simon-Garfunkel, en analoog de andere files. De laatst voor de deadline ingeleverde versie wordt nagekeken.
  2. En ook een papieren versie van het verslag (inclusief de C++-code van alle files, en eventueel de makefile) deponeren in de speciaal daarvoor bestemde doos "Programmeermethoden" bij kamer 159 van het Snellius-gebouw.
    Overal duidelijk datum en namen van de (maximaal twee) makers vermelden, in het bijzonder als commentaar in de eerste regels van de C++-code.
    Het verslag (uiteraard weer in LaTeX, zie de eerdere opgaven) moet het volgende bevatten: een zeer korte beschrijving van het programma, een beschrijving van punten waarop het programma faalt (indien van toepassing), en een tabel met gewerkte uren, uitgesplitst per week en per persoon. En een referentie betreffende Minesweeper. En een grafiek (zie het bijbehorende werkcollege voor tips) waarin staat hoe lang een winnend of verliezend spelletje voor de random speler duurt — voor verschillende beginconfiguraties.
Te gebruiken compiler: als hij maar C++ vertaalt; het programma moet in principe zowel op een Linux-machine (met g++) als onder Visual C++ of Code::Blocks draaien. Test dus in principe op beide systemen! Het programma wordt doorgaans nagekeken met behulp van de compiler die (uiteraard) in het commentaar bovenin het programma vermeld staat. Normering: layout 1; grafiek 1; verslag 1; commentaar 1; modulariteit (OOP, functies) 2; werking 4. Eventuele aanvullingen en verbeteringen: lees de huidige WWW-bladzijde: www.liacs.leidenuniv.nl/~kosterswa/pm/op4pm.php.