Пример #1
0
        /*
         * INTERACTION WITH GUI
         */

        public static void create()
        {
            //Reads the textBoxes in MainWindow and translates them into data we can work with
            MainWindow.sudokuTextBoxes[hintIndex].BackColor = System.Drawing.Color.White;
            //re-initialize our variables
            waitingForUpdate = new Queue <sudokuField>();
            solvedFields     = 0;
            singleField      = false;
            fields           = new sudokuField[81];

            //Creates our sudoku from the textboxes found in MainWindow
            for (int i = 0; i < 81; i++)
            {
                String txt = MainWindow.sudokuTextBoxes[i].Text;
                //If there's a valid sudoku-number in the box, we use that. Else, we leave it blank
                String pattern = "[1-9]";
                if (System.Text.RegularExpressions.Regex.IsMatch(txt, pattern))
                {
                    fields[i]     = new sudokuField(Int32.Parse(txt) - 1); //Remember to convert the number to "machine-friendly" numbers (0-8)
                    solvedFields += 1;
                }
                else
                {
                    fields[i] = new sudokuField();
                }
            }

            if (sudokuIsInvalid())
            {
                throw new InvalidOperationException("The entered sudoku isn't valid");
            }
        }
Пример #2
0
        public static void hint()
        {
            //Solves a single field, thus giving the user a little help
            singleField = true;

            loneCandidates();

            for (int i = 0; i < 50; i++) //Not the most efficient solution, but it should work
            {
                solvingAlgorithms();     //Then we don't have to worry about edge-cases
            }

            if (waitingForUpdate.Count > 0)   //A field is ready for update!
            {
                sudokuField tmpField = waitingForUpdate.Peek();
                handleQueue();

                hintIndex = Array.IndexOf(fields, tmpField); //Write down location where "hint" is given
                MainWindow.sudokuTextBoxes[hintIndex].BackColor = System.Drawing.Color.Beige;
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("Can't help you here, sorry");
            }
        }
Пример #3
0
        static void handleQueue()
        {
            //Method checks the waitingForUpdate Queue, and updates all sudokuFields stored within
            //Also prints the new fields to MainWindow
            //This is the only method that should access field.updateField()!
            //If singleStep is set to true, only a single field will be fixed
            while (waitingForUpdate.Count > 0)
            {
                //Insert number in code and GUI
                sudokuField currentField = waitingForUpdate.Dequeue();
                currentField.updateField();

                if (sudokuIsInvalid())
                {
                    throw new InvalidOperationException("Something went wrong. Make sure you entered a valid sudoku");
                }

                MainWindow.sudokuTextBoxes[Array.IndexOf(fields, currentField)].Text = (currentField.getNumber() + 1).ToString();
                solvedFields += 1;

                //Updates the candidates of surrounding fields
                sudokuField[] surroundingFields = getSurroundings(currentField);

                foreach (sudokuField f in surroundingFields)
                {
                    removeCandidate(f, currentField.getNumber());
                }

                //Exit method if only one field is wanted
                if (singleField)
                {
                    return;
                }
            }
        }
Пример #4
0
        static void lookForPairsIn(sudokuField[] array)
        {
            //Spots if two fields in array share the same two (and only two) candidates. If they do, these two numbers can't be placed anywhere else in arrat
            for (int index = 0; index < 8; index++)
            {
                if (array[index].getNumberOfCandidates() == 2)  //First field has two candidates
                {
                    sudokuField firstField      = array[index];
                    int[]       firstCandidates = firstField.getCandidates();

                    for (int index2 = index + 1; index2 < 9; index2++)
                    {
                        if (array[index2].getNumberOfCandidates() == 2)
                        {
                            sudokuField secondField      = array[index2];
                            int[]       secondCandidates = secondField.getCandidates();

                            if (firstCandidates[0] == secondCandidates[0] && firstCandidates[1] == secondCandidates[1]) //The candidates match?
                            {
                                removeCandidateFromArrayExcept(firstCandidates[0], array, firstField, secondField);     //Remove the two candidates from the rest of array
                                removeCandidateFromArrayExcept(firstCandidates[1], array, firstField, secondField);
                            }
                        }
                    }
                }
            }
        }
Пример #5
0
        static void mustBeInThisRowOrColumn()
        {
            //If a number in a row/column can only be placed in a given segment, this number can't be placed anywhere else in that segment
            //Likewise, if a number can only be placed in a given row/column of a segment, this number can't be placed anywhere else in that row/column
            //Sort of a wrapper for knownSegmentOfArray()
            for (int i = 0; i < 9; i++)
            {
                sudokuField[] row     = getRow(i);
                sudokuField[] column  = getColumn(i);
                sudokuField[] segment = getSegment(i);

                //To test for columns (vertical) we need to mirror the segment, since knownSegmentOfArray groups index 0,1,2 , 3,4,5 and 6,7,8 together

                /*
                 * Original    Transformed
                 * 0 1 2       0 3 6
                 * 3 4 5       1 4 7
                 * 6 7 8       2 5 8
                 */
                sudokuField[] mirroredSegment = new sudokuField[9];
                for (int c = 0; c < 8; c++)
                {
                    mirroredSegment[c] = segment[(3 * c) % 8];
                }
                mirroredSegment[8] = segment[8];


                knownSegmentOfArray(row, getSegment);
                knownSegmentOfArray(column, getSegment);
                knownSegmentOfArray(segment, getRow);
                knownSegmentOfArray(mirroredSegment, getColumn);
            }
        }
Пример #6
0
        static void knownSegmentOfArray(sudokuField[] array, delGetArrayFromSudokuField overlapFunction)
        {
            //This method determines if we know for sure which third of an array a given number is located in.
            //If the number must be placed in this third, then it can't be placed anywhere else in the overlapping segment/row
            bool[] numberIsPlaced = new bool[9];

            for (int c = 0; c < 9; c++)
            {
                int tmp = array[c].getNumber();
                if (tmp > -1)
                {
                    numberIsPlaced[tmp] = true;
                }
            }

            for (int number = 0; number < 9; number++)
            {
                if (!numberIsPlaced[number])       //Number isn't placed yet
                {
                    bool[] segments = new bool[3]; //Can number be placed in column?
                    for (int ii = 0; ii < 9; ii++)
                    {
                        if (array[ii].isCandidate(number)) //Number can be placed in this field
                        {
                            segments[ii / 3] = true;       //Can be placed in this segment
                        }
                    }
                    int noOfSegments = 0; //The number of segments where this number can be placed

                    for (int ii = 0; ii < 3; ii++)
                    {
                        if (segments[ii])
                        {
                            noOfSegments += 1;
                        }
                    }

                    int foundSegment = -1;                      //The found segment

                    sudokuField[] overlap = new sudokuField[0]; //Row and column initialized as empty
                                                                //This will hold the sudokuFields of found segment - if any

                    if (noOfSegments == 1)
                    {
                        for (int ii = 0; ii < 3; ii++)
                        {
                            if (segments[ii])
                            {
                                foundSegment = ii;
                            }
                        }
                        overlap = overlapFunction(array[3 * foundSegment]);
                    }
                    //Remove number as candidate from segment - except in the row/column (array)
                    removeCandidateFromArrayExcept(number, overlap, array);
                }
            }
        }
Пример #7
0
 static void removeCandidate(sudokuField field, int number)
 {
     //Removes the candidate "number" from the given field, and enqueues the field in waitingForUpdate, if neccessary
     if (field.removeCandidate(number))
     {
         //Now there's only one candidate left - so f needs updating too
         waitingForUpdate.Enqueue(field);
     }
 }
Пример #8
0
        static void lookForHiddenPairsIn(sudokuField[] array)
        {
            //Two numbers only occur as candidates in the same two fields. No other number can be placed in these fields
            for (int number1 = 0; number1 < 8; number1++)
            {
                if (occurencesAsCandidate(number1, array) == 2)
                {
                    //Find locations
                    int firstOccurence  = -1;
                    int secondOccurence = -1;
                    for (int i = 0; i < 9; i++)
                    {
                        if (array[i].isCandidate(number1))   //This is one of the occurences
                        {
                            if (firstOccurence < 0)
                            {
                                firstOccurence = i;
                            }
                            else
                            {
                                secondOccurence = i;
                            }
                        }
                    }

                    for (int number2 = number1 + 1; number2 < 9; number2++)
                    {
                        //Are these numbers candidates in the exact same fields?
                        sudokuField first  = array[firstOccurence];
                        sudokuField second = array[secondOccurence];
                        if (occurencesAsCandidate(number2, array) == 2)
                        {
                            bool pairFound = true;
                            for (int i = 0; i < 9; i++)
                            {
                                if (array[i].isCandidate(number1) != array[i].isCandidate(number2))
                                {
                                    //They weren't candidates to the same fields - no pair here
                                    pairFound = false;
                                    break;
                                }
                            }

                            if (pairFound)
                            {
                                removeAllCandidatesExcept(array[firstOccurence], number1, number2);
                                removeAllCandidatesExcept(array[secondOccurence], number1, number2);
                            }
                        }
                    }
                }
            }
        }
Пример #9
0
        public static sudokuField[] getRow(sudokuField field)
        {
            //Returns the row (horizontal) that the given field is part of
            int index = Array.IndexOf(fields, field);

            sudokuField[] row   = new sudokuField[9];
            int           rowNo = index / 9;

            for (int i = 0; i < 9; i++)
            {
                row[i] = fields[i + (rowNo * 9)];
            }
            return(row);
        }
Пример #10
0
        public static sudokuField[] getColumn(sudokuField field)
        {
            //Returns the column (vertical) that the given field is part of
            int index = Array.IndexOf(fields, field);

            sudokuField[] column   = new sudokuField[9];
            int           columnNo = index % 9;

            for (int i = 0; i < 9; i++)
            {
                column[i] = fields[columnNo + (i * 9)];
            }
            return(column);
        }
Пример #11
0
        static sudokuField[] getSurroundings(sudokuField field)
        {
            //Returns an array of alle the fields in the same row, column and segment

            sudokuField[] row     = getRow(field);
            sudokuField[] column  = getColumn(field);
            sudokuField[] segment = getSegment(field);
            //Combine into one array - surroundingFields. This array will have duplicates, but that shouldn't really matter ...
            sudokuField[] surroundingFields = new sudokuField[27];
            Array.Copy(row, 0, surroundingFields, 0, row.Length);
            Array.Copy(column, 0, surroundingFields, row.Length, column.Length);
            Array.Copy(segment, 0, surroundingFields, row.Length + column.Length, segment.Length);

            return(surroundingFields);
        }
Пример #12
0
 static void removeAllCandidatesExcept(sudokuField field, params int[] numbers)
 {
     //Removes all candidates from field, except "numbers".
     for (int i = 0; i < 9; i++)
     {
         if (Array.IndexOf(numbers, i) >= 0)   //This number should be skipped
         {
             continue;
         }
         else
         {
             removeCandidate(field, i);
         }
     }
 }
Пример #13
0
        public static sudokuField[] getSegment(sudokuField field)
        {
            //Returns the 3x3 grid the given field is part of
            sudokuField[] segment = new sudokuField[9];
            int           index   = Array.IndexOf(fields, field);
            int           x       = (index % 9) / 3; //0,0 is segment in top-right corner
            int           y       = (index / 9) / 3;

            for (int i = 0; i < 9; i++)
            {
                int innerX = i % 3;
                int innerY = i / 3;
                int finalX = x * 3 + innerX;
                int finalY = y * 3 + innerY;
                segment[i] = fields[finalX + 9 * finalY];
            }
            return(segment);
        }
Пример #14
0
 public static void Create()
 {
     fields = new sudokuField[81];
     //Creates our sudoku from the textboxes found in Form1
     for (int i = 0; i < 81; i++)
     {
         String txt = Form1.sudokuTextBoxes[i].Text;
         //If there's a valid sudoku-number in the box, we use that. Else, we leave it blank
         String pattern = "[1-9]";
         if (System.Text.RegularExpressions.Regex.IsMatch(txt, pattern))
         {
             fields[i] = new sudokuField(Int32.Parse(txt) - 1); //Remember to convert the number to "machine-friendly" numbers (0-8)
         }
         else
         {
             fields[i] = new sudokuField();
         }
     }
 }
Пример #15
0
        static void handleQueue()
        {
            //Method checks the waitingForUpdate Queue, and updates all sudokuFields stored within
            //Also prints the new fields to Form1
            while (waitingForUpdate.Count > 0)
            {
                sudokuField fieldInQueue = waitingForUpdate.Dequeue();
                fieldInQueue.updateField();
                Form1.sudokuTextBoxes[Array.IndexOf(fields, fieldInQueue)].Text = (fieldInQueue.getNumber() + 1).ToString();

                //Updates the candidates of surrounding fields
                sudokuField[] surroundingFields = getSurroundings(fieldInQueue);

                foreach (sudokuField f in surroundingFields)
                {
                    removeCandidate(f, fieldInQueue.getNumber());
                }
            }
        }
Пример #16
0
        static void loneCandidates()
        {
            //Simply checks on the candidates of all fields.
            //Should only be called once, as the very first solve-algo
            //After this, the candidates should be self-maintaining
            for (int i = 0; i < 81; i++)
            {
                sudokuField   field        = fields[i];
                sudokuField[] surroundings = getSurroundings(field);

                //Update candidates of this field, according to surrounding numbers
                foreach (sudokuField f in surroundings)
                {
                    int number = f.getNumber();
                    if (number > -1)
                    {
                        removeCandidate(field, number);
                    }
                }
            }
        }
Пример #17
0
        public static void Solve()
        {
            //TODO: Make solve-ladder - and their functions, of course
            //Simple solve - first step
            //Written here for testing backbone - will be moved later
            //TODO: Move simple solve
            for (int i = 0; i < 81; i++)
            {
                sudokuField   field        = fields[i];
                sudokuField[] surroundings = getSurroundings(field);

                //Update candidates of field, according to surrounding numbers
                foreach (sudokuField f in surroundings)
                {
                    int number = f.getNumber();
                    if (number > -1)
                    {
                        removeCandidate(field, number);
                    }
                }
                //Better empty the queue now
                handleQueue();
            }
        }