001 package de.hska.java.aufgaben.backtracking;
002
003 import java.util.Arrays;
004
005
006 /**
007 * Das Spielfeld für das Englische Solitär mit 32 Feldern.
008 * Die einzelnen Felder haben "kartesische" Koordinaten von 0 bis 6 in der Breite
009 * und 0 bis 6 in der Höhe.
010 * </p>
011 <table border=1>
012 <tr><td> </td><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td></tr>
013 <tr><td>0</td><td></td><td> </td><td>X</td><td>X</td><td>X</td><td> </td><td> </td></tr>
014 <tr><td>1</td><td> </td><td> </td><td>X</td><td>X</td><td>X</td><td> </td><td> </td></tr>
015 <tr><td>2</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td></tr>
016 <tr><td>3</td><td>X</td><td>X</td><td>X</td><td>O</td><td>X</td><td>X</td><td>X</td></tr>
017 <tr><td>4</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td></tr>
018 <tr><td>5</td><td> </td><td> </td><td>X</td><td>X</td><td>X</td><td> </td><td> </td></tr>
019 <tr><td>6</td><td> </td><td> </td><td>X</td><td>X</td><td>X</td><td> </td><td> </td></tr>
020 </table>
021 *
022 * @author Christian Pape
023 *
024 */
025 public class SolitaerSpielfeld {
026
027 private static final int BESETZT = 1;
028
029 private static final int FREI = 2;
030
031 private static final int RECHTS = 0;
032 private static final int OBEN = 1;
033 private static final int LINKS = 2;
034 private static final int UNTEN = 3;
035
036 /**
037 * Enthält die erlaubten Richtungen, in die gesprungen werden darf.
038 * In der Praxis würde man besser Aufzählungstypen (enum) verwenden.
039 */
040 private static int [] richtungen = {RECHTS, OBEN, LINKS, UNTEN};
041
042 /**
043 * Das Spielfeld mit den Werten 1 = Stein, 2 = Leeres Feld und 0 = nicht benutztes Feld.
044 * Die Startkonfiguration wird als Voreinstellung verwendet.
045 */
046 private int [] [] spielfeld = {
047 {0, 0, 1, 1, 1, 0, 0},
048 {0, 0, 1, 1, 1, 0, 0},
049 {1, 1, 1, 1, 1, 1, 1},
050 {1, 1, 1, 2, 1, 1, 1},
051 {1, 1, 1, 1, 1, 1, 1},
052 {0, 0, 1, 1, 1, 0, 0},
053 {0, 0, 1, 1, 1, 0, 0}
054 };
055
056 /**
057 * Die Breite des Spielfelds (sollte immer 7 sein).
058 */
059 public int getBreite() {
060 return spielfeld.length;
061 }
062
063 /**
064 * Die Höhe des Spielfelds (sollte immer 7 sein).
065 */
066 public int getHoehe() {
067 return spielfeld.length;
068 }
069
070 public void feldFreimachen(int x, int y) {
071 spielfeld[x][y] = FREI;
072 }
073
074 public void feldBesetzen(int x, int y) {
075 spielfeld[x][y] = BESETZT;
076 }
077
078 /**
079 * Kopiert den Zustand des Spielfelds <code>vonSpielfeld</code>
080 * in das Spielfeld <code>nachSpielfeld</code>
081 */
082 public void kopiereSpielfeld(SolitaerSpielfeld vonSpielfeld, SolitaerSpielfeld nachSpielfeld) {
083 for (int x = 0; x < getBreite(); x++) {
084 for (int y = 0; y < getHoehe(); y++) {
085 nachSpielfeld.spielfeld[x][y] = vonSpielfeld.spielfeld[x][y];
086 }
087 }
088 }
089
090 /**
091 * Prüft, ob ein Spielstein an Stelle x und y, ein leeres Feld
092 * an Stelle neuesX und neuesY ist und eine Spielfigur dazwischen voranden ist.
093 * Es wird nicht geprüft, ob von x,y korrekt 2 Stellen nach links/rechts oder
094 * oben/unten gesprungen wurde.
095 */
096 private boolean isGueltigerZug(int x, int y, int neuesX, int neuesY) {
097 return 0 <= x && x < spielfeld.length
098 && 0 <= y && y < spielfeld[x].length
099 && 0 <= neuesX && neuesX < spielfeld.length
100 && 0 <= neuesY && neuesY < spielfeld[neuesX].length
101 && spielfeld[neuesX][neuesY] == FREI
102 && spielfeld[(x + neuesX) / 2][(y + neuesY) / 2] == BESETZT
103 && spielfeld[x][y] == BESETZT;
104
105 }
106
107 /**
108 * Nimmt die "Spielfigur" vom Feld (x,y) und spring in die gegeben <code>richtung</code>
109 * zwei Felder weiter in das leere Feld. Die Spielfigur dazwischen wird weggebenommen.
110 * Wenn es sich nicht um einen gütligen Sprung handelt, dann wird false zurückgegeben und
111 * das Spielfeld bleibt unverändert.
112 *
113 * @return true, wenn es sich um einen gültigen Sprung handelt, ansonsten false.
114 */
115 public boolean springe(int x, int y, int richtung) {
116 int neuesX = getNeuesX(x, richtung);
117 int neuesY = getNeuesY(y, richtung);
118
119 if ( isGueltigerZug(x, y, neuesX, neuesY)) {
120 feldBesetzen(neuesX, neuesY);
121 feldFreimachen(x, y);
122 // Das mittlere Feld bekommt man einfach als Mittelpunkt
123 // der beiden kartesischen Koordinate von Start und Zielpunkt des
124 // Sprunges
125 feldFreimachen((x + neuesX) / 2, (y + neuesY) / 2);
126
127 return true;
128 }
129
130 return false;
131 }
132
133
134 /**
135 * Macht einen Sprung von (x,y) in die gegeben <code>richtung</code>
136 * wieder rückgängig. Es wird nicht geprüft, ob der Sprung wirklich
137 * erlaubt ist.
138 */
139 public void zurueckSpringen(int x, int y, int richtung) {
140 int neuesX = getNeuesX(x, richtung);
141 int neuesY = getNeuesY(y, richtung);
142
143 feldFreimachen(neuesX, neuesY);
144 feldBesetzen(x, y);
145 feldBesetzen((x + neuesX) / 2, (y + neuesY) / 2);
146 }
147
148 /**
149 * Gibt die x-Koordinate für einen Sprung ausgehend von <code>x</code>
150 * in die gegeben <code>richtung</code> zurück.
151 */
152 private int getNeuesX(int x, int richtung) {
153 int neuesX = x;
154 switch (richtung) {
155 case RECHTS: neuesX += 2;
156 break;
157 case LINKS: neuesX -= 2;
158 }
159 return neuesX;
160 }
161
162 /**
163 * Gibt die y-Koordinate für einen Sprung ausgehend von <code>y</code>
164 * in die gegeben <code>richtung</code> zurück.
165 */
166 private int getNeuesY(int y, int richtung) {
167 int neuesY = y;
168
169 switch (richtung) {
170 case OBEN: neuesY -= 2;
171 break;
172 case UNTEN: neuesY += 2;
173 }
174
175 return neuesY;
176 }
177 /**
178 * Gibt den Inhalt dieses Spielfelds auf dem Bildschirm aus.
179 * Die Werte haben folgende Bedeutung:
180 * <ul>
181 * <li>0 = kein gültiges Spielfeld.</li>
182 * <li>1 = Feld mit einem Spielstein.</li>
183 * <li>2 = Feld ohne Spielstein.</li>
184 * </ul>
185 */
186 public void ausgeben() {
187 for (int x = 0; x < spielfeld.length; x++) {
188 for (int y = 0; y < spielfeld[x].length; y++) {
189 System.out.print(spielfeld[x][y]);
190 }
191 System.out.println();
192 }
193 System.out.println();
194 }
195
196 /**
197 * Gibt genau dann true zurück, wenn eine Spielfigur
198 * an der Position (x,y) vorhanden ist.
199 */
200 public boolean isBesetzt(int x, int y) {
201 return spielfeld[x][y] == BESETZT;
202 }
203
204 /**
205 * Gibt ein Feld mit allen Werten für die Sprungrichtungen zurück.
206 */
207 public int [] getRichtungen() {
208 // es wird immer ein Kopie zurückgegeben, um zu verhindern,
209 // das die Werte innerhalb des Feldes richtungen verändert werden
210 return Arrays.copyOf(richtungen, richtungen.length); // JDK 1.6 nötig
211 }
212 }