Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Advent of Code 2020 Day 14 Parts 1 and 2 solution by Mike LeSauvage
- public class DockingDataAnalyzer : MonoBehaviour
- {
- [SerializeField] TextAsset dockingDataTextfile = null; //Hooked up in the input text in the Unity editor.
- string maskRegex = @"mask = ([10X]{36})$"; //Gets the 36-digit mask
- string memWriteRegex = @"mem\[(?<address>\d+)\] = (?<data>\d+)"; //Gets the memory address (labelled address) and the data to be written (labelled data)
- // Start is called before the first frame update
- void Start()
- {
- string[] stringSeparator = { "\r\n" }; //Find two new lines for breaks. Windows encoding has both carriage return and line feed.
- string[] dockingMemoryStrings = dockingDataTextfile.text.Split(stringSeparator, System.StringSplitOptions.RemoveEmptyEntries);
- SolvePartOne(dockingMemoryStrings);
- SolvePartTwo(dockingMemoryStrings);
- }
- void SolvePartTwo(string[] dockingMemoryStrings)
- {
- //floatingBitPositions stores which bits are Xs in the provided mask, in order from rightmost to leftmost bit.
- //EG: floatingBitPositions[0]=4 tells you that the rightmost X was in bit position 4 such as: X0100
- // floatingBitPositions[1]=7 tells you the next X was in position 7 so mask could now be: X11X0100
- List<int> floatingBitPositions = new List<int>();
- Hashtable memory = new Hashtable();
- long startingORMask = 0;
- long cleanAddressANDMask = 0;
- // Overall approach
- // -----------------
- // (1) Loop across the file. When a mask is found:
- // (2) Get a clean address AND mask that can clear the address' bits where Xs are present (so they can be iterated through for all combinations.)
- // (3) Get a starting OR mask that will be used to set all the 1s where there were 1s in the original mask.
- // (4) Record the bit positions of all the floating bits, from right to left, in the floatingBitPositions list.
- //
- // (5) Loop across each of the memory writes.
- // (6) Get an address where the X-position bits are cleared to zero using the clean address AND mask.
- // (7) Loop for a count of the number of bit combinations for the floating Xs. EG: 4 Xs = 2^4=16 loops (from 0000 to 1111).
- // (8) Check each bit in the count and map every '1' to the corresponding bit's position in the floatingBitPositions, ORing it in to the starting OR mask.
- // (9) Apply the OR mask to the memory address.
- // (10)Write the data out, using a hash so that duplicate locations are overwritten.
- foreach (string s in dockingMemoryStrings)
- {
- MatchCollection allMatches = Regex.Matches(s, maskRegex);
- if (allMatches.Count == 1) //(1)
- {
- floatingBitPositions.Clear();
- //Prepare the address AND mask. This is used for clearing all the bits in the address where the //(2)
- //floating bits are located for setting when iterating through all floating bit combinations.
- string cleanAddressANDMaskString = allMatches[0].Groups[1].Value.Replace('0', '1');
- cleanAddressANDMaskString = cleanAddressANDMaskString.Replace('X', '0');
- cleanAddressANDMask = Convert.ToInt64(cleanAddressANDMaskString, 2);
- //Prepare the starting OR mask. This mask will later be manipulated to add 1s in the position of the //(3)
- //floating bits to give every combination of of the mask (ie: 4 Xs is 16 combinations)
- char[] maskChars = allMatches[0].Groups[1].Value.ToCharArray();
- for (int i = maskChars.Length - 1; i >= 0; i--)
- {
- if (maskChars[i] == 'X')
- {
- maskChars[i] = '0';
- floatingBitPositions.Add(maskChars.Length - i - 1); //(4)
- }
- }
- string maskString = new string(maskChars);
- startingORMask = Convert.ToInt64(maskString, 2);
- }
- allMatches = Regex.Matches(s, memWriteRegex);
- if (allMatches.Count == 1) //(5)
- {
- //Get address and clear floating bit locations.
- long address = long.Parse(allMatches[0].Groups["address"].Value);
- address &= cleanAddressANDMask; //(6)
- long data = long.Parse(allMatches[0].Groups["data"].Value);
- long bitRange = (long)Mathf.Pow(2, floatingBitPositions.Count); //Eg, 3 bits is 2^3=8 loop from 0->7 which will cover 000 to 111
- //Loop for all combinations given by the number of bits.
- for (long i = 0; i < bitRange; i++) //(7)
- {
- long orMask = startingORMask;
- //Set up the OR Mask to include bits set on this combination
- for (int bitNum = 0; bitNum < floatingBitPositions.Count; bitNum++)
- {
- //Maps the bit combination of i to the floating bits in the original mask.
- //So if i is 6 its bits are 1010. If the mask was 0X100XX01X0 it will be mapped to 0 '1' 1 0 0 '0' '1' 0 1 '0' 0 (in quotes are injected)
- //This requires floatingBitPositions to be set up with indexes matching bits from right to left.
- // Meaning: floatingBitPositions[0] is the rightmost X bit in the mask
- // floatingBitPositions[1] is the X bit to the left of that one, etc..
- if (IsBitSet(i, bitNum)) //(8)
- {
- int equivalentBitPositionInFullMask = floatingBitPositions[bitNum];
- long setOneBitMask = (long)1 << equivalentBitPositionInFullMask;
- orMask |= setOneBitMask;
- }
- }
- //OR mask is now set up with the Xs filled with 0s or 1s. Apply to address.
- long maskedAddress = address | orMask; //(9)
- memory[maskedAddress] = data; //(10)
- }
- }
- }
- PrintMemorySum(memory);
- }
- bool IsBitSet(long fromNumber, int bitPosition)
- {
- long mask = (long)1 << bitPosition;
- return (fromNumber & mask) > 0;
- }
- void SolvePartOne(string[] dockingMemoryStrings)
- {
- Hashtable memory = new Hashtable();
- long andMask = 0;
- long orMask = 0;
- foreach (string s in dockingMemoryStrings)
- {
- MatchCollection allMatches = Regex.Matches(s, maskRegex);
- if (allMatches.Count == 1)
- {
- string maskString = allMatches[0].Groups[1].Value;
- string andMaskString = maskString.Replace('X', '1');
- string orMaskString = maskString.Replace('X', '0');
- andMask = Convert.ToInt64(andMaskString, 2);
- orMask = Convert.ToInt64(orMaskString, 2);
- }
- allMatches = Regex.Matches(s, memWriteRegex);
- if (allMatches.Count == 1)
- {
- long address = long.Parse(allMatches[0].Groups["address"].Value);
- long data = long.Parse(allMatches[0].Groups["data"].Value);
- data = data & andMask;
- data = data | orMask;
- memory[address] = data;
- }
- }
- PrintMemorySum(memory);
- }
- void PrintMemorySum(Hashtable memory)
- {
- long memorySum = 0;
- foreach (DictionaryEntry memEntry in memory)
- {
- memorySum += (long)memEntry.Value;
- }
- Debug.Log($"Sum of all data in memory: {memorySum}");
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement