| OLD | NEW |
| 1 part of pop_pop_win.game; | 1 part of pop_pop_win.game; |
| 2 | 2 |
| 3 class Game { | 3 class Game { |
| 4 final Field field; | 4 final Field field; |
| 5 final Array2d<SquareState> _states; | 5 final Array2d<SquareState> _states; |
| 6 final EventHandle<EventArgs> _updatedEvent = new EventHandle<EventArgs>(); | 6 final StreamController _updatedEvent = new StreamController(); |
| 7 final EventHandle<GameState> _gameStateEvent = new EventHandle<GameState>(); | 7 final StreamController<GameState> _gameStateEvent = |
| 8 new StreamController<GameState>(); |
| 8 | 9 |
| 9 GameState _state; | 10 GameState _state; |
| 10 int _bombsLeft; | 11 int _bombsLeft; |
| 11 int _revealsLeft; | 12 int _revealsLeft; |
| 12 DateTime _startTime; | 13 DateTime _startTime; |
| 13 DateTime _endTime; | 14 DateTime _endTime; |
| 14 | 15 |
| 15 Game(Field field) : | 16 Game(Field field) |
| 16 this.field = field, | 17 : this.field = field, |
| 17 _state = GameState.reset, | 18 _state = GameState.reset, |
| 18 _states = new Array2d<SquareState>(field.width, field.height, SquareState.hi
dden) { | 19 _states = new Array2d<SquareState>(field.width, field.height, |
| 20 SquareState.hidden) { |
| 19 assert(field != null); | 21 assert(field != null); |
| 20 _bombsLeft = field.bombCount; | 22 _bombsLeft = field.bombCount; |
| 21 _revealsLeft = field.length - field.bombCount; | 23 _revealsLeft = field.length - field.bombCount; |
| 22 } | 24 } |
| 23 | 25 |
| 24 int get bombsLeft => _bombsLeft; | 26 int get bombsLeft => _bombsLeft; |
| 25 | 27 |
| 26 int get revealsLeft => _revealsLeft; | 28 int get revealsLeft => _revealsLeft; |
| 27 | 29 |
| 28 GameState get state => _state; | 30 GameState get state => _state; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 bool canReveal(int x, int y) { | 73 bool canReveal(int x, int y) { |
| 72 final currentSS = _states.get(x, y); | 74 final currentSS = _states.get(x, y); |
| 73 if (currentSS == SquareState.hidden) { | 75 if (currentSS == SquareState.hidden) { |
| 74 return true; | 76 return true; |
| 75 } else if (_canChord(x, y)) { | 77 } else if (_canChord(x, y)) { |
| 76 return true; | 78 return true; |
| 77 } | 79 } |
| 78 return false; | 80 return false; |
| 79 } | 81 } |
| 80 | 82 |
| 81 List<Coordinate> reveal(int x, int y) { | 83 List<Point> reveal(int x, int y) { |
| 82 _ensureStarted(); | 84 _ensureStarted(); |
| 83 require(canReveal(x, y), "Item cannot be revealed."); | 85 require(canReveal(x, y), "Item cannot be revealed."); |
| 84 final currentSS = _states.get(x, y); | 86 final currentSS = _states.get(x, y); |
| 85 | 87 |
| 86 List<Coordinate> reveals; | 88 List<Point> reveals; |
| 87 | 89 |
| 88 // normal reveal | 90 // normal reveal |
| 89 if (currentSS == SquareState.hidden) { | 91 if (currentSS == SquareState.hidden) { |
| 90 if (field.get(x, y)) { | 92 if (field.get(x, y)) { |
| 91 _setLost(); | 93 _setLost(); |
| 92 reveals = <Coordinate>[]; | 94 reveals = <Point>[]; |
| 93 } else { | 95 } else { |
| 94 reveals = _doReveal(x, y); | 96 reveals = _doReveal(x, y); |
| 95 } | 97 } |
| 96 } else if (_canChord(x, y)) { | 98 } else if (_canChord(x, y)) { |
| 97 reveals = _doChord(x, y); | 99 reveals = _doChord(x, y); |
| 98 } | 100 } |
| 99 _update(); | 101 _update(); |
| 100 | 102 |
| 101 if (_state == GameState.lost) { | 103 if (_state == GameState.lost) { |
| 102 return null; | 104 return null; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 final adjFlags = _getAdjacentCount(x, y, SquareState.flagged); | 167 final adjFlags = _getAdjacentCount(x, y, SquareState.flagged); |
| 166 if (adjFlags == adjCount) { | 168 if (adjFlags == adjCount) { |
| 167 return true; | 169 return true; |
| 168 } | 170 } |
| 169 } | 171 } |
| 170 } | 172 } |
| 171 } | 173 } |
| 172 return false; | 174 return false; |
| 173 } | 175 } |
| 174 | 176 |
| 175 List<Coordinate> _doChord(int x, int y) { | 177 List<Point> _doChord(int x, int y) { |
| 176 // this does not repeat a bunch of validations that have already happened | 178 // this does not repeat a bunch of validations that have already happened |
| 177 // be careful | 179 // be careful |
| 178 final currentSS = _states.get(x, y); | 180 final currentSS = _states.get(x, y); |
| 179 assert(currentSS == SquareState.revealed); | 181 assert(currentSS == SquareState.revealed); |
| 180 | 182 |
| 181 final flagged = new List<int>(); | 183 final flagged = new List<int>(); |
| 182 final hidden = new List<int>(); | 184 final hidden = new List<int>(); |
| 183 final adjCount = field.getAdjacentCount(x, y); | 185 final adjCount = field.getAdjacentCount(x, y); |
| 184 assert(adjCount > 0); | 186 assert(adjCount > 0); |
| 185 | 187 |
| 186 bool failed = false; | 188 bool failed = false; |
| 187 | 189 |
| 188 for (final i in field.getAdjacentIndices(x, y)) { | 190 for (final i in field.getAdjacentIndices(x, y)) { |
| 189 if (_states[i] == SquareState.hidden) { | 191 if (_states[i] == SquareState.hidden) { |
| 190 hidden.add(i); | 192 hidden.add(i); |
| 191 if (field[i]) { | 193 if (field[i]) { |
| 192 failed = true; | 194 failed = true; |
| 193 } | 195 } |
| 194 } else if (_states[i] == SquareState.flagged) { | 196 } else if (_states[i] == SquareState.flagged) { |
| 195 flagged.add(i); | 197 flagged.add(i); |
| 196 } | 198 } |
| 197 } | 199 } |
| 198 | 200 |
| 199 // for now we assume counts have been checked | 201 // for now we assume counts have been checked |
| 200 assert(flagged.length == adjCount); | 202 assert(flagged.length == adjCount); |
| 201 | 203 |
| 202 var reveals = <Coordinate>[]; | 204 var reveals = <Point>[]; |
| 203 | 205 |
| 204 // if any of the hidden are bombs, we've failed | 206 // if any of the hidden are bombs, we've failed |
| 205 if (failed) { | 207 if (failed) { |
| 206 // TODO: assert one of the flags must be wrong, right? | |
| 207 _setLost(); | 208 _setLost(); |
| 208 } else { | 209 } else { |
| 209 for (final i in hidden) { | 210 for (final i in hidden) { |
| 210 final c = field.getCoordinate(i); | 211 final c = field.getCoordinate(i); |
| 211 if (canReveal(c.item1, c.item2)) { | 212 if (canReveal(c.item1, c.item2)) { |
| 212 reveals.addAll(reveal(c.item1, c.item2)); | 213 reveals.addAll(reveal(c.item1, c.item2)); |
| 213 } | 214 } |
| 214 } | 215 } |
| 215 } | 216 } |
| 216 | 217 |
| 217 return reveals; | 218 return reveals; |
| 218 } | 219 } |
| 219 | 220 |
| 220 List<Coordinate> _doReveal(int x, int y) { | 221 List<Point> _doReveal(int x, int y) { |
| 221 assert(_states.get(x, y) == SquareState.hidden); | 222 assert(_states.get(x, y) == SquareState.hidden); |
| 222 _states.set(x, y, SquareState.revealed); | 223 _states.set(x, y, SquareState.revealed); |
| 223 _revealsLeft--; | 224 _revealsLeft--; |
| 224 assert(_revealsLeft >= 0); | 225 assert(_revealsLeft >= 0); |
| 225 var reveals = [new Coordinate(x, y)]; | 226 var reveals = [new Point(x, y)]; |
| 226 if (_revealsLeft == 0) { | 227 if (_revealsLeft == 0) { |
| 227 _setWon(); | 228 _setWon(); |
| 228 } else if (field.getAdjacentCount(x, y) == 0) { | 229 } else if (field.getAdjacentCount(x, y) == 0) { |
| 229 for (final i in field.getAdjacentIndices(x, y)) { | 230 for (final i in field.getAdjacentIndices(x, y)) { |
| 230 if (_states[i] == SquareState.hidden) { | 231 if (_states[i] == SquareState.hidden) { |
| 231 final c = field.getCoordinate(i); | 232 final c = field.getCoordinate(i); |
| 232 reveals.addAll(_doReveal(c.item1, c.item2)); | 233 reveals.addAll(_doReveal(c.item1, c.item2)); |
| 233 assert(state == GameState.started || state == GameState.won); | 234 assert(state == GameState.started || state == GameState.won); |
| 234 } | 235 } |
| 235 } | 236 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 250 void _setLost() { | 251 void _setLost() { |
| 251 assert(state == GameState.started); | 252 assert(state == GameState.started); |
| 252 for (int i = 0; i < field.length; i++) { | 253 for (int i = 0; i < field.length; i++) { |
| 253 if (field[i]) { | 254 if (field[i]) { |
| 254 _states[i] = SquareState.bomb; | 255 _states[i] = SquareState.bomb; |
| 255 } | 256 } |
| 256 } | 257 } |
| 257 _setState(GameState.lost); | 258 _setState(GameState.lost); |
| 258 } | 259 } |
| 259 | 260 |
| 260 void _update() => _updatedEvent.add(EventArgs.empty); | 261 void _update() => _updatedEvent.add(null); |
| 261 | 262 |
| 262 void _setState(GameState value) { | 263 void _setState(GameState value) { |
| 263 assert(value != null); | 264 assert(value != null); |
| 264 assert(_state != null); | 265 assert(_state != null); |
| 265 assert((_state == GameState.reset) == (_startTime == null)); | 266 assert((_state == GameState.reset) == (_startTime == null)); |
| 266 if (_state != value) { | 267 if (_state != value) { |
| 267 _state = value; | 268 _state = value; |
| 268 if (_state == GameState.started) { | 269 if (_state == GameState.started) { |
| 269 _startTime = new DateTime.now(); | 270 _startTime = new DateTime.now(); |
| 270 } else if (gameEnded) { | 271 } else if (gameEnded) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 286 int _getAdjacentCount(int x, int y, SquareState state) { | 287 int _getAdjacentCount(int x, int y, SquareState state) { |
| 287 int val = 0; | 288 int val = 0; |
| 288 for (final i in field.getAdjacentIndices(x, y)) { | 289 for (final i in field.getAdjacentIndices(x, y)) { |
| 289 if (_states[i] == state) { | 290 if (_states[i] == state) { |
| 290 val++; | 291 val++; |
| 291 } | 292 } |
| 292 } | 293 } |
| 293 return val; | 294 return val; |
| 294 } | 295 } |
| 295 } | 296 } |
| OLD | NEW |