//20 Create the VoxelGrid constructor for a tower of sudoku games /// <summary> /// Constructs a VoxelGrid of Sudoku games /// </summary> /// <param name="numberOfGames">The amount of layers - games to be stacked</param> /// <param name="origin">The origin of the grid</param> /// <param name="voxelSize">The size of each <see cref="Voxel"/></param> public VoxelGrid(int numberOfGames, Vector3 origin, float voxelSize) { GridSize = new Vector3Int(9, numberOfGames, 9); Origin = origin; VoxelSize = voxelSize; Voxels = new Voxel[GridSize.x, GridSize.y, GridSize.z]; //21 Start the population of the grid from Y, reading a new game at each level for (int y = 0; y < GridSize.y; y++) { //Generate a random index to be read int gameNumber = Random.Range(1, 1000); //Read the sudoku game var sudokuGame = CSVReader.ReadSudokuGame(gameNumber); //Store which index of the 81 is being read for the current voxel //This also resets the value at each layer int valueIndex = 0; //22 Populate the layer with SudokuVoxels for (int x = 0; x < GridSize.x; x++) { for (int z = 0; z < GridSize.z; z++) { //32 Create the SudokuVoxel and store it in the Voxels array Voxels[x, y, z] = new SudokuVoxel(new Vector3Int(x, y, z), this, sudokuGame[valueIndex]); valueIndex++; } } } }
//50 Copy Solve to an IEnumerator /// <summary> /// Animates the solution of the tower /// </summary> /// <returns>Each step of the solution</returns> IEnumerator AnimatedSolution() { //51 Add the Y iteration to the begining for (int y = 0; y < _voxelGrid.GridSize.y; y++) { for (int x = 0; x < _voxelGrid.GridSize.x; x++) { for (int z = 0; z < _voxelGrid.GridSize.z; z++) { SudokuVoxel sVoxel = (SudokuVoxel)_voxelGrid.Voxels[x, y, z]; if (sVoxel.State == 0) { for (int i = 1; i < 10; i++) { if (Possible(sVoxel, i)) { sVoxel.ChangeState(i); //52 Add yield return after changing the state yield return(new WaitForSeconds(0.1f)); //53 Start recursion with Coroutine StartCoroutine(AnimatedSolution()); if (GameAsList(y).Count(v => v.State == 0) != 0) { sVoxel.ChangeState(0); //54 Add yield return after backtracking yield return(new WaitForSeconds(0.1f)); } } } //55 Switch return to yield return yield return(new WaitForSeconds(0.1f)); } } } //56 Switch return to yield return yield return(new WaitForSeconds(0.15f)); } }
//38 Create the Solve method for a single layer /// <summary> /// Solves the a layer(game) of the tower /// </summary> /// <param name="y">The y coordinate of the game to be solved</param> private void Solve(int y) { //39 Iterate through X and Z indexes of layer Y for (int x = 0; x < _voxelGrid.GridSize.x; x++) { for (int z = 0; z < _voxelGrid.GridSize.z; z++) { //40 Get the SudokuVoxel to be evalauted, casting from Voxel SudokuVoxel sVoxel = (SudokuVoxel)_voxelGrid.Voxels[x, y, z]; //41 Test if state of SudokuVoxel is 0 (empty cell) if (sVoxel.State == 0) { //42 Try to change to the numbers between 1 and 9 for (int i = 1; i < 10; i++) { if (Possible(sVoxel, i)) { //43 If it is possible, change it sVoxel.ChangeState(i); //44 Initiate the process again, moving to the next empty cell, recursively Solve(y); //45 This step is only reached if the solution succedded or failed //Count the amount of empty spaces to see if solution succeeded if (GameAsList(y).Count(v => v.State == 0) != 0) { //47 If solution failed, change the state of this voxel back to 0, backtracking sVoxel.ChangeState(0); } } } //48 Exit method if all numbers have been tested and failed return; } } } return; }
//34 Create the method to evaluate if a SudokuVoxel can be changed to a value /// <summary> /// Evaluates if a <see cref="SudokuVoxel"/> can be changed to a specific state /// </summary> /// <param name="sVoxel">The <see cref="SudokuVoxel"/> to be evaluated</param> /// <param name="test">The value to be tested</param> /// <returns>A bool representing if the movement is valid or not</returns> private bool Possible(SudokuVoxel sVoxel, int test) { //35 Check in row (X) for (int i = 0; i < 9; i++) { SudokuVoxel rowVoxel = (SudokuVoxel)_voxelGrid.Voxels[i, sVoxel.Index.y, sVoxel.Index.z]; if (rowVoxel.State == test) { return(false); } } //36 Check in column (Z) for (int i = 0; i < 9; i++) { SudokuVoxel columnVoxel = (SudokuVoxel)_voxelGrid.Voxels[sVoxel.Index.x, sVoxel.Index.y, i]; if (columnVoxel.State == test) { return(false); } } //37 Check in 3x3 cell //Starting indexes to be evaluated int x0; int z0; //Define starting index in X if (sVoxel.Index.x < 3) { x0 = 0; } else if (sVoxel.Index.x < 6) { x0 = 3; } else { x0 = 6; } //Define starting index in Z if (sVoxel.Index.z < 3) { z0 = 0; } else if (sVoxel.Index.z < 6) { z0 = 3; } else { z0 = 6; } for (int x = x0; x < x0 + 3; x++) { for (int z = z0; z < z0 + 3; z++) { SudokuVoxel cellVoxel = (SudokuVoxel)_voxelGrid.Voxels[x, sVoxel.Index.y, z]; if (cellVoxel.State == test) { return(false); } } } return(true); }