View Javadoc

1   // START LICENSE
2   // JSet - a Java JSet card board game implementation
3   // Copyright (C) 2004 Jerome Lacoste
4   //
5   // This program is free software; you can redistribute it and/or modify
6   // it under the terms of the GNU General Public License as published by
7   // the Free Software Foundation; either version 2 of the License, or (at
8   // your option) any later version.
9   //
10  // This program is distributed in the hope that it will be useful, but
11  // WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // General Public License for more details.
14  //
15  // You should have received a copy of the GNU General Public License
16  // along with this program; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  // END LICENSE
19  
20  package org.cb.jset.client;
21  
22  import org.apache.log4j.Logger;
23  import org.cb.jset.*;
24  import org.cb.jset.server.RemoteSetGame;
25  
26  import java.util.List;
27  import java.util.ArrayList;
28  
29  /***
30   * A player that finds sets automatically.
31   *
32   * @author jerome@coffeebreaks.org - last modified by $LastChangedBy: jerome $
33   * @version $Id: SmartAutoPlayer.java 123 2004-04-14 23:45:53Z jerome $
34   */
35  public class SmartAutoPlayer implements SetGameListener
36  {
37    private Logger _logger;
38    private SetFinderThread _thread;
39    private MatchingSetFinder _finder;
40    private String _name;
41    private NetworkGame _game;
42    private BoardImpl _board = new BoardImpl();
43  
44    private final GameController _gameController = new GameController();
45  
46    /***
47     * Creates a new instance with the specified player playerName.
48     */
49    public SmartAutoPlayer(final String playerName)
50    {
51      _logger = Logger.getLogger("SmartAutoPlayer-" + playerName);
52      _name = playerName;
53      _finder = new MatchingSetFinder();
54      _thread = new SetFinderThread();
55    }
56  
57    public String name()
58    {
59      return _name;
60    }
61  
62    private void printCards(final String msg, final CardProperties[] cards)
63    {
64      if (_logger.isInfoEnabled())
65      {
66        final StringBuffer buf = new StringBuffer(msg);
67        buf.append(CardProperties.toString(cards));
68        _logger.info(buf.toString());
69      }
70    }
71  
72    void startPlayingGame(final RemoteSetGame game)
73    {
74      final NetworkGame networkGame = new NetworkGame("SmartAutoPlayerUser");
75      networkGame.setRemoteGame(game);
76      _game = networkGame;
77      _game.addBoardListener(_gameController);
78      _game.addGameListener(_gameController);
79      _game.start();
80      _thread.start();
81    }
82  
83  
84    /***
85     * Control events coming from the game instance.
86     * 
87     * FIXME we probably need to add multithreading handling on the model.
88     */
89    class GameController implements SetGameBoardListener, SetGameListener
90    {
91      /***
92       * @inheritDoc
93       */
94      public void cardsAdded(final CardProperties[] cards)
95      {
96        _board.addCards(cards);
97      }
98  
99      /***
100      * @inheritDoc
101      */
102     public void setRemoved(final CardSet set)
103     {
104       try
105       {
106         _board.matchSet(set);
107       }
108       catch (Exception e)
109       {
110         throw new IllegalStateException("BoardException should not happen here: " + e.getMessage());
111       }
112     }
113 
114     /***
115      * @inheritDoc
116      */
117     public void gameChange(final GameEvent event)
118     {
119       // FIXME
120     }
121   }
122 
123   // FIXME: not sure if we really need that.
124   public synchronized void gameChange(final GameEvent event)
125   {
126     if (event.getType() == GameEvent.END)
127     {
128       notifyAll();
129     }
130   }
131 
132   class SetFinderThread extends Thread
133   {
134     public void run()
135     {
136       play();
137     }
138   }
139 
140   private void play()
141   {
142     while (! _game.wasDisconnected())
143     {
144       tryToFindSet();
145     }
146   }
147 
148   void tryToFindSet()
149   {
150     if (_logger.isInfoEnabled())
151     {
152       _logger.info("-- cards added - starting to find --");
153     }
154     int sleepTime = (int) (Math.random() * 6000);
155     if (_logger.isInfoEnabled())
156     {
157       _logger.info("Sleep for " + sleepTime + "ms.");
158     }
159     try
160     {
161       synchronized (SmartAutoPlayer.this)
162       {
163         wait(sleepTime);
164       }
165     }
166     catch(InterruptedException e)
167     {
168     }
169 
170     if (true) // only for human opponent.
171     {
172       sleepTime = 60000;
173       try
174       {
175         Thread. sleep(sleepTime);
176       }
177       catch (InterruptedException e)
178       {
179       }
180     }
181 
182     if (_logger.isInfoEnabled())
183     {
184       _logger.info("-- Awaken! -- ");
185     }
186     if (_game.wasDisconnected())
187     {
188       _logger.info("-- Connection was closed in the meantime -- ");
189       return;
190     }
191     if (_logger.isInfoEnabled())
192     {
193       _logger.info("-- Searching for sets -- ");
194     }
195     printCards("-- Cards on BoardImpl:", _board.getCards());
196 
197     final List elements = new ArrayList();
198     for (int i = 0; i < _board.getCards().length; i++)
199     {
200       final CardProperties cardProperties = _board.getCards()[i];
201       elements.add(new JSetCard(cardProperties));
202     }
203     final CardSet[] sets = _finder.findSets(elements);
204     printMatchingSets(sets);
205     if (sets.length > 0)
206     {
207       final int randIdx = (int) (sets.length * Math.random());
208       if (_logger.isInfoEnabled())
209       {
210         _logger.info("Trying to remove set Idx" + randIdx + ": " + sets[randIdx]);
211       }
212       try
213       {
214         _game.removeSet(sets[randIdx]);
215       }
216       catch (MatchingException e)
217       {
218         if (_logger.isInfoEnabled())
219         {
220           _logger.info("Matching not accepted!", e);
221         }
222       }
223     }
224         // we should be smarter here as some cards may be shared within several sets
225         // we risk to be blocked!
226 //                for (int i = 0; i < sets.length; i++) {
227 //                    _connection.removeSet(sets[i]);
228 //                }
229 //            }
230 
231   }
232 
233   void printMatchingSets(final CardSet[] foundSets)
234   {
235     if (_logger.isInfoEnabled())
236     {
237       final int maxPrinted = 5;
238       _logger.info("Found " + foundSets.length + " sets.");
239       int i;
240       for (i = 0; i < foundSets.length && i < maxPrinted; i++)
241       {
242         _logger.info("CardSet[" + i + "]:" + foundSets[i]);
243       }
244       if (i < foundSets.length)
245       {
246         _logger.info("Skipping " + (foundSets.length - i) + " set(s)...");
247       }
248     }
249   }
250 }