-
Notifications
You must be signed in to change notification settings - Fork 10
/
controller_2048.e
451 lines (423 loc) · 10.5 KB
/
controller_2048.e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
note
description: "This class takes care of the control of the game."
author: ""
date: "August 25, 2014"
revision: "0.01"
class
CONTROLLER_2048
create
make, make_with_board
feature -- Initialisation
make_with_board (new_board: BOARD_2048)
-- Creates a controller with reference to a provided board
require
new_board /= Void
do
board := new_board
ensure
board = new_board
end
make
-- Creates a controller from scratch. The controller must create the
-- classes that represent and take care of the logic of the game.
do
coord_last_random_cell := [0, 0]
create board.make
ensure
board /= Void
end
feature {ANY}
coord_last_random_cell: TUPLE [INTEGER, INTEGER]
-- Tuple containing the coordinates of the last random cell.
feature -- Game State
board: BOARD_2048
-- Reference to the object that maintains the state of the game
-- and takes care of the games logic.
is_finished: BOOLEAN
-- Indicates whether the game is finished or not.
-- Game finishes when either 2048 is reached, or if there is no possible movement.
local
finished: BOOLEAN -- Auxiliary variable to capture the finalization desicion
do
finished := False
if not board.can_move_up and not board.can_move_down and not board.can_move_left and not board.can_move_right then
finished := True
else
finished := board.is_winning_board
end
Result := finished
end
last_random_cell_coordinates: TUPLE [INTEGER, INTEGER]
-- Returns the coordinates of th last randomly introduced
-- cell. Value should be (0,0) if no cell has been introduced in the last movement
-- or if the game state is the initial state.
do
Result := coord_last_random_cell
end
feature -- Movement commands
up
-- Moves the cells to the uppermost possible point of the game board.
-- Movement colapses cells with the same value.
-- It adds one more random cell with value 2 or 4, after the movement.
require
board.can_move_up
local
i, k, j: INTEGER
do
--First I add the cells that can be added
from
j := 1
until
j > 4
loop
from
i := 1
until
i >= 4
loop
if board.elements.item (i, j).value /= 0 then
k := i + 1;
from
-- search for the next element /= 0
until
(k > 4) or (board.elements.item (k, j).value /= 0)
loop
k := k + 1;
end
if (k <= 4) then
if (board.elements.item (i, j).value = board.elements.item (k, j).value) then
board.set_cell (i, j, (board.elements.item (k, j).value + board.elements.item (i, j).value))
board.set_cell (k, j, 0)
i := k + 1
else
i := k
end
else
i := k
end
else
i := i + 1
end
end --end loop i
j := j + 1
end --end loop j
-- occupy available cells at the top.
from --
j := 1
until
j > 4
loop
from
i := 1
until
i >= 4
loop
if board.elements.item (i, j).value = 0 then
k := i + 1;
from
-- search for the next element /= 0
until
(k > 4) or (board.elements.item (k, j).value /= 0)
loop
k := k + 1;
end
if (k <= 4) then
board.set_cell (i, j, board.elements.item (k, j).value)
board.set_cell (k, j, 0)
i := i + 1
else
i := k
end
else
i := i + 1
end
end --end loop i
j := j + 1
end --end loop j
set_random_free_cell
end --end do
down -- Moves the cells to the lowermost possible point of the game board.
-- Movement colapses cells with the same value.
-- It adds one more random cell with value 2 or 4, after the movement.
require
board.can_move_down
local
i, j, aux: INTEGER
do
-- add all possible cells downward
from -- columns
i := 1
until
i > 4
loop
from -- rows (from the lowermost to the uppermost row)
j := 4
until
j <= 1
loop
if board.elements.item (j, i).value /= 0 then
aux := j;
j := j - 1;
from
-- search for the next element /= 0
until
(j < 1) or (board.elements.item (j, i).value /= 0)
loop
j := j - 1;
end
if j >= 1 then -- if search is succesful
if board.elements.item (aux, i).value = board.elements.item (j, i).value then
board.set_cell (aux, i, (board.elements.item (aux, i).value + board.elements.item (j, i).value))
board.set_cell (j, i, 0)
j := j - 1;
end
end
else
j := j - 1;
end -- end if /=0
end -- end loop j
i := i + 1;
end -- end loop i
--occupy all empty spaces downward
from -- columns
i := 1
until
i > 4
loop
from -- rows (from the lowermost to the uppermost row)
j := 4
until
j = 1
loop
if ((board.elements.item (j, i).value = 0) and (board.elements.item (j - 1, i).value) /= 0) then -- if j,i = 0 and the one above it is =/ 0
board.set_cell (j, i, board.elements.item (j - 1, i).value)
board.set_cell (j - 1, i, 0)
if (j < 4) then --if not at the lowermost cell
j := j + 1; -- continues moving downward until it reaches an ocupied cell
else
j := j - 1; -- continues moving upward
end
else
j := j - 1;
end
end -- end loop j
i := i + 1;
end -- end loop i
set_random_free_cell
end -- end do
left
-- Moves the cells to the leftmost possible point of the game board.
-- Movement colapses cells with the same value.
-- It adds one more random cell with value 2 or 4, after the movement.
require
board.can_move_left
local
i, j, k: INTEGER
do
from
i := 1
until
i > 4
loop
from
j := 1
until
j >= 4
loop
if board.elements.item (i, j).value /= 0 then
k := j + 1
from
until
(k > 4) or (board.elements.item (i, k).value /= 0)
loop
k := k + 1
end
if (k <= 4) then
if (board.elements.item (i, j).value = board.elements.item (i, k).value) then
board.set_cell (i, j, (board.elements.item (i, k).value + board.elements.item (i, j).value))
board.set_cell (i, k, 0)
j := k + 1
else
j := k
end -- end if
else
j := k
end
else
j := j + 1
end -- end if /=0
end --end loop j
i := i + 1
end --end loop i
from --
i := 1
until
i > 4
loop
from
j := 1
until
j >= 4
loop
if (board.elements.item (i, j).value = 0) and (board.elements.item (i, j + 1).value /= 0) then
board.set_cell (i, j, board.elements.item (i, j + 1).value)
board.set_cell (i, j + 1, 0)
if (j = 1) then --if at the leftrmost cell
j := j + 1; -- continues moving to the right until it reaches an occupied cell
else
j := j - 1; -- continues moving left
end
else
j:= j + 1
end -- end if
end --end loop j
i := i + 1
end --end loop i
set_random_free_cell
end --end do
right
-- Moves the cells to the rightmost possible point of the game board.
-- Movement colapses cells with the same value.
-- It adds one more random cell with value 2 or 4, after the movement.
require
board.can_move_right
local
i, j, k, v: INTEGER
do
from
i := 1
until
i > 4
loop
from
j := 4
until
j <= 1
loop
if board.elements.item (i, j).value /= 0 then
if j > 1 then
k := j - 1
from
until
(k <= 1) or (board.elements.item (i, k).value /= 0)
loop
k := k - 1
end
if (k >= 1) then
if (board.elements.item (i, j).value = board.elements.item (i, k).value) then
board.set_cell (i, j, (board.elements.item (i, k).value + board.elements.item (i, j).value))
board.set_cell (i, k, 0)
j := k - 1
else
j := k
end
end
end
else
j := j - 1
end
end --end loop j
i := i + 1
end --end loop i
from --
i := 1
until
i > 4
loop
from
j := 4
until
j < 1
loop
if board.elements.item (i, j).value /= 0 then
v := board.elements.item (i, j).value
board.set_cell (i, j, 0)
position_right (i, v)
j := j - 1;
else
j := j - 1
end --end if
end --end loop j
i := i + 1
end --end loop i
set_random_free_cell
end --end do
feature {NONE} -- Auxiliary routines
position_right (row, val: INTEGER)
-- Method that receives as a parameter a row, and verifies the position which is more to the right
-- which is empty in that row and also inserts the value passed as parameter
local
column: INTEGER
do
from
column := 4
until
column < 1
loop
if board.elements.item (row, column).value = 0 then
board.set_cell (row, column, val)
column := 0
else
column := column - 1
end --end if
end --end loop
end --end do
random_number_two_or_four (random_sequence: RANDOM): INTEGER
-- Randomly returns two or four
local
random_number: INTEGER
do
random_number := (get_random (random_sequence, 2) + 1) * 2
Result := random_number
ensure
Result = 2 or Result = 4
end
get_random_seed: INTEGER
-- Returns a seed for random sequences
local
l_time: TIME
l_seed: INTEGER
do
create l_time.make_now
l_seed := l_time.hour
l_seed := l_seed * 60 + l_time.minute
l_seed := l_seed * 60 + l_time.second
l_seed := l_seed * 1000 + l_time.milli_second
Result := l_seed
end
get_random (random_sequence: RANDOM; ceil: INTEGER): INTEGER
-- Returns a random integer minor that ceil from a random sequence
require
ceil >= 0
do
random_sequence.forth
Result := random_sequence.item \\ ceil;
ensure
Result < ceil
end
Feature {SET_RANDOM_FREE_CELL_AT_CONTROLLER}
set_random_free_cell
require
not board.is_full
local
random_sequence : RANDOM
random_cell_row : INTEGER
random_cell_col : INTEGER
do
--initialize random seed
create random_sequence.set_seed(get_random_seed)
random_cell_row := get_random(random_sequence, 4) + 1;
random_cell_col := get_random(random_sequence, 4) + 1;
from
until
board.elements.item(random_cell_row, random_cell_col).is_available = True
loop
--generate a random position
random_cell_row := get_random(random_sequence, 4) + 1;
random_cell_col := get_random(random_sequence, 4) + 1;
end
-- set at cell random number
board.set_cell(random_cell_row, random_cell_col, random_number_two_or_four(random_sequence))
coord_last_random_cell := [random_cell_row,random_cell_col]
end
end