Ejemplo n.º 1
0
        public bool SameAs(NumberConstraint nc)
        {
            if (Type != nc.Type)
            {
                return(false);
            }

            if (Count != nc.Count)
            {
                return(false);
            }

            if (Cells.Count != nc.Cells.Count)
            {
                return(false);
            }

            foreach (var cell in Cells)
            {
                if (!nc.Cells.Contains(cell))
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 2
0
        private bool AddRuleChecked(NumberConstraint nc)
        {
            if (nc == null)
            {
                return(false);
            }

            if (!nc.IsRelevant)
            {
                return(false);
            }

            if (NumberConstraints.Any(nc.SameAs))
            {
                return(false);
            }

            foreach (var nc2 in NumberConstraints)
            {
                UncheckedRulePairs.Add(new KeyValuePair <NumberConstraint, NumberConstraint>(nc, nc2));
                UncheckedRulePairs.Add(new KeyValuePair <NumberConstraint, NumberConstraint>(nc2, nc));
            }

            NumberConstraints.Add(nc);
            NewRules.Add(nc);
            nc.Generation = Generation;
            return(true);
        }
Ejemplo n.º 3
0
        // Checks if cut between nc and this has meaningful rule
        public IEnumerable <NumberConstraint> ProbeCutWith(NumberConstraint nc)
        {
            var nc1only   = Cells.Where(c => !nc.Cells.Contains(c)).ToArray();
            var nc2only   = nc.Cells.Where(c => !Cells.Contains(c)).ToArray();
            var bothCells = Cells.Where(c => nc.Cells.Contains(c)).ToArray();

            // blues from RHS leak into this
            if (HasLesserOrEqualSemantics && nc.HasGreaterOrEqualSemantics)
            {
                if (nc.Count - nc2only.Length >= Count)
                {
                    if (nc.Count - nc2only.Length > Count)
                    {
                        throw new InvalidOperationException("Hm, something is fishey");
                    }

                    yield return(new NumberConstraint(0, nc1only, ConstraintType.Equal, null)
                    {
                        ExtraInfo = $"{IDString} and {nc.IDString} force these cells to be empty"
                    });
                }
            }

            // blues from this leak into rhs
            if (HasGreaterOrEqualSemantics && nc.HasLesserOrEqualSemantics)
            {
                if (nc.Count <= Count - nc1only.Length)
                {
                    if (nc.Count < Count - nc1only.Length)
                    {
                        throw new InvalidOperationException("Hm, something is fishey");
                    }

                    yield return(new NumberConstraint(nc1only.Length, nc1only, ConstraintType.Equal, null)
                    {
                        ExtraInfo = $"{IDString} and {nc.IDString} force these cells to be all-blue"
                    });
                }
            }

            // guaranteed min nr of cells bleeding into this
            if (nc.HasGreaterOrEqualSemantics)
            {
                if (nc.Count > nc2only.Length)
                {
                    yield return(new NumberConstraint(nc.Count - nc2only.Length, bothCells, ConstraintType.Minimum, null)
                    {
                        ExtraInfo = $"{bothCells.Length} cells of {IDString} overlap {nc.IDString}, with at least {nc.Count - nc2only.Length} blue ones in the overlap"
                    });
                }
            }
        }
Ejemplo n.º 4
0
        // does not work with non.vanilla
        public NumberConstraint Without(NumberConstraint nc)
        {
            Debug.Assert(Type == ConstraintType.Equal);
            Debug.Assert(nc.HasEqualSemantics);
            Debug.Assert(nc.IsStrictSubsetOf(this));

            var newCells = Cells.Where(c => !nc.Cells.Contains(c));
            var newCnt   = Count - nc.Count;

            return(new NumberConstraint(newCnt, newCells, ConstraintType.Equal, null)
            {
                ExtraInfo = IDString + " without " + nc.IDString
            });
        }
Ejemplo n.º 5
0
        public bool IsStrictSubsetOf(NumberConstraint nc)
        {
            if (Cells.Count == nc.Cells.Count)
            {
                return(false); // not a strict subset
            }
            foreach (var c in Cells)
            {
                if (!nc.Cells.Contains(c))
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 6
0
        public IEnumerable <NumberConstraint> NonConnectedMaximumDerivatives(NumberConstraint nc)
        {
            var endIdx = RingBuffer ? Cells.Length : Cells.Length - nc.Count + 1;

            for (var start = 0; start < endIdx; ++start)
            {
                var cells = new Cell[nc.Count];
                for (var i = start; i < start + nc.Count; ++i)
                {
                    cells[i - start] = Cells[i % Cells.Length];
                }
                if (cells.All(c => c != null) && cells.Any(c => c.State == CellState.Yellow))
                {
                    yield return(new NumberConstraint(nc.Count - 1, cells, ConstraintType.Maximum, null));
                }
            }
        }
Ejemplo n.º 7
0
 public bool HasCutWith(NumberConstraint nc2)
 {
     return(Cells.Any(c => nc2.Cells.Contains(c)));
 }
Ejemplo n.º 8
0
        private void CheckNonConn(CellState[] states, bool[] any, bool[] all, int bc, int i, NumberConstraint nc)
        {
            if (i == states.Length)
            {
                // Check solution
                var ok = states.Count(s => s == CellState.Blue) == nc.Count;
                if (ok)
                {
                    int fi = states.FirstIndexOf(CellState.Blue);
                    int li = states.LastIndexOf(CellState.Blue);

                    if (RingBuffer)
                    {
                        int cnt = -1;
                        int j   = fi;
                        while (states[j] == CellState.Blue)
                        {
                            j = (j - 1 + states.Length) % states.Length;
                            ++cnt;
                        }
                        j = fi;
                        while (states[j] == CellState.Blue)
                        {
                            j = (j + 1) % states.Length;
                            ++cnt;
                        }

                        ok = cnt < nc.Count;
                    }
                    else
                    {
                        ok = li - fi >= nc.Count;
                    }

                    if (ok)
                    {
                        if (Debug)
                        {
                            Console.WriteLine(states.Select(s => s == CellState.Blue ? "X" : "_").Aggregate((s1, s2) => s1 + " " + s2));
                        }
                        for (var j = 0; j < states.Length; ++j)
                        {
                            if (states[j] == CellState.Blue)
                            {
                                any[j] = true;
                            }
                            else
                            {
                                all[j] = false;
                            }
                        }
                    }
                }
            }
            else
            {
                if (states[i] == CellState.Yellow)
                {
                    if (bc < nc.Count)
                    {
                        states[i] = CellState.Blue;
                        CheckNonConn(states, any, all, bc + 1, i + 1, nc);
                    }

                    states[i] = CellState.Black;
                    CheckNonConn(states, any, all, bc + 0, i + 1, nc);

                    states[i] = CellState.Yellow;
                }
                else
                {
                    CheckNonConn(states, any, all, bc + (states[i] == CellState.Blue ? 1 : 0), i + 1, nc);
                }
            }
        }
Ejemplo n.º 9
0
        public IEnumerable <SolveStep> GenerateStepsFor(NumberConstraint nc)
        {
            if (nc.Type == ConstraintType.Connected)
            {
                var states = Cells.Select(c => c?.State ?? CellState.Black).ToArray();
                var any    = states.Select(s => false).ToArray();
                var all    = states.Select(s => true).ToArray();

                var endIdx = RingBuffer ? Cells.Length : Cells.Length - nc.Count + 1;
                for (var start = 0; start < endIdx; ++start)
                {
                    var ok = true;
                    for (var i = start; i < start + nc.Count; ++i)
                    {
                        if (states[i % Cells.Length] == CellState.Black)
                        {
                            ok = false;
                            break;
                        }
                    }
                    if (ok)
                    {
                        for (var i = start + nc.Count; i < start + Cells.Length; ++i)
                        {
                            if (states[i % Cells.Length] == CellState.Blue)
                            {
                                ok = false;
                                break;
                            }
                        }
                    }

                    if (ok)
                    {
                        for (var i = start; i < start + nc.Count; ++i)
                        {
                            any[i % Cells.Length] = true;
                        }

                        for (var i = start + nc.Count; i < start + Cells.Length; ++i)
                        {
                            all[i % Cells.Length] = false;
                        }
                    }
                }

                for (var i = 0; i < Cells.Length; ++i)
                {
                    if (Cells[i]?.State == CellState.Yellow)
                    {
                        if (all[i] && Cells[i].MaySolve(CellState.Blue))
                        {
                            yield return(new SolveStep(Cells[i], CellState.Blue, "All conceivable connected solutions of " + nc.IDString + " contain this cell"));
                        }
                        if (!any[i] && Cells[i].MaySolve(CellState.Black))
                        {
                            yield return(new SolveStep(Cells[i], CellState.Black, "All conceivable connected solutions of " + nc.IDString + " do NOT contain this cell"));
                        }
                    }
                }
            }
            else if (nc.Type == ConstraintType.NonConnected)
            {
                // TODO: This stuff is wrong for n>2, because YBYBY may work
                var states = Cells.Select(c => c?.State ?? CellState.Black).ToArray();
                var endIdx = RingBuffer ? Cells.Length : Cells.Length - nc.Count + 2;

                var any = states.Select(s => false).ToArray();
                var all = states.Select(s => true).ToArray();

                if (Debug)
                {
                    Console.WriteLine("---");
                    Console.WriteLine(states.Select(s => s == CellState.Blue ? "X" : s == CellState.Yellow ? "?" : "_").Aggregate((s1, s2) => s1 + " " + s2));
                }

                CheckNonConn(states, any, all, 0, 0, nc);

                if (any.All(a => !a))
                {
                    throw new InvalidOperationException("No valid solution found...");
                }

                if (Debug)
                {
                    Console.WriteLine("any");
                    Console.WriteLine(any.Select(s => s ? "X" : "_").Aggregate((s1, s2) => s1 + " " + s2));
                    Console.WriteLine("all");
                    Console.WriteLine(all.Select(s => s ? "X" : "_").Aggregate((s1, s2) => s1 + " " + s2));
                    Console.WriteLine();
                }

                /*for (var start = 0; start < endIdx; ++start)
                 * {
                 *  var ok = true;
                 *  // n-1 blues
                 *  for (var i = start; i < start + nc.Count - 1; ++i)
                 *      if (states[i % Cells.Length] == CellState.Black)
                 *      {
                 *          ok = false;
                 *          break;
                 *      }
                 *
                 *  if (RingBuffer)
                 *  {
                 *      if (states[(start - 1 + Cells.Length) % Cells.Length] == CellState.Blue)
                 *          ok = false;
                 *      if (states[(start + nc.Count - 1) % Cells.Length] == CellState.Blue)
                 *          ok = false;
                 *  }
                 *  else
                 *  {
                 *      if (start > 0 && states[start - 1] == CellState.Blue)
                 *          ok = false;
                 *      if (start + nc.Count - 1 < Cells.Length && states[start + nc.Count - 1] == CellState.Blue)
                 *          ok = false;
                 *  }
                 *
                 *  if (ok)
                 *  {
                 *      var bc = 0;
                 *      for (var i = start + nc.Count - 1; i != start; i = (i + 1) % Cells.Length)
                 *          if (states[i % Cells.Length] == CellState.Blue)
                 ++bc;
                 *
                 *      if (bc >= 2)
                 *          ok = false;
                 *
                 *      // fixed blue
                 *      if (ok && bc == 1)
                 *      {
                 *          for (var i = start; i < start + nc.Count - 1; ++i)
                 *              any[i % Cells.Length] = true;
                 *
                 *          for (var i = start + nc.Count - 1; i < start + Cells.Length; ++i)
                 *              all[i % Cells.Length] = false;
                 *      }
                 *
                 *      // non-fixed blue
                 *      if (ok && bc == 0)
                 *      {
                 *          var endJIdx = RingBuffer ? start + Cells.Length - 1 : Cells.Length;
                 *          for (var j = start + nc.Count; j < endJIdx; ++j)
                 *              if (states[j % Cells.Length] == CellState.Yellow)
                 *              {
                 *                  for (var i = start; i < start + nc.Count - 1; ++i)
                 *                      any[i % Cells.Length] = true;
                 *
                 *                  for (var i = start + nc.Count - 1; i < start + Cells.Length; ++i)
                 *                      if (i % Cells.Length == j % Cells.Length)
                 *                          any[i % Cells.Length] = true;
                 *                      else
                 *                          all[i % Cells.Length] = false;
                 *              }
                 *
                 *          if (!RingBuffer)
                 *          {
                 *              for (var j = 0; j < start - 1; ++j)
                 *                  if (states[j % Cells.Length] == CellState.Yellow)
                 *                  {
                 *                      for (var i = start; i < start + nc.Count - 1; ++i)
                 *                          any[i % Cells.Length] = true;
                 *
                 *                      for (var i = start + nc.Count - 1; i < start + Cells.Length; ++i)
                 *                          if (i % Cells.Length == j % Cells.Length)
                 *                              any[i % Cells.Length] = true;
                 *                          else
                 *                              all[i % Cells.Length] = false;
                 *                  }
                 *          }
                 *      }
                 *  }
                 * }*/

                //Debugger.Break();
                for (var i = 0; i < Cells.Length; ++i)
                {
                    if (Cells[i]?.State == CellState.Yellow)
                    {
                        if (all[i] && Cells[i].MaySolve(CellState.Blue))
                        {
                            yield return(new SolveStep(Cells[i], CellState.Blue, "All conceivable non-connected solutions of " + nc.IDString + " contain this cell"));
                        }
                        if (!any[i] && Cells[i].MaySolve(CellState.Black))
                        {
                            yield return(new SolveStep(Cells[i], CellState.Black, "All conceivable non-connected solutions of " + nc.IDString + " do NOT contain this cell"));
                        }
                    }
                }

                /*
                 * for (var i = 0; i < Cells.Length; ++i)
                 *  if (Cells[i]?.State == CellState.Yellow && Cells[i].MaySolve)
                 *  {
                 *      if (all[i])
                 *          yield return new SolveStep(Cells[i], CellState.Blue, "All conceivable solutions of " + nc.IDString + " contain this cell");
                 *      if (!any[i])
                 *          yield return new SolveStep(Cells[i], CellState.Black, "All conceivable solutions of " + nc.IDString + " do NOT contain this cell");
                 *  }
                 *
                 * // for n consecutive with all blue, one yellow, yellow must be black
                 * for (var start = 0; start < endIdx; ++start)
                 * {
                 *  var bc = 0;
                 *  var yp = -1;
                 *  for (var i = start; i < start + nc.Count; ++i)
                 *  {
                 *      if (states[i % Cells.Length] == CellState.Blue) bc += 1;
                 *      if (states[i % Cells.Length] == CellState.Yellow) yp = i;
                 *  }
                 *
                 *  if (bc == nc.Count - 1 && yp >= 0)
                 *  {
                 *      if (Cells[yp].MaySolve)
                 *          yield return new SolveStep(Cells[yp], CellState.Black, "Otherwise, the resulting connected sequence would violate " + nc.IDString);
                 *  }
                 * }
                 *
                 * // for < n consecutive yellow with black borders, all must be black
                 * for (var start = 0; start < Cells.Length; ++start)
                 * {
                 *  if (states[start] != CellState.Black)
                 *      continue;
                 *  if (states[(start + 1) % Cells.Length] != CellState.Yellow)
                 *      continue;
                 *
                 *  var i = start + 1;
                 *  var cnt = 1;
                 *  while (cnt < nc.Count && states[(start + i) % Cells.Length] != CellState.Black)
                 *  {
                 ++i;
                 ++cnt;
                 *  }
                 * }*/
            }
            else
            {
                throw new NotImplementedException();
            }
        }