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 шт):
Вообще вся задача сводится к тому, чтобы сгенерировать 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, и вы убедитесь в этом сами на практике.
