001 /**
002 *
003 */
004 package jagafa;
005
006 import jagafa.object.Board;
007 import jagafa.object.Card;
008 import jagafa.object.Distributor;
009 import jagafa.object.GoneCardHeap;
010 import jagafa.object.Player;
011 import jagafa.rule.RuleSet;
012 import jagafa.scores.ScoreTable;
013
014 import java.awt.event.ActionEvent;
015 import java.awt.event.ActionListener;
016 import java.util.Iterator;
017 import java.util.LinkedList;
018 import java.util.List;
019 import java.util.Observable;
020
021 import javax.swing.Timer;
022 import javax.swing.event.EventListenerList;
023
024 /**
025 * @author Besitzer
026 *
027 */
028 public abstract class JassRoundCore extends Observable {
029
030 /* TODO: Externalize FINAL_ROUND_SCORE and LAST_TURN_SCORE */
031 private static final int LAST_TURN_SCORE = 5;
032
033 private static final int FINAL_ROUND_SCORE = 152;
034
035 private static final int PLAYERS = 4;
036
037 private static final String UPDATED_EVENT = "UPDATED";
038
039 private static final int BOARD_SIZE = 4;
040
041 private EventListenerList listeners_;
042
043 private RuleSet rules_;
044
045 private Board activeBoard_;
046
047 private List<Player> players_;
048
049 private Player activePlayer_;
050
051 private Iterator<Player> playerIterator_;
052
053 private Player lastTurnWinner_;
054
055 private GoneCardHeap goneHeap_;
056
057 protected boolean running_ = false;
058
059 protected Timer refreshTimer_;
060
061 protected Timer aiTimer_;
062
063 protected ScoreTable scoreTable_;
064
065 /**
066 * Initialize a new game using the RuleSet given
067 */
068 public JassRoundCore(RuleSet rules) {
069 reset();
070 this.setRules(rules);
071
072
073 this.toggleNotify();
074 }
075
076 /**
077 * Set the RuleSet
078 */
079 public void setRules(RuleSet r) {
080 this.rules_ = r;
081 this.sortHands();
082 }
083
084 public boolean isRunning() {
085 return this.running_;
086 }
087
088 /**
089 * Returns the active Players' id
090 */
091 public int activePlayerNr() {
092 for (int i = 0; i < PLAYERS; i++) {
093 Player p = this.players_.get(i);
094 if (p == activePlayer()) {
095 return i;
096 }
097 }
098 return -1;
099 }
100
101 /**
102 * Returns the active Player
103 */
104 public Player activePlayer() {
105 return this.activePlayer_;
106 }
107
108 /**
109 * Counts the score on a board
110 */
111 protected int getScore(Board board) {
112 int sum = 0;
113 for (int i = 0; i < BOARD_SIZE; i++) {
114 sum += rules_.getScore(board.get(i));
115 }
116
117 return sum;
118 }
119
120 /**
121 * Returns the winning Player of the board given
122 */
123 protected Player getWinner(Board board) {
124 for (int i = 0; i < BOARD_SIZE; i++) {
125 Card c = board.get(i);
126 if (rules_.compareHigher(c, board)) {
127
128 int startPlayer = Integer.valueOf(lastTurnWinner_.getName()).intValue();
129 int winner = startPlayer + i;
130 if (winner >= PLAYERS) {
131 winner -= PLAYERS;
132 }
133
134 return this.getPlayer(winner);
135 }
136 }
137 return null;
138 }
139
140 /**
141 * Returns true if the game is over
142 */
143 public boolean isRoundOver() {
144 int sum1 = this.getPlayer(0).getScore() + this.getPlayer(2).getScore();
145 int sum2 = this.getPlayer(1).getScore() + this.getPlayer(3).getScore();
146 if (sum1 + sum2 == FINAL_ROUND_SCORE) {
147 return true;
148 }
149 if (sum1 + sum2 == FINAL_ROUND_SCORE + LAST_TURN_SCORE) {
150 return true;
151 }
152
153 return false;
154
155 }
156
157 /**
158 * Sets the active player to the next
159 */
160 protected Player nextPlayer() {
161 if (!this.playerIterator_.hasNext()) {
162 this.playerIterator_ = this.players_.iterator();
163 }
164 this.activePlayer_ = playerIterator_.next();
165 return activePlayer();
166 }
167
168 /**
169 * Set the active player
170 */
171 public void setActivePlayer(Player playerToSet) {
172 while (this.activePlayer() != playerToSet) {
173 this.nextPlayer();
174 }
175 }
176
177 /**
178 * Notify observers and fire all action-listeners
179 */
180 public void toggleNotify() {
181 this.setChanged();
182 this.notifyObservers();
183 this.clearChanged();
184 this.fireAction();
185 }
186 /*
187 public void addActionListener(ActionListener l) {
188 this.listeners_.add(ActionListener.class, l);
189 }
190 */
191 private void fireAction() {
192 Object[] listeners = this.listeners_.getListenerList();
193 for (int i = listeners.length - 2; i >= 0; i -= 2) {
194 if (listeners[i] == ActionListener.class) {
195 ActionEvent fooEvent = new ActionEvent(this, 0, UPDATED_EVENT);
196 ((ActionListener) listeners[i + 1]).actionPerformed(fooEvent);
197 }
198 }
199
200 }
201
202 /**
203 * Returns the player with the id given
204 */
205 public Player getPlayer(int i) {
206 while (i >= 4) {
207 i -= 4;
208 }
209 return this.players_.get(i);
210 }
211
212 /**
213 * Returns the Player which was the winner of the previous turn
214 */
215 protected Player getLastTurnWinner() {
216 return this.lastTurnWinner_;
217 }
218
219 /**
220 * Returns an id for the player p
221 */
222 public int getPlayerNr(Player p) {
223 for (int i = 0; i < PLAYERS; i++) {
224 if (this.getPlayer(i) == p) {
225 return i;
226 }
227
228 }
229 return -1;
230
231 }
232
233 /**
234 * Returns the RuleSet
235 */
236 public RuleSet getRules() {
237 return this.rules_;
238 }
239
240 /**
241 * Returns the Gone Card Heap
242 */
243 public GoneCardHeap getGoneHeap() {
244 return this.goneHeap_;
245 }
246
247 /**
248 * Returns the Partner of Player pl
249 */
250 public Player getPartner(Player pl) {
251 int nr = this.getPlayerNr(pl);
252 nr += 2;
253 if (nr >= 4) {
254 nr -= PLAYERS;
255 }
256
257 return this.getPlayer(nr);
258 }
259
260 /**
261 * Returns the opponents of the Player p
262 */
263 public Player[] getOpponents(Player p) {
264 Player opp[] = new Player[2];
265
266 int nr = this.getPlayerNr(p);
267
268 nr += 1;
269 if (nr > 3) {
270 nr -= PLAYERS;
271 }
272 opp[0] = this.getPlayer(nr);
273 nr = this.getPlayerNr(opp[0]) + 2;
274 if (nr > 3) {
275 nr -= PLAYERS;
276 }
277 opp[1] = this.getPlayer(nr);
278 return opp;
279
280 }
281
282 /**
283 * Checks wether a card is valid to play on the active Board or not
284 */
285 public boolean isValidPlay(Card toPlay) {
286 if (refreshTimer_==null) {
287 return false;
288 }
289
290 if (!refreshTimer_.isRunning()) {
291 return this.rules_.isValid(toPlay, activePlayer().getHand(),
292 this.activeBoard_);
293 } else {
294
295 return false;
296
297 }
298 }
299
300 /**
301 * Returns the active Board
302 */
303 public Board activeBoard() {
304 return this.activeBoard_;
305 }
306
307 /**
308 * Reset everything
309 */
310 public void reset() {
311 this.running_ = false;
312
313 this.players_ = new LinkedList<Player>();
314 this.listeners_ = new EventListenerList();
315 this.activeBoard_ = new Board();
316 this.goneHeap_ = new GoneCardHeap();
317
318 initPlayers();
319
320 distributeCards();
321
322 this.playerIterator_ = players_.iterator();
323 this.activePlayer_ = this.playerIterator_.next();
324 this.lastTurnWinner_ = this.activePlayer_;
325 this.toggleNotify();
326
327
328
329
330 }
331
332
333 /**
334 * Distribute the cards to the four players
335 */
336 private void distributeCards() {
337 Distributor.distributeCardsTo(this.players_);
338 sortHands();
339 }
340
341 /**
342 * Sort the players hands (only if the RuleSet is set)
343 *
344 */
345 private void sortHands() {
346 if (this.getRules() == null) {
347 return;
348 }
349 for (int i = 0; i < PLAYERS; i++) {
350 Player p = this.getPlayer(i);
351 p.getHand().sort(this.getRules());
352 }
353 }
354
355 protected abstract void initPlayers();
356
357 protected void setLastTurnWinner(Player winner) {
358 this.lastTurnWinner_ = winner;
359
360 }
361
362 protected void addPlayer(Player newPlayer) {
363 this.players_.add(newPlayer);
364 }
365
366 /**
367 * Sets the score table
368 * @param table The relevant score table where the rounds score will be reported
369 */
370 public void setScoreTable(ScoreTable table) {
371 this.scoreTable_ = table;
372
373 }
374
375 /**
376 * Get the score table
377 * @return The score table relevant for this round
378 */
379 public ScoreTable getScoreTable() {
380 return this.scoreTable_;
381 }
382
383 /**
384 * Update the score table after a round is finished
385 * (Report round scores to top-level game)
386 */
387 protected void reportScores() {
388 if (!this.isRoundOver()) {
389 return;
390 }
391 if (getScoreTable() != null) {
392 int scores[] = new int[4];
393 for (int i = 0; i < 4; i++) {
394 scores[i] = this.getPlayer(i).getScore();
395 }
396
397 this.getScoreTable().addScores(scores, this.getRules());
398
399 /*
400 if (this.getScoreTable().isGameOver()) {
401 int t1 = this.getScoreTable().getScores()[0]
402 + this.getScoreTable().getScores()[2];
403 int t2 = this.getScoreTable().getScores()[1]
404 + this.getScoreTable().getScores()[3];
405 System.out.println("Schieber is over! " + t1 + " " + t2);
406 this.running_ = false;
407 }*/
408 }
409 }
410
411 public void stop() {
412 this.running_ = false;
413 if (this.aiTimer_ != null && this.refreshTimer_!=null) {
414 this.aiTimer_.stop();
415 this.refreshTimer_.stop();
416 }
417
418 }
419 }