2048-ml

git clone git://git.codymlewis.com/2048-ml.git
Log | Files | Refs | README | LICENSE

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 
     85     def no_adjacents(self):
     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