3

I am writing a Sudoku application and am currently working on the game generation algorithm. I managed to figure out how to quickly generate a solution (not solve). I am stumped on how to remove some of the numbers to actually make it into a puzzle, though. My first inclination was to randomly remove a certain number of cells based on the difficulty, but that is not the correct algorithm, because it often renders a puzzle that is unsolvable or has multiple solutions. It also might generate puzzles that don't reflect the requested difficulty.

Here is the code that I have so far. I removed most of the irrelevant code, but if you would like to see something that isn't implemented but used below, please let me know. I can also provide my attempt at the Puzzlefy method if you would like, but I opted out of immediately posting it since it's blatantly wrong (even though it "works").

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sudoku
{
    public class Game
    {
        public enum Difficulty
        {
            VeryEasy,
            Easy,
            Medium,
            Difficult,
            Evil
        }

        private readonly int?[,] _currentItems = new int?[9,9];
        private readonly int?[,] _solution = new int?[9,9];
        private readonly int?[,] _startingItems = new int?[9,9];
        private readonly Difficulty _difficulty;

        public Game(Difficulty difficulty)
        {
            _difficulty = difficulty;
            GenerateSolution();
            Puzzlefy();
        }

        private void GenerateSolution()
        {
            var random = new Random();
            var availableNumbers = new Stack<List<int?>>(81);
            var x = 0;
            var y = 0;

            availableNumbers.Push(AllowableNumbers(_solution, 0, 0).ToList());
            while (x < 9 && y < 9)
            {
                var currentAvailableNumbers = AllowableNumbers(_solution, x, y).ToList();
                availableNumbers.Push(currentAvailableNumbers);

                // back trace if the board is in an invalid state
                while (currentAvailableNumbers.Count == 0)
                {
                    _solution[x, y] = null;
                    availableNumbers.Pop();
                    currentAvailableNumbers = availableNumbers.Peek();
                    x -= y >= 1 ? 0 : 1;
                    y = y >= 1 ? y - 1 : 8;
                }

                var index = random.Next(currentAvailableNumbers.Count);
                _solution[x, y] = currentAvailableNumbers[index];
                currentAvailableNumbers.RemoveAt(index);

                x += y < 8 ? 0 : 1;
                y = y < 8 ? y + 1 : 0;
            }
        }

        private void Puzzlefy()
        {
            CopyCells(_solution, _startingItems);

            // remove some stuff from _startingItems

            CopyCells(_startingItems, _currentItems);
        }
    }
}

I am not looking for code, rather an algorithm. How would I go about removing the numbers from the solution to make it into a puzzle?

Tyler Crompton
  • 12,284
  • 14
  • 65
  • 94
  • I'm not sure if this helps at all, but a "proper" sudoku is also supposed to be symmetric - the provided (or removed) cells are not random, but follow a pattern left-to-right, top-to-bottom, or mirrored. I'm not sure if this has any effect on the likelihood of generating a working puzzle, or not. – GalacticCowboy Feb 13 '13 at 17:17
  • I do agree. While there's nothing fundamentally wrong an asymmetric puzzle, it's aesthetically displeasing. I found that the random removal usually didn't give too terrible of symmetry, but theoretically, it could make all the givens in the same corner. – Tyler Crompton Feb 13 '13 at 17:21

2 Answers2

3

Here is a paper on sudoku generation

I think that you will need a sudoku solver that will also count the number of solutions available, then substract numbers in such a way that there is always only one available solution.

You could apply the same method to adding numbers to the grid, then check the number of possible solution and keep adding when the number of solution is greater than 1 and backtracking when the number of solutions is 0

Eric
  • 19,525
  • 19
  • 84
  • 147
  • I was actually looking at that too, but it briefly describes how to remove the cells and then determine the difficulty instead of the other way around. Repetitively doing it that way until a puzzle of the desired difficulty is achieved will yield a very inefficient algorithm. – Tyler Crompton Feb 13 '13 at 17:19
0

There is no "easy" way to remove clues from a completed Sudoku grid as the removal process is not linear.

After each removal of a cell or clue you need to check if the Sudoku only has a unique solution.

To check this you need to run a solver that can count all possible solutions (you can stop it after 2 possibilities are found to save time).

The two most popular algorithm used both for solving a Sudoku, counting all the Sudoku solutions and removing cells are backtracking algorithms and dancing links algorithms.

This article explains really well how the dancing links algorithm can be used in Sudokus: http://garethrees.org/2007/06/10/zendoku-generation/#section-2

Here is another description of a dancing link algorithm in Sudokus written in JavaScript: http://www.sudokubum.com/documentation.html

And here is the full paper about dancing links algorithms in general: http://lanl.arxiv.org/pdf/cs/0011047

dthill
  • 31
  • 1
  • 4