public void Survival_with_two_living_neighbours() { var neighbours = Enumerable .Range(0, 2) .Select(i => new Cell { State = CellState.Alive }); var cell = new Cell { State = CellState.Alive, Neighbours = neighbours }; Survival_if_two_or_three_living_neigbours(cell); }
public void Four_living_neighbours_death() { var neighbours = Enumerable .Range(0, 4) .Select(i => new Cell { State = CellState.Alive }); var cell = new Cell { State = CellState.Alive, Neighbours = neighbours }; More_than_three_living_neigbours_death(cell); }
public void Birth_if_three_living_neighbours() { var neighbours = Enumerable .Range(0, 3) .Select(i => new Cell { State = CellState.Alive }); var cell = new Cell { State = CellState.Dead, Neighbours = neighbours }; Birth_if_three_living_neighbours(cell); }
private bool SolveRecurse(Cell nextCell) { // Our base case: No more unsolved cells to select, // thus puzzle solved if (nextCell.row == -1) return true; // Loop through all candidates in the cell foreach (int candidate in m_cellConstraintMatrix[nextCell.row, nextCell.col]) { writer.WriteLine("{4} -> ({0}, {1}) : {2} ({3})", nextCell.row, nextCell.col, m_cellConstraintMatrix[nextCell.row, nextCell.col], m_cellConstraintMatrix[nextCell.row, nextCell.col].Count, steps++); SelectCandidate(nextCell, candidate); // Move to the next cell. // if it returns false backtrack if (SolveRecurse(NextCell()) == false) { ++steps; writer.WriteLine("{0} -> BACK", steps); UnselectCandidate(nextCell, candidate); continue; } else // if we recieve true here this means the puzzle was solved earlier return true; } // return false if path is unsolvable return false; }
private void SelectCandidate(Cell aCell, int candidate) { HashSet<Cell> changedCells = new HashSet<Cell>(); // place candidate on grid m_grid[aCell.row, aCell.col] = candidate; // remove from bucket list bucketList[m_cellConstraintMatrix[aCell.row, aCell.col].Count].Remove(aCell); // remove candidate from cell constraint matrix m_cellConstraintMatrix[aCell.row, aCell.col][candidate] = false; // add the candidate to the cell, row, col, region constraint matrices m_colConstraintMatrix[aCell.col][candidate] = true; m_rowConstraintMatrix[aCell.row][candidate] = true; m_regionConstraintMatrix[aCell.row / 3, aCell.col / 3][candidate] = true; /**** RIPPLE ACROSS COL, ROW, REGION ****/ // (propagation) // remove candidates across unsolved cells in the same // row and col. for (int i = 0; i < 9; i++) { // only change unsolved cells containing the candidate if (m_grid[aCell.row, i] == 0) { if (m_cellConstraintMatrix[aCell.row, i][candidate] == true) { // shift affected cells down the bucket list bucketList[m_cellConstraintMatrix[aCell.row, i].Count].Remove(new Cell(aCell.row, i)); bucketList[m_cellConstraintMatrix[aCell.row, i].Count - 1].Add(new Cell(aCell.row, i)); // remove the candidate m_cellConstraintMatrix[aCell.row, i][candidate] = false; //update changed cells (for backtracking) changedCells.Add(new Cell(aCell.row, i)); } } // only change unsolved cells containing the candidate if (m_grid[i, aCell.col] == 0) { if (m_cellConstraintMatrix[i, aCell.col][candidate] == true) { // shift affected cells down the bucket list bucketList[m_cellConstraintMatrix[i, aCell.col].Count].Remove(new Cell(i, aCell.col)); bucketList[m_cellConstraintMatrix[i, aCell.col].Count - 1].Add(new Cell(i, aCell.col)); // remove the candidate m_cellConstraintMatrix[i, aCell.col][candidate] = false; //update changed cells (for backtracking) changedCells.Add(new Cell(i, aCell.col)); } } } // (propagation) // remove candidates across unsolved cells in the same // region. int grid_row_start = aCell.row / 3 * 3; int grid_col_start = aCell.col / 3 * 3; for (int row = grid_row_start; row < grid_row_start + 3; row++) for (int col = grid_col_start; col < grid_col_start + 3; col++) // only change unsolved cells containing the candidate if (m_grid[row, col] == 0) { if (m_cellConstraintMatrix[row, col][candidate] == true) { // shift affected cells down the bucket list bucketList[m_cellConstraintMatrix[row, col].Count].Remove(new Cell(row, col)); bucketList[m_cellConstraintMatrix[row, col].Count - 1].Add(new Cell(row, col)); // remove the candidate m_cellConstraintMatrix[row, col][candidate] = false; //update changed cells (for backtracking) changedCells.Add(new Cell(row, col)); } } // add cell to solved list unsolved.Remove(aCell); solved.Add(aCell); changed.Push(changedCells); }
// Backtracking method. Undoes the specified selection private void UnselectCandidate(Cell aCell, int candidate) { // 1) Remove selected candidate from grid m_grid[aCell.row, aCell.col] = 0; // 2) Add that candidate back to the cell constraint matrix. // Since it wasn't selected, it can still be selected in the // future m_cellConstraintMatrix[aCell.row, aCell.col][candidate] = true; // 3) Put cell back in the bucket list bucketList[m_cellConstraintMatrix[aCell.row, aCell.col].Count].Add(aCell); // 4) Remove the candidate from the row, col, and region constraint matrices m_rowConstraintMatrix[aCell.row][candidate] = false; m_colConstraintMatrix[aCell.col][candidate] = false; m_regionConstraintMatrix[aCell.row / 3, aCell.col / 3][candidate] = false; // 5) Add the candidate back to any cells that changed from // its selection (propagation). foreach (Cell c in changed.Pop()) { // shift affected cells up the bucket list bucketList[m_cellConstraintMatrix[c.row, c.col].Count].Remove(c); bucketList[m_cellConstraintMatrix[c.row, c.col].Count + 1].Add(c); m_cellConstraintMatrix[c.row, c.col][candidate] = true; } // 6) Add the cell back to the list of unsolved solved.Remove(aCell); unsolved.Add(aCell); }
private void PopulateCandidates() { //Add possible candidates by checking //the rows, columns and grid for (int row = 0; row < 9; row++) { for (int col = 0; col < 9; col++) { //if solved, then there are no possible candidates if (m_grid[row, col] > 0) { m_cellConstraintMatrix[row, col].SetAll(false); solved.Add(new Cell(row, col)); } else { // populate each cell with possible candidates // by checking the row, col, and grid associated // with that cell foreach (int candidate in m_rowConstraintMatrix[row]) m_cellConstraintMatrix[row, col][candidate] = false; foreach (int candidate in m_colConstraintMatrix[col]) m_cellConstraintMatrix[row, col][candidate] = false; foreach (int candidate in m_regionConstraintMatrix[row / 3, col / 3]) m_cellConstraintMatrix[row, col][candidate] = false; Cell c = new Cell(row, col); bucketList[m_cellConstraintMatrix[row, col].Count].Add(c); unsolved.Add(c); } } } }
public void No_neighbours_death() { var cell = new Cell { State = CellState.Alive, Neighbours = Enumerable.Empty<ICell>() }; Less_than_two_neighbours_death(cell); }