iRoygbiv
iRoygbiv

Reputation: 875

Optimising the game of life

I'm writing a game of life program in mathematica however there is a caveat in that I need to be able to apply the reproduction rules to some percentage of the cells, I want to try a new method using MapAt but liveNeighbors doesn't work elementwise, and I can't think of a way of fixing it without doing exactly what I did before (lots of messy indexing), does anyone have any suggestions? (I am assuming this will be more efficient then the old method, which is listed below, if not please let me know, I am just a beginner!).

What I am trying to do:

 Map[ArrayPlot,FixedPointList[MapAt[update[#,liveNeighbors[#]]&,#,coords]&,Board, 1]]

What I have done already:

LifeGame[ n_Integer?Positive, steps_] := Module [{Board, liveNeighbors, update},
  Board = Table [Random [Integer], {n}, {n}];
  liveNeighbors[ mat_] := 
   Apply[Plus,Map[RotateRight[mat,#]&,{{-1,-1},{-1, 0},{-1,1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}]];
  update[1, 2] := 1;
  update[_, 3] := 1;
  update[ _, _] := 0;
  SetAttributes[update, Listable];
 Seed = RandomVariate[ProbabilityDistribution[0.7 UnitStep[x] + 0.3 UnitStep[x - 1], {x, 0, 1, 1}], {n, n}];
 FixedPointList[Table[If[Seed[[i, j]] == 1,update[#[[i, j]], liveNeighbors[#][[i, j]]],#[[i, j]]], {i, n}, {j, n}]&, Board, steps]]]

Thanks!

Upvotes: 2

Views: 1083

Answers (3)

Sasha
Sasha

Reputation: 5954

In[156]:= 
LifeGame2[n_Integer?Positive, steps_] := 
 Module[{Board, liveNeighbors, update},
  Board = RandomInteger[1, {n, n}];
  liveNeighbors[mat_] := 
   ListConvolve[{{1, 1, 1}, {1, 0, 1}, {1, 1, 1}}, 
    ArrayPad[mat, 1, "Periodic"]];
  SetAttributes[update, Listable];
  Seed = RandomVariate[BernoulliDistribution[0.3], {n, n}];
  update[0, el_, nei_] := el;
  update[1, 1, 2] := 1;
  update[1, _, 3] := 1;
  update[1, _, _] := 0;
  FixedPointList[MapThread[update, {Seed, #, liveNeighbors[#]}, 2] &, 
   Board, steps]
  ]

This implementation does the same as yours, except is quite a lot faster:

In[162]:= AbsoluteTiming[
 res1 = BlockRandom[SeedRandom[11]; LifeGame[20, 100]];]

Out[162]= {6.3476347, Null}

In[163]:= Timing[BlockRandom[Seed[11]; LifeGame2[20, 100]] == res1]

Out[163]= {0.047, True}

Upvotes: 5

Michael Pilat
Michael Pilat

Reputation: 6520

Assuming you don't have to roll your own code for a homework problem, have you considered just using the built-in CellularAutomaton function?

Straight from the documentation, the 2D CA rule:

GameOfLife = {224, {2, {{2, 2, 2}, {2, 1, 2}, {2, 2, 2}}}, {1, 1}};

And iterate over a 100x100 grid for 100 steps:

ArrayPlot[CellularAutomaton[GameOfLife, RandomInteger[1, {100, 100}], {{{100}}}]]

output of CellularAutomaton

It would at least give you a baseline for a speed comparison.

Instead of MapAt, you could use Part with the Span syntax to replace a whole subarray at once:

a = ConstantArray[0, {5, 5}];
a[[2 ;; 4, 2 ;; 4]] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}

a in MatrixForm

HTH!

Upvotes: 4

Related Questions