~~NOTOC~~ ====== Skakbrikker med interface og abstrakt superklasse ====== {{ :images:chess.jpg?500 |}} ---- ===== Motivation ===== I skak har hver brik sine egne regler for, hvordan den må flytte sig på brættet. En konge må f.eks. kun flytte ét felt ad gangen, mens et tårn kan bevæge sig flere felter i lige linjer. Men uanset hvilken brik det er, så kan de **alle forsøge at lave et træk**. Det gør interfaces relevante: De sikrer, at alle brikker har en metode til at lave et træk, selvom reglerne for bevægelse er forskellige. For at genbruge fælles egenskaber (som farve og symbol) laver vi også en abstrakt superklasse `Brik`, som alle konkrete brikker nedarver fra. ----- ===== Opgave ===== 1. Definér et interface `IBrik` med en metode: bool MovePiece(IBrik[,] board, int fromRow, int fromCol, int toRow, int toCol); som prøver at flytte brikken på skakbrættet. Metoden skal returnere `true`, hvis trækket er lovligt og brikken flyttes, ellers `false`. 2. Definér en **abstrakt** klasse . Klassen skal indeholde: - En egenskab `Farve` af typen enum `BrikFarve` (Hvid/Sort). (eller blot en char) - En abstrakt egenskab `Symbol` (char), som viser brikkens symbol. 3. Lav en konkret klasse `Konge`, som nedarver fra `Brik`. * Implementér `MovePiece` metoden for kongens bevægelsesregler: * Kongen må flytte ét felt i alle retninger (op, ned, til siderne og diagonalt). 4. Skriv et simpelt test program, som: - Opretter et 8x8 skakbræt (array af `IBrik`), - Placér en hvid konge i position `(0, 0)`, - Læs brugerinput til at flytte brikken: * Fra række/kolonne og til række/kolonne (tal mellem 0 og 7), - Kald `MovePiece` og vis om trækket lykkedes eller ej, - Vis brættet i konsollen efter hvert træk med brikkernes symboler. ----- ===== Hint og gode råd ===== ++++ Hint - er trækket inde for pladen | Husk at tjekke, at de angivne rækker og kolonner er inden for brættets grænser (0 til 7). bool ErIndenforBræt(int row, int col) { return row >= 0 && row < 8 && col >= 0 && col < 8; } ++++ ++++ Hint - er det en brik op destinationsfeltet | I `MovePiece`-metoden kan du tjekke om destinationen er tom eller har en modstanders brik: if (board[toRow, toCol] == null || board[toRow, toCol].Farve != this.Farve) { // lovligt træk } ++++ ++++ Hint - er trækket inde for pladen | For kongens regler: flyt kun ét felt i alle retninger (inkl. diagonalt): int rowDiff = Math.Abs(toRow - fromRow); int colDiff = Math.Abs(toCol - fromCol); if (rowDiff <= 1 && colDiff <= 1 && (rowDiff + colDiff != 0)) { // gyldigt træk } ++++ ++++ Hint - opdatering af board efter træk | Når trækket er gyldigt, skal du opdatere brættet således: board[toRow, toCol] = this; board[fromRow, fromCol] = null; ++++ ----- ===== Udvidelse ===== * Implementér flere brikker som `Taarn` (tårn), `Loeber` (løber) med deres regler. * Tilføj spil-logik, så to spillere kan skiftes til at flytte brikker. * Tilføj validering, så spilleren ikke kan flytte en brik der ikke tilhører dem. ----- ===== Perspektivering ===== I denne øvelse kombinerer vi: * **Interface** — for at sikre, at alle brikker har en `MovePiece` metode. * **Abstrakt klasse** — for at samle fælles egenskaber som `Farve` og `Symbol`. Dette er en grundlæggende måde at tænke objektorienteret programmering på — med fokus på både **kontrakter (interfaces)** og **genbrug af kode (nedarvning)**. ----