Example #1
0
        public override object CalculateResult()
        {
            return new Range(1, 100, true)
                .SelectMany(n => new Range(1, n, true)
                    .Where(r =>
                    {
                        var numerators = new Range(n - r + 1, n, true).Select(x => (long)x).ToArray();
                        var denominators = new Range(2, r, true).Select(x => (long)x).ToArray();

                        for (int i = 0; i < numerators.Length; i++)
                        {
                            long numerator = numerators[i];
                            if (numerator > 1)
                            {
                                for (int j = 0; j < denominators.Length; j++)
                                {
                                    long denominator = denominators[j];
                                    if (denominator > 1)
                                    {
                                        long divisor = MathUtilities.GreatestCommonDivisor(numerator, denominator);
                                        numerator /= divisor;
                                        denominator /= divisor;

                                        denominators[j] = denominator;
                                    }
                                }
                                numerators[i] = numerator;
                            }
                        }

                        if (denominators.Any(d => d != 1))
                        {
                            throw new InvalidOperationException();
                        }

                        long value = 1;
                        for (int i = 0; i < numerators.Length; i++)
                        {
                            value *= numerators[i];
                            if (value > 1000000)
                            {
                                return true;
                            }
                        }
                        return false;
                    }))
                .Count();
        }
Example #2
0
    /// <summary>
    /// Scans the tickets associated with the specified notes.
    /// </summary>
    /// <param name="notes">The notes containing the ticket information.</param>
    /// <returns>
    /// The ticket scanning error rate and your parsed ticket.
    /// </returns>
    public static (int ErrorRate, IDictionary <string, int> Ticket) ScanTickets(IList <string> notes)
    {
        int indexOfFirstTicket  = notes.IndexOf("your ticket:") + 1;
        int indexOfSecondTicket = notes.IndexOf("nearby tickets:") + 1;

        var rules = new Dictionary <string, ICollection <Range> >(indexOfFirstTicket - 2);

        // Parse the rules
        foreach (string line in notes.Take(indexOfFirstTicket - 2))
        {
            (string name, string instruction) = line.Bifurcate(':');
            string[] split = instruction.Split(" or ", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);

            var ranges = new Range[split.Length];

            for (int i = 0; i < split.Length; i++)
            {
                (int start, int end) = split[i].AsNumberPair <int>('-');
                ranges[i]            = new(start, end);
            }

            rules[name] = ranges;
        }

        var allTickets = new IList <int> [notes.Count - indexOfSecondTicket + 1];

        allTickets[0] = notes[indexOfFirstTicket]
                        .AsNumbers <int>()
                        .ToArray();

        // Parse the nearby tickets
        for (int i = indexOfSecondTicket; i < notes.Count; i++)
        {
            allTickets[i - indexOfSecondTicket + 1] = notes[i]
                                                      .AsNumbers <int>()
                                                      .ToArray();
        }

        int invalidValues = 0;
        var validTickets  = new List <IList <int> >();

        // Find the valid tickets
        for (int i = 1; i < allTickets.Length; i++)
        {
            var  ticket  = allTickets[i];
            bool isValid = true;

            for (int j = 0; j < ticket.Count && isValid; j++)
            {
                int value = ticket[j];

                foreach (ICollection <Range> ranges in rules.Values)
                {
                    isValid = ranges.Any((p) => InRange(value, p));

                    if (isValid)
                    {
                        break;
                    }
                }

                if (!isValid)
                {
                    invalidValues += value;
                }
            }

            if (isValid)
            {
                validTickets.Add(ticket);
            }
        }

        // Store indexes where each field could be located
        var possibleIndexes = new Dictionary <string, List <int> >(rules.Keys.Count);
        var allIndexes      = Enumerable.Range(0, allTickets[0].Count).ToList();

        foreach (string key in rules.Keys)
        {
            possibleIndexes[key] = new List <int>(allIndexes);
        }

        var indexes = new Dictionary <int, string>();

        while (possibleIndexes.Values.Any((p) => p.Count > 1))
        {
            // For any fields where the index is known, remove it from all the other possibilities
            foreach (var index in possibleIndexes.Where((p) => p.Value.Count == 1))
            {
                int foundIndex = index.Value[0];

                indexes[foundIndex] = index.Key;

                foreach (List <int> other in possibleIndexes.Values.Where((p) => p.Count > 1))
                {
                    other.Remove(foundIndex);
                }
            }

            // No need to iterate through the rules for fields we know the index for
            foreach (var rule in rules.Where((p) => possibleIndexes[p.Key].Count > 1))
            {
                // Check if all the values for this index fit the current rule
                for (int index = 0; index < possibleIndexes.Count; index++)
                {
                    bool areAllValid = true;

                    for (int j = 0; j < validTickets.Count; j++)
                    {
                        IList <int> ticket = validTickets[j];
                        int         value  = ticket[index];

                        bool isInRange = rule.Value.Any((p) => InRange(value, p));

                        if (!isInRange)
                        {
                            // This index cannot be the field associated with this rule
                            areAllValid = false;
                            break;
                        }
                    }

                    if (!areAllValid)
                    {
                        // This index cannot be for the field associated with this rule
                        possibleIndexes[rule.Key].Remove(index);
                    }
                }
            }
        }

        // Build up the ticket from the indexes found
        var yourTicket = new Dictionary <string, int>(indexes.Count);

        foreach (var index in indexes)
        {
            yourTicket[index.Value] = allTickets[0][index.Key];
        }

        return(invalidValues, yourTicket);