0

数独パズルを解く Visual Studio 2008 を使用して C# アプリケーションを作成しようとしています。私の問題は、アプリケーションで新しいパズルを生成するためのコードを理解できないように見えることです。私が実装しようとしているアイデアは次のとおりです。

  1. 空のパズルから始める
  2. パズル内のすべてのセルに数字を生成する
  3. 必要な難易度に基づいて、適切な数のセルを空にする
  4. パズルを解く
  5. パズルのスコアは、必要な難易度の許容範囲内ですか?

6a. NO の場合 -> パズルを再生成 (1 へ)

6b. YES の場合 -> パズル生成 (表示)

「新しいゲーム」ボタンの使用コード:

    //--------------------------------------------------
    // Starting a new game menu button
    //--------------------------------------------------
    public void NewToolStripMenuItem_Click(System.Object sender, System.EventArgs e)
    {

        if (GameStarted) // this cheking part seems to work (message is displayed and game gets saved if selected)
        {
            MsgBoxResult response = (MsgBoxResult)(MessageBox.Show("Doriți salvarea jocului curent?", "Salvează jocul curent...", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question));

            if (response == MsgBoxResult.Yes)
            {
                SaveGameToDisk(false);
            }
            else if (response == MsgBoxResult.Cancel)
            {
                return;
            }
        }

        // Changing the cursor while generating
        System.Windows.Forms.Cursor.Current = Cursors.WaitCursor;
        ToolStripStatusLabel1.Text = "Se generează un puzzle nou...";

        // Creating an instance for the SudokuPuzzle class
        SudokuPuzzle sp = new SudokuPuzzle();
        string puzzle = string.Empty;

        // Determining the difficulty level selected (from menu objects)
        if (EasyToolStripMenuItem.Checked)
        {
            puzzle = sp.GetPuzzle(1);
        }
        else if (MediumToolStripMenuItem.Checked)
        {
            puzzle = sp.GetPuzzle(2);
        }
        else if (DifficultToolStripMenuItem.Checked)
        {
            puzzle = sp.GetPuzzle(3);
        }
        else if (ExtremelyDifficultToolStripMenuItem.Checked)
        {
            puzzle = sp.GetPuzzle(4);
        }
        else if (EmptyPuzzleToolStripMenuItem.Checked)
        {
            puzzle = sp.GetPuzzle(5);
        }

        // Changing to default cursor
        System.Windows.Forms.Cursor.Current = Cursors.Default;

        StartNewGame();

        // Initialisation of the grid
        int counter = 0;
        for (int row = 1; row <= 9; row++)
        {
            for (int col = 1; col <= 9; col++)
            {
                if (puzzle[counter].ToString() != "0")
                {
                    SetCell(col, row, System.Convert.ToInt32(puzzle[counter].ToString()), (short)0);
                }
                counter++;
            }
        }
    }

したがって、次の関数 GetPuzzle(1) のコードは次のようになります。

    //--------------------------------------------------
    // Obtaining a new puzzle (of the required level)
    //--------------------------------------------------
    public string GetPuzzle(int level)
    {
        int score = 0;
        string result;
        do
        {
            result = GenerateNewPuzzle(level, ref score);
            if (result != string.Empty)
            {
                // Verify if the generated puzzle is of the selected dificulty
                switch (level)
                {
                    // The average for dificutly 1
                    case 1:
                        if (score >= 42 && score <= 46)
                        {
                            goto endOfDoLoop;
                        }
                        break;
                    // The average for dificutly 2
                    case 2:
                        if (score >= 49 && score <= 53)
                        {
                            goto endOfDoLoop;
                        }
                        break;
                    // The average for dificutly 3                                   case 3:
                        if (score >= 56 && score <= 60)
                        {
                            goto endOfDoLoop;
                        }
                        break;
                    // The average for dificutly 4
                    case 4:
                        if (score >= 112 && score <= 116)
                        {
                            goto endOfDoLoop;
                        }
                        break;
                }
            }
        } while (!false); // loops ending 
    endOfDoLoop:
        return result;
    }

次に使用する関数は GenerateNewPuzzle() です。

    //--------------------------------------------------
    // Generating a new puzzle
    //--------------------------------------------------
    public string GenerateNewPuzzle(int level, ref int score)
    {
        int c;
        int r;
        string str;
        int numberofemptycells = 0;

        // Initializing the entire grid
        for (r = 1; r <= 9; r++)
        {
            for (c = 1; c <= 9; c++)
            {
                actual[c, r] = 0;
                possible[c, r] = string.Empty;
            }
        }

        // Empty the stacks used
        ActualStack.Clear();
        PossibleStack.Clear();

        // Complete by solving an empty grid
        try
        {
            // First used logical methods to solve the grid
            if (!SolvePuzzle())
            {
                // Then use brute force
                SolvePuzzleByBruteForce();
            }
        }
        catch (Exception)
        {
            // If there’s any error, return emptry string
            return string.Empty;
        }

        // Create a copy for the actual array
        actual_backup = (int[,])(actual.Clone());

        // Set the number of empty cells based on the difficulty  level
        switch (level)
        {
            // For difficulty level 1
            case 1:
                numberofemptycells = RandomNumber(40, 45);
                break;
            // For difficulty level 2
            case 2:
                numberofemptycells = RandomNumber(46, 49);
                break;
            // For difficulty level 3
            case 3:
                numberofemptycells = RandomNumber(50, 53);
                break;
            // For difficulty level 4
            case 4:
                numberofemptycells = RandomNumber(54, 58);
                break;
        }

        // Empty the stacks used by brute force
        ActualStack.Clear();
        PossibleStack.Clear();
        BruteForceStop = false;

        // Create empty cells
        CreateEmptyCells(numberofemptycells);

        // Convert the values from the actual array to string
        str = string.Empty;
        for (r = 1; r <= 9; r++)
        {
            for (c = 1; c <= 9; c++)
            {
                str += (string)(actual[c, r].ToString());
            }
        }

        // Verrify that the puzzle has only one solution
        int tries = 0;
        do
        {
            totalscore = 0;
            try
            {
                if (!SolvePuzzle())
                {
                    // If puzzle is not solved and difficulty level is 1-3
                    if (level < 4)
                    {
                        // Choose another combination of cells to empty
                        VacateAnotherPairOfCells(ref str);
                        tries++;
                    }
                    else
                    {
                        // Puzzles of difficulty 4 don’t guranty a single solution
                        SolvePuzzleByBruteForce();
                        goto endOfDoLoop;
                    }
                }
                else
                {
                    // The puzzle has 1 solution
                    goto endOfDoLoop;
                }
            }
            catch (Exception)
            {
                return string.Empty;
            }

            // If too many tries are executed, exit at 50
            if (tries > 50)
            {
                return string.Empty;
            }
        }
        while (true);
    endOfDoLoop:

        // Return the obtained score and the puzzle as a string
        score = totalscore;
        return str;
    }

そして最後の便利な (私が思うに) 関数、VacateAnotherPairOfCells():

    //--------------------------------------------------
    // Empty another pair of cells
    //--------------------------------------------------
    private void VacateAnotherPairOfCells(ref string str)
    {
        int c;
        int r;

        // Search for a pair of cells to empty (the empty cells should be simetrical from the center of the grid)
        do
        {
            c = RandomNumber(1, 9);
            r = RandomNumber(1, 9);
        } while (!(int.Parse(str[(c - 1) + (r - 1) * 9].ToString()) == 0));

        // Restore the value of the cell from the backup array
        str = str.Remove(System.Convert.ToInt32((c - 1) + (r - 1) * 9), 1);
        str = str.Insert(System.Convert.ToInt32((c - 1) + (r - 1) * 9), (string)(actual_backup[c, r].ToString()));

        // Restore the value of the simetrical cell
        str = str.Remove(System.Convert.ToInt32((10 - c - 1) + (10 - r - 1) * 9), 1);
        str = str.Insert(System.Convert.ToInt32((10 - c - 1) + (10 - r - 1) * 9), (string)(actual_backup[10 - c, 10 - r].ToString()));

        // Search for another pair of cells that can be emptyed
        do
        {
            c = RandomNumber(1, 9);
            r = RandomNumber(1, 9);
        } while (!(int.Parse(str[(c - 1) + (r - 1) * 9].ToString()) != 0));

        // Delete the cell from the string
        str = str.Remove(System.Convert.ToInt32((c - 1) + (r - 1) * 9), 1);
        str = str.Insert(System.Convert.ToInt32((c - 1) + (r - 1) * 9), "0");

        // Delete the simetrical cell from the string
        str = str.Remove(System.Convert.ToInt32((10 - c - 1) + (10 - r - 1) * 9), 1);
        str = str.Insert(System.Convert.ToInt32((10 - c - 1) + (10 - r - 1) * 9), "0");

        // Reinitilisation of the grid
        short counter = (short)0;
        for (int row = 1; row <= 9; row++)
        {
            for (int col = 1; col <= 9; col++)
            {
                if (System.Convert.ToInt32(str[counter].ToString()) != 0)
                {
                    actual[col, row] = System.Convert.ToInt32(str[counter].ToString());
                    possible[col, row] = (string)(str[counter].ToString());
                }
                else
                {
                    actual[col, row] = 0;
                    possible[col, row] = string.Empty;
                }
                counter++;
            }
        }
    }
} }

他のすべてが機能するため、残りの関数とコードは必要ではないと思いました。空のパズルまたは部分的なパズルをインポートすると、アプリケーションは、自動生成されたグリッドを解決するために使用されるのと同じ方法を使用して、自動的に解決できます。しかし、メニューから「新しいパズル」をクリックすると、アプリケーションはエラーなしでスタックします (そのため、プロセスを強制終了する必要があります)。

おそらく、これは有効なボードを生成する最も簡単な方法ではありません。コードが長くなって申し訳ありませんが、これを修正して使用する必要があります。私はこれを自分で何度も修正しようとしましたが、過去 2 か月で解決策が見つかりませんでした (この問題に関する私の無能さから多くの欲求不満が生じただけです)。

4

1 に答える 1