C# Form does not refresh - c#

I have a problem with my program (Minesweeper game)
this is my Board class (mines board)
class Board
{
private Cell[,] MinesBoard;
private int maxrow, maxcol;
private int numOfMines;
public bool isLose;
private List<Point> MinesLocation;
private Random rnd;
private List<Point> randomPoint;
public delegate void OnClickEventHandler(object sender, CellClickEventArgs e);
public event OnClickEventHandler OnCellClick;
public int NumOfMines
{
get { return numOfMines; }
}
public int Column
{
get { return maxcol; }
}
public int Row
{
get { return maxrow; }
}
private void GetRandomPoints(int maxr, int maxc)
{
Point t = new Point();
t.X = rnd.Next(0, maxr);
t.Y = rnd.Next(0, maxc);
if (!randomPoint.Contains(t))
randomPoint.Add(t);
}
public Board(int _row, int _col, int _mines)
{
isLose = false;
maxrow = _row;
maxcol = _col;
numOfMines = _mines;
rnd = new Random(DateTime.Now.Ticks.GetHashCode());
randomPoint = new List<Point>();
MinesBoard = new Cell[_row, _col];
MinesLocation = new List<Point>();
for (int i = 0; i < maxrow; ++i)
for (int j = 0; j < maxcol; ++j)
{
MinesBoard[i, j] = new Cell();
//MinesBoard[i, j].button = new Button();
//MinesBoard[i, j].IsMine = false;
//MinesBoard[i, j].IsOpen = false;
//MinesBoard[i, j].MineAround = 0;
}
for (int i = 0; i < numOfMines; ++i)
GetRandomPoints(maxrow, maxcol);
foreach (Point p in randomPoint)
{
if (MinesBoard[p.X, p.Y].IsMine == false)
{
MinesBoard[p.X, p.Y].IsMine = true;
MinesLocation.Add(p);
}
}
}
public void DrawBoard(Form frm)
{
int id = 0;
for (int i = 0; i < maxrow; ++i)
for (int j = 0; j < maxcol; ++j)
{
frm.Controls.Remove(MinesBoard[i, j].button);
MinesBoard[i, j].button.Name = "btnCell" + id.ToString();
++id;
MinesBoard[i, j].button.Size = new Size(25, 25);
MinesBoard[i, j].button.Location = new Point(j * 25, 60 + i * 25);
//MinesBoard[i, j].button.FlatStyle = FlatStyle.Flat;
//CellClickEventArgs args = new CellClickEventArgs(new Point(i, j));
MinesBoard[i, j].button.Click += new System.EventHandler(CellClick);
MinesBoard[i, j].button.MouseDown += new MouseEventHandler(CellMouseDown);
//=========
MinesBoard[i, j].button.Tag = new Point(i, j);
//MinesBoard[i, j].button.Tag = MinesBoard[i, j].button;
//=========
if (MinesBoard[i, j].IsMine)
MinesBoard[i, j].button.Text = "z";
else
MinesBoard[i, j].button.Text = "";
frm.Controls.Add(MinesBoard[i, j].button);
}
}
when I change number of mines, it doesn't change correctly. But the rows and columns is OK
this is my Form1 class
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
private Board board;
private void frmMain_Load(object sender, EventArgs e)
{
board = new Board(8, 10, 15);
board.DrawBoard(this);
}
private void optionToolStripMenuItem_Click(object sender, EventArgs e)
{
frmOption option = new frmOption(board.Row, board.Column, board.NumOfMines);
if (option.ShowDialog() == DialogResult.OK)
{
board = new Board(option.Rows, option.Columns, option.Mines);
this.Size = new Size(board.Column * 25 + 5, board.Row * 25 + 88);
board.DrawBoard(this);
}
}
here is the picture:
8x10 15 mines
5x5 5 mines
when I set number of mines is 5, but it shows only 3 (1 z letter is 1 mine)
could you give me any solutions, thank you very much.!!!

When you click on the tool strip menu item, you're creating a new board, which will cause the old buttons to stay on the form (resize the form to see all of the old buttons). You will notice, that the mines are placed on the same buttons as before. This is caused by the old buttons staying in front of the new ones. Therefore, you need to clear the old board before creating a new one. Example:
public void Clear(Form frm)
{
for (int i = 0; i < maxrow; ++i)
{
for (int j = 0; j < maxcol; ++j)
{
frm.Controls.Remove(MinesBoard[i, j].button);
}
}
}
Call this directly before creating the new board:
private void optionToolStripMenuItem_Click(object sender, EventArgs e)
{
if (board != null)
{
board.Clear(this);
}
board = new Board(5, 5, 5);
this.Size = new Size(board.Column * 25 + 5, board.Row * 25 + 88);
board.DrawBoard(this);
}
Be sure to fix the bug mentioned by #AndersJH as well :)

I hope I don't misunderstand the question here. But the method GetRandomPoints does not guarantee to add a point to the list of random points. If the point exists, it will not be added.
I would suggest something like this:
while(randomPoint.Count < numOfMines)
{ GetRandomPoints(maxrow, maxcol); }

Related

How to create an array with pictureboxes in Windows Forms (C#)

I am fairly new to C# and I can't figure out how to create an array with visible picture boxes inside the cs file. In this example I want to create 200 picture boxes 10x20 to create an grid for a tetris game. This is my code, I can't get any of the pictures to show but the code runs just fine.
Image[] blockImage = {
TetrisSlutprojekt.Properties.Resources.TileEmpty,
TetrisSlutprojekt.Properties.Resources.TileCyan,
TetrisSlutprojekt.Properties.Resources.TileBlue,
TetrisSlutprojekt.Properties.Resources.TileRed,
TetrisSlutprojekt.Properties.Resources.TileGreen,
TetrisSlutprojekt.Properties.Resources.TileOrange,
TetrisSlutprojekt.Properties.Resources.TilePurple,
TetrisSlutprojekt.Properties.Resources.TileYellow
};
PictureBox[] blockBoxes = new PictureBox[200];
private void CreateBoxes()
{
for (int i = 0; i < blockBoxes.Length; i++)
{
blockBoxes[i] = new System.Windows.Forms.PictureBox();
blockBoxes[i].Name = "pbBox" + i;
blockBoxes[i].Size = new Size(30, 30);
blockBoxes[i].Visible = true;
}
}
private void PlaceBoxes()
{
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < columns; x++)
{
blockBoxes[y].Top = y * blockWidth;
blockBoxes[x].Left = x * blockWidth;
}
}
}
private void FillBoxes()
{
for (int i = 0; i < blockBoxes.Length; i++)
{
blockBoxes[i].Image = blockImage[4];
}
}
Add them to the Form:
private void CreateBoxes()
{
for (int i = 0; i < blockBoxes.Length; i++)
{
blockBoxes[i] = new System.Windows.Forms.PictureBox();
blockBoxes[i].Name = "pbBox" + i;
blockBoxes[i].Size = new Size(30, 30);
blockBoxes[i].Visible = true;
this.Controls.Add(blockBoxes[i]); // <--- HERE
}
}

Trying to match Color of button and its picture

Basically, I need to match to match the Picture and the color, so that result will be that whenever I press the burger it becomes blue, and when I click something else it becomes green.
NOW it just randomly goes green or blue whenever I click the button with no reliance on the clicked picture.
Again, I need to match to match the picture and the color, so that result will be that whenever I press the burger it becomes blue, and when I click something else it becomes green.
I will now add screenshots of the form when it starts and what happens, and the entire code.
Thanks in advance.
Start : https://prnt.sc/jnad9j
When Clicked : https://prnt.sc/jnadie
CODE:
for (int i = 0; i < arr.GetLength(0); i++)
{
cx = x;
for (int j = 0; j<arr.GetLength(1); j++)
{
value = rnd.Next(0, 2);
t = new Button();
t.Tag = new Place(i, j);
if (value == 0)
rndmimg = rnd.Next(1, 2);
else rndmimg = rnd.Next(2, 6);
t.BackColor = Color.Red;
t.BackgroundImageLayout = ImageLayout.Stretch;
t.BackgroundImage = Image.FromFile("..\\..\\Pictures\\"+rndmimg+".png");
t.Bounds = new Rectangle(cx, y, w, h);
t.Click += new System.EventHandler(this.qqq_Click);
this.Controls.Add(t);
arr [i, j] = t;
cx += w;
}
y += h;
}
public Form1() => InitializeComponent();
private void Form1_Load(object sender, EventArgs e) => rnd = new Random();
private void qqq_Click(object sender, EventArgs e)
{
int px;
int py;
Place pl = (Place)(((Button)sender).Tag);
px = pl.GetR();
py = pl.C;
rndmcus = rnd.Next(0, 2); // Rndmcus determines color when button is clicked
if (rndmcus == 0)
{
mishvalue = 0;
arr[px, py].BackColor = Color.Green;
arr[px, py].Enabled = false;
}
if (rndmcus == 1)
{
mishvalue = 1;
arr[px, py].BackColor = Color.Blue;
arr[px, py].Enabled = false;
}
((Button)sender).Text = " ";
scanner();
}
public void scanner()
{
int counter = 0;
for (int i = 0; i < arr.GetLength(0); i++)
for (int j = 0; j < arr.GetLength(0); j++)
if (arr[i, j].Text == " ")
counter++;
if (counter == boardsize * boardsize)
this.Close();
}
class Place
{
private int r;
private int c;
public Place(int r, int c)
{
this.r = r;
this.c = c;
}
public int GetR() => r;
public int C => c;
public void SetR(int r) => this.r = r;
public void SetC(int c) => this.c = c;
}
Assign all your button an id then access it in the event
for (int j = 0; j < arr.GetLength(1); j++)
{
value = rnd.Next(0, 2);
t = new Button();
t.ID = j.ToString();
Button button = (Button)sender;
string buttonId = button.ID;
Associate color with the id in like a Dictionary.

Design an algorithm for guessing a card number

I am making a card guessing game.there are 100 cards place in 10rows and 10 columns each card with a number and user have to find a number he is thinking of. i want to devise an algorithm to determine whether a given number is written on one of the cards by turning up less than 20 cards.I hav created the buttons dynamically, now im having hard time making a logic to search through them.This is my code.
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
int rememberlast = 0, move = 0;
object savelastobject;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
int sizee = 50, where = 0;
this.Height = 0;
this.Width = 0;
var generatedNum = new List<int>();
var random = new Random();
while (generatedNum.Count < 100)
{
var tempo = random.Next(0, 100);
if (generatedNum.Contains(tempo)) continue;
generatedNum.Add(tempo);
}
char[] text2 = text.ToCharArray();
for (int x = 0; x < 10; x++)
{
for (int y = 0; y < 10; y++)
{
Button ta = new Button();
ta.Name = x.ToString()+y.ToString();
ta.Width = sizee;
ta.Height = sizee;
ta.Tag = generatedNum[where];
where++;
ta.BackColor = Color.Red;
ta.Location = new Point(70 * y, 70 * x);
Controls.Add(ta);
ta.Click += new System.EventHandler(this.button_Click);
this.Width += 90 * x / 13;
this.Height += 90 * x / 8;
}
}
}
private void button_Click(object sender, EventArgs e)
{
Control me = (Control)sender;
rememberlast = int.Parse(me.Tag.ToString());
savelastobject = me;
me.Text = me.Tag.ToString();
me.Enabled = true;
me.BackColor = Color.Gray;
move++;
label2.Text = move.ToString();
me.Enabled = true;
me.Text = me.Tag.ToString();
me.BackColor = Color.Gray;
me.Refresh();
Thread.Sleep(1000);
if (move == 20)
{
MessageBox.Show("Total Moves Consumed");
Application.Restart();
}
if (me.Tag.ToString() == textBox1.Text)
{
//Control him = (Control)savelastobject;
//him.BackColor = Color.LightBlue;
me.BackColor = Color.LightBlue;
MessageBox.Show("You Win");
Application.Restart();
}
}
}
}

C# - How can I create 2 separate button arrays with different controls without them causing problems with the other?

I am currently trying to develop a form of battleships on c# windows form.
Here is the code I am trying to use.. the trouble I have been having is how to create a second set of buttons (another 10x10) behind the other, with two sets of controls so I can switch between the two.
I have everything like AI and automated setups, I just need to have 2 button controls. I hope someone can help me out with this! Many thanks!
private List<List<Button>> grid = new List<List<Button>>();
public UserForm()
{
InitializeComponent();
byte numRows = 10;
byte numCols = 10;
for (byte i = 0; i < numRows; i++)
{
grid.Add(ButtonRowCreator(numCols, 25, (i+1) * 50));
}
}
public List<Button> ButtonRowCreator(byte numOfBtnsNeeded, int x, int y)
{
List<Button> btns = new List<Button>();
for (int i = 0; i < numOfBtnsNeeded; i++)
{
Button btn = new Button();
btn.Size = new Size(50, 50);
btn.Location = new Point(x + (i * btn.Width), y);
btns.Add(btn);
btn.Font = new Font("Georiga", 10);
this.Controls.Add(btn);
btn.Click += new EventHandler(btn_Click);
}
return btns;
}
void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
int curRow = -1, curCol = -1;
for(int i = 0; i < grid.Count; i++)
{
int index = grid[i].IndexOf(btn);
if (index != -1)
{
curRow = i;
curCol = index;
Console.WriteLine("curRow = " + curRow.ToString() + ", curCol = " + curCol.ToString());
}
}
// ... now you can use "curRow", "curCol" and "grid" to do something ...
foreach (List<Button> row in grid)
{
foreach (Button col in row)
{
col.ForeColor = Color.Gray;
}
}
if (board[curRow, curCol] == 1)
{
if (btn.Text == "Hit")
{
}
else
{
btn.Text = "Hit";
btn.BackColor = Color.Red;
hit++;
}
if (hit == 17)
{
MessageBox.Show("Congratulations, You Sunk Their Battleships!");
MessageBox.Show("Thanks For Playing!");
MessageBox.Show("Goodbye!");
}
}
else
{
btn.Text = "Miss!";
btn.BackColor = Color.Blue;
}
I think this is what you're after?
It looks like a lot of your code is used to figure out what button is clicked on. This information can be stored on the button object itself in the Tag property and greatly simplifies the code.
private Button[,] _grid1;
private Button[,] _grid2;
public UserForm()
{
InitializeComponent();
_grid1 = new Button[10, 10];
_grid2 = new Button[10, 10];
CreateGrid(_grid1, 10, 10, 25, 0, 20, true);
CreateGrid(_grid2, 10, 10, 25, 250, 20, false);
}
public void CreateGrid(Button[,] grid, int numOfRows, int numOfCols, int offsetX, int offsetY, int buttonSize, bool enabled)
{
for (byte i = 0; i < numOfRows; i++)
{
for (byte j = 0; j < numOfCols; j++)
{
grid[i,j] = ButtonCreator(i, j, offsetX, offsetY, buttonSize, enabled);
}
}
}
public Button ButtonCreator(int row, int col, int x, int y, int buttonSize, bool enabled)
{
Button btn = new Button();
btn.Size = new Size(buttonSize, buttonSize);
btn.Location = new Point(x + (col * buttonSize), y + (row * buttonSize));
btn.Font = new Font("Georiga", 10);
this.Controls.Add(btn);
btn.Click += new EventHandler(btn_Click);
btn.Tag = row + "," + col;
btn.Enabled = enabled;
return btn;
}
void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
string[] coord = btn.Tag.ToString().Split(',');
int curRow = Convert.ToInt32(coord[0]);
int curCol = Convert.ToInt32(coord[1]);
Console.WriteLine(curRow = " + curRow + ", curCol = " + curCol);
// ... now you can use "curRow", "curCol" to do something ...
_grid1[curRow, curCol].BackColor = Color.Red;
}

How can I invoke PaintEventArgs for results returned by EventArgs from Web Service

I have this code:
public partial class Form1 : Form
{
private int size;
public Form1()
{
InitializeComponent();
size = 10;
}
private void runAutomat_Click(object sender, EventArgs e)
{
var myMatrix = new int[size][];
for (int i = 0; i < size; i++)
{
myMatrix[i] = new int[size];
for (int j = 0; j < size; j++)
myMatrix[i][j] = 0;
}
var cw = new MyWebService();
var result = cw.FillMatrix(myMatrix, size);
}
}
Next I want to draw grid for result, but I don't have idea how to send it to method with PaintEventArgs. For example something like this:
private void PB_Paint(object sender, PaintEventArgs e)
{
int cellSize = 2;
for (int x = 0; x < size; ++x)
for (int y = 0; y < size; ++y)
{
if (result [y, x].state == 1)
e.Graphics.FillRectangle(new System.Drawing.SolidBrush(Color.Cyan), new Rectangle(y * cellSize, x * cellSize, cellSize, cellSize));
else if (result [y, x].state == 2)
e.Graphics.FillRectangle(new System.Drawing.SolidBrush(Color.Yellow), new Rectangle(y * cellSize, x * cellSize, cellSize, cellSize));
}
}
I know it is incorrect and I need better solution.
You could store the value of result as a form level variable and then call this.Refresh() to make the form redraw.
public partial class Form1 : Form
{
//Guessing what the data type is:
private int[,] _result;
private void runAutomat_Click(object sender, EventArgs e)
{
//snip
_result = cw.FillMatrix(myMatrix, size);
this.Refresh();
}
}
Ok, I think I found temporary solution.
using WFConsume.localhost;
public partial class Form1 : Form
{
private int size;
private localhost.Cell [][]cells;
public Form1()
{
InitializeComponent();
size = 10;
}
}
private void runAutomat_Click(object sender, EventArgs e)
{
var myMatrix = new int[size][];
for (int i = 0; i < size; i++)
{
myMatrix[i] = new int[size];
for (int j = 0; j < size; j++)
myMatrix[i][j] = 0;
}
MyWebService cw = new MyWebService();
cells = cw.FillMatrix(myMatrix, size);
}
It's working in form level. Thank you DavidG for a tips!

Categories