Source code: org/zazof/jteg/JTEGStateMachine.java
1 package org.zazof.jteg;
2
3 import java.util.*;
4
5 /**
6 *
7 * This class encapsulates the current state of the JTEGClient
8 *
9 * <p>
10 * It implements Model-View-Controller.<br> Classes can subscribe to the JTEGStateMachine,
11 * and they will be notified of changes in the state of the client.
12 * <p>
13 * JTEGStateMachine implements the Singleton Pattern
14 *
15 * @author Yves Vandewoude
16 * @date Januari 2001
17 */
18
19 public class JTEGStateMachine
20 {
21
22 /**
23 * Returns a reference to the StateMachine
24 * (Implementation of the Singleton Pattern)
25 *
26 * @returns Instance of a JTEGStateMachine
27 */
28 public static JTEGStateMachine getInstance()
29 {
30 if ($instance == null) $instance = new JTEGStateMachine();
31 return $instance;
32 }
33
34 /**
35 * Returns the current state
36 *
37 * @returns Current state, which is one of the stateconstants
38 */
39 public int getCurrentState()
40 {
41 return $currentState;
42 }
43
44
45 /**
46 * Sets the current state
47 *
48 * @param newState The new state that the StateMachine should have
49 * @throws IllegalStateException If the desired state can not be reached from the current state
50 */
51 public void setCurrentState(int newState)
52 throws IllegalStateException
53 {
54 if (possibleTransition(getCurrentState(), newState))
55 {
56 $currentState = newState;
57 notifyListeners();
58 }
59 else
60 throw new IllegalStateException("IllegalStateTransition: OriginalState = " + $currentState + ", NewState = " + newState);
61 }
62
63 /**
64 * Adds a listener to the listenerlist.
65 *
66 * @param newListener A StateListener that wishes to subscribe to the statemachine
67 */
68 public void subscribe(StateListener newListener)
69 {
70 $listeners.add(newListener);
71 }
72
73 /**
74 * Removes a listener from the listenerlist.
75 *
76 * @param oldListener A StateListener that wishes to unsubscribe from the statemachine
77 */
78 public void unsubscribe(StateListener listenerToBeRemoved)
79 {
80 $listeners.remove(listenerToBeRemoved);
81 }
82
83
84 // *************************************************
85 //
86 // Private variables and/or methods
87 //
88 // *************************************************
89
90 /*
91 * The private constructor (Singleton)
92 */
93 private JTEGStateMachine()
94 {
95 matrixInit();
96 }
97
98 /*
99 * Will notify all registered listeners that the state has changed
100 */
101 private void notifyListeners()
102 {
103 Enumeration listeners = $listeners.elements();
104 while (listeners.hasMoreElements()){
105 StateListener l = (StateListener) listeners.nextElement();
106 l.stateChanged(getCurrentState());
107 }
108 }
109
110 /*
111 * Initializes the connectionmatrix
112 */
113 private void matrixInit()
114 {
115 // In Java, the default value of a boolean is 'false'. So only allowed transitions will be set to true
116
117 $transitionMatrix[DISCONNECTED][DISCONNECTED] = true;
118 $transitionMatrix[DISCONNECTED][CONNECTING] = true;
119
120 $transitionMatrix[CONNECTING][OBSERVING] = true;
121 $transitionMatrix[CONNECTING][CHOOSING_COLORS] = true;
122 $transitionMatrix[CONNECTING][DISCONNECTED] = true;
123
124 $transitionMatrix[OBSERVING][OBSERVING] = true;
125 $transitionMatrix[OBSERVING][DISCONNECTED] = true;
126
127 $transitionMatrix[CHOOSING_COLORS][CHOOSING_COLORS] = true;
128 $transitionMatrix[CHOOSING_COLORS][CONNECTED] = true;
129
130 $transitionMatrix[CONNECTED][DISCONNECTED] = true;
131 $transitionMatrix[CONNECTED][GAME_STARTED] = true;
132 $transitionMatrix[CONNECTED][CONNECTED] = true;
133
134 $transitionMatrix[GAME_STARTED][CONNECTED] = true; // When there is a problem starting the game (only one player e.g.)
135 $transitionMatrix[GAME_STARTED][DISCONNECTED] = true;
136 $transitionMatrix[GAME_STARTED][GAME_STARTED] = true;
137 $transitionMatrix[GAME_STARTED][PLACING_ARMIES] = true;
138
139 $transitionMatrix[PLACING_ARMIES][DISCONNECTED] = true;
140 $transitionMatrix[PLACING_ARMIES][ARMIES_PLACED] = true;
141 $transitionMatrix[PLACING_ARMIES][PLACING_ARMIES] = true;
142 $transitionMatrix[PLACING_ARMIES][EXCHANGING_CARDS] = true;
143
144 $transitionMatrix[ARMIES_PLACED][DISCONNECTED] = true;
145 $transitionMatrix[ARMIES_PLACED][ARMIES_PLACED] = true;
146 $transitionMatrix[ARMIES_PLACED][PLACING_ARMIES] = true;
147 $transitionMatrix[ARMIES_PLACED][ATTACKING] = true;
148 $transitionMatrix[ARMIES_PLACED][WAITING_FOR_OTHER_PLAYERS] = true;
149
150 $transitionMatrix[ATTACKING][DISCONNECTED] = true;
151 $transitionMatrix[ATTACKING][ATTACKING] = true;
152 $transitionMatrix[ATTACKING][MOVING_AFTER_ATTACK] = true;
153 $transitionMatrix[ATTACKING][REGROUPING_ARMIES] = true;
154 $transitionMatrix[ATTACKING][GETTING_CARD] = true;
155 $transitionMatrix[ATTACKING][WAITING_FOR_OTHER_PLAYERS] = true;
156 $transitionMatrix[ATTACKING][CONNECTED] = true; // When the player has won the game
157
158 $transitionMatrix[MOVING_AFTER_ATTACK][DISCONNECTED] = true;
159 $transitionMatrix[MOVING_AFTER_ATTACK][ATTACKING] = true;
160 $transitionMatrix[MOVING_AFTER_ATTACK][MOVING_AFTER_ATTACK] = true;
161 $transitionMatrix[MOVING_AFTER_ATTACK][REGROUPING_ARMIES] = true;
162 $transitionMatrix[MOVING_AFTER_ATTACK][GETTING_CARD] = true;
163 $transitionMatrix[MOVING_AFTER_ATTACK][WAITING_FOR_OTHER_PLAYERS] = true;
164 $transitionMatrix[MOVING_AFTER_ATTACK][CONNECTED] = true; // When the player has won the game
165
166 $transitionMatrix[REGROUPING_ARMIES][DISCONNECTED] = true;
167 $transitionMatrix[REGROUPING_ARMIES][REGROUPING_ARMIES] = true;
168 $transitionMatrix[REGROUPING_ARMIES][ARMIES_REGROUPED] = true;
169 $transitionMatrix[REGROUPING_ARMIES][GETTING_CARD] = true;
170 $transitionMatrix[REGROUPING_ARMIES][WAITING_FOR_OTHER_PLAYERS] = true;
171
172 $transitionMatrix[ARMIES_REGROUPED][DISCONNECTED] = true;
173 $transitionMatrix[ARMIES_REGROUPED][ARMIES_REGROUPED] = true;
174 $transitionMatrix[ARMIES_REGROUPED][GETTING_CARD] = true;
175 $transitionMatrix[ARMIES_REGROUPED][WAITING_FOR_OTHER_PLAYERS] = true;
176 $transitionMatrix[ARMIES_REGROUPED][REGROUPING_ARMIES] = true;
177
178 $transitionMatrix[GETTING_CARD][DISCONNECTED] = true;
179 $transitionMatrix[GETTING_CARD][WAITING_FOR_OTHER_PLAYERS] = true;
180 $transitionMatrix[GETTING_CARD][GETTING_CARD] = true;
181
182 $transitionMatrix[WAITING_FOR_OTHER_PLAYERS][DISCONNECTED] = true;
183 $transitionMatrix[WAITING_FOR_OTHER_PLAYERS][EXCHANGING_CARDS] = true;
184 $transitionMatrix[WAITING_FOR_OTHER_PLAYERS][PLACING_ARMIES] = true;
185 $transitionMatrix[WAITING_FOR_OTHER_PLAYERS][WAITING_FOR_OTHER_PLAYERS] = true;
186 $transitionMatrix[WAITING_FOR_OTHER_PLAYERS][ATTACKING] = true;
187 $transitionMatrix[WAITING_FOR_OTHER_PLAYERS][CONNECTED] = true;
188
189 $transitionMatrix[EXCHANGING_CARDS][DISCONNECTED] = true;
190 $transitionMatrix[EXCHANGING_CARDS][EXCHANGING_CARDS] = true;
191 $transitionMatrix[EXCHANGING_CARDS][PLACING_ARMIES] = true;
192
193 }
194
195
196 private boolean possibleTransition(int sourceState, int destinationState)
197 {
198 return $transitionMatrix[sourceState][destinationState];
199 }
200
201
202
203
204
205 private boolean[][] $transitionMatrix = new boolean[NB_OF_STATES][NB_OF_STATES]; // At location $transitionMatrix[state1][state2], is noted whether the state1->state2 transition is allowed
206 private Vector $listeners = new Vector(8);
207 private static int $currentState = 0; // = DISCONNECTED
208 private static JTEGStateMachine $instance;
209
210
211
212 // *************************************************
213 //
214 // These are all the states in the JTEGClient
215 //
216 // *************************************************
217
218
219 // Note on the values of the constants. We leave some room so that in the future, we can add states without messing up the order...
220
221 public static final int DISCONNECTED = 0; // We have no connection with the server
222 public static final int CONNECTING = 1;
223 public static final int CHOOSING_COLORS = 2; // The client is choosing his color
224 public static final int CONNECTED = 3; // We established a connection with the server, but the game was not started yet
225 public static final int OBSERVING = 4;
226 public static final int GAME_STARTED = 5; // The game has started
227 public static final int EXCHANGING_CARDS = 6; // The client is exchanging cards
228 public static final int PLACING_ARMIES = 7; // The client is placing armies
229 public static final int ARMIES_PLACED = 8; // All armies have been placed
230 public static final int ATTACKING = 9; // The client is attacking
231 public static final int MOVING_AFTER_ATTACK = 10; // The client is moving armies after an attack
232 public static final int REGROUPING_ARMIES = 11; // The client is regrouping his armies
233 public static final int ARMIES_REGROUPED = 12; // Armies have been regrouped
234 public static final int GETTING_CARD = 13; // The client is receiving a card...
235 public static final int WAITING_FOR_OTHER_PLAYERS = 14; // When other players are playing...
236
237 static final int NB_OF_STATES = 15;
238 static final boolean DEBUG = false;
239 }