private static bool CheckSeveralMissingColumn(GridSquareScript selection, GridSquareScript[] gridSquares) { int col = GridMaths.ColumnForSquare(selection.Index); GridSquareScript[] emptyColSquares = EmptyGridsAtIndexes(GridMaths.GridColumnIndices(col), gridSquares, selection); int[] emptyIndices = emptyColSquares.Select(x => x.Index).Distinct().ToArray(); int[] bigSquareIndices = emptyColSquares.Select(x => GridMaths.BigSquareForSquare(x.Index)).Distinct().ToArray(); List <int> usableSquares = new List <int>(); for (int i = 0; i < bigSquareIndices.Length; i++) { int box = bigSquareIndices[i]; if (!DoesBigSquareContainNumber(box, selection, gridSquares)) { int[] checks = emptyIndices.Intersect(GridMaths.GridColumnInSquare(col, box)).ToArray(); if (checks.Length > 0) { usableSquares.AddRange(checks); } } } if (usableSquares.Count > 0) { return(usableSquares.All(x => DoesRowContainNumber(GridMaths.RowForSquare(x), selection, gridSquares))); } return(true); }
public GridSquareScript GetFtueTargetAtIndex(int index) { GridSquareScript target = TargetAtIndex(index); target.SetAsFtueTarget(); return(target); }
/// <summary> /// Check, like the hash, but for numbers in boxes and cols/rows /// </summary> /// <param name="selection"></param> /// <param name="gridSquares"></param> /// <returns>True if this index is only available square for number in relation to number in big squares/cols/rows</returns> private static GridSolutionType CheckSeveralMissing(GridSquareScript selection, GridSquareScript[] gridSquares) { bool missingRow = CheckSeveralMissingRow(selection, gridSquares); bool missingCol = CheckSeveralMissingColumn(selection, gridSquares); print($"[CHECK] missing passed row: {missingRow} col: {missingCol}"); return((missingRow || missingCol) ? GridSolutionType.SeveralMissing : GridSolutionType.None); }
private void CreatorSquareSelected(GridSquareScript sender) { if (currentSelection != null && !currentSelection.Equals(sender)) { currentSelection.DeselectCreatorSquare(); } currentSelection = gridSquares[sender.Index]; }
private static GridSquareScript[] GridsAtIndexes(int[] indexes, GridSquareScript[] gridSquares) { GridSquareScript[] grids = new GridSquareScript[indexes.Length]; for (int i = 0; i < indexes.Length; i++) { if (gridSquares.Length > i && gridSquares[i] != null) { grids[i] = gridSquares[indexes[i]]; } } return(grids); }
private static GridSquareScript[] EmptyGridsAtIndexes(int[] indexes, GridSquareScript[] gridSquares, GridSquareScript selection) { GridSquareScript[] grids = new GridSquareScript[indexes.Length]; for (int i = 0; i < indexes.Length; i++) { if (gridSquares.Length > i && gridSquares[i] != null) { grids[i] = gridSquares[indexes[i]]; } } return(grids.Where(x => x.Number == 0 || !selection.IsTarget).ToArray()); }
public void SquareSelected(GridSquareScript sender) { if (!sender.Equals(currentSelection)) { for (int i = 0; i < gridSquares.Length; i++) { gridSquares[i].ResetSquare(); } currentSelection = TargetAtIndex(sender.Index); HighlightSquare(currentSelection.Index); print($"New selection!! {sender.Index}"); } }
private static GridSolutionType OnlyAvailableNumberCheck(GridSquareScript selection, GridSquareScript[] gridSquares) { int row = GridMaths.RowForSquare(selection.Index); int col = GridMaths.ColumnForSquare(selection.Index); int bigSquare = GridMaths.BigSquareForSquare(selection.Index); int[] rowMissing = MissingNumbersInRow(gridSquares, row); int[] colMissing = MissingNumbersInColumn(gridSquares, col); int[] bigMissing = MissingNumbersInBigSquare(gridSquares, bigSquare); bool overlapCheck = rowMissing.Intersect(colMissing).Intersect(bigMissing).ToArray().Length == 0; print($"Only available row: {string.Join(",", rowMissing)} col; {string.Join(",", colMissing)} big; {string.Join(",", bigMissing)} "); return(overlapCheck ? GridSolutionType.SingleRule : GridSolutionType.None); }
public void InitGridWithRules(MainGameData gameData, Action <GridAnswer[]> completion) { rules = gameData.Ruleset; gridSquares = tileContainer.GetComponentsInChildren <GridSquareScript>(); targets = new List <GridSquareScript>(); //allSquares = new int[0]; currentSelection = null; completionCallback = completion; levelTitle.text = $"LEVEL {gameData.Level}"; int[] levelData = rules.levelData.Select(x => Int32.Parse(x.ToString())).ToArray(); print($"Level data count: {levelData.Length}"); if (levelData.Length == gridSquares.Length) { for (int i = 0; i < levelData.Length; i++) { bool isTarget = rules.targetIndexes.Contains(i); gridSquares[i].SetupGridSquare(i, levelData[i], isTarget, SquareSelected); if (isTarget) { targets.Add(gridSquares[i]); } } } keyboardController.SetKeyboardClickHandler(KeyboardInput); keyboardController.SetKeyboardEnabled(false); keyboardController.ShowKeyboard(); if (gameData.answers != null) { GridAnswer[] errors = gameData.answers.Where(x => x.correct == false).ToArray(); GridAnswer[] corrects = gameData.answers.Where(x => x.correct == true).ToArray(); if (errors.Length > 0) { StartCoroutine(ShowPreviousErrors(errors, ShowNextTarget)); if (corrects.Length == 0) { return; } } if (corrects.Length > 0) { StartCoroutine(ShowPreviousCorrects(corrects)); return; } } ShowNextTarget(); }
private IEnumerator ShowPreviousCorrects(GridAnswer[] corrects) { for (int i = 0; i < corrects.Length; i++) { GridSquareScript gridSquare = gridSquares[corrects[i].index]; gridSquare.UpdateGridNumber(corrects[i].number); gridSquare.MarkSquareCorrect(); } yield return(new WaitForSeconds(1.5f)); for (int i = 0; i < corrects.Length; i++) { GridSquareScript gridSquare = gridSquares[corrects[i].index]; gridSquare.ResetSquare(); } yield return(new WaitForSeconds(0.25f)); }
private static bool DoesSquareForceColumnNumber(int big, GridSquareScript selection, int col, GridSquareScript[] gridSquares) { print($"DoesSquare {big} ForceColumn {col} Number: {selection.Number}"); bool numberCheck = DoesBigSquareContainNumber(big, selection, gridSquares); if (DoesBigSquareContainNumber(big, selection, gridSquares)) { return(false); } int[] emptyIndices = EmptyGridsAtIndexes(GridMaths.GridBigSquareIndices(big), gridSquares, selection).Select(x => x.Index).Distinct().ToArray(); int[] noColIndices = emptyIndices.Where(x => !DoesColumnContainNumber(GridMaths.ColumnForSquare(x), selection, gridSquares)).ToArray(); int[] noRowIndices = emptyIndices.Where(x => !DoesRowContainNumber(GridMaths.RowForSquare(x), selection, gridSquares)).ToArray(); int[] forcedColumns = noColIndices.Intersect(noRowIndices).Select(GridMaths.ColumnForSquare).Distinct().ToArray(); print($"Empty indices in square {big} = {string.Join(",", emptyIndices)} - no col indices ({string.Join(",", noColIndices)}) no row indices ({string.Join(",", noRowIndices)}) = {string.Join(",", forcedColumns)} = {col}"); return(forcedColumns.Length == 1 && forcedColumns[0] == col); }
private GridAnswer[] ValidateTargets() { List <GridAnswer> answers = new List <GridAnswer>(); for (int i = 0; i < targets.Count; i++) { GridSquareScript target = targets[i]; bool correct = GridSolver.SolveGridAtIndex(gridSquares, target) != GridSolutionType.None; target.MarkSquareComplete(); //MarkSquareIncorrect(); print($"Target {target.Index} ({target.Number}) is correct? {correct}"); answers.Add(new GridAnswer { index = target.Index, number = target.Number, correct = correct }); } return(answers.ToArray()); }
private IEnumerator ShowPreviousErrors(GridAnswer[] errors, Action completion) { for (int i = 0; i < errors.Length; i++) { GridSquareScript gridSquare = gridSquares[errors[i].index]; gridSquare.UpdateGridNumber(errors[i].number); gridSquare.MarkSquareIncorrect(); } yield return(new WaitForSeconds(1.5f)); for (int i = 0; i < errors.Length; i++) { GridSquareScript gridSquare = gridSquares[errors[i].index]; gridSquare.UpdateGridNumber(0); gridSquare.ResetSquare(); } yield return(new WaitForSeconds(0.25f)); completion?.Invoke(); }
/// <summary> /// Simple overlap check to duplicate numbers in the same row, column or big square /// </summary> /// <param name="number"></param> /// <param name="index"></param> /// <param name="gridSquares"></param> /// <returns>True if no duplicate numbers for the selected index</returns> private static bool SingleRuleCheck(GridSquareScript selection, GridSquareScript[] gridSquares) { int row = GridMaths.RowForSquare(selection.Index); int col = GridMaths.ColumnForSquare(selection.Index); int bigSquare = GridMaths.BigSquareForSquare(selection.Index); //print($"Grid - keyboard number: {number} on square: {index}"); bool existsInRow = DoesRowContainNumber(row, selection, gridSquares); bool existsInCol = DoesColumnContainNumber(col, selection, gridSquares); bool existsInBig = DoesBigSquareContainNumber(bigSquare, selection, gridSquares); bool failed = existsInRow || existsInCol || existsInBig; if (!existsInRow && !existsInCol && !existsInBig) { //TODO add check for only number } print($"[CHECK] Simple overlap test: row: {existsInRow} col: {existsInCol} big: {existsInBig} => {failed}"); return(failed); }
private static int[] GridEmptyIntersectIndices(GridSquareScript[] gridSquares, GridSquareScript selection) { int square = GridMaths.BigSquareForSquare(selection.Index); GridSquareScript[] emptySquares = EmptyGridsAtIndexes(GridMaths.GridBigSquareIndices(square), gridSquares, selection); int[] emptyIndices = EmptyGridsAtIndexes(GridMaths.GridBigSquareIndices(square), gridSquares, selection).Select(x => x.Index).Distinct().ToArray(); //check how many row are in the empty indicies int[] emptyCols = emptyIndices.Where(x => !DoesColumnContainNumber(GridMaths.ColumnForSquare(x), selection, gridSquares)).ToArray(); int[] emptyRows = emptyIndices.Where(x => !DoesRowContainNumber(GridMaths.RowForSquare(x), selection, gridSquares)).ToArray(); int[] intersectIndices = emptyCols.Intersect(emptyRows).ToArray(); print($"GridEmptyIntersectIndices: ({string.Join(",", emptyIndices)}) empty rows: {string.Join(",", emptyRows)} cols: {string.Join(",", emptyCols)} intersect: {string.Join(",", intersectIndices)}"); return(emptyCols.Intersect(emptyRows).ToArray()); }
/// <summary> /// Check for if number is present in other columns or rows to rule out other positions so only one available position /// </summary> /// <param name="selection"></param> /// <param name="gridSquares"></param> /// <returns>True if this index is only available square for number in relation to number in cols/rows outside of big square </returns> private static GridSolutionType OnlyAvailableSquareHashCheck(GridSquareScript selection, GridSquareScript[] gridSquares) { return(GridEmptyIntersectIndices(gridSquares, selection).Length == 0 ? GridSolutionType.OnlyAvailable : GridSolutionType.None); }
private static bool DoesBigSquareContainNumber(int big, GridSquareScript selection, GridSquareScript[] gridSquares) { GridSquareScript[] bigSquareSquares = GridsAtIndexes(GridMaths.GridBigSquareIndices(big), gridSquares); return(bigSquareSquares.Any(x => x.Number == selection.Number && !x.IsTarget)); //x.Index != selection.Index); }
private static bool DoesColumnContainNumber(int col, GridSquareScript selection, GridSquareScript[] gridSquares) { GridSquareScript[] colSquares = GridsAtIndexes(GridMaths.GridColumnIndices(col), gridSquares); return(colSquares.Any(x => x.Number == selection.Number && !x.IsTarget));//x.Index != selection.Index); }
private static bool DoesRowContainNumber(int row, GridSquareScript selection, GridSquareScript[] gridSquares) { GridSquareScript[] rowSquares = GridsAtIndexes(GridMaths.GridRowIndices(row), gridSquares); return(rowSquares.Any(x => x.Number == selection.Number && !x.IsTarget));//&& x.Index != selection.Index); }
private static GridSolutionType CheckDoubleDeduction(GridSquareScript[] gridSquares, GridSquareScript selection) { int[] intersectIndices = GridEmptyIntersectIndices(gridSquares, selection); int[] missingRows = intersectIndices.Select(GridMaths.RowForSquare).Where(x => x != GridMaths.RowForSquare(selection.Index)).Distinct().ToArray(); int[] missingCols = intersectIndices.Select(GridMaths.ColumnForSquare).Where(x => x != GridMaths.ColumnForSquare(selection.Index)).Distinct().ToArray(); print($"Intersect indices: {string.Join(", ", intersectIndices)} Missing rows: {string.Join(", ", missingRows)} cols: {string.Join(", ", missingCols)}"); int forceRowCount = 0; int big = GridMaths.BigSquareForSquare(selection.Index); for (int i = 0; i < missingRows.Length; i++) { int[] otherBigRows = GridMaths.OtherBigSquaresForRow(missingRows[i], big); for (int j = 0; j < otherBigRows.Length; j++) { if (DoesSquareForceRowNumber(otherBigRows[j], selection, missingRows[i], gridSquares)) { forceRowCount += 1; } } } int forceColCount = 0; for (int i = 0; i < missingCols.Length; i++) { int[] otherBigCols = GridMaths.OtherBigSquaresForColumn(missingCols[i], big); for (int j = 0; j < otherBigCols.Length; j++) { if (DoesSquareForceColumnNumber(otherBigCols[j], selection, missingCols[i], gridSquares)) { forceColCount += 1; } } } print($"[CHECK] Double deduction: Forced rows: {missingRows.Length} = {forceRowCount} && cols: {missingCols.Length} = {forceColCount} check: {forceColCount == missingCols.Length && forceRowCount == missingRows.Length}"); return((forceColCount == missingCols.Length && forceRowCount == missingRows.Length) ? GridSolutionType.DoubleDeduction : GridSolutionType.None); }
public bool ValidateFtueTarget(GridSquareScript target) { return(GridSolver.SolveGridAtIndex(gridSquares, target) != GridSolutionType.None); }
//enum GridSolutionType //{ // None = 0, // SingleRow = 1, // SingleColumn = 2, // SingleSquare = 3, // CompleteRow = 4, // CompleteColumn = 5, // CompleteSquare = 6, // OnlyAvailable = 7, // NakedSingle = 8, // SeveralMissingRow = 9, // SeveralMissingColumn = 10, // DoubleDeduction = 11 //} #region - Public API public static GridSolutionType SolveGridAtIndex(GridSquareScript[] gridSquares, GridSquareScript selection) { if (SingleRuleCheck(selection, gridSquares)) { return(GridSolutionType.None); } GridSolutionType check = SimpleCompletionCheck(selection.Index, gridSquares); if (check != GridSolutionType.None) { return(check); } check = OnlyAvailableNumberCheck(selection, gridSquares); if (check != GridSolutionType.None) { return(check); } check = OnlyAvailableSquareHashCheck(selection, gridSquares); if (check != GridSolutionType.None) { return(check); } check = CheckForNakedSingle(selection.Index, gridSquares); if (check != GridSolutionType.None) { return(check); } check = CheckSeveralMissing(selection, gridSquares); if (check != GridSolutionType.None) { return(check); } check = CheckDoubleDeduction(gridSquares, selection); if (check != GridSolutionType.None) { return(check); } return(GridSolutionType.None); }