MODULE Schaken_john; (* John Lataire *) (* Het schaakbord bestaat uit een matrix van 8 rijen en 8 kolommen. Het schaakspel wordt gespeeld tussen de witte en zwarte stukken, we beperken het hier tot 3 types van stukken: dame, loper en toren. Een dame mag in alle 8 richtingen (ook schuin) bewegen, een loper mag enkel schuin bewegen en een toren mag enkel recht bewegen. Alle drie mogen per zet een onbeperkt aantal vakjes in een bepaalde richting zetten, zolang ze maar binnen het bord blijven. Gegeven is een bepaalde schaaksituatie (run het programma). Gevraagd: (1) Maak de procedure 'IsZetBinnenBord' die voor een gegeven stuk en gegeven richting nagaat of het stuk nog binnen het bord is als het 1 stap in die richting zet. Gebruik hier best de gegeven array 'gZetVectoren', bestudeer deze!! (2) Maak de procedure 'KanStukSlaanInRichting' die voor een gegeven stuk en richting nagaat of het stuk in die richting een ander vijandelijk stuk kan slaan. De procedure geeft terug of dit kan en indien dit kan de index van het vijandelijk stuk in de lijst 'gStukken'. Het stuk voert de zet NIET uit. Merk bovendien op dat een stuk niet over een ander mag springen. (3) Maak de procedure 'IsGeldigeRichting' die nagaat of een stuk in een bepaalde richting mag bewegen (zie schaakregels). Gebruik voor de berekening liefst ORD(richting). (4) Tel voor alle stukken hoeveel vijandelijke stukken het kan slaan (in alle geldige richtingen) en druk dit af. Tip: maak gebruik van (3). (5) Speel het schaakspel vanuit de gegeven situatie: wit en zwart spelen om beurten, wit begint. Elke kleur pakt om beurten 1 vijandelijk stuk. Speel tot geen van beide kleuren nog een stuk kan slaan. Als 1 kleur niets kan pakken, moet hij niets zetten (voor de gemakkelijkheid). Druk de zetten en de overblijvende stukken af. Er zijn soms meerdere zetten mogelijk. Indien haalbaar zoek je tussen alle keuzes degene die het voordeligst is voor wit (= meest overblijvende stukken), anders mag je een zet naar keuze uitvoeren. Opmerkingen: - maak de procedures algemeen, zodat ze voor elke gegeven schaaksituatie blijven werken. - merk op dat je in een procedure een RETURN niet noodzakelijk op het einde moet zetten. Je mag de RETURN ook in het midden binnen iteraties zetten, de procedure wordt dan onmiddellijk beeindigd. Dit kan handig zijn. - maak gebruik van de procedure 'WrStukRc' voor het afdrukken, definitie: PROCEDURE WrStukRc(stuk: StukRc); *) FROM IO IMPORT WrStr, WrLn, RdCard, WrCard, RdInt, WrInt, RdKey, RdLn, WrFixReal; CONST AANTAL_STUKKEN = 6; (* aantal stukken op het bord *) BORD_GROOTTE = 8; TYPE RichtingEn = (VOORUIT, VOORUIT_RECHTS, RECHTS, ACHTERUIT_RECHTS, ACHTERUIT, ACHTERUIT_LINKS, LINKS, VOORUIT_LINKS); (* alle 8 mogelijke richtingen, schuin & recht, in wijzerszin *) VectorRc = RECORD rij, kolom: INTEGER; END; TypeEn = (DAME, TOREN, LOPER); KleurEn = (WIT, ZWART); StukRc = RECORD (* eigenschappen van een stuk *) type: TypeEn; kleur: KleurEn; positie: VectorRc; gepakt: BOOLEAN; (* of stuk gepakt is, staat initieel op FALSE *) END; VAR (* globale variabelen *) gStukken: ARRAY[1..AANTAL_STUKKEN] OF StukRc; (* lijst met alle stukken van het bord *) gBord: ARRAY[1..BORD_GROOTTE],[1..BORD_GROOTTE] OF [0..AANTAL_STUKKEN]; (* het schaakbord, 0 betekent een lege vak, een stuk op die positie wordt aangegeven met de index uit gStukken *) gZetVectoren: ARRAY RichtingEn OF VectorRc; (* voor elke richting bepaalt de vector hoe 1 stap in die richting te zetten, vector voor VOORUIT is (1, 0), VOORUIT_LINKS is (1, -1), ACHTERUIT_RECHTS is (-1, 1), enz. gebruik dit in combinatie met de gegeven procedure VoegVectorToe, definitie: PROCEDURE VoegVectorToe(VAR vector1: VectorRc; vector2: VectorRc); procedure telt vector2 op bij vector 1 *) (************************** GEGEVEN PROCEDURES ***********************************) PROCEDURE Initialisatie(); (* Initialisatie van alle globale variabelen *) VAR i: CARDINAL; positie: VectorRc; BEGIN gZetVectoren[VOORUIT] := VectorRc{ 1, 0}; gZetVectoren[VOORUIT_RECHTS] := VectorRc{ 1, 1}; gZetVectoren[RECHTS] := VectorRc{ 0, 1}; gZetVectoren[ACHTERUIT_RECHTS] := VectorRc{-1, 1}; gZetVectoren[ACHTERUIT] := VectorRc{-1, 0}; gZetVectoren[ACHTERUIT_LINKS] := VectorRc{-1, -1}; gZetVectoren[LINKS] := VectorRc{ 0, -1}; gZetVectoren[VOORUIT_LINKS] := VectorRc{ 1, -1}; gStukken[1] := StukRc{DAME, WIT, VectorRc{4, 1}, FALSE}; gStukken[2] := StukRc{LOPER, WIT, VectorRc{1, 1}, FALSE}; gStukken[3] := StukRc{TOREN, WIT, VectorRc{8, 4}, FALSE}; gStukken[4] := StukRc{TOREN, ZWART, VectorRc{1, 4}, FALSE}; gStukken[5] := StukRc{LOPER, ZWART, VectorRc{6, 6}, FALSE}; gStukken[6] := StukRc{DAME, ZWART, VectorRc{8, 8}, FALSE}; FOR i := 1 TO AANTAL_STUKKEN DO (* vullen gBord *) positie := gStukken[i].positie; gBord[positie.rij][positie.kolom] := i; END; END Initialisatie; PROCEDURE VoegVectorToe(VAR vector1: VectorRc; vector2: VectorRc); (* procedure telt vector2 op bij vector 1 *) BEGIN vector1.rij := vector1.rij + vector2.rij; vector1.kolom := vector1.kolom + vector2.kolom; END VoegVectorToe; PROCEDURE WrStukRc(stuk: StukRc); (* schrijft de eigenschappen van een stuk naar het scherm *) BEGIN IF stuk.kleur = WIT THEN WrStr("witte "); ELSE WrStr("zwarte ");END; CASE stuk.type OF DAME: WrStr("dame"); | LOPER: WrStr("loper"); | TOREN: WrStr("toren"); END; WrStr(" op ");WrCard(stuk.positie.rij, 0);WrStr(", ");WrCard(stuk.positie.kolom, 0); END WrStukRc; (********************************************************************************) (******** wat hierboven staat, moet je normaal gezien niet aan te passen *********) (************************ ZET HIER UW PROCEDURES *********************************) PROCEDURE IsZetBinnenBord(stuk:StukRc;richting:RichtingEn):BOOLEAN; VAR nieuwePos:VectorRc; BEGIN nieuwePos:=stuk.positie; VoegVectorToe(nieuwePos,gZetVectoren[richting]); IF (nieuwePos.rij<9) AND (nieuwePos.rij>0) AND (nieuwePos.kolom<9) AND (nieuwePos.kolom>0) THEN RETURN TRUE ELSE RETURN FALSE; END; END IsZetBinnenBord; PROCEDURE KanStukSlaanInRichting(stuk:StukRc;richting:RichtingEn;VAR index:INTEGER):BOOLEAN; VAR i:INTEGER; BEGIN WHILE IsZetBinnenBord(stuk, richting) DO VoegVectorToe(stuk.positie,gZetVectoren[richting]); FOR i:= 1 TO AANTAL_STUKKEN DO (* J*) IF NOT gStukken[i].gepakt THEN IF (stuk.positie.rij=gStukken[i].positie.rij) AND (stuk.positie.kolom=gStukken[i].positie.kolom) THEN index:=i; IF stuk.kleur<>gStukken[index].kleur THEN (*Checken of het wel een tegenstander is*) RETURN TRUE; ELSE RETURN FALSE; END; END; END; END; END; RETURN FALSE; END KanStukSlaanInRichting; PROCEDURE IsGeldigeRichting(stuk:StukRc;richting:RichtingEn):BOOLEAN; BEGIN CASE stuk.type OF DAME: RETURN TRUE;| (*de dame mag elke zet uitvoeren*) TOREN: IF ORD(richting) MOD 2 = 0 THEN (*de toren mag elke EVEN zet uitvoeren:ORD(vooruit) = 0,ORD(achteruit) = 2*) RETURN TRUE; ELSE RETURN FALSE; END;| LOPER: IF ORD(richting) MOD 2 = 1 THEN (* de loper mag elke ONEVEN zet uitvoeren *) RETURN TRUE; ELSE RETURN FALSE; END; END; END IsGeldigeRichting; PROCEDURE AantalStukkenSlaan(stuk:StukRc; VAR slaRichting: RichtingEn):INTEGER; VAR richt:RichtingEn; aantal,tempIndex:INTEGER; BEGIN aantal:=0; FOR richt:= VOORUIT TO VOORUIT_LINKS DO IF IsGeldigeRichting(stuk,richt) THEN IF KanStukSlaanInRichting(stuk,richt,tempIndex) THEN slaRichting := richt; (* richting van slaan geven we als VAR-parameter terug *) aantal:=aantal + 1; END; END; END; RETURN aantal; END AantalStukkenSlaan; PROCEDURE Play; VAR turn:KleurEn; played,played2:BOOLEAN; index,slaagstuk,i:INTEGER; richting:RichtingEn; c : CHAR; BEGIN turn:=ZWART; played2:=TRUE; LOOP IF turn = ZWART THEN WrStr("WIT aan zet: "); turn:= WIT; ELSE turn:= ZWART; WrStr("ZWART aan zet: "); END; played:=FALSE; FOR index:= 1 TO AANTAL_STUKKEN DO IF NOT gStukken[index].gepakt THEN (* J *) IF (gStukken[index].kleur = turn) AND NOT played THEN (*controleren of het zijn beurt is*) IF AantalStukkenSlaan(gStukken[index],richting)>0 THEN IF KanStukSlaanInRichting(gStukken[index],richting,slaagstuk) THEN WrStukRc(gStukken[index]);WrStr(" pakt stuk ");WrStukRc(gStukken[slaagstuk]);WrLn; (* J *) gBord[gStukken[index].positie.rij][gStukken[index].positie.kolom]:=0; (*het stuk van haar oorspronkelijke plaats weghalen*) gStukken[index].positie:=gStukken[slaagstuk].positie; (*het stuk op de plaats zetten van het geslaagde stuk*) gStukken[slaagstuk].gepakt:=TRUE; gBord[gStukken[index].positie.rij][gStukken[index].positie.kolom]:=index; played:= TRUE; END; END; END; END; END; IF NOT played AND played2 THEN (*deze zes regels bepalen of er gespeeld werd*) played2:=FALSE; (*indien dit niet het geval, gaat men na of er de vorige keer gespeeld werd*) ELSIF NOT played AND NOT played2 THEN (*indien de vorige keer niet gespeeld werd, wordt het programma beeindigd*) EXIT; (*indien de vorige keer wel gespeeld werd, wordt er bijgehouden in played 2 dat er deze keer niet gespeeld werd*) ELSIF played THEN played2:=TRUE; (*indien deze keer wel gespeeld werd, wordt played2 geinitialiseerd*) END; END; (* LOOP *) END Play; (*********************************************************************************) VAR x: CHAR; i: CARDINAL; tempRichting:RichtingEn; BEGIN WrLn; Initialisatie(); WrStr("De initieel gegeven schakensituatie:");WrLn;WrLn; FOR i := 1 TO AANTAL_STUKKEN DO WrStukRc(gStukken[i]); WrStr(" kan "); WrInt(AantalStukkenSlaan(gStukken[i], tempRichting),0); (*Schrijft erbij hoeveel stukken dit stuk kan slaan*) WrStr(" stuk(ken) slaan"); WrLn; END; Play; END Schaken_john.