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); }
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); }
// 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" }); } } }
// 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 }); }
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); }
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)); } } }
public bool HasCutWith(NumberConstraint nc2) { return(Cells.Any(c => nc2.Cells.Contains(c))); }
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); } } }
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(); } }