applyMask($testMatrix, $size, $mask); $penalty = $this->calculateMaskPenalty($testMatrix, $size); if ($penalty < $lowestPenalty) { $lowestPenalty = $penalty; $bestMask = $mask; } } return $bestMask; } /** * Wendet eine Maske auf die Matrix an */ public function applyMask(array &$matrix, int $size, MaskPattern $maskPattern): void { for ($row = 0; $row < $size; $row++) { for ($col = 0; $col < $size; $col++) { if ($matrix[$row][$col] === null) { continue; } if (!$this->isFunctionModule($row, $col, $size)) { if ($maskPattern->shouldMask($row, $col)) { $matrix[$row][$col] = !$matrix[$row][$col]; } } } } } /** * Berechnet die Strafpunkte für eine maskierte Matrix */ public function calculateMaskPenalty(array $matrix, int $size): int { $penalty = 0; // Regel 1: Aufeinanderfolgende Module gleicher Farbe $penalty += $this->evaluateConsecutiveModulesPenalty($matrix, $size); // Regel 2: Blöcke gleicher Farbe $penalty += $this->evaluateSameColorBlocksPenalty($matrix, $size); // Regel 3: Muster, die Finder-Pattern ähneln $penalty += $this->evaluateFinderPatternLikePenalty($matrix, $size); // Regel 4: Ausgewogenheit schwarzer und weißer Module $penalty += $this->evaluateBalancePenalty($matrix, $size); return $penalty; } /** * Evaluiert die Strafe für aufeinanderfolgende Module gleicher Farbe */ private function evaluateConsecutiveModulesPenalty(array $matrix, int $size): int { $penalty = 0; // Zeilen prüfen for ($row = 0; $row < $size; $row++) { $count = 1; for ($col = 1; $col < $size; $col++) { if ($matrix[$row][$col] === $matrix[$row][$col - 1]) { $count++; } else { if ($count >= 5) { $penalty += 3 + ($count - 5); } $count = 1; } } if ($count >= 5) { $penalty += 3 + ($count - 5); } } // Spalten prüfen for ($col = 0; $col < $size; $col++) { $count = 1; for ($row = 1; $row < $size; $row++) { if ($matrix[$row][$col] === $matrix[$row - 1][$col]) { $count++; } else { if ($count >= 5) { $penalty += 3 + ($count - 5); } $count = 1; } } if ($count >= 5) { $penalty += 3 + ($count - 5); } } return $penalty; } /** * Evaluiert die Strafe für 2x2 Blöcke gleicher Farbe */ private function evaluateSameColorBlocksPenalty(array $matrix, int $size): int { $penalty = 0; for ($row = 0; $row < $size - 1; $row++) { for ($col = 0; $col < $size - 1; $col++) { $color = $matrix[$row][$col]; if ($color === $matrix[$row][$col + 1] && $color === $matrix[$row + 1][$col] && $color === $matrix[$row + 1][$col + 1]) { $penalty += 3; } } } return $penalty; } /** * Evaluiert die Strafe für Muster, die wie Finder-Pattern aussehen */ private function evaluateFinderPatternLikePenalty(array $matrix, int $size): int { $penalty = 0; // Vereinfachte Implementation return $penalty; } /** * Evaluiert die Strafe für unausgewogene schwarze/weiße Module */ private function evaluateBalancePenalty(array $matrix, int $size): int { $darkCount = 0; $totalCount = $size * $size; for ($row = 0; $row < $size; $row++) { for ($col = 0; $col < $size; $col++) { if ($matrix[$row][$col] === true) { $darkCount++; } } } $darkPercentage = $darkCount * 100 / $totalCount; $deviation = abs($darkPercentage - 50) / 5; return (int) ($deviation * 10); } /** * Prüft, ob ein Modul ein Funktionsmodul ist (also nicht maskiert werden sollte) */ private function isFunctionModule(int $row, int $col, int $size): bool { // Finder-Pattern und Separatoren if (($row < 9 && $col < 9) || ($row < 9 && $col >= $size - 8) || ($row >= $size - 8 && $col < 9)) { return true; } // Timing-Pattern if ($row === 6 || $col === 6) { return true; } // Format-Informationen if (($row < 9 && $col === 8) || ($row === 8 && $col < 9) || ($row === 8 && $col >= $size - 8) || ($row >= $size - 8 && $col === 8)) { return true; } // Dark Module bei Version 1 if ($row === 8 && $col === 13) { return true; } return false; } }