<commit_before>﻿// Copyright (c) <NAME>, 2015. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

namespace MartinCostello.AdventOfCode.Puzzles.Y2020
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    /// <summary>
    /// A class representing the puzzle for <c>https://adventofcode.com/2020/day/14</c>. This class cannot be inherited.
    /// </summary>
    [Puzzle(2020, 14, RequiresData = true)]
    public sealed class Day14 : Puzzle
    {
        /// <summary>
        /// Gets the sum of all values left in memory after processing completes using version 1.
        /// </summary>
        public long SumOfRemainingValuesV1 { get; private set; }

        /// <summary>
        /// Gets the sum of all values left in memory after processing completes using version 2.
        /// </summary>
        public long SumOfRemainingValuesV2 { get; private set; }

        /// <summary>
        /// Runs the specified program.
        /// </summary>
        /// <param name="program">The instructions of the program to run.</param>
        /// <param name="version">The emulator version to use.</param>
        /// <returns>
        /// The sum of the values in memory once the program has been run.
        /// </returns>
        public static long RunProgram(IList<string> program, int version)
        {
            const string MaskPrefix = "mask = ";

            char[] splitChars = { '[', ']', '=' };
            StringSplitOptions splitOptions = StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries;

            string mask = string.Empty;
            var memory = new Dictionary<long, long>(program.Count);

            foreach (string instruction in program)
            {
                if (instruction.StartsWith(MaskPrefix, StringComparison.Ordinal))
                {
                    // Flip the mask to match the endianness of BitArray
                    string maskValue = instruction[MaskPrefix.Length..];
                    mask = new string(maskValue.Reverse().ToArray());
                }
                else
                {
                    (long address, long value) = DecodeInstruction(instruction);

                    if (version == 1)
                    {
                        long maskedValue = value;

                        for (int i = 0; i < mask.Length; i++)
                        {
                            switch (mask[i])
                            {
                                case '0':
                                    maskedValue &= ~(1L << i);
                                    break;

                                case '1':
                                    maskedValue |= 1L << i;
                                    break;
                            }
                        }

                        memory[address] = maskedValue;
                    }
                    else
                    {
                        long onesMask = 0;

                        var floatingIndexes = new List<int>();

                        for (int i = 0; i < mask.Length; i++)
                        {
                            switch (mask[i])
                            {
                                case '1':
                                    onesMask |= 1L << i;
                                    break;

                                case 'X':
                                    floatingIndexes.Add(i);
                                    break;
                            }
                        }

                        var addresses = new HashSet<long>();

                        for (int i = 0; i < floatingIndexes.Count; i++)
                        {
                            long maskedAddress = address | onesMask;

                            for (int j = 0; j < floatingIndexes.Count; j++)
                            {
                                addresses.Add(maskedAddress &= ~(1L << floatingIndexes[i]));
                                addresses.Add(maskedAddress |= 1L << floatingIndexes[j]);
                                addresses.Add(maskedAddress |= 1L << floatingIndexes[i]);
                                addresses.Add(maskedAddress &= ~(1L << floatingIndexes[j]));
                            }
                        }

                        foreach (int index in addresses)
                        {
                            memory[index] = value;
                        }
                    }
                }
            }

            return memory.Values.Sum();

            (long address, long value) DecodeInstruction(string instruction)
            {
                string[] split = instruction.Split(splitChars, splitOptions);
                return (ParseInt64(split[1]), ParseInt64(split[2]));
            }
        }
<commit_msg>Solve day 14 part 2<commit_after>﻿// Copyright (c) <NAME>, 2015. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

namespace MartinCostello.AdventOfCode.Puzzles.Y2020
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    /// <summary>
    /// A class representing the puzzle for <c>https://adventofcode.com/2020/day/14</c>. This class cannot be inherited.
    /// </summary>
    [Puzzle(2020, 14, RequiresData = true)]
    public sealed class Day14 : Puzzle
    {
        /// <summary>
        /// Gets the sum of all values left in memory after processing completes using version 1.
        /// </summary>
        public long SumOfRemainingValuesV1 { get; private set; }

        /// <summary>
        /// Gets the sum of all values left in memory after processing completes using version 2.
        /// </summary>
        public long SumOfRemainingValuesV2 { get; private set; }

        /// <summary>
        /// Runs the specified program.
        /// </summary>
        /// <param name="program">The instructions of the program to run.</param>
        /// <param name="version">The emulator version to use.</param>
        /// <returns>
        /// The sum of the values in memory once the program has been run.
        /// </returns>
        public static long RunProgram(IList<string> program, int version)
        {
            const string MaskPrefix = "mask = ";

            char[] splitChars = { '[', ']', '=' };
            StringSplitOptions splitOptions = StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries;

            int floatingBits = 0;
            string mask = string.Empty;

            var memory = new Dictionary<long, long>(program.Count);

            foreach (string instruction in program)
            {
                if (instruction.StartsWith(MaskPrefix, StringComparison.Ordinal))
                {
                    // Flip the mask to match the endianness of BitArray
                    string maskValue = instruction[MaskPrefix.Length..];
                    mask = new string(maskValue.Reverse().ToArray());
                    floatingBits = mask.Count((p) => p == 'X');
                }
                else
                {
                    (long address, long value) = DecodeInstruction(instruction);

                    if (version == 1)
                    {
                        long maskedValue = value;

                        for (int i = 0; i < mask.Length; i++)
                        {
                            switch (mask[i])
                            {
                                case '0':
                                    maskedValue &= ~(1L << i);
                                    break;

                                case '1':
                                    maskedValue |= 1L << i;
                                    break;
                            }
                        }

                        memory[address] = maskedValue;
                    }
                    else
                    {
                        long limit = (long)Math.Pow(2, floatingBits);

                        for (long i = 0; i < limit; i++)
                        {
                            long baseAddress = address;
                            int offset = 0;

                            for (int bit = 0; bit < mask.Length; bit++)
                            {
                                char ch = mask[bit];

                                if (ch == '1')
                                {
                                    baseAddress |= 1L << bit;
                                }
                                else if (ch == 'X')
                                {
                                    if (((i >> offset) & 1) == 0)
                                    {
                                        baseAddress &= ~(1L << bit);
                                    }
                                    else
                                    {
                                        baseAddress |= 1L << bit;
                                    }

                                    offset++;
                                }
                            }

                            memory[baseAddress] = value;
                        }
                    }
                }
            }

            return memory.Values.Sum();

            (long address, long value) DecodeInstruction(string instruction)
            {
                string[] split = instruction.Split(splitChars, splitOptions);
                return (ParseInt64(split[1]), ParseInt64(split[2]));
            }
        }

{'fraction_non_alphanumeric': 0.09163184181021303, 'fraction_numerical': 0.010600346549791051, 'mean_word_length': 0.9683049147442327, 'pattern_counts': {'":': 0, '<': 74, '<?xml version=': 0, '>': 46, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 25, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1354101', 'n_tokens_mistral': 2309, 'n_tokens_neox': 2092, 'n_words': 614}