Как сделать ограниченное создание рандомных бомб?
Начал писать игру "Сапер", не могу решить проблему с ограниченным созданием бомб. Вообще программа работает, но как то коряво, потому что я обошел проблему созданием процентного соотношения. Но мне не нравится! И вот как эту проблему решить?
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
int width = 10;
int height = 10;
int offset = 30;
int bombPercent = 30;
FieldButton[,] field;
public void Generater()
{
Random random = new Random();
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
FieldButton newButton = new FieldButton();
newButton.Location = new Point(x * offset, (y + 1) * offset);
newButton.Size = new Size(offset, offset);
if (random.Next(0, 100) <= bombPercent)
{
newButton.isBomb = true;
}
Controls.Add(newButton);
newButton.MouseUp += new MouseEventHandler(GGorWin);
field[x, y] = newButton;
}
}
}
public void GGorWin(object sender, MouseEventArgs e)
{
FieldButton clickedButton = (FieldButton)sender;
if (e.Button == MouseButtons.Left)
{
if (clickedButton.isBomb)
{
GG();
}
else
{
LetsGO(clickedButton);
}
}
if (e.Button == MouseButtons.Right)
{
clickedButton.Text = "Ф";
}
}
public void GG()
{
foreach (FieldButton button in field)
{
if (button.isBomb)
{
button.Text = "*";
}
}
MessageBox.Show("Вы проиграли");
Application.Restart();
}
void LetsGO(FieldButton clickedButton)
{
int bombsAround = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (field[x, y] == clickedButton)
{
bombsAround = BombsAround(x, y);
}
}
}
if (bombsAround == 0)
{
}
else
{
clickedButton.Text = "" + bombsAround;
}
clickedButton.Enabled = false;
}
int BombsAround(int x1, int y1)
{
int bombsAround = 0;
for (int x = x1 - 1; x <= x1 + 1; x++)
{
for (int y = y1 - 1; y <= y1 + 1; y++)
{
if (x >= 0 && x < width && y >= 0 && y < height)
{
if (field[x, y].isBomb == true)
{
bombsAround++;
}
}
}
}
return bombsAround;
}
private void новаяИграToolStripMenuItem_Click(object sender, EventArgs e)
{
field = new FieldButton[width, height];
Generater();
}
}
public class FieldButton : Button
{
public bool isBomb ;
}
Ответы (2 шт):
На первый взгляд, хотелось бы написать простое исправление кода, типа такого:
public void Generater(int bMax) // здесь bMax - кол-во бомб, котрые надо сгенерировать
{
int bCounter=0;
Random random = new Random();
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
FieldButton newButton = new FieldButton();
newButton.Location = new Point(x * offset, (y + 1) * offset);
newButton.Size = new Size(offset, offset);
if (random.Next(0, 100) <= bombPercent)
{
newButton.isBomb = true;
bCounter++; // здесь мы увеличили "счетчик бомб"
}
Controls.Add(newButton);
newButton.MouseUp += new MouseEventHandler(GGorWin);
field[x, y] = newButton;
// а теперь можно проверить, не достигли ли мы необходимого кол-ва
if (bCounter==bMax)
break;
}
// эта проверка нужна по той причине, что break "выкидывает" нас наружу только одного цикла
if (bCounter==bMax)
break;
}
Но самом деле у этого кода есть две проблемы: 1) он может не сгенерировать нужного кол-ва бомб. Оба цикла отработают, а bMax не будет достигнут. 2) при генерации нужного кол-ва бомб код заканчивает работу, не сгенериовав всё игровое поле!
Чтобы это исправить, хорошо бы поменять сам метод генерации бомб: сделать не цикл по поординатам (и второй вложенный цикл по другим координатам), а цикл по кол-ву бомб, который генерирует их со случайными координатами.
Но у Вас в коде "совмещено" два процесса: генерация "кнопок" (которые нужно сгенерировать в любом случае, независимо от того, с бомбой кнопка или нет) и установка признака "эта кнопка - с бомбой"!
Поэтому я бы разделил функцию Generater() на две - генерации поля и генерации бомб.
я попробовал написать код "на коленке", и, заранее извиняюсь, еслив нём есть ошибки:
private void новаяИграToolStripMenuItem_Click(object sender, EventArgs e)
{
field = new FieldButton[width, height];
GenerateFields();
GenerateBombs( bombPercent );
}
public void GenerateFields()
{
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
FieldButton newButton = new FieldButton();
newButton.Location = new Point(x * offset, (y + 1) * offset);
newButton.Size = new Size(offset, offset);
Controls.Add(newButton);
newButton.MouseUp += new MouseEventHandler(GGorWin);
field[x, y] = newButton;
}
}
}
public void GenerateBombs(int bombPercent)
{
// нам передали процент полей, который должны быть заминированы.
// Сделаем из него абсолютное кол-во бомб:
int bMax = width * height * bombPercent / 100;
Random random = new Random();
int bCounter=0;
while ( bombPercent< bMax){
// теперь гененрируем случайные координаты бомбы
int randx = random.Next( 0, width );
int randy = random.Next( 0, height );
if ( !field[randx, randy].isBomb )
{
field[randx, randy].isBomb = true;
bCounter++; // увеличиваем кол-во сгенерированных бомб
// проверка условия нужна для реализации принципа "две бомбы в одну воронку не падают":
// если поле уже "заминировано" - то его повторное минирование не увеличит счетчик
}
}
}
Надеюсь, основную идею он доносит.
Где могут быть ошибки: например, я мог перепутать width и height
Еще по поводу кода: слелующим этапом может стать "причёсывание кода": например, не увлекайтесь глобальными переменными. Пробуйте передавать в функцию только то, что необходимо.
Ну, а потом можно взяться за разделенеи уровней "отображения" и "работы с данными" (разделение на View и Controller).
Без помощи пользователя S.H - не получилось бы, огромное Спасибо!
public void GenerateBombs(int bombs)
{
int row, col;//индексы клетки
int n = 0;//количество поставленных мин
Random rnd = new Random();
do
{
row = rnd.Next(0,width);
col = rnd.Next(0,height);
if (!field[row, col].isBomb)
{
field[row, col].isBomb = true;
n++;
}
}
while (n != bombs);//проверка как раз таки
}
private void новаяИграToolStripMenuItem_Click(object sender, EventArgs e)
{
field = new FieldButton[width, height];
GenerateFields();
GenerateBombs(bombs);
}
public void GenerateFields()
{
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
FieldButton newButton = new FieldButton();
newButton.Location = new Point(x * offset, (y + 1) * offset);
newButton.Size = new Size(offset, offset);
Controls.Add(newButton);
newButton.MouseUp += new MouseEventHandler(GGorWin);
field[x, y] = newButton;
}
}
}