Closed fred-cook closed 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)
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)
Scores on the doors for each method, with GPU and GPU2 being methods 3 and 2 confusingly
Write a small class which can generate grids
parameters
grid_shape: tuple[int, int]
num_mines: int
methods
generate_grids -> np.ndarray