/** * Numbering of black runs: j * Count of black runs in a row: k * Row size (amount of cells): n * left most starting position of run j: rjs * right most ending position of run j: rje * length of black run: LB * * @param null $rowNumber * @param null $colNumber * @return array */ private function initRunRangeFor($rowNumber = null, $colNumber = null) { if (!($rowNumber == null xor $colNumber == null)) { throw new \RuntimeException('specify either row OR col number and not both'); } $r = array(); $labels = $colNumber != null ? $this->labels->getLabelsForColumn($colNumber) : $this->labels->getLabelsForRow($rowNumber); if (empty($labels)) { return $r; } $n = $colNumber != null ? $this->labels->getSizeY() : $this->labels->getSizeX(); $k = count($labels); $r[1]['s'] = 0; for ($j = 2; $j <= $k; $j++) { $r[$j]['s'] = 0; for ($i = 1; $i <= $j - 1; $i++) { $LB = $labels[$i - 1]; $r[$j]['s'] += $LB + 1; } } for ($j = 1; $j <= $k - 1; $j++) { $r[$j]['e'] = $n - 1; for ($i = $j + 1; $i <= $k; $i++) { $LB = $labels[$i - 1]; $r[$j]['e'] -= $LB + 1; } } $r[$k]['e'] = $n - 1; return $r; }
/** * @param Label $labels * @param array $fieldOverride option to inject a pre-defined state, only useful for unittests * @param RunRange\RunRange|null $runRangeOverride option to inject a pre-defined state, only useful for unittests * @return array */ public function solve(\Nonogram\Label\Label $labels, array $fieldOverride = array(), RunRange $runRangeOverride = null) { $timeStart = microtime(true); $this->init($labels, $fieldOverride, $runRangeOverride); if ($labels->hasHiddenCounts()) { return $this->field; } $iterations = 0; do { $updateCounter = 0; //iterate over all rows foreach ($this->field as $rowNum => &$row) { if (!empty($this->finishedRows) && in_array($rowNum, $this->finishedRows)) { continue; } $blackRuns = $this->labels->getLabelsForRow($rowNum + 1); $r =& $this->runRanges->getRangesForRow($rowNum + 1); foreach ($this->rules as $rule) { if ($rule::RESULT_LINE_SOLVED === $rule->apply($row, $blackRuns, $r)) { $this->finishedRows[] = $rowNum; } $updateCounter += $this->processUpdateCounter($rule); } } if (count($this->field) === 1) { return $this->field; } //iterate over all columns for ($colNum = 0; $colNum < $this->labels->getSizeX(); $colNum++) { if (!empty($this->finishedCols) && in_array($colNum, $this->finishedCols)) { continue; } //compose a new sequence of the column $sequence = array(); for ($rowNum = 0; $rowNum < $this->labels->getSizeY(); $rowNum++) { $sequence[$rowNum] =& $this->field[$rowNum][$colNum]; } $blackRuns = $this->labels->getLabelsForColumn($colNum + 1); $r =& $this->runRanges->getRangesForColumn($colNum + 1); foreach ($this->rules as $rule) { if ($rule::RESULT_LINE_SOLVED === $rule->apply($sequence, $blackRuns, $r)) { $this->finishedCols[] = $colNum; } $updateCounter += $this->processUpdateCounter($rule); } } $iterations++; } while ($updateCounter > 0); $this->lastSolvingTime = microtime(true) - $timeStart; $this->solvingStatistics['Iterations'] = $iterations; $this->solvingStatistics['Solving time'] = $this->lastSolvingTime; return $this->field; }
/** * Returns the number of rows (vertical size) * * required for drawing the field */ public function getSizeY() { return $this->labels->getSizeY(); }