public override void PropogateChange(int i, int j, BoardSolver bs) { for (int k = 0; k < bs.final.sudoku.settings.numHorizontal; k++) { if (k != i) { bs.EnsureNotPossible(k, j, bs.GetValue(i, j)); } } for (int k = 0; k < bs.final.sudoku.settings.numVertical; k++) { if (k != j) { bs.EnsureNotPossible(i, k, bs.GetValue(i, j)); } } // Locate the box we are in int boxX = (int)((i / (bs.final.sudoku.settings.numHorizontalThins + 1)) * (bs.final.sudoku.settings.numHorizontalThins + 1)); int boxY = (int)((j / (bs.final.sudoku.settings.numVerticalThins + 1)) * (bs.final.sudoku.settings.numVerticalThins + 1)); for (int a = 0; a < (bs.final.sudoku.settings.numHorizontalThins + 1); a++) { for (int b = 0; b < (bs.final.sudoku.settings.numVerticalThins + 1); b++) { if ((a + boxX != i) || (b + boxY != j)) { bs.EnsureNotPossible(a + boxX, b + boxY, bs.GetValue(i, j)); } } } }
public override List <BoardNotifications.BoardError> GetErrors(BoardSolver bs) { List <BoardNotifications.BoardError> errors = new List <BoardNotifications.BoardError>(); var ts = bs.final.sudoku.GetVariant(VariantList.VariantType.Thermo.ToString()).serializer as ThermoSerializer; for (int i = 0; i < bs.final.sudoku.settings.numHorizontal; i++) { for (int j = 0; j < bs.final.sudoku.settings.numVertical; j++) { for (int k = 0; k < 4; k++) { (int x, int y)newPos = (i + ThermoSerializer.directions[k, 0], j + ThermoSerializer.directions[k, 1]); if (bs.GetValue(i, j) != "" && bs.GetValue(newPos.x, newPos.y) != "") { int res1, res2; if (!int.TryParse(bs.GetValue(i, j), out res1)) { List <(int x, int y)> boxes = new List <(int x, int y)>(); boxes.Add((i, j)); errors.Add(new BoardNotifications.BoardError( BoardNotifications.ErrorType.SELECTION_INVALID, boxes, "This box must be numeric." )); } else if (!int.TryParse(bs.GetValue(newPos.x, newPos.y), out res2)) { List <(int x, int y)> boxes = new List <(int x, int y)>(); boxes.Add((newPos.x, newPos.y)); errors.Add(new BoardNotifications.BoardError( BoardNotifications.ErrorType.SELECTION_INVALID, boxes, "This box must be numeric." )); } else if (ts.incoming[i, j, k] && res1 <= res2) { List <(int x, int y)> affected = new List <(int x, int y)>(); affected.Add((i, j)); affected.Add((newPos.x, newPos.y)); errors.Add(new BoardNotifications.BoardError( BoardNotifications.ErrorType.SELECTION_INVALID, affected, "Thermo rules require that numbers increase along lines, meaning we require " + bs.GetValue(i, j) + " > " + bs.GetValue(newPos.x, newPos.y) )); } } } } } return(errors); }
public override BoardSolver.SolveResult RestrictGrid(BoardSolver bs) { BoardSolver.SolveResult r = BoardSolver.SolveResult.Unchanged; var ts = bs.final.sudoku.GetVariant(VariantList.VariantType.Thermo.ToString()).serializer as ThermoSerializer; for (int i = 0; i < bs.final.sudoku.settings.numHorizontal; i++) { for (int j = 0; j < bs.final.sudoku.settings.numVertical; j++) { for (int k = 0; k < 4; k++) { if (ts.incoming[i, j, k]) { r = bs.Combine(r, bs.EnsureLarger(i, j, i + ThermoSerializer.directions[k, 0], j + ThermoSerializer.directions[k, 1])); } if (ts.outgoing[i, j, k]) { r = bs.Combine(r, bs.EnsureLarger(i + ThermoSerializer.directions[k, 0], j + ThermoSerializer.directions[k, 1], i, j)); } } } } return(r); }
public static BoardSolver.SolveResult RestrictSum(BoardSolver boardSolver, List <(int x, int y)> points, int sum)
public BoardSolverShould() { _gameBoard = new GameBoard(); _humanPlayer = new HumanPlayer(Symbol.Cross, new InputChecker()); _boardSolver = new BoardSolver(); }
public override BoardSolver.SolveResult RestrictGrid(BoardSolver bs) { var ss = bs.final.sudoku.GetVariant(VariantList.VariantType.Sandwich.ToString()).serializer as SandwichSerializer; bool changed = false; foreach (var box in ss.serializedObject.boxes) { var points = new List <(int x, int y)>(); if (box.posx == BoxController.topBox || box.posx == BoxController.botBox) { int oneIndex = -1; int oneCounts = 0; int nineIndex = -1; int nineCounts = 0; for (int i = 0; i < bs.final.sudoku.settings.numHorizontal; i++) { if (bs.Allows(box.posy, i, 1.ToString())) { oneCounts++; oneIndex = i; } if (bs.Allows(box.posy, i, 9.ToString())) { nineCounts++; nineIndex = i; } } if (oneCounts == 1 && nineCounts == 1) { for (int i = Mathf.Min(oneIndex, nineIndex) + 1; i < Mathf.Max(oneIndex, nineIndex); i++) { points.Add((box.posy, i)); } } } else if (box.posy == BoxController.topBox || box.posy == BoxController.botBox) { int oneIndex = -1; int oneCounts = 0; int nineIndex = -1; int nineCounts = 0; for (int j = 0; j < bs.final.sudoku.settings.numHorizontal; j++) { if (bs.Allows(j, box.posx, 1.ToString())) { oneCounts++; oneIndex = j; } if (bs.Allows(j, box.posx, 9.ToString())) { nineCounts++; nineIndex = j; } } if (oneCounts == 1 && nineCounts == 1) { for (int j = Mathf.Min(oneIndex, nineIndex) + 1; j < Mathf.Max(oneIndex, nineIndex); j++) { points.Add((j, box.posx)); } } } else { continue; } var r = SumUtility.RestrictSum(bs, points, int.Parse(box.answer)); if (r == BoardSolver.SolveResult.Impossible) { return(r); } if (r == BoardSolver.SolveResult.Solved) { changed = true; } } if (changed) { return(BoardSolver.SolveResult.Solved); } return(BoardSolver.SolveResult.Unchanged); }
public override void PropogateChange(int i, int j, BoardSolver bs) { }
public override List <BoardNotifications.BoardError> GetErrors(BoardSolver bs) { List <BoardNotifications.BoardError> errors = new List <BoardNotifications.BoardError>(); var ss = bs.final.sudoku.GetVariant(VariantList.VariantType.Sandwich.ToString()).serializer as SandwichSerializer; foreach (var box in ss.serializedObject.boxes) { if (box.posx == BoxController.topBox || box.posx == BoxController.botBox) { int oneIndex = -1; int oneCounts = 0; int nineIndex = -1; int nineCounts = 0; for (int i = 0; i < bs.final.sudoku.settings.numHorizontal; i++) { if (bs.GetValue(box.posy, i) == "1") { oneCounts++; oneIndex = i; } if (bs.GetValue(box.posy, i) == "9") { nineCounts++; nineIndex = i; } } if (oneCounts == 1 && nineCounts == 1) { List <(int x, int y)> points = new List <(int x, int y)>(); bool bad = false; for (int i = Mathf.Min(oneIndex, nineIndex) + 1; i < Mathf.Max(oneIndex, nineIndex); i++) { points.Add((box.posy, i)); if (bs.GetValue(box.posy, i) == "") { bad = true; } } if (!bad) { int s = 0; foreach (var v in points) { int res; if (int.TryParse(bs.GetValue(v.x, v.y), out res)) { s += res; } else { List <(int x, int y)> p = new List <(int x, int y)>(); p.Add(v); errors.Add(new BoardNotifications.BoardError(BoardNotifications.ErrorType.SELECTION_INVALID, p, "This box must be numeric.")); } } if (s != int.Parse(box.answer)) { errors.Add(new BoardNotifications.BoardError(BoardNotifications.ErrorType.SUM_INVALID, points, "These boxes must sum to " + box.answer)); } } } } else if (box.posy == BoxController.topBox || box.posy == BoxController.botBox) { int oneIndex = -1; int oneCounts = 0; int nineIndex = -1; int nineCounts = 0; for (int j = 0; j < bs.final.sudoku.settings.numHorizontal; j++) { if (bs.GetValue(j, box.posx) == "1") { oneCounts++; oneIndex = j; } if (bs.GetValue(j, box.posx) == "9") { nineCounts++; nineIndex = j; } } if (oneCounts == 1 && nineCounts == 1) { List <(int x, int y)> points = new List <(int x, int y)>(); bool bad = false; for (int j = Mathf.Min(oneIndex, nineIndex) + 1; j < Mathf.Max(oneIndex, nineIndex); j++) { points.Add((j, box.posx)); if (bs.GetValue(j, box.posx) == "") { bad = true; } } if (!bad) { int s = 0; foreach (var v in points) { int res; if (int.TryParse(bs.GetValue(v.x, v.y), out res)) { s += res; } else { List <(int x, int y)> p = new List <(int x, int y)>(); p.Add(v); errors.Add(new BoardNotifications.BoardError(BoardNotifications.ErrorType.SELECTION_INVALID, p, "This box must be numeric.")); } } if (s != int.Parse(box.answer)) { errors.Add(new BoardNotifications.BoardError(BoardNotifications.ErrorType.SUM_INVALID, points, "These boxes must sum to " + box.answer)); } } } } } return(errors); }
// Use this for initialization public void init(int w, int h, SpriteRenderer bgRender) { Vector3 dim = 1.6f * Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0)); if (Screen.width < Screen.height) { boardSize = (float)dim.x / (float)w; } else { boardSize = (float)dim.y / (float)h; } Vector3 center = new Vector3((float)w / 2.0f - .5f, (float)h / 2.0f - .5f, 0) * boardSize; transform.localPosition = -center; transform.localScale = new Vector3(boardSize, boardSize, 1); width = w; height = h; blocks = new Block[w, h]; background = bgRender; bgSize = new Vector3((float)width / 4f, (float)height / 4f, 1); background.transform.localScale = new Vector3(bgSize.x, bgSize.y, bgSize.z); background.transform.parent = transform; oldBG = background.color; newBG = background.color; name = "Board"; emptyBlockFolder = new GameObject(); emptyBlockFolder.name = "Empty Blocks"; emptyBlockFolder.transform.parent = transform; emptyBlockFolder.transform.localPosition = new Vector3(0, 0, 0); emptyBlockFolder.transform.localScale = new Vector3(1, 1, 1); blockFolder = new GameObject(); blockFolder.name = "Blocks"; blockFolder.transform.parent = transform; blockFolder.transform.localPosition = new Vector3(0, 0, 0); blockFolder.transform.localScale = new Vector3(1, 1, 1); switchFolder = new GameObject(); switchFolder.name = "Switches"; switchFolder.transform.parent = transform; switchFolder.transform.localPosition = new Vector3(0, 0, 0); switchFolder.transform.localScale = new Vector3(1, 1, 1); enemyFolder = new GameObject(); enemyFolder.name = "Enemy Folder"; enemyFolder.transform.parent = transform; enemyFolder.transform.localScale = new Vector3(1, 1, 1); solidBlocks = new List <Block>(); enemyList = new List <Enemy>(); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { addEmptyBlock(x, y); } } initPlayer(); //Track_AI_List = new List<TrackerAI> (); // addTraversalAI(); //addTrackerAI(); initExit(); solver = new BoardSolver(this); }
public override BoardSolver.SolveResult RestrictGrid(BoardSolver bs) { bool changed = false; for (int v = 1; v <= 9; v++) { for (int i = 0; i < bs.final.sudoku.settings.numHorizontal; i++) { int v_located = 0; for (int j = 0; j < bs.final.sudoku.settings.numVertical; j++) { if (bs.Allows(i, j, v.ToString())) { v_located++; } } if (v_located == 0) { return(BoardSolver.SolveResult.Impossible); } if (v_located == 1) { for (int j = 0; j < bs.final.sudoku.settings.numVertical; j++) { if (bs.Allows(i, j, v.ToString()) && bs.GetValue(i, j) != v.ToString()) { changed = true; bs.SetValue(i, j, v.ToString()); } } } } for (int j = 0; j < bs.final.sudoku.settings.numVertical; j++) { int v_located = 0; for (int i = 0; i < bs.final.sudoku.settings.numHorizontal; i++) { if (bs.Allows(i, j, v.ToString())) { v_located++; } } if (v_located == 0) { return(BoardSolver.SolveResult.Impossible); } if (v_located == 1) { for (int i = 0; i < bs.final.sudoku.settings.numHorizontal; i++) { if (bs.Allows(i, j, v.ToString()) && bs.GetValue(i, j) != v.ToString()) { changed = true; bs.SetValue(i, j, v.ToString()); } } } } for (int a = 0; a < bs.final.sudoku.settings.numHorizontal; a += (int)(bs.final.sudoku.settings.numHorizontalThins + 1)) { for (int b = 0; b < bs.final.sudoku.settings.numVertical; b += (int)(bs.final.sudoku.settings.numVerticalThins + 1)) { // Check for box (a, b) int v_located = 0; for (int x = 0; x < (bs.final.sudoku.settings.numHorizontalThins + 1); x++) { for (int y = 0; y < (bs.final.sudoku.settings.numVerticalThins + 1); y++) { if (bs.Allows(a + x, b + y, v.ToString())) { v_located++; } } } if (v_located == 0) { return(BoardSolver.SolveResult.Impossible); } if (v_located == 1) { for (int x = 0; x < (bs.final.sudoku.settings.numHorizontalThins + 1); x++) { for (int y = 0; y < (bs.final.sudoku.settings.numVerticalThins + 1); y++) { if (bs.Allows(a + x, b + y, v.ToString()) && bs.GetValue(a + x, b + y) != v.ToString()) { changed = true; bs.SetValue(a + x, b + y, v.ToString()); } } } } } } } if (changed) { return(BoardSolver.SolveResult.Solved); } return(BoardSolver.SolveResult.Unchanged); }
public override List <BoardNotifications.BoardError> GetErrors(BoardSolver bs) { List <BoardNotifications.BoardError> errors = new List <BoardNotifications.BoardError>(); for (int v = 1; v <= 9; v++) { for (int i = 0; i < bs.final.sudoku.settings.numHorizontal; i++) { List <(int x, int y)> boxes = new List <(int x, int y)>(); for (int j = 0; j < bs.final.sudoku.settings.numVertical; j++) { if (bs.GetValue(i, j) == v.ToString()) { boxes.Add((i, j)); } } if (boxes.Count > 1) { errors.Add(new BoardNotifications.BoardError(BoardNotifications.ErrorType.COL_INVALID, boxes, "This column can only have a single " + v)); } } for (int j = 0; j < bs.final.sudoku.settings.numVertical; j++) { List <(int x, int y)> boxes = new List <(int x, int y)>(); for (int i = 0; i < bs.final.sudoku.settings.numHorizontal; i++) { if (bs.GetValue(i, j) == v.ToString()) { boxes.Add((i, j)); } } if (boxes.Count > 1) { errors.Add(new BoardNotifications.BoardError(BoardNotifications.ErrorType.ROW_INVALID, boxes, "This row can only have a single " + v)); } } for (int a = 0; a < bs.final.sudoku.settings.numHorizontal; a += (int)(bs.final.sudoku.settings.numHorizontalThins + 1)) { for (int b = 0; b < bs.final.sudoku.settings.numVertical; b += (int)(bs.final.sudoku.settings.numVerticalThins + 1)) { // Check for box (a, b) List <(int x, int y)> boxes = new List <(int x, int y)>(); for (int x = 0; x < (bs.final.sudoku.settings.numHorizontalThins + 1); x++) { for (int y = 0; y < (bs.final.sudoku.settings.numVerticalThins + 1); y++) { if (bs.GetValue(a + x, b + y) == v.ToString()) { boxes.Add((a + x, b + y)); } } } if (boxes.Count > 1) { errors.Add(new BoardNotifications.BoardError(BoardNotifications.ErrorType.BOX_INVALID, boxes, "This box can only have a single " + v)); } } } } return(errors); }
public abstract List <BoardNotifications.BoardError> GetErrors(BoardSolver bs);
// Only returns Impossible, Solved, or Unchanged public abstract BoardSolver.SolveResult RestrictGrid(BoardSolver bs);
public abstract void PropogateChange(int i, int j, BoardSolver bs);
public SolveResult Solve() { for (int i = 0; i < final.sudoku.settings.numHorizontal; i++) { for (int j = 0; j < final.sudoku.settings.numVertical; j++) { // Trigger the propogate for all already set vlaues. if (GetValue(i, j) != "") { SetValue(i, j, GetValue(i, j)); } } } SolveResult s = ApplyRules(); if (s == SolveResult.Impossible) { return(s); } if (s == SolveResult.Solved) { return(s); } // In any other case, we can continue solving. if (!settings.bruteForce) { return(s); } // Find the smallest possible switch box (int x, int y)bestPoint = (-1, -1); int best = final.sudoku.AllValues().Count + 1; for (int i = 0; i < final.sudoku.settings.numHorizontal; i++) { for (int j = 0; j < final.sudoku.settings.numVertical; j++) { if ((final.possible_values[i, j].Count < best) && (final.possible_values[i, j].Count != 1)) { best = final.possible_values[i, j].Count; bestPoint = (i, j); } } } // Split on (i, j) int amountSolved = 0; int amountIncomplete = 0; SolveState newFinal = new SolveState(); foreach (var k in final.possible_values[bestPoint.x, bestPoint.y]) { BoardSolver bs = new BoardSolver(); bs.Initialise(final, settings); var r = bs.Solve(); if (r == SolveResult.Solved) { amountSolved++; newFinal = bs.final; } if (r == SolveResult.Incomplete) { amountIncomplete++; if (amountSolved == 0) { newFinal = bs.final; } } if (r == SolveResult.MaybeMultiple) { newFinal = bs.final; amountSolved++; amountIncomplete++; } if (r == SolveResult.Multiple) { return(r); } if (r == SolveResult.Impossible) { continue; } } if ((amountSolved == 0) && (amountIncomplete == 0)) { return(SolveResult.Impossible); } final = newFinal; if (amountSolved > 1) { return(SolveResult.Multiple); } if (amountIncomplete == 0) { return(SolveResult.Solved); } if (amountSolved == 0) { return(SolveResult.Incomplete); } return(SolveResult.MaybeMultiple); }