fred-cook / lad-sweeper

minesweeper clone
MIT License
1 stars 0 forks source link

solved grid maker #1

Closed fred-cook closed 1 year ago

fred-cook commented 1 year ago

Write a small class which can generate grids

parameters

methods

fred-cook commented 1 year ago

Written a new version that's an order of magnitude faster:

class GridGenerator2:
    def __init__(self, grid_shape=(16,16), num_mines=44):
        self.grid_shape = grid_shape
        self.size = grid_shape[0] * grid_shape[1]
        self.num_mines = num_mines

        self.rng = np.random.default_rng()

    def generate_n_grids(self, N):
        padded_shape = (N, self.grid_shape[0]+2, self.grid_shape[1]+2)
        mined_grids = self.generate_n_mined_boards(N)
        padded = np.zeros(padded_shape, dtype=np.int8)
        padded[:,1:-1,1:-1] = mined_grids
        strides = (padded.strides[0],) + padded.strides[1:]*2
        new_shape = (N, self.grid_shape[0], self.grid_shape[1], 3, 3)

        neighbours = as_strided(padded, new_shape, strides)
        vals = np.abs(np.sum(neighbours, axis=(-1, -2)))
        return np.where(mined_grids == -1, -1, vals)

    def generate_n_coords(self, N):
        return np.vstack([self.rng.permutation(self.size)
                          for _ in range(N)])[:,:self.num_mines]

    def generate_n_mined_boards(self, N):
        boards = np.zeros((N, self.size), dtype=np.int8)
        rows = np.arange(N)[:,None] * np.ones(self.num_mines,
                                              dtype=np.int8)
        mines = self.generate_n_coords(N)
        boards[(rows.flatten(), mines.flatten())] = -1
        return boards.reshape(N, *self.grid_shape)
fred-cook commented 1 year ago

Another! Only a little bit faster:

class GridGenerator3:
    def __init__(self, grid_shape=(16, 16), num_mines=44):
        self.grid_shape = grid_shape
        self.size = grid_shape[0] * grid_shape[1]
        self.num_mines = num_mines

        self.rng = np.random.default_rng()

        self.neibs = self.get_1d_neighbours()

    def get_1d_neighbours(self):
        padded_shape = (self.grid_shape[0] + 2, self.grid_shape[1] + 2)
        padded = np.full(padded_shape, -1, dtype=np.int8)
        padded[1:-1, 1:-1] = np.arange(self.size).reshape(self.grid_shape)
        neibs = as_strided(padded, (*self.grid_shape, 3, 3), padded.strides*2)
        neibs = neibs.reshape(-1, 9)
        neibs[:,4] = -1
        return neibs

    def generate_n_coords(self, N):
        return np.vstack([self.rng.permutation(self.size)
                          for _ in range(N)])[:,:self.num_mines]

    def generate_n_mined_boards(self, N):
        boards = np.zeros((N, self.size), dtype=np.int8)
        rows = np.arange(N)[:,None] * np.ones(self.num_mines,
                                              dtype=np.int8)
        mines = self.generate_n_coords(N)
        boards[(rows.flatten(), mines.flatten())] = -1
        return np.c_[boards, np.zeros(N, dtype=np.int8)]

    def generate_n_grids(self, N):
        boards = self.generate_n_mined_boards(N)
        counts = boards.flatten()[np.tile(self.neibs, (N, 1))].reshape(N, self.size, -1)
        counts = np.abs(np.sum(counts, -1))
        return np.where(boards[:,:-1]==-1, boards[:,:-1], counts)
fred-cook commented 1 year ago

gpu

Scores on the doors for each method, with GPU and GPU2 being methods 3 and 2 confusingly