def contract(self): """ Generate a new Board whose columns and rows are contracted; e.g. all columns consisting only of empty elements are removed and all elements are pushed as far to the bottom of the board as possible (taking up the space of formerly empty elements). :return: A board instance whose physical configuration is contracted. """ # For each column, determine indices in that column that are empty col_empty_indices = { col: [ idx for idx, elem in enumerate(self._extract_col(col)) if elem.is_empty() ] for col in range(len(self.board[0])) } # Generate a list where each sublist is a properly contracted version of each column shifted_cols = [ ([EmptyColor()] * len(col_empty_indices[idx])) + filter(lambda elem: not elem.is_empty(), self._extract_col(idx)) for idx in range(len(self.board[0])) ] # Remove all columns that only have empty colors cols_contracted = filter( lambda col: any((not elem.is_empty() for elem in col)), shifted_cols, ) # In order to create a grid again, the columns generated above need to be transposed return Board.from_grid(zip(*cols_contracted))
def pop_from(self, coord): """ Determine the board configuration resulting from an attempted flood pool pop at the specified coordinate. :param coord: Coordinate on this board. :return: A new Board resulting from popping the flood pool at the given location. :raises InvalidPopException: If a pop is not allowed from the given coordinate. """ # Get a list of all the indices that can be popped from this location to_pop = self.flood_indices(coord) # The game forbids popping an index where the flood size is unity if len(to_pop) == 1: raise InvalidPopException( 'Unable to pop from a flood group with only one element') # Create a new grid with popped items changed to EmptyColors empty = EmptyColor() update_grid = [[ empty if Coordinate(i, j) in to_pop else self.board[i][j] for j in range(len(self.board[i])) ] for i in range(len(self.board))] return Board.from_grid(update_grid).contract()
def coordinate_map_to_grid(coordinate_map): """ Transform a coordinate map to a two-dimensional grid. :param coordinate_map: Map from Coordinate to Color. :return: A list of lists representing the same data as the map. """ if not coordinate_map: return [] max_row = max([coord.i for coord in coordinate_map.keys()]) max_col = max([coord.j for coord in coordinate_map.keys()]) return [[ coordinate_map.get(Coordinate(i, j), EmptyColor()) for j in range(max_col + 1) ] for i in range(max_row + 1)]
def load_board(board_image_file_name): """ Parse the input board screenshot into a Board object. :param board_image_file_name: Path to the screenshot of the board. :return: A Board instance representing the input board. """ img = cv2.imread(board_image_file_name, cv2.IMREAD_COLOR) coordinate_map = {} for i in range(10): for j in range(10): pixel_i = IMAGE_BLOCK_START_I + i * IMAGE_BLOCK_OFFSET pixel_j = IMAGE_BLOCK_START_J + j * IMAGE_BLOCK_OFFSET bgr = img[pixel_i][pixel_j] color_code = struct.pack('BBB', *bgr).encode('hex') if color_code == 'e4eff7': coordinate_map[Coordinate(i, j)] = EmptyColor() else: coordinate_map[Coordinate(i, j)] = Color(color_code) return Board.from_coordinate_map(coordinate_map)
def test_empty_eq(self): a = EmptyColor() b = EmptyColor() self.assertEqual(a, b)
import unittest from color import Color from color import EmptyColor non_empty = Color('name') empty = EmptyColor() class TestColor(unittest.TestCase): def test_nonempty_init(self): self.assertIsNotNone(non_empty) self.assertEqual(non_empty.name, 'name') def test_nonempty_is_empty(self): # Colors are always considered non-empty self.assertFalse(non_empty.is_empty()) def test_nonempty_eq(self): a = Color('a') b = Color('b') c = Color('a') self.assertEqual(a, c) self.assertNotEqual(a, b) self.assertNotEqual(b, c) def test_nonempty_repr(self): self.assertEqual(repr(non_empty), 'name') def test_nonempty_str(self):
import unittest import board from board import Board from color import Color from color import EmptyColor from coordinate import Coordinate defined_color = Color('COLOR') empty_color = EmptyColor() class TestBoardUtils(unittest.TestCase): def test_coordinate_map_to_grid(self): coordinate_map = { Coordinate(0, 0): defined_color, Coordinate(1, 0): defined_color, Coordinate(0, 1): empty_color, } expect_grid = [ [defined_color, empty_color], [defined_color, empty_color], ] self.assertEqual(board.coordinate_map_to_grid(coordinate_map), expect_grid) self.assertEqual(board.coordinate_map_to_grid(None), []) def test_grid_to_coordinate_map(self): grid = [ [defined_color, empty_color], [defined_color, empty_color],