generations = $generations; $this->boardWidth = $boardWidth; $this->boardHeight = $boardHeight; // Empty the image directory array_map('unlink', glob(Image::IMAGE_PATH . "/*.*")); // Calculate the number of columns and rows on the board $this->rows = ($this->boardWidth/(Cell::WIDTH + Cell::SPACING)); $this->columns = ($this->boardHeight/(Cell::HEIGHT + Cell::SPACING)); // Populate the board with dead cells for ($column = 0; $column < $this->columns; $column++) { for ($row = 0; $row < $this->rows; $row++) { $this->matrix[$column][$row] = new Cell($column, $row); } } } /** * Populate the matrix with a random set of cells * * @param int $density */ public function randomMatrix($density = 600) { for($i=0;$i<(($this->boardWidth*$this->boardHeight)/$density);$i++) { $this->matrix[mt_rand(0, ($this->columns-1))][mt_rand(0, ($this->rows-1))]->birth(); } } private function matrixClone() { $matrixClone = []; for($matrixX = 0; $matrixX < $this->columns; $matrixX++) { for ($matrixY = 0; $matrixY < $this->rows; $matrixY++) { $matrixClone[$matrixX][$matrixY] = clone $this->matrix[$matrixX][$matrixY]; } } return $matrixClone; } /** * Generate the game of life */ public function generate() { // Fill the matrix with a random set of cells $this->randomMatrix(); //process the matrix for($generationNum = 0; $generationNum < $this->generations; $generationNum++) { $matrixTemp = $this->matrixClone(); // initiate a new generation $generationImage = new Image($this->boardWidth, $this->boardHeight); for($matrixX = 0; $matrixX < $this->columns; $matrixX++) { for($matrixY = 0; $matrixY < $this->rows; $matrixY++) { $cell = $matrixTemp[$matrixX][$matrixY]; $livingNeighbours = $this->livingCellNeighbourCount($cell); if ($cell->isAlive()) { if ($livingNeighbours < 2 || $livingNeighbours > 3) { $cell->kill(); } } else { if ($livingNeighbours == 3) { $cell->birth(); } } if($cell->isAlive()) { $generationImage->renderCell($cell); } } } //check there are still some 'living' cells if($this->extinctionHasOccured()) { break; } //write the XML if($generationNum > 2) { $this->xml .= " 7 ".__DIR__.'/'.Image::IMAGE_PATH."/G_".str_pad(($generationNum-2),3,"0",STR_PAD_LEFT).".png "; } if($generationNum > 3) { $this->xml .= " 1 ".__DIR__.'/'.Image::IMAGE_PATH."/G_".str_pad(($generationNum-2),3,"0",STR_PAD_LEFT).".png ".__DIR__.'/'.Image::IMAGE_PATH."/G_".str_pad(($generationNum-1),3,"0",STR_PAD_LEFT).".png "; } $this->matrix = $matrixTemp; $generationImage->write(Image::IMAGE_PATH . "/G_".str_pad($generationNum,3,"0",STR_PAD_LEFT)); } file_put_contents(self::XML_PATH, "". $this->xml .""); } /** * Look at all the cells surrounding this cell and * count how many are still alive * * @param Cell $cell * @return int */ private function livingCellNeighbourCount(Cell $cell) { // init $neighbours = 0; // Loop through each of the surrounding cells for($dx = -1; $dx <= 1; $dx++) { for($dy=-1; $dy <= 1; $dy++) { //skip the cell we are checking if($dx == 0 && $dy == 0) { continue; } if(!isset($this->matrix[($cell->getPositionX()+$dx)][($cell->getPositionY()+$dy)])) { continue; } if($this->matrix[($cell->getPositionX()+$dx)][($cell->getPositionY()+$dy)]->isAlive()) { $neighbours++; } } } // Return the number of living neighbours return (int)$neighbours; } /** * Check if there are any cells alive * * @return bool */ private function extinctionHasOccured() { for ($row = 0; $row < $this->rows; $row++) { for ($column = 0; $column < $this->columns; $column++) { if ($this->matrix[$column][$row]->isAlive()) { return false; } } } return true; } } $gol = new GameOfLifeBackground(15); $gol->generate(); ?>