private void Expand(Dir[,] choice, int r, int c, int from, int to, int totalScore, int stage, int mask) { if (r == n_) { from *= 3; to *= 3; int fromStart = 0, fromEnd = 2; if ((stage & 0x1) > 0) { // can only accept states with no start or end fromEnd = 0; } else if (stage == 0x2) { // has end in the column but no start, can only accept states with start (only) fromStart = 1; fromEnd = 1; } int toAdd = 0; if ((stage & 0x2) > 0) toAdd = 2; else if (stage == 0x1) toAdd = 1; for (int fromAdd = fromStart; fromAdd <= fromEnd; fromAdd++) { List<Entry> parents = prev_[from + fromAdd]; for (int i = 0; i < parents.Count; i++) { int currentScore = parents[i].score + totalScore; DisjointSet groups = new DisjointSet(n_); bool invalid = false; for (int j = 0; j < n_; j++) { if (choice[j, 0] == Dir.Down || choice[j, 1] == Dir.Up) { groups.Union(j, j - 1); } if (choice[j, 0] == Dir.Left || choice[j, 1] == Dir.Right) { // find out whether the rhs has connected to anything above it int rhs = (parents[i].groups >> j * 2) & 0x3; int connected = -1; for (int k = j - 1; k >= 0; k--) { if (choice[k, 0] == Dir.Left || choice[k, 1] == Dir.Right) { if (((parents[i].groups >> k * 2) & 0x3) == rhs) { connected = k; break; } } } if (connected != -1) { invalid |= !groups.Union(connected, j); // this forms a closed loop, which is an invalid formation if (invalid) break; } // else rhs does not connect to anything above it } } if (invalid) continue; toAdd = Math.Max(toAdd, fromAdd); List<Entry> current = next_[to + toAdd]; int toGroups = groups.Normalize(mask); bool fnd = false; var currentSolution = parents[i].solution.Select(s => s).ToList(); currentSolution.Add((Dir[,])choice.Clone()); for (int j = 0; j < current.Count; j++) { if (current[j].groups == toGroups) { if (currentScore > current[j].score) { current[j].score = currentScore; current[j].solution = currentSolution; } fnd = true; break; } } if (!fnd) { current.Add(new Entry(toGroups, currentScore, currentSolution)); } } } return; } for (int k = 0; k < Dirs.Values.GetLength(0); k++) { if (grid_[r, c] == 0 && k > 0) break; if (stage == 1 && Dirs.Values[k, 0] == Dir.None && k > 0) break; if ((stage & 0x2) > 0 && Dirs.Values[k, 1] == Dir.None && k > 0) break; if (r > 0 && (choice[r - 1, 0] == Dir.Up && Dirs.Values[k, 1] != Dir.Up || choice[r - 1, 1] == Dir.Down && Dirs.Values[k, 0] != Dir.Down)) continue; if (Dirs.Values[k, 0] == Dir.Down && (r == 0 || choice[r - 1, 1] != Dir.Down)) continue; if (Dirs.Values[k, 1] == Dir.Up && (r == 0 || choice[r - 1, 0] != Dir.Up)) continue; if (Dirs.Values[k, 1] == Dir.Down && r == n_ - 1) continue; if (Dirs.Values[k, 0] == Dir.Up && r == n_ - 1) continue; choice[r, 0] = Dirs.Values[k, 0]; choice[r, 1] = Dirs.Values[k, 1]; int fromBit = 0; int toBit = 0; if (choice[r, 0] == Dir.Left) { fromBit = 1; } else if (choice[r, 1] == Dir.Right) { fromBit = 2; } if (choice[r, 0] == Dir.Right) { toBit = 2; } else if (choice[r, 1] == Dir.Left) { toBit = 1; } int nextStage = stage; if (Dirs.Values[k, 0] == Dir.None && k > 0) nextStage |= 0x1; else if (Dirs.Values[k, 1] == Dir.None && k > 0) nextStage |= 0x2; int nextMask = mask; if (choice[r, 1] == Dir.Left || choice[r, 0] == Dir.Right) { nextMask |= 1 << r; } Expand(choice, r + 1, c, from * 3 + fromBit, to * 3 + toBit, k == 0 ? totalScore : totalScore + grid_[r, c], nextStage, nextMask); } }