<commit_before><?php

namespace App\Services;

use App\Exceptions\SolverException;
use Generator;

class HatSolver
{
    public function one(array $participants, array $exclusions = []) : array
    {
        $hat = array_keys($participants);
        shuffle($hat);

        $generator = $this->yieldCombinations($exclusions, $hat);
        if (! $generator->valid()) {
            throw new SolverException('Cannot solve');
        }

        return $generator->current();
    }

    public function all(array $participants, array $exclusions = []) : Generator
    {
        return $this->yieldCombinations($exclusions, array_keys($participants));
    }

    private function yieldCombinations(array $exclusions, array $hat) : Generator
    {
        return $this->solve(0, [], $exclusions, $hat);
    }

    private function solve(int $participantIdx, array $combination, array $exclusions, array $hat) : Generator
    {
        // End of a loop, we've found a possible combination
        if ($hat === []) {
            yield $combination;
        }

        $actualExclusions = array_key_exists($participantIdx, $exclusions) ? $exclusions[$participantIdx] : [];
        $actualHat = array_diff($hat, $actualExclusions, [$participantIdx]);

        foreach ($actualHat as $possibleParticipant) {
            $possibilityCombination = $combination + [$participantIdx => $possibleParticipant];
            $possibilityHat = array_diff($hat, [$possibleParticipant]);

            yield from $this->solve($participantIdx + 1, $possibilityCombination, $exclusions, $possibilityHat);
        }
    }
}<commit_msg>Comment HatSolver<commit_after><?php

namespace App\Services;

use App\Exceptions\SolverException;
use Arr;
use Generator;

class HatSolver
{
    public function one(array $participants, array $exclusions = []) : array
    {
        $generator = $this->all($participants, $exclusions);
        if (! $generator->valid()) {
            throw new SolverException('Cannot solve');
        }

        return $generator->current();
    }

    public function all(array $participants, array $exclusions = []) : Generator
    {
        $hat = array_keys($participants);
        shuffle($hat);

        return $this->solve(0, [], $exclusions, $hat);
    }

    private function solve(int $participantIdx, array $combination, array $allExclusions, array $currentHat) : Generator
    {
        // End of a loop, we've found a possible combination
        if ($currentHat === []) {
            yield $combination;
        }

        // Get the exclusions requested for that participant
        // And remove them from the hat (+ the current participant)
        $exclusions = Arr::get($allExclusions, $participantIdx, []);
        $hat = array_diff($currentHat, $exclusions, [$participantIdx]);

        // If nothing available in the hat for that participant
        // Then nothing will happen and the combination will be lost
        foreach ($hat as $drawnParticipant) {
            // Create a new possible solution with the participant drawn
            $newCombination = $combination + [$participantIdx => $drawnParticipant];
            $newHat = array_diff($currentHat, [$drawnParticipant]);

            // Further check if this solution is possible
            yield from $this->solve($participantIdx + 1, $newCombination, $allExclusions, $newHat);
        }
    }
}
{'fraction_non_alphanumeric': 0.12029629629629629, 'fraction_numerical': 0.0011851851851851852, 'mean_word_length': 2.862700228832952, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5185718', 'n_tokens_mistral': 988, 'n_tokens_neox': 914, 'n_words': 245}