C# - Как поместить заданное кол-во мин рандомом в массиве

Сразу говорю, я новичок в c#. У меня есть задача сделать типа сапера, но который сразу открывает решение.

static void Main(string[] args)
        {
            Console.Write("Введите ширину поля: ");
            int q = Convert.ToInt32(Console.ReadLine());

            Console.Write("Введите длину поля: ");
            int w = Convert.ToInt32(Console.ReadLine());

            Console.Write("Введите число мин: ");
            int c = Convert.ToInt32(Console.ReadLine());


            Random rand = new Random();

            var charArray = new char[q, w];
            var intArray = new int[q, w];
            for (int i = 0; i < q; i++)
            {
                for (int j = 0; j < w; j++)
                {
                    intArray[i, j] = rand.Next(2);
                    charArray[i, j] = intArray[i, j] == 0 ? '_' : '*';
                    Console.Write(charArray[i, j]);
                }
                Console.WriteLine();
            }

        }

    }
}

Должны вывестись две матрицы. На первой должно быть все закрыто, то есть должны быть только символы: _ и *

0 - это места без мин, заменил я их символом _

1 - это места с минами, заменил я их символом звездочки, но они не принимают введеное пользователем количество мин. А нужно, чтобы символов "*" было столько, сколько и мин.

А во второй матрице должно вывестись уже открытое решение игры. То есть ячейки, рядом с которыми есть мины, должны принять число, значущее кол-во мин рядом с этой ячейкой.

Помогите, пожалуйста..

Текущий код после компиляции


Ответы (1 шт):

Автор решения: aepot

Вообще вся задача сводится к тому, чтобы сгенерировать c случайных уникальных чисел. И потом используя эти числа расставить единички в массиве. Сам алгоритм генерации и расстановки можно реализовать разными способами, и способ зависит от ваших знаний и контекста задания. Есть один гарантированный способ это сделать эффективно в случае если размер матрицы небольшой, скажем меньше миллиона элементов.

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

int rows = 10;
int cols = 10;
int minesCount = 5;

int[] indexes = new int[rows * cols];
// заполняю индексами
for (int i = 0; i < indexes.Length; i++)
{
    indexes[i] = i;
}
Random rnd = new Random();
// перемешиваю
for (int i = 0; i < indexes.Length; i++)
{
    int randomIndex = rnd.Next(indexes.Length);
    int x = indexes[randomIndex];
    indexes[randomIndex] = indexes[i];
    indexes[i] = x;
}

Теперь можно считать, что массив indexes содержит уникальные случайные числа. Алгоритм описан хорошо в Википедии.

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

int[,] matrix = new int[rows, cols];
for (int i = 0; i < minesCount; i++)
{
    int index = indexes[i];
    int row = index / cols;
    int col = index % cols;
    matrix[row, col] = 1;
}

Теперь можно вывести матрицу в консоль.

for (int i = 0; i < rows; i++)
{
    for (int j = 0; j < cols; j++)
    {
        Console.Write(matrix[i, j]);
    }
    Console.WriteLine();
}

Пример вывода в консоль

0000001000
0000000010
0000000000
0000000000
0000000000
0000000000
0000000000
0100000000
1000000000
0000000010

При этом вам не нужно хранить матрицу с символами, она будет дублировать данные матрицы с числами, а дублирование данных в приложении - всегда плохо. Это источник лишних ошибок. Чтобы вывести звездочки с подчеркиваниями можно сделать просто вот так.

Console.Write(matrix[i, j] == 1 ? '*' : '_');

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


Обратите внимание, что при условии что x - это координата по горизонтали, matrix[x, y] это неверная нотация, верная matrix[y, x]. Потому что первый индекс указывает на номер строки, а второй - на номер колонки, а строки же располагаются по высоте, одна за другой.

Чтобы не путаться, советую делать как я matrix[row, col]. В вашем примере q - это ширина, так? А вот и нет, вы считываете ширину, но задаете ее как высоту, и наоборот. Попробуйте задать разные q и w, например 5 и 10, и вы убедитесь в этом сами на практике.

→ Ссылка