Test Failed
Push — master ( 0d2523...299604 )
by Midori
01:39
created

GameOfLife::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 2
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace MidoriKocak\GameOfLife;
4
5
6
class GameOfLife
7
{
8
    /**
9
     * @var \DOMDocument
10
     */
11
    private $xml;
12
13
    /**
14
     * @var Life
15
     */
16
    private $life;
17
18
    /**
19
     * @var World
20
     */
21
    private $world;
22
23
    /**
24
     * @var Organisms
25
     */
26
    private $organisms;
27
28
    /**
29
     * @var int
30
     */
31
    private $size;
32
33
    /**
34
     * @var int
35
     */
36
    private $iterations;
37
38
    /**
39
     * @var int
40
     */
41
    private $species;
42
43
    private $outputFilename = "out.xml";
44
45
    public function __construct(string $filename, string $outputFilename = null)
46
    {
47
        $this->loadXML($filename);
48
49
        if($outputFilename != null){
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $outputFilename of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
50
            $this->outputFilename = $outputFilename;
51
        }
52
53
        $world = $this->xml->getElementsByTagName('world')->item(0);
54
        $this->size = $world->getElementsByTagName('cells')->item(0)->nodeValue;
55
        $this->iterations = $world->getElementsByTagName('iterations')->item(0)->nodeValue;
56
        $this->species = $world->getElementsByTagName('species')->item(0)->nodeValue;
57
58
        $this->createWorld();
59
        $this->createOrganisms();
60
        $this->createLife();
61
    }
62
63
    private function loadXML($filename)
64
    {
65
        if (!file_exists($filename)) {
66
            throw new \Exception('File not found.');
67
        }
68
69
        $handler = fopen($filename, "r");
70
71
        if (!$handler) {
72
            throw new \Exception('File open failed.');
73
        }
74
75
        $xmlString = stream_get_contents($handler);
76
        $this->xml = new \DOMDocument();
77
        $this->xml->loadXML($xmlString);
78
        fclose($handler);
79
80
        return true;
81
    }
82
83
    public function start($verbose = true)
84
    {
85 View Code Duplication
        if ($this->organisms == null || $this->species == null || $this->iterations == null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
86
            throw new \Exception('Not ready yet');
87
        }
88
89
        $this->life->start($verbose);
90
91
        if ($this->life->isEnded()) {
92
            self::createXMLfromCells("data/".$this->outputFilename, $this->organisms->getCells(), $this->species, $this->iterations);
93
        }
94
95
        return true;
96
    }
97
98
    public function generateOutput()
99
    {
100
        if ($this->organisms == null || $this->world == null || $this->life !== null) {
101
            throw new \Exception('Not ready yet');
102
        }
103
104
        if (!$this->life->isEnded()) {
105
            throw new \Exception('You cannot generate output while life continues');
106
        }
107
108
        self::createXMLfromCells(
109
            "out.xml",
110
            $this->organisms->getCells(),
111
            $this->world->getSpecies(),
112
            $this->world->getIterations()
113
        );
114
    }
115
116
    private function createLife()
117
    {
118
        if ($this->organisms !== null && $this->world !== null) {
119
            $this->life = new Life($this->world, $this->organisms);
120
        } else {
121
            throw new \Exception('Not ready yet');
122
        }
123
    }
124
125
    private function createWorld()
126
    {
127 View Code Duplication
        if ($this->size == null || $this->species == null | $this->iterations == null) {
0 ignored issues
show
Bug introduced by
Are you sure you want to use the bitwise | or did you mean ||?
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
128
            throw new \Exception('Not ready yet');
129
        }
130
131
        if ($this->size < 0 || $this->species < 0 || $this->iterations < 0) {
132
            throw new \InvalidArgumentException("World arguments should be positive.");
133
        }
134
135
        $this->world = new World($this->size, $this->species, $this->iterations);
136
    }
137
138
    private function createOrganisms()
139
    {
140 View Code Duplication
        if ($this->size == null || $this->species == null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
141
            throw new \Exception('Not ready yet');
142
        }
143
144
        if ($this->size < 0 || $this->species < 0) {
145
            throw new \InvalidArgumentException("Organisms arguments should be positive.");
146
        }
147
        $cellsArray = self::createSquareMatrixWithZeors($this->size);
148
        $organisms = $this->xml->getElementsByTagName('organism');
149
150
        /**
151
         * @var \DOMElement $organism
152
         */
153
        foreach ($organisms as $organism) {
154
            $j = $organism->getElementsByTagName('x_pos')->item(0)->nodeValue;
155
            $i = $organism->getElementsByTagName('y_pos')->item(0)->nodeValue;
156
            $value = $organism->getElementsByTagName('species')->item(0)->nodeValue;
157
158
            $cellsArray[$i][$j] = $value;
159
        }
160
161
        $this->checkCells($cellsArray, $this->species);
162
163
        $this->organisms = new Organisms($cellsArray);
164
    }
165
166
    public static function createXMLfromCells($filename, array $matrix, int $species, int $iterations)
167
    {
168
        $domtree = new \DOMDocument('1.0', 'UTF-8');
169
170
        $xmlRoot = $domtree->createElement("life");
171
172
        $xmlRoot = $domtree->appendChild($xmlRoot);
173
174
175
        $world = $domtree->createElement("world");
176
        $xmlRoot->appendChild($world);
177
178
        $world->appendChild($domtree->createElement('cells', sizeof($matrix)));
179
        $world->appendChild($domtree->createElement('species', $species));
180
        $world->appendChild($domtree->createElement('iterations', $iterations));
181
182
        $organisms = $domtree->createElement("organisms");
183
184
185
        $xmlRoot->appendChild($organisms);
186
187
        for ($i = 0; $i < sizeof($matrix); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
188
            for ($j = 0; $j < sizeof($matrix[0]); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
189
                if ($matrix[$i][$j] !== 0) {
190
                    $organism = $domtree->createElement('organism');
191
                    $organism->appendChild($domtree->createElement('x_pos', $j));
192
                    $organism->appendChild($domtree->createElement('y_pos', $i));
193
                    $organism->appendChild($domtree->createElement('species', $matrix[$i][$j]));
194
                    $organisms->appendChild($organism);
195
                }
196
            }
197
        }
198
199
        file_put_contents($filename, $domtree->saveXML());
200
    }
201
202
    /**
203
     * @param int $size
204
     * @return array
205
     */
206
    public static function createSquareMatrixWithZeors(int $size)
207
    {
208
209
        $matrix = array_fill(0, $size, array_fill(0, $size, 0));
210
        return $matrix;
211
    }
212
213
    /**
214
     * @param int $n
215
     * @param int $m
216
     * @param int $max
217
     *
218
     * @return array
219
     */
220
    public static function createRandomMatrix(int $n, int $m, int $max)
221
    {
222
        $matrix = array_fill(0, $n, array_fill(0, $m, 0));
223
224
        for ($i = 0; $i < $n; $i++) {
225
            for ($j = 0; $j < $m; $j++) {
226
                $matrix[$i][$j] = rand(0, $max);
227
            }
228
        }
229
230
        return $matrix;
231
    }
232
233
    /**
234
     * @param int[][] $cells
235
     * @param int $species
236
     */
237
    private function checkCells(array $cells, int $species)
238
    {
239
        if (empty($cells) || empty($cells[0])) {
240
            throw new \InvalidArgumentException("Cells can't be empty");
241
        }
242
        for ($i = 0; $i < sizeof($cells); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
243
            for ($j = 0; $j < sizeof($cells[0]); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
244
                if ($cells[$i][$j] < 0 || $cells[$i][$j] > ($species + 1)) {
245
                    throw new \InvalidArgumentException("Cells can't be empty");
246
                }
247
            }
248
        }
249
    }
250
251
}