# 2048-ml

git clone git://git.codymlewis.com/2048-ml.git

Board.py (7608B)

```      1 import math
2 import random
3
4 import Tile
5
6
7 '''
8 Object for the 2048 Board
9 '''
10
11
12 class Board:
13     '''
14     A 2048 board class
15     '''
16
17     def __init__(self, width, height):
18         self.__width = width
19         self.__height = height
20         self.__score = 0
21         self.__tiles = [[None for _ in range(width)] for _ in range(height)]
22         self.__max_num_len = 1
23         self.__available_tiles = [i for i in range(width * height)]
24         for _ in range(1 if random.randint(1, 100) < 95 else 2):
25             self.spawn_tile()
26
27     def get_game_state(self):
28         '''Return a flattened list of the current game state'''
29         return [int(t) if t else 0 for r in self.__tiles for t in r]
30
31     def get_score(self):
32         '''Get the current score of the game'''
33         return self.__score
34
35     def spawn_tile(self):
36         '''Spawn a random new Tile on the board'''
37         coord = random.sample(self.__available_tiles, 1)[0]
38         i = coord % self.__width
39         j = math.floor(coord / self.__width)
40         self.__tiles[i][j] = Tile.Tile(
41             2 if random.randint(1, 100) < 95 else 4,
42             self.__max_num_len
43         )
44         self.take_space(i, j)
45
46     def take_space(self, col, row):
47         '''Mark a space in the board as taken'''
48         self.__available_tiles.remove(row * self.__width + col)
49
50     def give_space(self, col, row):
51         '''Unmark a space in the board as taken'''
52         self.__available_tiles.append(row * self.__width + col)
53
54     def combine_tiles(self, i, j, k, l):
55         '''Combine 2 tiles on the board'''
56         self.__tiles[k][l] += self.__tiles[i][j]
57         self.__tiles[i][j] = None
58         self.give_space(i, j)
59         self.__score += int(self.__tiles[k][l])
60         if self.__tiles[k][l].max_num_len > self.__max_num_len:
61             self.update_mnl(self.__tiles[k][l].max_num_len)
62         else:
63             self.__tiles[k][l].max_num_len = self.__max_num_len
64
65     def update_mnl(self, new_len):
66         '''Update the maximum number length'''
67         self.__max_num_len = new_len
68         for i in range(self.__height):
69             for j in range(self.__width):
70                 if self.__tiles[i][j]:
71                     self.__tiles[i][j].max_num_len = new_len
72
73     def move_tile(self, i, j, k, l):
74         '''Move a tile across the board'''
75         if i != k or j != l:
76             self.__tiles[k][l] = self.__tiles[i][j]
77             self.take_space(k, l)
78             self.__tiles[i][j] = None
79             self.give_space(i, j)
80
81     def game_over(self):
82         '''Check when the game is over'''
83         return len(self.__available_tiles) == 0 and self.no_adjacents()
84
86         '''Check that there are no equal adjecent tiles'''
87         for i in range(self.__height):
88             for j in range(self.__width):
89                 p = j < self.__width - 1 and self.__tiles[i][j + 1] == self.__tiles[i][j]
90                 q = i < self.__height - 1 and self.__tiles[i + 1][j] == self.__tiles[i][j]
91                 if p or q:
92                     return False
93         return True
94
95     def left(self):
96         '''Slide the tiles to the left'''
97         if not self.can_left():
98             return False
99         for i in range(self.__height):
100             pivot = 0
101             for j in range(1, self.__width):
102                 if self.__tiles[i][j]:
103                     if self.__tiles[i][j] == self.__tiles[i][pivot]:
104                         self.combine_tiles(i, j, i, pivot)
105                     else:
106                         if self.__tiles[i][pivot]:
107                             pivot += 1
108                         self.move_tile(i, j, i, pivot)
109         return True
110
111     def can_left(self):
112         '''Check if anything can move left'''
113         for i in range(self.__height):
114             for j in range(1, self.__width):
115                 p = self.__tiles[i][j]
116                 q = not self.__tiles[i][j - 1] or \
117                     self.__tiles[i][j] == self.__tiles[i][j - 1]
118                 if p and q:
119                     return True
120         return False
121
122     def right(self):
123         '''Slide the tiles to the right'''
124         if not self.can_right():
125             return False
126         for i in range(self.__height - 1, -1, -1):
127             pivot = self.__width - 1
128             for j in range(self.__width - 2, -1, -1):
129                 if self.__tiles[i][j]:
130                     if self.__tiles[i][j] == self.__tiles[i][pivot]:
131                         self.combine_tiles(i, j, i, pivot)
132                     else:
133                         if self.__tiles[i][pivot]:
134                             pivot -= 1
135                         self.move_tile(i, j, i, pivot)
136         return True
137
138     def can_right(self):
139         '''Check if anything can move right'''
140         for i in range(self.__height - 1, -1, -1):
141             for j in range(self.__width - 2, -1, -1):
142                 p = self.__tiles[i][j]
143                 q = not self.__tiles[i][j + 1] or \
144                     self.__tiles[i][j] == self.__tiles[i][j + 1]
145                 if p and q:
146                     return True
147         return False
148
149     def up(self):
150         '''Slide the tiles up'''
151         if not self.can_up():
152             return False
153         for j in range(self.__width):
154             pivot = 0
155             for i in range(1, self.__height):
156                 if self.__tiles[i][j]:
157                     if self.__tiles[i][j] == self.__tiles[pivot][j]:
158                         self.combine_tiles(i, j, pivot, j)
159                     else:
160                         if self.__tiles[pivot][j]:
161                             pivot += 1
162                         self.move_tile(i, j, pivot, j)
163         return True
164
165     def can_up(self):
166         '''Check if anything can move up'''
167         for j in range(self.__width):
168             for i in range(1, self.__height):
169                 p = self.__tiles[i][j]
170                 q = not self.__tiles[i - 1][j] or \
171                     self.__tiles[i][j] == self.__tiles[i - 1][j]
172                 if p and q:
173                     return True
174         return False
175
176     def down(self):
177         '''Slide the tiles down'''
178         if not self.can_down():
179             return False
180         for j in range(self.__width - 1, -1, -1):
181             pivot = self.__width - 1
182             for i in range(self.__height - 2, -1, -1):
183                 if self.__tiles[i][j]:
184                     if self.__tiles[i][j] == self.__tiles[pivot][j]:
185                         self.combine_tiles(i, j, pivot, j)
186                     else:
187                         if self.__tiles[pivot][j]:
188                             pivot -= 1
189                         self.move_tile(i, j, pivot, j)
190         return True
191
192     def can_down(self):
193         '''Check if anything can move down'''
194         for j in range(self.__width - 1, -1, -1):
195             for i in range(self.__height - 2, -1, -1):
196                 p = self.__tiles[i][j]
197                 q = not self.__tiles[i + 1][j] or \
198                     self.__tiles[i][j] == self.__tiles[i + 1][j]
199                 if p and q:
200                     return True
201         return False
202
203     def __str__(self):
204         result = f"Score: {self.__score}\n"
205         for i in range(self.__height):
206             result += ("_" if i == 0 else "=") * \
207                 (self.__width * (self.__max_num_len + 2)) + "\n"
208             for j in range(self.__width):
209                 result += "|" + \
210                     (str(self.__tiles[i][j]) if self.__tiles[i][j]
211                         else " " * self.__max_num_len) + "|"
212             result += "\n"
213         result += "-" * (self.__width * (self.__max_num_len + 2)) + "\n"
214         return result
```