Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: client/samples/dartcombat/state.dart

Issue 9303020: Move all samples but swarm from client/samples/ to samples/ . (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * Stores the actual data on a player's boat grid, the UI representation for its
7 * grid and the status of each shot. Acts as a controller handling isolate
8 * messages (from the main isolate message and shots from the enemy), and UI
9 * events.
10 */
11 // TODO(sigmund): move UI setup out of here, e.g. into a controller class.
12 class PlayerState extends Isolate {
13
14 /** internal id for this player. */
15 int _id;
16
17 /** Set up of boats on the board. */
18 BoatGrid boats;
19
20 /** State of shots taken by the enemy on this player's board. */
21 GridState localGrid;
22
23 /** State of shots this player has taken on the enemy. */
24 GridState enemyGrid;
25
26 /** Total shots made. */
27 int totalShots;
28
29 /** Total hits. */
30 int totalHits;
31
32 /** Total misses. */
33 int totalMisses;
34
35 /** Total boats that we have sunk. */
36 int boatsSunk;
37
38 /** Interface to interact with the enemy. */
39 Enemy enemy;
40
41 /** UI representation of this player's grid. */
42 PlayerGridView _ownView;
43
44 /** UI representation of the enemy's grid. */
45 EnemyGridView _enemyView;
46
47 /** Port used for testing purposes. */
48 SendPort _portForTest;
49
50 // This can take no arguments for now (wait for isolate redesign).
51 PlayerState() : super.light() {}
52
53 void main() {
54 this.port.receive((message, SendPort replyTo) {
55 dispatch(message, replyTo);
56 });
57 }
58
59 /** dispatches all messages that are expected in this isolate. */
60 void dispatch(var message, SendPort replyTo) {
61 int action = message['action'];
62 List args = message['args'];
63 switch (action) {
64 // message from the main program, setting this as player 1 or 2
65 case MessageIds.SETUP:
66 handleSetup(args[0]);
67 break;
68 // message from the main program, giving port to talk with other player
69 case MessageIds.SET_ENEMY:
70 enemy = new Enemy(args[0]);
71 break;
72 // message from the other player indicating it's ready to play.
73 case MessageIds.ENEMY_IS_READY:
74 _enemyView.setEnemyReady();
75 replyTo.send([true], null);
76 break;
77 // message from the other player indicating a shot.
78 case MessageIds.SHOOT:
79 List res = handleShot(args[0], args[1]);
80 replyTo.send([true, res], null);
81 break;
82 // message from the unit test (used to make tests deterministic)
83 case MessageIds.SET_PORT_FOR_TEST:
84 _portForTest = args[0];
85 replyTo.send([true], null);
86 break;
87 default:
88 break;
89 }
90 }
91
92 /** Handles a message from the main isolate to setup this player. */
93 void handleSetup(int id) {
94 _id = id;
95 boats = new BoatGrid();
96 localGrid = new GridState();
97 enemyGrid = new GridState();
98 totalShots = 0;
99 totalHits = 0;
100 totalMisses = 0;
101 boatsSunk = 0;
102
103 _ownView = new PlayerGridView(this, document.query("#p${id}own"));
104 _enemyView = new EnemyGridView(this, document.query("#p${id}enemy"));
105 if (_portForTest != null) {
106 _portForTest.call(["_TEST:handleSetup", id]);
107 }
108 }
109
110 /** Handles a shot message from the enemy player. */
111 List handleShot(int x, int y) {
112 List res = boats.shoot(localGrid, x, y);
113 switch (res[0]) {
114 case Constants.MISS:
115 _ownView.addMiss(x, y);
116 break;
117 case Constants.HIT:
118 _ownView.addHit(x, y);
119 break;
120 case Constants.SUNK:
121 _ownView.addHit(x, y);
122 break;
123 }
124 if (_portForTest != null) {
125 _portForTest.call(["_TEST:handleShot", _id, res[0], x, y]);
126 }
127 return res;
128 }
129
130 /** local action to add a boat in the grid. */
131 void addBoat(Boat boat) {
132 boats.placeBoats([boat]);
133 assert(enemy != null);
134 enemy.ready();
135 }
136
137 /** local action to generate an asynchronous shot at the enemy. */
138 void shoot(int x, int y) {
139 superShot(x, y, _id % 2 == 0);
140 }
141
142 /** A single shot on (x, y). */
143 void singleShot(int x, int y) {
144 if (_canShoot(x, y)) {
145 _recordPendingShot(x, y);
146 Future<int> res = enemy.shoot(x, y); // async shot!
147 res.then((int result) {
148 _recordShotResult(result, x, y);
149 });
150 res.handleException((String error) {
151 _recordFailedShot(x, y);
152 return true;
153 });
154 }
155 }
156
157 /**
158 * Takes 1 shot, if it's a hit, it then shoots to each of the 4 cardinal
159 * directions until a boat is sunk. When [parallel] all directions are
160 * explored in parallel.
161 */
162 void superShot(int x, int y, bool parallel) {
163 if (_canShoot(x, y)) {
164 _recordPendingShot(x, y);
165 Future<int> firstShot = enemy.shoot(x, y);
166 firstShot.then((int res) {
167 _recordShotResult(res, x, y);
168 if (res == Constants.HIT) {
169 // no miss, but no sunk, search around
170 _exploreAllDirections(x, y, parallel);
171 }
172 });
173 firstShot.handleException((String error) {
174 _recordFailedShot(x, y);
175 return true;
176 });
177 }
178 }
179
180 static final LEFT_DIR = const [-1, 0];
181 static final RIGHT_DIR = const [1, 0];
182 static final UP_DIR = const [0, -1];
183 static final DOWN_DIR = const [0, 1];
184
185 Future<bool> _exploreAllDirections(int x, int y, bool parallel) {
186 Completer<bool> superShot_ = new Completer<bool>();
187 if (parallel) {
188 final arr = new List<Future<bool>>();
189 arr.add(_exploreDirectionHelper(LEFT_DIR, x, y));
190 arr.add(_exploreDirectionHelper(RIGHT_DIR, x, y));
191 arr.add(_exploreDirectionHelper(UP_DIR, x, y));
192 arr.add(_exploreDirectionHelper(DOWN_DIR, x, y));
193 Futures.wait(arr).then((arrValues) {
194 superShot_.complete(true);
195 });
196 } else {
197 _seqExploreDirectionHelper(LEFT_DIR, x, y, superShot_,
198 _seqExploreDirectionHelper(RIGHT_DIR, x, y, superShot_,
199 _seqExploreDirectionHelper(UP_DIR, x, y, superShot_,
200 _seqExploreDirectionHelper(DOWN_DIR, x, y, superShot_, null))))(fa lse);
201 }
202 return superShot_.future;
203 }
204 Function _seqExploreDirectionHelper(List<int> dir, int x, int y,
205 Completer<bool> seq, void _next(bool res)) {
206 return (bool res) {
207 if (res) {
208 seq.complete(true);
209 } else {
210 _exploreDirectionHelper(dir, x, y).then(
211 (_next != null) ? _next : (void _(v) {seq.complete(false);}));
212 }
213 };
214 }
215
216 Future<bool> _exploreDirectionHelper(List<int> dir, int x, int y) {
217 Completer<bool> sunk = new Completer<bool>();
218 _followDir(x + dir[0], y + dir[1], dir[0], dir[1], sunk);
219 return sunk.future;
220 }
221
222 void _followDir(int x, int y, int incX, int incY, Completer<bool> sunk) {
223 if (_canShoot(x, y)) {
224 _recordPendingShot(x, y);
225 Future<int> shot = enemy.shoot(x, y);
226 shot.then((int res) {
227 _recordShotResult(res, x, y);
228 switch (res) {
229 case Constants.HIT:
230 if (!sunk.future.isComplete) {
231 _followDir(x + incX, y + incY, incX, incY, sunk);
232 }
233 break;
234 case Constants.SUNK:
235 sunk.complete(true);
236 break;
237 case Constants.MISS:
238 sunk.complete(false);
239 break;
240 }
241 });
242 shot.handleException((String error) {
243 _recordFailedShot(x, y);
244 sunk.completeException(error);
245 return true;
246 });
247 // We don't actually chain sunk.cancel with shot.cancel because individual
248 // shots can't be cancelled.
249 } else {
250 sunk.complete(false);
251 }
252 }
253
254 /** checks that a shot is in range and has not been done before. */
255 bool _canShoot(int x, int y) {
256 return _inRange(x, y) && enemyGrid.valueAt(x, y) == null;
257 }
258
259 /** checks that a shot is in range. */
260 bool _inRange(int x, int y) {
261 return x >= 0 && y >=0 && x < Constants.SIZE && y < Constants.SIZE;
262 }
263
264 /** register a pending shot in the local enemyGrid state and update the UI. */
265 void _recordPendingShot(int x, int y) {
266 totalShots++;
267 _enemyView.statusBar.updateStatus();
268 _enemyView.addMaybeHit(x, y);
269 enemyGrid.pending(x, y);
270 }
271
272 /** record a cancelled shot in the local enemyGrid state and update the UI. */
273 void _recordCancelledShot(int x, int y) {
274 totalShots--;
275 _enemyView.removeMaybeHit(x, y);
276 _enemyView.statusBar.updateStatus();
277 enemyGrid.clear(x, y);
278 }
279
280 /** record a failing shot in the local enemyGrid state and update the UI. */
281 void _recordFailedShot(int x, int y) {
282 _recordCancelledShot(x, y);
283 }
284
285 /** register the result of a shot and update the UI. */
286 void _recordShotResult(int shotResult, int x, int y) {
287 switch(shotResult) {
288 case Constants.MISS:
289 totalMisses++;
290 _enemyView.addMiss(x, y);
291 enemyGrid.miss(x, y);
292 break;
293 case Constants.HIT:
294 totalHits++;
295 _enemyView.addHit(x, y);
296 enemyGrid.hit(x, y);
297 break;
298 case Constants.SUNK:
299 totalHits++;
300 boatsSunk++;
301 _enemyView.addHit(x, y);
302 enemyGrid.hit(x, y);
303 break;
304 }
305 _enemyView.statusBar.updateStatus();
306 }
307 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698