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    }