Change the rules of Life Life-like cellular automaton are cellular automaton that are similar to Conway's Game of Life, in that they operate on a (theoretically) infinitely large square grid, where each cell has exactly 8 neighbours, and is one of 2 states, namely alive and dead.

However, these Like-like versions are different in a crucial way: the rules for a given cell to come alive and the rules for a given cell to survive to the next generation.

For example, classic Game of Life uses the rule B3/S23, meaning that it takes 3 alive cells to birth a new one, and either 2 or 3 living neighbours to survive. For this challenge, we will assume that neighbours do not include itself, so each cell has exactly 8 neighbours.

Your task is, given a starting configuration, a birth rule, a survival rule and a positive integer (the number of generations to be run), simulate the Life-like automaton using those rules for the number of generations given in the shortest code possible. The starting configuration will be a square matrix/2-dimensional array or a multiline string, you may choose. The others may be given in any reasonable format and method.

For example, if the birth rule was 12345678 (any living neighbours), the survival rule was 2357 and the starting configuration was

0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0


the next two generations would be

Generation 1:           Generation 2:

0 0 0 0 0               1 1 1 1 1
0 1 1 1 0               1 1 0 1 1
0 1 0 1 0               1 0 1 0 1
0 1 1 1 0               1 1 0 1 1
0 0 0 0 0               1 1 1 1 1


If the number of generations given was 10, the output would be something along the lines of

0 1 1 1 0
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
0 1 1 1 0


You do not have to handle changes that happen outside of the bounds given by the input matrix, however, all cells outside the matrix begin dead. Therefore, the input matrix may be any size, up to the maximum value your language can support. You do not have to output the board between generations.

This is a code-golf so the shortest code wins.

Test cases

These use the B/S notation to indicate the rules used

B2/S2, generations = 100, configuration:

1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0


Output:

0 0 0 0 0 0 0 0
0 1 0 0 0 0 1 0
1 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0




B1357/S2468, generations = 12, configuration:

1 0 1 0 1 0
0 1 1 0 1 0
1 0 0 0 0 0
0 0 0 0 0 1
1 1 1 1 1 0
0 1 1 0 0 1


Output:

0 1 0 0 0 0
0 1 1 1 1 0
0 1 0 1 1 0
1 1 1 0 0 0
0 0 1 1 1 0
0 1 1 0 0 0


If you need to generate more test cases, you can use this wonderful simulator. Please make sure to limit the board size
MATL, 24 23 bytes
xx:&quot;tt3Y6Z+1Gm&lt;8M2Gmb*+

Inputs are:

Array with birth rule
Array with survival rule
Number of generations
Matrix with initial cell configuration, using ; as row separator.

Try it online! Or see test cases: 1, 2.
For a few bytes more you can see the evolution in ASCII art.
Explanation
xx      % Take two inputs implicitly: birth and survival rules. Delete them
        % (but they get copied into clipboard G)
:&quot;      % Take third input implicitly: number of generations. Loop that many times
  tt    %   Duplicate twice. This implicitly takes the initial cell configuration
        %   as input the first time. In subsequent iterations it uses the cell 
        %   configuration from the previous iteration
  3Y6   %   Push Moore neighbourhood: [1 1 1; 1 0 1; 1 1 1]
  Z+    %   2D convolution, maintaining size
  1G    %   Push first input from clipboard G: birth rule
  m     %   Ismember: gives true for cells that fulfill the birth rule
  &lt;     %   Less than (element-wise): a cell is born if it fulfills the birth rule
        %   *and* was dead
  8M    %   Push result of convolution again, from clipboard M
  2G    %   Push second input from clipboard G: survival rule
  m     %   Ismember: gives true for cells that fulfill the survival rule
  b     %   Bubble up the starting cell configuration
  *     %   Multiply (element-wise): a cell survives if it fulfills the survival
        %   rule *and* was alive
  +     %   Add: a cell is alive if it has been born or has survived, and those
        %   are exclusive cases. This produces the new cell configuration
        % Implicit end loop. Implicit display