-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path2048.py
228 lines (183 loc) · 5.67 KB
/
2048.py
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
"""
Clone of 2048 game.
"""
import random
import poc_2048_gui
# Directions, DO NOT MODIFY
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
# Offsets for computing tile indices in each direction.
# DO NOT MODIFY this dictionary.
OFFSETS = {UP: (1, 0), DOWN: (-1, 0), LEFT: (0, 1), RIGHT: (0, -1)}
def merge(line):
"""
Function that merges a single row or column in 2048.
:param line: array with elements
:return: new array of elements after the merge operation
"""
newline = shift(list(line))
for index in range(len(newline)):
if index + 1 < len(newline):
if newline[index] != 0 \
and newline[index] == newline[index + 1] != 0:
newline[index] *= 2
newline[index + 1] = 0
newline = shift(newline)
return newline
def shift(array):
"""
Function that remove the zeros from array after it append them at the end
:param array: elements list
:return: new array of elements after the shift
"""
total_zeros_counter = 0
while True:
zeros_counter = 0
for index in range(len(array)):
if array[index] == 0:
del array[index]
zeros_counter += 1
break
total_zeros_counter += zeros_counter
if zeros_counter == 0:
break
for index in range(total_zeros_counter):
array.append(0)
return array
def rotate_cw_matrix(matrix):
"""
Rotate matrix clockwise
:param matrix: input matrix
:return: rotated matrix
"""
aux = zip(*matrix[::-1])
return [list(row) for row in aux]
def rotate_ccw_matrix(matrix):
"""
Rotate matrix counter clockwise
:param matrix: input matrix
:return: rotated matrix
"""
aux = zip(*matrix)[::-1]
return [list(row) for row in aux]
class TwentyFortyEight:
"""
Class to run the game logic.
"""
def __init__(self, grid_height, grid_width):
self._height = grid_height
self._width = grid_width
self._grid = None
self.reset()
def reset(self):
"""
Reset the game so the _grid is empty except for two
initial tiles.
"""
self._grid = [[0] * self._width for _ in range(self._height)]
for row in range(self._height):
for col in range(self._width):
self._grid[row][col] = 0
self.new_tile()
self.new_tile()
def __str__(self):
"""
Return a string representation of the _grid for debugging.
"""
result = "["
for row in range(self._height):
if row == 0:
result += str(self._grid[row]) + "\n"
elif row == self._height - 1:
result += " " + str(self._grid[row]) + "]"
else:
result += " " + str(self._grid[row]) + "\n"
return result
def get_grid_height(self):
"""
Get the _height of the board.
"""
return self._height
def get_grid_width(self):
"""
Get the _width of the board.
"""
return self._width
def move(self, direction):
"""
Move all tiles in the given direction and add a new tile if any
tiles moved.
:param direction: direction of the move over the _grid
"""
initial_grid = list(self._grid)
if direction == UP:
rotated_grid = rotate_ccw_matrix(self._grid)
rotated_grid = [merge(row) for row in rotated_grid]
self._grid = rotate_cw_matrix(rotated_grid)
elif direction == DOWN:
rotated_grid = rotate_cw_matrix(self._grid)
rotated_grid = [merge(row) for row in rotated_grid]
self._grid = rotate_ccw_matrix(rotated_grid)
elif direction == LEFT:
self._grid = [merge(row) for row in self._grid]
elif direction == RIGHT:
self._grid = [merge(row[::-1])[::-1] for row in self._grid]
if initial_grid != self._grid:
self.new_tile()
def new_tile(self):
"""
Create a new tile in a randomly selected empty
square. The tile should be 2 90% of the time and
4 10% of the time.
"""
if not self.is_grid_full():
random_num = random.randint(0, 10)
new_tile_value = 4 if random_num > 9 else 2
while True:
rand_column_idx = random.randrange(0, self._width)
rand_row_idx = random.randrange(0, self._height)
if self.get_tile(rand_row_idx, rand_column_idx) == 0:
self.set_tile(rand_row_idx, rand_column_idx, new_tile_value)
break
def set_tile(self, row, col, value):
"""
Set the tile at position row, col to have the given value.
:param value: tile value
:param col: column index
:param row: row index
"""
self._grid[row][col] = value
def get_tile(self, row, col):
"""
Return the value of the tile at position row, col.
:param col: column index
:param row: row index
"""
return self._grid[row][col]
def is_grid_full(self):
"""
Return if the grid has any empty (0) tile
"""
for row in range(self._height):
for col in range(self._width):
if self._grid[row][col] == 0:
return False
return True
#TESTS
game = TwentyFortyEight(4, 4)
print game
print "\n\nUP"
game.move(UP)
print game
print "\n\nDOWN"
game.move(DOWN)
print game
print "\n\nRIGHT"
game.move(RIGHT)
print game
print "\n\nLEFT"
game.move(LEFT)
print game
poc_2048_gui.run_gui(TwentyFortyEight(4, 4))