Числа, встречающиеся дважды в одном и том же столбце и строке в программе доски судоку

Этот код вызывает у меня головную боль. Подводя итог, цель моей программы — создать полные доски судоку, которые можно будет использовать в будущем для игры. Я почти у цели. У меня нет повторяющихся чисел в более мелких сетках, но я все еще получаю повторяющиеся числа в более крупной сетке.

Снимок экрана моей программы, отображающий мою проблему:

Предисловие к моему коду:

  • gameGrid — это 2d-массив из 9 массивов, каждый из которых состоит из 9 индексов.
  • btnGrid — зеркало gameGrid, но предназначено для кнопок в графическом интерфейсе.
  • GridXX относится к каждой меньшей сетке 3x3 на доске судоку.

Остальная часть кода объясняется программно внутри функции. Я считаю, что проблема заключается в частях «checkCol» и «checkRow», которые отмечены комментариями.

Мы очень ценим любую помощь и заранее благодарим всех комментаторов.

private void generateBtn_Click(object sender, EventArgs e){
Random r = new Random();
//Row and Col max is one less as arrays start at 0
int rowMax = 9;
int colMax = 9;

for (int i = 0; i < rowMax; i++)
{
    for (int j = 0; j < colMax; j++)
    {
        bool checking = false;
        bool foundSame = false;
        while (checking == false)
        {
            foundSame = false;
            string num = r.Next(1, 10).ToString();
            Debug.WriteLine(num);
            //check row
            for (int k = 0; k < rowMax; k++) {
                if (gameGrid[i,k] == num) {  foundSame = true; break; }
                if (gameGrid[i,k] == "") { break; }
            }
            //check col
            for (int k = 0; k < colMax; k++)
            {
                if (gameGrid[k,j] == num) { foundSame = true; break; }
            }
            //check square
            if (grid00.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid00, num); }
            if (grid10.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid10, num); }
            if (grid20.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid20, num); }

            if (grid01.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid01, num); }
            if (grid11.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid11, num); }
            if (grid21.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid21, num); }

            if (grid02.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid02, num); }
            if (grid12.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid12, num); }
            if (grid22.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid22, num); }


            if (foundSame == false)
            {
                checking = true;
                gameGrid[i,j] = num;
                btnGrid[i,j].Text = num;
                
            }
        }
        
        
    }
}}

Я бы начал с допустимой доски в качестве входных данных и вместо этого выполнил несколько случайных перестановок. Под перестановкой я подразумеваю перестановку двух случайных позиций в одной ячейке и выравнивание чисел в других ячейках, но у меня нет точного представления, как это сделать. Я добавил тег алгоритма.

yacc 11.08.2024 05:12

@EpicAshman, почему у тебя if (gameGrid[i,k] == "") { break; } в checkRow?.

Nguyen Manh Cuong 11.08.2024 06:39

И почему число является случайным числом, я думаю, что в алгоритме доски судоку этого не должно быть random.

Nguyen Manh Cuong 11.08.2024 06:43

Проверка того, пуста ли строка, была на ранней стадии, о которой я забыл. Я использую его для генерации случайных решений судоку, поскольку одна из моих будущих запланированных функций — добавить решение головоломок отдельно от программы, после чего станет доступно функциональное решение.

EpicAshman 11.08.2024 07:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Основная проблема, по-видимому, не в частях «checkCol» и «checkRow». Вместо этого код не проверяет наличие foundSame после двух false циклов, прежде чем он проверит соответствующую меньшую сетку. Таким образом, например, если for было foundSame из-за того, что дубликат был найден в большей сетке, но он не найден в соответствующей меньшей сетке, тогда true устанавливается в foundSame, и, таким образом, значение устанавливается там, даже если оно повторяет значение в строке или столбце более крупной сетки. Вот почему цифры могут повторяться в более крупной сетке, но не в пределах более мелкой (обратите внимание, я предполагаю, что функция false, которая не показана, работает правильно).

Относительно простой и легкий способ исправить это — просто добавить флажок, чтобы checkIfContains не был установлен в операторах foundSame для каждой из ваших меньших сеток. Таким образом, для первого варианта строка кода должна выглядеть примерно так:

if (!foundSame && grid00.Contains(btnGrid[i, j])) { foundSame = checkIfContains(grid00, num); }

Я не задумывался тщательно о том, может ли это когда-нибудь произойти, но я считаю, что потенциальная проблема заключается в том, что может возникнуть бесконечный цикл. Это произойдет, если ни одно из значений от 1 до 9 не может соответствовать требованиям для конкретной ячейки, т. е. каждое из них является дубликатом в строке или столбце более крупной сетки или в меньшей сетке. Чтобы избежать этого, один из способов — создать массив из 9 значений if, где каждое значение изначально установлено в bool непосредственно перед false. В конце этого цикла, если while (checking == false) равно foundSame, установите значение массива, соответствующее true, в num. Кроме того, если все значения массива равны true, то никакое значение не будет работать, поэтому код должен выйти из цикла, выполнив что-то вроде создания исключения (хотя вы можете сначала зарегистрировать это каким-либо образом), а затем возможно, очистите доску и попробуйте еще раз.


Наконец, как указано в комментарии Нгуен Мань Куонга, ваша строка true в коде для проверки строк потенциально проблематична. Однако, поскольку вы не показали свой код инициализации, это сомнительно. Если пустых ячеек никогда не бывает, эта строка ничего не делает. С другой стороны, если перед ячейкой, содержащей дублирующую ячейку в строке, есть пустая ячейка, код выйдет из цикла, не устанавливая if (gameGrid[i,k] == "") { break; } в foundSame.

Тем не менее, я не вижу никакой реальной цели в наличии этой строки, поэтому ее, вероятно, следует удалить или хотя бы закомментировать.

Да, проверку на пустую строку я забыл взять из ранней версии. Но чтение вашего решения имеет смысл, и я не могу поверить, что это была моя оплошность, лол, большое спасибо.

EpicAshman 11.08.2024 07:05

@EpicAshman Всегда пожалуйста. Я только что понял, что есть еще одна потенциальная проблема, а именно возникновение бесконечного цикла. Таким образом, я обновил свой ответ в средней части, чтобы учесть эту возможность. Однако, как я уже сказал там, я не знаю, может ли это когда-нибудь произойти. Если вы уверены, что этого никогда не произойдет, вы можете проигнорировать это, хотя относительно легко сделать то, что я предлагаю, просто чтобы убедиться.

John Omielan 11.08.2024 07:26

Вот подход к созданию полной доски.

var possibles = new List<int>[9, 9];
var board = new int[9, 9];
for (var i = 0; i < 9; i++)
    for (var j = 0; j < 9; j++)
    {
        possibles[i, j] = Enumerable.Range(1, 9).ToList();
        board[i, j] = 0;
    }

var query =
    from i in Enumerable.Range(0, 9)
    from j in Enumerable.Range(0, 9)
    where possibles[i, j].Any()
    select new { i, j, };

var random = new Random();
for (var n = 0; n < 81; n++)
{
    var least = query.MinByWithTies(x => possibles[x.i, x.j].Count).OrderBy(x => random.Next()).First();

    var selected = possibles[least.i, least.j][random.Next(possibles[least.i, least.j].Count)];

    possibles[least.i, least.j] = new List<int>();
    board[least.i, least.j] = selected;

    var ii = least.i / 3 * 3;
    var jj = least.j / 3 * 3;

    for (var k = 0; k < 9; k++)
    {
        possibles[least.i, k] = possibles[least.i, k].Except(new[] { selected }).ToList();
        possibles[k, least.j] = possibles[k, least.j].Except(new[] { selected }).ToList();
        possibles[ii + k / 3, jj + k % 3] = possibles[ii + k / 3, jj + k % 3].Except(new[] { selected }).ToList();
    }
}

Все начинается с сетки возможностей и доски. Он находит все ячейки с наименьшим количеством вариантов и случайным образом выбирает один. Затем он заполняет эту ячейку и удаляет число из всех возможных строк, столбцов и блоков, связанных с этой ячейкой.

Всего это повторяется 81 раз.

Единственная драма заключается в том, что иногда он терпит неудачу, но достаточно часто удается просто повторить весь процесс в виде исключения. .First() не работает в строке var least.

Вот пример вывода действительной сетки:

Создание сетки занимает менее полсекунды.

Привет, я только что скопировал код в свой, и мой intelisense не распознает метод .IsEmpty() при просмотре списка. Есть мысли? Выплевывание CS1061

EpicAshman 11.08.2024 07:21

@EpicAshman — это в библиотеке, которую я использую. Я исправлю код.

Enigmativity 11.08.2024 08:45

Другие вопросы по теме