Programmeermethoden 1998
Vierde programmeeropgave

De vierde programmeeropgave van het vak Programmeermethoden in het najaar van 1998 heet Dammen; zie ook het tiende werkcollege.

Voor deze programmeeropgave gaan we het damspel programmeren, zij het ietwat aangepast. Het is de bedoeling een klasse Dambord te maken, die onder meer memberfuncties heeft als afdrukken, spelerzet en computerzet. Uiteraard heeft deze klasse ook een constructor en een destructor. Verder moeten gedane zetten met behulp van een stapel ongedaan gemaakt kunnen worden.

Het "normale" damspel gaat als volgt. Op een 10 bij 10 bord, waarvan de vakjes afwisselend wit en zwart zijn, wordt gespeeld met 20 witte en 20 zwarte schijven. Deze staan aan het begin op de zwarte velden: in de beginstand staan de witte schijven op de 4 onderste rijen, de zwarte schijven op de 4 bovenste. Op de onderste rij is het meest linkse veld zwart.
Om de beurt doen de spelers -wit W en zwart Z geheten- een zet; wit begint. Tijdens een zet wordt een steen van de eigen kleur diagonaal één plaats opgeschoven, naar een leeg veld, in de richting van de zijde waar aan het begin de schijven van de tegenstander stonden. Bij deze opgave mag ook één vakje recht vooruit geschoven worden; elke schijf heeft dus 0, 1, 2 of 3 schuif-mogelijkheden. Er kan ook geslagen worden: er wordt dan over een schijf van de tegenstander (die wordt weggehaald) naar een leeg veld er onmiddellijk achter gesprongen, eventueel zelfs achteruit of opzij: dit heet een slagzet. In principe kan een steen in maximaal 8 richtingen (vanzelfsprekend minder bij de randen van het bord) slaan, dus ook horizontaal en verticaal. Als er keuze is tussen zetten geldt dat als er een slagzet is, deze gedaan moet worden; is die er niet, dan een gewone schuifzet. Als er toch nog keuze is uit verschillende zetten, mag er willekeurig gekozen worden, eventueel met behulp van een zelfgemaakte strategie.
Liefhebbers mogen hier hun eigen creativiteit inzetten - mits ze het niet eenvoudiger maken. Eventueel mag een boolean gebruikt worden die kan verbieden horizontaal/verticaal te spelen, zodat het "gewone" damspel ontstaat. Ook mogen in de beginstand eventueel alle plaatsen in de onderste en bovenste rijen gevuld worden met schijven - wellicht leidt dit tot een interessanter spel.
Het spel is afgelopen als de speler die aan beurt is niet meer kan zetten, bijvoorbeeld omdat hij/zij geen schijven meer heeft: de andere speler heeft dan gewonnen. Bij deze programmeeropgave komen geen "dammen" voor: een schijf die aan de andere kant van het bord is gekomen blijft daar staan; alleen achteruit slaan mag nog. Ook "meerslag" komt niet voor.

We spelen het spel als volgt. Allereerst mag de menselijke speler zijn/haar kleur kiezen; de computer speelt dan voor de andere kleur. Vervolgens mag ook de grootte van het bord gekozen worden: het aantal rijen m en het aantal kolommen n. Normaal geldt dus dat m = 10 en n = 10. Het aantal rijen met witte stenen r in de beginstand mag ook gekozen worden; normaal zijn dat er r = 4. Er zijn altijd evenveel rijen met zwarte stenen. Voor m = 6, n = 7 en r = 2 is de beginstand:

     | Z Z Z |
     |Z Z Z Z|
     |       |
     |       |
     | W W W |
     |W W W W|

Per rij staan in het begin op de zwarte vakjes n/2 witte schijven - voor oneven n naar boven of beneden afgerond al naar gelang het aantal zwarte vakjes in de rij. Schrijf een constructor die een pointerstructuur aanlegt, waarbij ieder vakje, naast bijvoorbeeld een char als inhoud, tevens een array met 8 pointers naar de onmiddellijke buren heeft. Dit is misschien niet zo efficiënt, maar vraagt wel om precisie.
Alles wat gebeurt wordt op een stapel bijgehouden, en spelerzetten kunnen zelfs herhaald teruggenomen worden. Hiertoe moeten alle standen worden bijgehouden, of liever gezegd: zodra de speler zet, wordt de oude stand opgeslagen. Er moet dus een memberfunctie kopieer gemaakt worden, die de gehele pointerstructuur kopieert! Eventueel mogen ook de computerzetten onthouden worden - en teruggenomen.
Verder dient er een recursieve memberfunctie vervolg geschreven worden die gegeven een zekere stand het totale aantal mogelijke vervolgpartijen, dat overigens erg groot kan zijn, uitrekent. Dit onderdeel is zeker niet eenvoudig; mocht het ontbreken, dan kost dat één punt.
Als de speler aan zet is, wordt de stand -in eenvoudig formaat- op het scherm getoond, en kan de speler zijn/haar zet doen, of juist de laatste eigen zet (en meteen de tussenliggende computerzet) terugnemen, of het aantal vervolgpartijen voor de huidige stand laten uitrekenen. Als er een niet toegestane zet wordt geprobeerd, moet de speler natuurlijk opnieuw kiezen. De speler mag altijd zelf vrij kiezen uit de mogelijke (slag)zetten, waarbij slaan -zoals eerder beschreven- voorgaat.

Enkele algemene opmerkingen:

Uiterste inleverdatum: voor voltijdstudenten: vrijdag 11 december 1998, 17.00 uur; voor deeltijdstudenten: vrijdag 18 december 1998. In te leveren: schijfje met de C++-files en de makefile (of een en ander per email aan kosters@liacs.nl sturen), en listing op papier, dit alles in de bak in de metalen boekenkast achterin de gang bij de Indyzaal. Te gebruiken compiler: als het maar C++ is. Normering: layout 1; commentaar 2; modulariteit en OOP 3; werking 4.


Vragen en/of opmerkingen kunnen worden gestuurd naar: kosters@liacs.nl.

12 november 1998 - http://www.liacs.nl/home/kosters/pm/op4pm98.html