Advertisement
Guest User

SquareSwap4NoPath96.cs

a guest
Oct 11th, 2021
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 20.20 KB | None | 0 0
  1. using System;
  2. using System.Linq;
  3. using System.Text;
  4. using System.Collections.Generic;
  5.  
  6. // SquareSwap4NoPath96.cs
  7. // used for a breadth-first exhaustive search for an answer at
  8. // https://puzzling.stackexchange.com/questions/111932/can-you-reactivate-a-4x4-magic-square
  9. // still "a work in progress" so not very tidied up...
  10.  
  11.  
  12. using IntCode = System.UInt64;
  13.  
  14. public struct CellState : IEquatable<CellState>
  15. {
  16.   public byte Value { get; set; }
  17.   public byte MovesLeft { get; set; }
  18.  
  19.   public override bool Equals(object obj)
  20.   {
  21.     return obj is CellState other && Equals(other);
  22.   }
  23.  
  24.   public bool Equals(CellState other)
  25.   {
  26.     return Value == other.Value && MovesLeft == other.MovesLeft;
  27.   }
  28.  
  29.   public override int GetHashCode()
  30.   {
  31.     return Value * 256 + MovesLeft;
  32.   }
  33.  
  34.   public bool IsSwapValid(CellState other)
  35.   {
  36.     if (Value > other.Value)
  37.       return MovesLeft >= other.Value && other.MovesLeft > 0;
  38.     else
  39.       return other.MovesLeft >= Value && MovesLeft > 0;
  40.   }
  41. }
  42.  
  43.  
  44.  
  45.  
  46.  
  47. public class GridState : IEquatable<GridState>
  48. {
  49.   private static CellState[] MakeCellStates(params string[] initialRows)
  50.   {
  51.     int columnCount = initialRows[0].Length;
  52.     var result = new CellState[initialRows.Length * columnCount];
  53.     for (int row = 0; row < initialRows.Length; row++)
  54.     {
  55.       if (initialRows[row].Length != columnCount)
  56.         throw new ArgumentException("All rows must be the same length", nameof(initialRows));
  57.       for (int col = 0; col < columnCount; col++)
  58.       {
  59.         int value = _mainNumbers.IndexOf(initialRows[row][col]);
  60.         if (value < 0)
  61.           throw new ArgumentException("Row contained invalid character: " + initialRows[row]);
  62.  
  63.         result[row * columnCount + col] = new CellState { Value = (byte)value, MovesLeft = (byte)value };
  64.       }
  65.     }
  66.     return result;
  67.   }
  68.  
  69.   public GridState(params string[] initialRows)
  70.     : this(initialRows[0].Length, MakeCellStates(initialRows))
  71.   { }
  72.  
  73.   public GridState(int columnCount, CellState[] cellStates)
  74.   {
  75.     if (cellStates.Length % columnCount != 0)
  76.       throw new ArgumentOutOfRangeException();
  77.     ColumnCount = columnCount;
  78.     CellStates = cellStates;
  79.   }
  80.  
  81.   public int SetMagicConstant()
  82.   {
  83.     MagicConstant = 0;
  84.     if (RowCount == ColumnCount)
  85.     {
  86.       int totalValues = CellStates.Sum(c => (int)c.Value);
  87.       if (totalValues % ColumnCount == 0)
  88.         MagicConstant = totalValues / ColumnCount;
  89.     }
  90.     return MagicConstant;
  91.   }
  92.  
  93.   public int ColumnCount { get; }
  94.   public int RowCount => CellStates.Length / ColumnCount;
  95.  
  96.   private static int MagicConstant { get; set; }
  97.  
  98.   public CellState[] CellStates { get; }
  99.  
  100.   public CellState this[int row, int col]
  101.   {
  102.     get
  103.     {
  104.       if (row < 0 || row > RowCount)
  105.         throw new ArgumentOutOfRangeException(nameof(row));
  106.       if (col < 0 || col > ColumnCount)
  107.         throw new ArgumentOutOfRangeException(nameof(col));
  108.       return CellStates[row * ColumnCount + col];
  109.     }
  110.   }
  111.  
  112.   private static readonly string _mainNumbers = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#";
  113.   private static readonly string _subscriptNumbers = "₀₁₂₃₄₅₆₇₈₉₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊₊";
  114.  
  115.   public override string ToString()
  116.   {
  117.     int rowLength = ColumnCount * 5;
  118.  
  119.     StringBuilder result = new StringBuilder(rowLength * RowCount * 2);
  120.  
  121.     for (int row = 0; row < RowCount; row++)
  122.     {
  123.       for (int col = 0; col < ColumnCount; col++)
  124.       {
  125.         var state = CellStates[row * ColumnCount + col];
  126.         result.Append(new[] { ' ', _mainNumbers[state.Value], _subscriptNumbers[state.MovesLeft], ' ', col < ColumnCount - 1 ? '|' : '\n' });
  127.       }
  128.       if (row < RowCount - 1)
  129.       {
  130.         result.Append(string.Join("+", Enumerable.Repeat("----", ColumnCount)));
  131.         result.Append("\n");
  132.       }
  133.     }
  134.     return result.ToString();
  135.   }
  136.  
  137.   public override bool Equals(object obj)
  138.   {
  139.     return base.Equals(obj) || obj is GridState other && Equals(other);
  140.   }
  141.  
  142.   public bool Equals(GridState other)
  143.   {
  144.     var otherCellStates = other.CellStates;
  145.     if (otherCellStates.Length != CellStates.Length)
  146.       return false;
  147.     for (int i = 0; i < CellStates.Length; i++)
  148.       if (!CellStates[i].Equals(otherCellStates[i]))
  149.         return false;
  150.     return true;
  151.   }
  152.  
  153.   public bool EqualValues(GridState other)
  154.   {
  155.     var otherCellStates = other.CellStates;
  156.     if (otherCellStates.Length != CellStates.Length)
  157.       return false;
  158.     for (int i = 0; i < CellStates.Length; i++)
  159.       if (!CellStates[i].Value.Equals(otherCellStates[i].Value))
  160.         return false;
  161.     return true;
  162.   }
  163.  
  164.   public override int GetHashCode()
  165.   {
  166.     int result = 0;
  167.     for (int i = 0; i < CellStates.Length; i++)
  168.       result = (result >> 18) ^ (result * 0x1413 + CellStates[i].GetHashCode());
  169.     return result;
  170.   }
  171.  
  172.   public int TotalMovesLeft => CellStates.Sum(c => c.MovesLeft);
  173.  
  174.   public GridState GetStateAfterSwap(SwapInfo swapInfo)
  175.   {
  176.     CellState stateFrom = this[swapInfo.rowFrom, swapInfo.colFrom];
  177.     CellState stateTo = this[swapInfo.rowTo, swapInfo.colTo];
  178.  
  179.     if (!stateFrom.IsSwapValid(stateTo))
  180.       throw new ArgumentOutOfRangeException(nameof(swapInfo), $"Invalid swap R{swapInfo.rowFrom + 1}C{swapInfo.colFrom + 1} with R{swapInfo.rowTo + 1}C{swapInfo.colTo + 1} for grid:\n{this.ToString()}");
  181.  
  182.     var cellStatesAfter = CellStates.ToArray();
  183.  
  184.     CellState stateFromAfter = new CellState { Value = (byte)stateTo.Value, MovesLeft = (byte)(stateTo.MovesLeft - (stateTo.Value > stateFrom.Value ? stateFrom.Value : 1)) };
  185.     CellState stateToAfter = new CellState { Value = (byte)stateFrom.Value, MovesLeft = (byte)(stateFrom.MovesLeft - (stateFrom.Value > stateTo.Value ? stateTo.Value : 1)) };
  186.  
  187.     cellStatesAfter[swapInfo.rowFrom * ColumnCount + swapInfo.colFrom] = stateFromAfter;
  188.     cellStatesAfter[swapInfo.rowTo * ColumnCount + swapInfo.colTo] = stateToAfter;
  189.  
  190.     return new GridState(ColumnCount, cellStatesAfter);
  191.   }
  192.  
  193.   public bool IsSwapValid(SwapInfo info) => this[info.rowFrom, info.colFrom].IsSwapValid(this[info.rowTo, info.colTo]);
  194.  
  195.   public bool IsOrdered()
  196.   {
  197.     for (int i = 0; i < CellStates.Length - 1; i++)
  198.       if (CellStates[i].Value > CellStates[i + 1].Value)
  199.         return false;
  200.     return true;
  201.   }
  202.  
  203.   public bool IsMagic()
  204.   {
  205.     if (MagicConstant == 0)
  206.       throw new InvalidOperationException("Cannot be magic - wrong dimensions or total...");
  207.     int count = ColumnCount;
  208.     return Enumerable.Range(0, count).Sum(i => (int)this[i, i].Value) == MagicConstant &&
  209.            Enumerable.Range(0, count).Sum(i => (int)this[count - 1 - i, i].Value) == MagicConstant &&
  210.            Enumerable.Range(0, count).All(i => Enumerable.Range(0, count).Sum(col => (int)this[i, col].Value) == MagicConstant &&
  211.                                                Enumerable.Range(0, count).Sum(row => (int)this[row, i].Value) == MagicConstant);
  212.   }
  213. }
  214.  
  215.  
  216. public struct SwapInfo : IEquatable<SwapInfo>
  217. {
  218.   public byte rowFrom { get; set; }
  219.   public byte colFrom { get; set; }
  220.   public byte rowTo { get; set; }
  221.   public byte colTo { get; set; }
  222.  
  223.   static Dictionary<SwapInfo, byte> _toByteDict = new Dictionary<SwapInfo, byte>(256);
  224.   static List<SwapInfo> _knownValidSwaps = new List<SwapInfo>(256); // only because dict isn't indexable...
  225.   static System.Threading.ReaderWriterLockSlim _byteDictLock = new System.Threading.ReaderWriterLockSlim();
  226.  
  227.   public byte CompressToByte()
  228.   {
  229.     if (!_toByteDict.TryGetValue(this, out byte result))
  230.     {
  231.       // Attention - this is a potential major bug if the same pattern used anywhere else... Dictionary is not thread safe.
  232.       // However, we avoid hash bucket re-organisation by pre-allocating 256 entries (enough for anything which can be converted to/from byte)
  233.       // and in this specific case, the lock isn't even needed because we're really doing all writing from the single thread that
  234.       // handles finding swaps from the starting position, but kept lock because
  235.       // later tweaks to the program might potentially make the lock necessary...
  236.       // the alternatives of concurrentdictionary or readerwriterlockslim would add more overhead for many millions of calls.
  237.       lock (_toByteDict)
  238.         if (!_toByteDict.TryGetValue(this, out result))
  239.         {
  240.           if (_toByteDict.Count > 255)
  241.             throw new InvalidOperationException("_toByteDict is full. refactoring required!");
  242.           result = (byte)_toByteDict.Count;
  243.           Console.WriteLine($"Allocated byte {result} to swap {this}");
  244.           _toByteDict.Add(this, result);
  245.           _knownValidSwaps.Add(this);
  246.         }
  247.     }
  248.     return result;
  249.   }
  250.  
  251.   public static SwapInfo ExpandFromByte(byte compressed)
  252.   {
  253.     return _knownValidSwaps[compressed];
  254.   }
  255.  
  256.  
  257.   public override bool Equals(object obj)
  258.   {
  259.     return obj is SwapInfo other && Equals(other);
  260.   }
  261.  
  262.   public bool Equals(SwapInfo other)
  263.   {
  264.     return rowFrom == other.rowFrom && colFrom == other.colFrom && rowTo == other.rowTo && colTo == other.colTo ||
  265.            rowFrom == other.rowTo && colFrom == other.colTo && rowTo == other.rowFrom && colTo == other.colFrom;
  266.   }
  267.  
  268.   public override int GetHashCode()
  269.   {
  270.     return Math.Min(rowFrom, rowTo) + Math.Max(rowFrom, rowTo) * 64 + Math.Min(colFrom, colTo) * 4096 + Math.Max(colFrom, colTo) * 262144;
  271.   }
  272.  
  273.   public override string ToString()
  274.   {
  275.     return $"R{rowFrom + 1}C{colFrom + 1}<>R{rowTo + 1}C{colTo + 1}";
  276.   }
  277. }
  278.  
  279.  
  280. public class PuzzleState
  281. {
  282.   public PuzzleState(GridState gridState, params SwapInfo[] movesDone)
  283.   {
  284.     GridState = gridState;
  285.     MovesDone = movesDone;
  286.   }
  287.  
  288.   public GridState GridState { get; private set; }
  289.  
  290.   public PuzzleState(params string[] lines)
  291.     : this(new GridState(lines))
  292.   {
  293.   }
  294.  
  295.   // parent and move count were never used, so removed these.
  296.  
  297.   public SwapInfo[] MovesDone { get; }
  298.  
  299.   private static SwapInfo[] ConcatSwapInfo(PuzzleState parent, SwapInfo move)
  300.   {
  301.     int parentLength = parent.MovesDone.Length;
  302.     var result = new SwapInfo[parentLength + 1];
  303.     Array.Copy(parent.MovesDone, result, parentLength);
  304.     result[parentLength] = move;
  305.     return result;
  306.   }
  307.  
  308.   private PuzzleState(PuzzleState parent, SwapInfo move, GridState gridState)
  309.     : this(gridState, ConcatSwapInfo(parent, move))
  310.   {
  311.     // bug in previous version before major refactoring left out this (now redundant!) line
  312.     AllowWrapAround = parent.AllowWrapAround;
  313.   }
  314.  
  315.   public bool IsSwapValid(SwapInfo info) => GridState.IsSwapValid(info);
  316.  
  317.   public bool AllowWrapAround { get; set; } = true;
  318.  
  319.   public IEnumerable<PuzzleState> GetStatesAfterValidMoves()
  320.   {
  321.     int fromRowLimit = AllowWrapAround ? GridState.RowCount : (GridState.RowCount - 1);
  322.     int fromColLimit = AllowWrapAround ? GridState.ColumnCount : (GridState.ColumnCount - 1);
  323.     for (int fromRow = 0; fromRow < fromRowLimit; fromRow++)
  324.     {
  325.       int toNextRow = (fromRow + 1) % GridState.RowCount;
  326.       for (int fromCol = 0; fromCol < GridState.ColumnCount; fromCol++)
  327.       {
  328.         CellState fromState = GridState[fromRow, fromCol];
  329.         if (fromState.MovesLeft < 1)
  330.           continue;
  331.  
  332.         CellState toState = GridState[toNextRow, fromCol];
  333.         if (fromState.IsSwapValid(toState))
  334.         {
  335.           var swapInfo = new SwapInfo { colFrom = (byte)fromCol, rowFrom = (byte)fromRow, colTo = (byte)fromCol, rowTo = (byte)toNextRow };
  336.           yield return new PuzzleState(this, swapInfo, GridState.GetStateAfterSwap(swapInfo));
  337.         }
  338.       }
  339.     }
  340.     for (int fromCol = 0; fromCol < fromColLimit; fromCol++)
  341.     {
  342.       int toNextCol = (fromCol + 1) % GridState.ColumnCount;
  343.       for (int fromRow = 0; fromRow < GridState.RowCount; fromRow++)
  344.       {
  345.         CellState fromState = GridState[fromRow, fromCol];
  346.         if (fromState.MovesLeft < 1)
  347.           continue;
  348.  
  349.         CellState toState = GridState[fromRow, toNextCol];
  350.         if (fromState.IsSwapValid(toState))
  351.         {
  352.           var swapInfo = new SwapInfo { colFrom = (byte)fromCol, rowFrom = (byte)fromRow, colTo = (byte)toNextCol, rowTo = (byte)fromRow };
  353.           yield return new PuzzleState(this, swapInfo, GridState.GetStateAfterSwap(swapInfo));
  354.         }
  355.       }
  356.     }
  357.   }
  358.  
  359.   //  static GridState targetState = new GridState("123", "456", "789");
  360.  
  361.   public bool IsTargetState => GridState.IsMagic();
  362.  
  363.   public IEnumerable<SwapInfo> GetSwaps()
  364.   {
  365.     return MovesDone;
  366.   }
  367. }
  368.  
  369. public struct CompressedGridState4 : IEquatable<CompressedGridState4>
  370. {
  371.   public static implicit operator CompressedGridState4(GridState source) => new CompressedGridState4(source);
  372.   public static implicit operator GridState(CompressedGridState4 source) => source.GetGridState();
  373.  
  374.   // now further compressed to 96 bits (was 128) to allow more space before reaching memory limit for hash tables.
  375.   UInt32 _compressedData1low;
  376.   UInt32 _compressedData2low;
  377.   UInt32 _compressedDataHigh;
  378.  
  379.   static int[] _possiblePositionsInit = Enumerable.Range(0, 16).ToArray();
  380.  
  381.   public CompressedGridState4(GridState source)
  382.   {
  383.     if (source.ColumnCount != 4 || source.CellStates.Length != 16)
  384.       throw new InvalidOperationException("This compression function assumes a 4 x 4 grid containing precisely the numbers 1-16");
  385.  
  386.     var cellStates = source.CellStates;
  387.     UInt64 multiplier1 = 1;
  388.     UInt64 multiplier2 = 1;
  389.     UInt64 _compressedData1 = 0;
  390.     UInt64 _compressedData2 = 0;
  391.  
  392.     List<int> possiblePositions = _possiblePositionsInit.ToList();
  393.  
  394.     for (uint i = 1; i <= 16; i++)
  395.     {
  396.       // find index of value i
  397.       int pos = 0;
  398.       while (cellStates[pos].Value != i)
  399.       {
  400.         if (pos >= cellStates.Length - 1)
  401.           throw new InvalidOperationException($"Value {i} not found in grid state");
  402.         else
  403.           pos++;
  404.       }
  405.       int posIndex = possiblePositions.IndexOf(pos);
  406.       if (posIndex == -1)
  407.         throw new InvalidOperationException($"Value {i} found at position {pos} which isn't possible! Possible: [{string.Join(",", possiblePositions)}]");
  408.  
  409.       _compressedData1 += multiplier1 * (uint)posIndex;
  410.       multiplier1 *= (uint)possiblePositions.Count;
  411.  
  412.       possiblePositions.RemoveAt(posIndex);
  413.  
  414.       _compressedData2 += multiplier2 * (uint)cellStates[pos].MovesLeft;
  415.       multiplier2 *= i + 1;
  416.  
  417.       //Console.WriteLine($"Compression diagnostic: i={i}, pos={pos} index {posIndex}, moves = {cellStates[pos].MovesLeft}, multiplier = {multiplier}, data = {_compressedData}");
  418.     }
  419.     // result was stored in 2 x 64 bits (128 bits total), but fits within 96 bits...
  420.     _compressedData1low = (uint)_compressedData1;
  421.     _compressedData2low = (uint)_compressedData2;
  422.     _compressedDataHigh = ((uint)(_compressedData1 >> 32)) | (8192 * (uint)(_compressedData2 >> 32));
  423.   }
  424.  
  425.   public GridState GetGridState()
  426.   {
  427.     var cellStates = new CellState[16];
  428.     UInt64 multiplier1 = 1;
  429.     UInt64 multiplier2 = 1;
  430.     // first expand back to 2 x 64 bits for further computations...
  431.     UInt64 _compressedData1 = _compressedData1low | ((UInt64)(_compressedDataHigh % 8192)) << 32;
  432.     UInt64 _compressedData2 = _compressedData2low | ((UInt64)(_compressedDataHigh / 8192)) << 32;
  433.  
  434.  
  435.     List<int> possiblePositions = Enumerable.Range(0, 16).ToList();
  436.  
  437.     for (byte i = 1; i <= 16; i++)
  438.     {
  439.       UInt64 nextMultiplier1 = multiplier1 * (uint)possiblePositions.Count;
  440.       int posIndex = (int)(_compressedData1 % nextMultiplier1 / multiplier1);
  441.       int pos = possiblePositions[posIndex];
  442.       possiblePositions.RemoveAt(posIndex);
  443.  
  444.       multiplier1 = nextMultiplier1;
  445.  
  446.       UInt64 nextMultiplier2 = multiplier2 * ((uint)i + 1);
  447.       byte movesLeft = (byte)(_compressedData2 % nextMultiplier2 / multiplier2);
  448.       multiplier2 = nextMultiplier2;
  449.  
  450.       cellStates[pos] = new CellState { Value = i, MovesLeft = movesLeft };
  451.  
  452.       //Console.WriteLine($"Decompression diagnostic: i={i}, pos={pos} index {posIndex}, moves = {cellStates[pos].MovesLeft}, multiplier = {multiplier}, data = {_compressedData}");
  453.     }
  454.  
  455.     return new GridState(4, cellStates);
  456.   }
  457.  
  458.   public override bool Equals(object obj)
  459.   {
  460.     return obj is CompressedGridState4 other && Equals(other) || obj is GridState otherExpanded && GetGridState().Equals(otherExpanded);
  461.   }
  462.  
  463.   public bool Equals(CompressedGridState4 other)
  464.   {
  465.     return _compressedDataHigh == other._compressedDataHigh && _compressedData2low == other._compressedData2low && _compressedData1low == other._compressedData1low;
  466.   }
  467.  
  468.   public override int GetHashCode()
  469.   {
  470.     return _compressedData1low.GetHashCode() + _compressedData2low.GetHashCode() + _compressedDataHigh.GetHashCode();
  471.   }
  472.  
  473. }
  474.  
  475.  
  476. public class SquareSwap
  477. {
  478.   static public void Main()
  479.   {
  480.     Console.OutputEncoding = System.Text.Encoding.UTF8;
  481.  
  482.     var startingState = new PuzzleState("867G", "143A", "9D2E", "BC5F") { AllowWrapAround = false };
  483.  
  484.     //    var startingState = new PuzzleState("1FE4", "BA58", "G69C", "732D") { AllowWrapAround = false }; // test starting state similar to "given" magic square
  485.  
  486.     //    var startingState = new PuzzleState("1FE4", "AB85", "769C", "G32D") { AllowWrapAround = false }; // test starting state similar to "given" magic square
  487.  
  488.  
  489.     var magicConstant = startingState.GridState.SetMagicConstant();
  490.  
  491.     Console.WriteLine($"Starting state [total moves left: {startingState.GridState.TotalMovesLeft}, magic constant = {magicConstant}]:");
  492.     Console.WriteLine(startingState.GridState);
  493.  
  494.     // test case for compression and decompression functions.
  495.     CompressedGridState4 comp = startingState.GridState;
  496.     Console.WriteLine($"Equality check: {comp.Equals((object)startingState.GridState)}");
  497.  
  498.     var workingSets = Enumerable.Range(0, startingState.GridState.TotalMovesLeft + 1).Select(i => new HashSet<CompressedGridState4>()).ToArray();
  499.  
  500.     workingSets[startingState.GridState.TotalMovesLeft].Add(startingState.GridState);
  501.  
  502.     bool found = false;
  503.  
  504.     for (int i = workingSets.Length - 1; i > 0 /*&& !found*/; i--)
  505.     {
  506.       Console.WriteLine($"Starting on working set #{i}, which has {workingSets[i].Count} members... [{Enumerable.Range(0, i).Sum(x => workingSets[x].Count)} already in later working sets]");
  507.  
  508.       System.Threading.Tasks.Parallel.ForEach(workingSets[i], key =>
  509.       {
  510.         GridState gridState = key; // implicit conversion to decompress
  511.         var puzzleState = new PuzzleState(gridState) { AllowWrapAround = false };
  512.         // non-compressed puzzle state is now only scoped to this block.
  513.  
  514.         if (puzzleState.IsTargetState)
  515.         {
  516.           found = true;
  517.           lock (workingSets[i])
  518.           {
  519.             Console.WriteLine("Found solution!");
  520.             Console.WriteLine($"... after swaps: {string.Join(", ", puzzleState.GetSwaps())}");
  521.             Console.WriteLine(puzzleState.GridState);
  522.           }
  523.         }
  524.         else
  525.           foreach (var nextState in puzzleState.GetStatesAfterValidMoves())
  526.           {
  527.             int movesLeft = nextState.GridState.TotalMovesLeft;
  528.             //var swapInfo = nextState.MovesDone.Last();
  529.             //Console.WriteLine($"Possible next state after swapping R{swapInfo.rowFrom + 1}C{swapInfo.colFrom + 1} with R{swapInfo.rowTo + 1}C{swapInfo.colTo + 1} [total moves left: {movesLeft}]:");
  530.             //Console.WriteLine(nextState.GridState);
  531.  
  532.             if (movesLeft >= i)
  533.               throw new InvalidOperationException("Total moves left didn't decrease???!");
  534.  
  535.             // implicit conversion to compressed data.
  536.             CompressedGridState4 nextGridStateCompressed = nextState.GridState;
  537.  
  538.             lock (workingSets[movesLeft])
  539.             {
  540.               if (workingSets[movesLeft].TryGetValue(nextGridStateCompressed, out var firstEquivalentState))
  541.               {
  542.                 // Console.WriteLine("Duplicate found!");
  543.               }
  544.               else
  545.               {
  546.                 workingSets[movesLeft].Add(nextGridStateCompressed);
  547. //                if (movesLeft == 131)
  548.   //                Console.WriteLine("131 moves left:\n" + nextState.GridState);
  549.               }
  550.             }
  551.           }
  552.       });
  553.       // allow dictionaries of compresed state to be reclaimed by garbage collector
  554.       workingSets[i] = null;
  555.     }
  556.   }
  557. }
  558.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement