private void Complete2More(RankInfo r0, RankInfo r1, ulong[] fillMask) { Parallel.For(0, Master.N, Master.ThreadingOptions, (i, loopState) => { var bbIdx = i / 8 + r0.BitboardIndex; var bitPos = r0.BitRank & BitBase.BitFiles[i % 8]; if ((bitPos & fillMask[bbIdx]) == 0) { var rootFill = GetRootFillMatrix(bbIdx, bitPos, fillMask); var occupancy = new ulong[Board.BitboardCount]; occupancy[bbIdx] = bitPos; if (SearchLast(new Node(new ulong[][] { rootFill }, occupancy))) { loopState.Stop(); } else { Events.OnProgress(); } } }); }
/// <summary> Performs the main search stage using the recursive algorithm. </summary> /// <param name="nodes"> The root nodes. </param> /// <param name="r2"> Data regarding the 3rd available rank. </param> private void NormalSearch(ConcurrentBag <Node> nodes, RankInfo r2) { Parallel.ForEach(nodes, Master.ThreadingOptions, (node, loopState) => { if (Search(node, r2.BitboardIndex, 2, r2.BitRank)) { loopState.Stop(); _cancelled = true; } else { Events.OnProgress(); } }); }
protected override void Solve() { /* The original fill mask contains not only redundant bits * but also the attack masks of queens in the preset. * * Additionally, we get the information about the first 3 available * ranks and store it in small data structures for later use. */ var fillMask = PresetMaker.Preset.Fill; var ranksInfo = new RankInfo[3]; for (var i = 0; i < 3; i++) { ranksInfo[i] = GetFreeRankInfo(i); } // Handle special cases when there are too little available ranks: switch (_lastFreeRankIdx) { case 0: // If it's just 1 rank then create an almost-complete // node out of the preset, and search the remaining rank. var node = new Node(new ulong[][] { fillMask }, new ulong[Board.BitboardCount]); SearchLast(node); return; case 1: // For completing 2 more ranks, there's a special function. Complete2More(ranksInfo[0], ranksInfo[1], fillMask); return; } /* Now gather root nodes. Notice the 'limit' variable: now that the 1st available * rank may not actually be the 1st, the end of the row must be indicated specially. */ var nodes = new ConcurrentBag <Node>(); var limit = ranksInfo[1].BitboardIndex + Board.Dimension; Parallel.For(0, Master.N, Master.ThreadingOptions, i => { var bbIdx = i / 8 + ranksInfo[0].BitboardIndex; var bitPos = ranksInfo[0].BitRank & BitBase.BitFiles[i % 8]; // The first available rank is not guaranteed to be // completely free so we perform the following check: if ((bitPos & fillMask[bbIdx]) == 0) { var rootFill = GetRootFillMatrix(bbIdx, bitPos, fillMask); for (var j = ranksInfo[1].BitboardIndex; j < limit; j++) { AddNode(nodes, rootFill, j, bbIdx, bitPos, ranksInfo[1].BitRank); } } }); if (_lastFreeRankIdx == 2) { // This means that, after the nodes, there is only 1 rank left // to complete. So we call a special last-stage function: LastRankSearch(nodes); } else { // More than 1 more ranks, therefore pass the nodes to the common function: NormalSearch(nodes, ranksInfo[2]); } }
/// <summary> Initializes a new CompletionSolver. </summary> public CompletionSolver() { _lastFreeRankInfo = GetFreeRankInfo(_lastFreeRankIdx); _bbLimit = _lastFreeRankInfo.BitboardIndex + Board.Dimension; ColumnHeight = _lastFreeRankIdx > 1 ? _lastFreeRankIdx - 1 : 1; }