A function in my program seems like it should work but occasionally gives the wrong output - c#

I wrote a function that checks for a given cell in a grid if it is a legal move following the rules of the board-game called Reversi otherwise known as Othello. The rules are that a circle can only be placed on the grid whenever the newly placed circle and a previous placed circle bounds one of the opponents circles. The majority of the time the function gives the right output (i.e. true when it is a legal move and false when it is a legal move), but some moves that are legal by the previously stated rules are not deemed as a legal move by the function.
I've tried to use the console to check at every step at which cell the function is currently looking and what the value of the cell is to determine what goes wrong. This has only led me to being even more confused.
The following code is the doomed-function:
bool legalMove(int row, int col)
{
// Check if the cell is occupied
if (board[row,col] != 0)
return false;
// Check if there's an opponents circle somewhere around it
for (int i = -1; i<=1; i++)
for (int j = -1; j<=1; j++)
{
if (i == 0 && j == 0)
continue;
int currentRow = row + i;
int currentCol = col + j;
if (currentRow >= 0 && currentRow < board.GetLength(0) && currentCol >= 0 && currentCol < board.GetLength(1) && board[currentRow,currentCol] == -turn)
{
// Now we know that there's an opponents circle somewhere around this space, we now check if it can be captured
while(true)
{
currentRow += i;
currentCol += j;
Console.WriteLine($"currentRow: {currentRow}, currentCol: {currentCol}, value: {board[currentRow,currentCol]}");
if (currentRow < 0 || currentRow >= board.GetLength(0) || currentCol < 0 || currentCol >= board.GetLength(1) || board[currentRow, currentCol] == 0)
return false; // Outside of the board or an empty space
else if (board[currentRow,currentCol] == turn)
return true; // No empty spaces between our cell and another cell of ours
}
}
}
return false; // No cell found around ours
}
What am I missing here?
Thanks in advance!
EDIT:
The entire program is the following (hope it can help):
/* TO-DO
* Make function out of no legal move and tidy up
* Calculate amount of circles of player to determine the winner
* Make victory label better
!!!Tidy up flipCircles method and fix legalMove method
Create a slider and make it change the gridSize
Make GUI change empty space when board gets smaller or bigger
Tidy up the 2x calling to check what the score is
*/
// Library imports
using System;
using System.Drawing;
using System.Security.Policy;
using System.Windows.Forms;
// Game class
class Game : Form
{
// Declare variables
private Board board;
private Button newGame, help;
private Font font;
private Label countRed, countBlue, gameState;
private TrackBar sizeBoard;
public int gridSize = 6;
public Game()
{
// Set the form properties
ClientSize = new Size(520, 670); Text = "Reversi";
// Creating the GUI and adding it to the form
newGame = new Button(); Controls.Add(newGame);
help = new Button(); Controls.Add(help);
font = new Font("Arial", 14);
countBlue = new Label(); Controls.Add(countBlue); countBlue.Font = font;
countRed = new Label(); Controls.Add(countRed); countRed.Font = font;
gameState = new Label(); Controls.Add(gameState); gameState.Font = font;
board = new Board(gridSize); Controls.Add(board);
// Settings of the GUI
newGame.Size = new Size(100, 30); newGame.Location = new Point(150, 10); newGame.Text = "New Game"; newGame.BackColor = Color.LightSlateGray;
help.Size = new Size(100, 30); help.Location = new Point(270, 10); help.Text = "Help"; help.BackColor = Color.LightSlateGray;
countBlue.Size = new Size(110, 30); countBlue.Location = new Point(150, 50); countBlue.Text = $"{board.countBlue} stones"; countBlue.ForeColor = Color.CornflowerBlue;
countRed.Size = new Size(110, 30); countRed.Location = new Point(150, 90); countRed.Text = $"{board.countRed} stones"; countRed.ForeColor = Color.Firebrick;
gameState.Size = new Size(150, 30); gameState.Location = new Point(270, 90); gameState.Text = $"{board.playersTurn}";
// Events //
// Label events
newGame.Click += reset;
help.Click += calculateHelp;
// Board events
board.MouseClick += clicked;
//Paint event
Paint += paint;
}
// Event-handlers //
// Label event-handlers
private void reset(object e, EventArgs ea)
{
board.Reset();
countBlue.Text = $"{board.countBlue} stones";
countRed.Text = $"{board.countRed} stones";
gameState.Text = $"{board.playersTurn}";
}
private void calculateHelp(object e, EventArgs ea)
{
board.SetHelp();
}
// Board event-handlers
private void clicked(object e, MouseEventArgs mea)
{
board.Clicked(mea.Location);
countBlue.Text = $"{board.countBlue} stones";
countRed.Text = $"{board.countRed} stones";
gameState.Text = $"{board.playersTurn}";
// Now check if there's a legalMove if not
//if (timesNoLegalMove > 1)
gameState.Text = $"{board.playersTurn}";
}
// Paint event-handler
private void paint(object e, PaintEventArgs pea)
{
Graphics gr = pea.Graphics;
gr.FillEllipse(Brushes.CornflowerBlue, 100, 45, 31, 31);
gr.FillEllipse(Brushes.Firebrick, 100, 85, 31, 31);
}
}
// Board class
class Board : Label
{
// Declare all global variables used in this class
private int[,] board;
private int size;
private int turn = 1; // 1 is blue, -1 is red
private bool legalMoveExists = true;
public int timesNoLegalMove = 0;
private bool help = false;
// Create the board and set settings + events
public Board(int gridSize)
{
size = gridSize;
Size = new Size(size * 50, size * 50);
Location = new Point(10 + (25 * (10 - size)), 120 + (25 * (10 - size)));
BackColor = Color.White;
board = new int[size, size];
startingState();
Paint += Draw;
}
// Sets the values of the center 4 squares to that of the starting circles
private void startingState()
{
board[(size / 2)-1, (size / 2)-1] = 1;
board[(size / 2), (size / 2)] = 1;
board[(size / 2), (size / 2) - 1] = -1;
board[(size / 2) - 1, (size / 2)] = -1;
}
// Resets the board when New Game is clicked
public void Reset()
{
for (int row = 0; row < board.GetLength(0); row++)
for (int col = 0; col < board.GetLength(1); col++)
board[row, col] = 0;
startingState();
turn = 1;
Invalidate();
}
public void SetHelp()
{
if (help)
help = false;
else
help = true;
Invalidate();
}
public string playersTurn
{
get
{
if (turn == 1)
return "It's Blue's turn";
if (turn == -1)
return "It's Red's turn";
else
{
if (countBlue > countRed)
return "Blue has won the game!";
if (countRed > countBlue)
return "Red has won the game!";
else
return "It's a draw!";
}
}
}
public int countRed
{
get
{
return board.Cast<int>().Count(n => n == -1);
}
}
public int countBlue
{
get
{
return board.Cast<int>().Count(n => n == 1);
}
}
bool legalMove(int row, int col)
{
// Check if the cell is occupied
if (board[row,col] != 0)
return false;
// Check if there's an opponents circle somewhere around it
for (int i = -1; i<=1; i++)
for (int j = -1; j<=1; j++)
{
if (i == 0 && j == 0)
continue;
int currentRow = row + i;
int currentCol = col + j;
if (currentRow >= 0 && currentRow < board.GetLength(0) && currentCol >= 0 && currentCol < board.GetLength(1) && board[currentRow,currentCol] == -turn)
{
// Now we know that there's an opponents circle somewhere around this space, we now check if it can be captured
while(true)
{
currentRow += i;
currentCol += j;
if (currentRow < 0 || currentRow >= board.GetLength(0) || currentCol < 0 || currentCol >= board.GetLength(1) || board[currentRow, currentCol] == 0)
return false; // Outside of the board or an empty space
else if (board[currentRow,currentCol] == turn)
return true; // No empty spaces between our cell and another cell of ours
}
}
}
return false; // No cell found around ours
}
private void flipCircles(int row, int col)
{
// Check all eight directions from the current position
for (int r = row - 1; r <= row + 1; r++)
{
for (int c = col - 1; c <= col + 1; c++)
{
// Skip the current position
if (r == row && c == col)
continue;
int rr = r;
int cc = c;
// Check if the next position in this direction is a valid position on the board
// and if it is occupied by the opponent's piece
if (rr >= 0 && rr < board.GetLength(0) && cc >= 0 && cc < board.GetLength(1) && board[rr, cc] == -turn)
{
// Keep moving in this direction until we find the current player's piece or an empty cell
while (true)
{
rr += r - row;
cc += c - col;
// If we have reached an invalid position or an empty cell, break out of the loop
if (rr < 0 || rr >= board.GetLength(0) || cc < 0 || cc >= board.GetLength(1) || board[rr, cc] == 0)
break;
// If we have found the current player's piece, flip all the pieces between the current position and the player's piece
if (board[rr, cc] == turn)
{
while (rr != r || cc != c)
{
rr -= r - row;
cc -= c - col;
board[rr, cc] = turn;
}
break;
}
}
}
}
}
}
// Sets the value of a clicked cell to either 1 (Blue), or -1 (Red)
public void Clicked(Point mea)
{
int rowClicked = mea.X / 50;
int colClicked = mea.Y /50;
if (legalMove(rowClicked, colClicked))
{
board[rowClicked, colClicked] = turn;
flipCircles(rowClicked, colClicked);
help = false;
turn = -turn;
legalMoveExists = false;
Invalidate();
}
}
// Draws the entire board and all circles
void Draw(object e, PaintEventArgs pea)
{
Graphics gr = pea.Graphics;
legalMoveExists = false;
for (int row = 0; row < board.GetLength(0); row++)
for (int col = 0; col < board.GetLength(1); col++)
{
// Draw the background tiles
if (row % 2 == 0 && col % 2 == 0 || row % 2 != 0 && col % 2 != 0)
gr.FillRectangle(Brushes.DarkGray, 50 * row, 50 * col, 50, 50);
// Draw circles
if (board[row, col] == 1) // Blue circles
gr.FillEllipse(Brushes.CornflowerBlue, 50 * row - 1, 50 * col - 1, 51, 51);
else if (board[row, col] == -1) // Red circles
gr.FillEllipse(Brushes.Firebrick, 50 * row - 1, 50 * col - 1, 51, 51);
// Check for legal moves and draw help circles if the help button has been pressed
else if (legalMove(row, col))
{
legalMoveExists = true;
timesNoLegalMove = 0;
if (help) // Help circles
gr.DrawEllipse(Pens.Black, 50 * row + 9, 50 * col + 9, 31, 31);
}
}
// Make this a function
if (!legalMoveExists)
{
turn = -turn;
timesNoLegalMove++;
Invalidate();
if (timesNoLegalMove > 1)
turn = 0;
}
}
}
// Main run
class Program
{
static void Main()
{
Application.Run(new Game());
}
}

Your question states that the function you wrote to scan the surrounding cells is failing sporadically and that it's difficult to diagnose. It was easy to reproduce the failures by running your code, but I wasn't able to see an obvious way to effectively debug it.
It "might" be more effective to improve the algorithm where it's more methodical in how it inspects the surrounding cells in the first place, which would also be easier to debug if necessary. One solid way to do this would be to use custom Iterators where you could use a standard foreach pattern to inspect virtual "lines" radiating in the eight directions. At each 'yield' you can check to see whether a determination can be made in terms of either a "legal move" or a "capture".
Here's a proof-of-concept grid that is intended to demonstrate how the iterators work. It doesn't evaluate the cells in terms of game play in any way but you can see how it would lend itself to doing that. The idea here is to click any cell and observe the markup of U-R-D-L. It may also help to see it working so you can clone this sample and set breakpoints.
Left, Right, Up, Down iterator examples are shown - diagonals would follow the same pattern. The mouse down control passes the starting cell coordinate position as a Point:
public IEnumerable<Point> CellsUp(Point point)
{
while (true)
{
point = new Point(point.X, point.Y - 1);
if (point.Y < 0) break;
yield return point;
}
}
public IEnumerable<Point> CellsRight(Point point, int max)
{
while (true)
{
point = new Point(point.X + 1, point.Y);
if (point.X == max) break;
yield return point;
}
}
public IEnumerable<Point> CellsDown(Point point, int max)
{
while (true)
{
yield return point;
point = new Point(point.X, point.Y + 1);
if (point.Y == max) break;
}
}
public IEnumerable<Point> CellsLeft(Point point)
{
while (true)
{
yield return point;
point = new Point(point.X - 1, point.Y);
if (point.X < 0) break;
}
}
The code lays the groundwork for a methodical scan outward from any given point.
private void legalMoveIterationStub(object? sender, EventArgs e)
{
clear();
if(sender is Control control)
{
control.BackColor = Color.Blue;
control.Refresh();
var pos = board.GetCellPosition(control);
var pt = new Point(pos.Column, pos.Row);
Control ctrl;
foreach (var point in CellsUp(pt))
{
ctrl = board.GetControlFromPosition(point.X, point.Y);
ctrl.Text = "U";
ctrl.Refresh();
Thread.Sleep(DEMO_DELAY_MS);
// This is where the cell inspects e.g. for "empty square"
// or color. Chances are, some condition will be met
// and you will break from here rather than iterate
// all the way to the edge of the board each time.
}
foreach (var point in CellsRight(pt, board.ColumnCount))
{
ctrl = board.GetControlFromPosition(point.X, point.Y);
ctrl.Text = "R";
ctrl.Refresh();
Thread.Sleep(DEMO_DELAY_MS);
}
foreach (var point in CellsDown(pt, board.ColumnCount))
{
ctrl = board.GetControlFromPosition(point.X, point.Y);
ctrl.Text = "D";
ctrl.Refresh();
Thread.Sleep(DEMO_DELAY_MS);
}
foreach (var point in CellsLeft(pt))
{
ctrl = board.GetControlFromPosition(point.X, point.Y);
ctrl.Text = "L";
ctrl.Refresh();
Thread.Sleep(DEMO_DELAY_MS);
}
}
}
The demo board has been mocked like this for testing purposes:
public partial class Game : Form
{
public Game()
{
InitializeComponent();
for (int col = 0; col < board.ColumnCount; col++)
{
for (int row = 0; row < board.RowCount; row++)
{
var tile = new Label
{
BorderStyle = BorderStyle.FixedSingle,
Anchor = (AnchorStyles)0xF,
Margin = new Padding(1),
TextAlign = ContentAlignment.MiddleCenter
};
board.Controls.Add(tile, col, row);
tile.MouseDown += legalMove;
}
}
}
void clear()
{
foreach (Control control in board.Controls)
{
control.Text = string.Empty;
control.BackColor = SystemColors.Control;
}
board.Refresh();
}
.
.
.
}

Related

How to debug a recursive function in unity C#

Im trying to make a maze generator using recursion. Its not working how its supposed to work, and Im trying to figure out where the error is. So I want to step through the recursion 1 iteration at the time. How do I do this?
private void DevideRecursive(int pMinX, int pMaxX, int pMinY, int pMaxY)
{
int randomX = Random.Range(pMinX +1, pMaxX);
int randomY = Random.Range(pMinY +1, pMaxY);
int randomWall = Random.Range(0, 4);
List<GameObject> WalllistX1 = new List<GameObject>();
List<GameObject> WalllistX2 = new List<GameObject>();
List<GameObject> WalllistY1 = new List<GameObject>();
List<GameObject> WalllistY2 = new List<GameObject>();
List<List<GameObject>> MainWallList = new List<List<GameObject>>();
MainWallList.Add(WalllistX1);
MainWallList.Add(WalllistX2);
MainWallList.Add(WalllistY1);
MainWallList.Add(WalllistY2);
//// add a wall on a random x coordinate
for (int x = pMinX; x < pMaxX; x++)
{
GameObject wall = Instantiate(WallHor);
wall.transform.position = new Vector2(tilesize * x + tilesize / 2, tilesize * randomY);
if (x < randomX)
{
WalllistX1.Add(wall);
}
else
{
WalllistX2.Add(wall);
}
}
//// add a wall on a random y coordinate
for (int y = pMinY; y < pMaxY ; y++)
{
GameObject wall = Instantiate(WallVer);
wall.transform.position = new Vector2(tilesize * randomX, tilesize * y + tilesize / 2);
if (y < randomY)
{
WalllistY1.Add(wall);
}
else
{
WalllistY2.Add(wall);
}
}
//make a hole in 3 out of tht 4 walls randomly
for (int i = 0; i < MainWallList.Count; i++)
{
if (randomWall != i)
{
RemoveWall(MainWallList[i]);
}
}
////
////
//// If either of the walls have a cell with only 1 grid stop the recursion
Debug.Log("randomX - pMinX:" + (randomX - pMinX));
Debug.Log("pMaxY - randomY:" + (pMaxY - randomY));
Debug.Log("pMaxX - randomX:" + (pMaxX - randomX));
Debug.Log("randomY - pMinY:" + (randomY - pMinY));
if (!(randomX - pMinX <= 1) || !(pMaxY - randomY <= 1))
{
Debug.Log("a");
DevideRecursive(pMinX, randomX, randomY, pMaxY);
}
else
{
return;
}
if (!(pMaxX - randomX <= 1) || !(pMaxY - randomY <= 1))
{
Debug.Log("b");
DevideRecursive(randomX, pMaxX, randomY, pMaxY);
}
else
{
return;
}
if (!(randomX - pMinX <= 1 )|| !(randomY - pMinY <= 1))
{
Debug.Log("c");
DevideRecursive(pMinX, randomX, pMinY, randomY);
}
else
{
return;
}
if (!(pMaxX - randomX <= 1) || !(randomY - pMinY <= 1))
{
Debug.Log("d");
DevideRecursive(randomX, pMaxX, pMinY, randomY);
}
else
{
return;
}
}
This is my Recursive method. It get called in the Start function.
The method creates 2 random walls(1 vertical, 1 horizontal). Which devides the room in 4 smaller rooms. Then it does the same thing for those rooms.
Any help is appriciated
You could modify the function to use async.
using System.Threading.Tasks;
void Start () {
DevideRecursive( ..params.. );
}
private async void DevideRecursive(int pMinX, int pMaxX, int pMinY, int pMaxY) {
// code
while (!Input.GetKeyDown(KeyCode.Space))
await Task.Yield ();
// code
DevideRecursive( .. params .. );
return
}
More infomation on aysnc in Unity here.
An IEnumerator could also be used, which gives you the option to control the function externally.

Optical Mark Recognition using C#

This is a function which determines if a point is within the boundary of the image and checks if it overlaps with other circle.
If it returns true then i check the threshold of the circle filled black and later save the point which is filled more than 90% into a list of points.
My program works in 2 steps
1) If it forms a circle with no overlaping.
2) If it is 90% filled.
I am facing a error that if i pass a image with only 1 circle it saves 1408 circles.I have no idea what i am doing wrong.
Below is the button click event
for (int i = 0; i < 50; i++)
{
for (int j = 0; j < 50; j++)
{
p.X = j;
p.Y = i;
if (isCircle(p))
{
if (checkThreshold(p) > 90)
{
pts.Insert(0, p);
}
}
}
}
Below given are the functions
private bool isCircle(Point p)
{
double count = 0;
Point curP = new Point();
//Point centre = new Point(24, 20);
int a = 0;
boundary.X = 50;
boundary.Y = 50;
for (int x = (p.X - radius); x <= (p.X - radius); x++)
{
for (int y = (p.Y - radius); y <= (p.Y - radius); y++)
{
if ((x < boundary.X) && (y < boundary.Y) && (x + radius < boundary.X) && (y + radius < boundary.Y))
{
curP.X = 0;
curP.Y = 0;
curP.X = x;
curP.Y = y; //stores new point to be sent in curP
while (a < pts.Count)
{
//point , centre, radius
if (checkOverlap(curP, pts[a], radius) == false) //send point to check if it overlaps or not
{
// MessageBox.Show("yellow");
count = 1;
break;
}
else
{
a++;
}
}
}
if (count == 1)
break;
}
if (count == 1)
break;
}
if (count == 1)
return true;
else return false;
}
Below given is the checkOverlap function
private bool checkOverlap(Point p, Point c, int radii)
{
Point listPoint;
listPoint = p;
//the following if condition checks if the point resides in the list or not
if ((((c.X - radii) < listPoint.X) && (listPoint.X > (c.X - radii))) && (((c.Y - radii) < listPoint.Y) && (listPoint.Y > (c.Y - radii))))
{
if ((((p.X - c.X) * (p.X - c.X)) - ((p.Y - c.Y) * (p.Y - c.Y))) < (radius * radius))
{
return false;
}
return true;
}
else
return true;
}
Not sure if this is THE issue, but your count variable should be an int due to the way you are testing for equality.

Drawing polygon

I want to realize method "Draw" of class Polygon
I have WindForms project, form, and the pictureBox1,
I want that "Draw" drawing polygon in pictureBox1 and I have opportunity to move image
I don't konw how to realize it. Help, please.
public class Polygon
{
public Point[] vertexes { get; protected set; }
public Polygon(params int[] vertex)
{
if (vertex == null || vertex.Length <= 2)
throw new Exception("someText");
if (vertex.Length % 2 != 0)
throw new Exception("someText");
vertexes = new Point[vertex.Length / 2];
ColorContour = System.Drawing.Color.DarkRed;
Priming = false;
for (int i = 0, j = 0; i < vertexes.Length; i++, j += 2)
vertexes[i] = new Point(vertex[j], vertex[j + 1]);
vertexes = Point.Sort(vertexes);
if (vertexes == null || vertexes.Length <= 2)
throw new Exception("someText");
}
public double Perimetr
{
get
{
double res = 0;
for (int i = 1; i < vertexes.Length; i++)
res += Point.Length(vertexes[i - 1], vertexes[i]);
return res;
}
}
public override void Move(int deltax, int deltay)
{
vertexes[0].x = deltax;
vertexes[0].y = deltay;
for (int i = 1; i < vertexes.Length; i++)
{
vertexes[i].x -= deltax;
vertexes[i].y -= deltay;
}
}
public void Zoom(double size)
{
if (size == 0)
return;
Point firstP = new Point(vertexes[0].x, vertexes[0].y);
Point Center = Point.CentrMass(vertexes);
for (int i = 0; i < vertexes.Length; ++i)
{
vertexes[i].x = Convert.ToInt32(size * (vertexes[i].x - Center.x) + Center.x);
vertexes[i].y = Convert.ToInt32(size * (vertexes[i].y - Center.y) + Center.y);
}
Move(firstP.x, firstP.y);
}
public void Draw( ??)
{
**????**
}
publicabstract double Square { get; }
You need to take in a System.Drawing.Graphics as a parameter, and call Graphics.DrawPolygon() function. Then in the picturebox, override or implement the OnPaint() event, and call your draw function with the Graphics you receive as a parameter (child of the eventargs) in OnPaint().

Creating Graphs and using them for path-finding algorithms

I am creating a program that randomly creates a maze, where every square can be reached from another. The next step I want to include in this program is a way to connect the paths from one square to another, preferably using Dijkstra's Shortest Path Algorithm.
However, this means I need to turn the MAze into a graph, like so:
How do I code this, I have never worked with algorithms like this before, and have no experience with this, so I will really need almost every step that is necessary to go from figure a to figure be explained to me.
Here is the code for maze creation:
public void GenerateMaze()
{
for (int x = 0; x < mazeWidth; x++)
for (int z = 0; z < mazeHeight; z++)
{
MazeCells[x, z].Walls[0] = true;
MazeCells[x, z].Walls[1] = true;
MazeCells[x, z].Walls[2] = true;
MazeCells[x, z].Walls[3] = true;
MazeCells[x, z].Visited = false;
}
MazeCells[0, 0].Visited = true;
EvaluateCell(new Vector2(0, 0));
}
public void resetMaze()
{
for (int x = 0; x < mazeWidth; x++)
for (int z = 0; z < mazeHeight; z++)
{
MazeCells[x, z].Visited = false;
}
RandomWalls(new Vector2(0, 0));
}
private void EvaluateCell(Vector2 cell)
{
List<int> neighborCells = new List<int>();
neighborCells.Add(0);
neighborCells.Add(1);
neighborCells.Add(2);
neighborCells.Add(3);
while (neighborCells.Count > 0)
{
int pick = rand.Next(0, neighborCells.Count);
int selectedNeighbor = neighborCells[pick];
neighborCells.RemoveAt(pick);
Vector2 neighbor = cell;
switch (selectedNeighbor)
{
case 0: neighbor += new Vector2(0, -1);
break;
case 1: neighbor += new Vector2(1, 0);
break;
case 2: neighbor += new Vector2(0, 1);
break;
case 3: neighbor += new Vector2(-1, 0);
break;
}
if (
(neighbor.X >= 0) &&
(neighbor.X < mazeWidth) &&
(neighbor.Y >= 0) &&
(neighbor.Y < mazeHeight)
)
{
if (!MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited)
{
MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited = true;
MazeCells[(int)cell.X, (int)cell.Y].Walls[selectedNeighbor] = false;
MazeCells[(int)neighbor.X, (int)neighbor.Y].Walls[(selectedNeighbor + 2) % 4] = false;
EvaluateCell(neighbor);
}
}
}
}
//Removes random walls
private void RandomWalls(Vector2 cell)
{
List<int> neighborCells = new List<int>();
neighborCells.Add(0);
neighborCells.Add(1);
neighborCells.Add(2);
neighborCells.Add(3);
while (neighborCells.Count > 0)
{
int pick = rand.Next(0, neighborCells.Count);
int selectedNeighbor = neighborCells[pick];
neighborCells.RemoveAt(pick);
Vector2 neighbor = cell;
switch (selectedNeighbor)
{
case 0: neighbor += new Vector2(0, -1);
break;
case 1: neighbor += new Vector2(1, 0);
break;
case 2: neighbor += new Vector2(0, 1);
break;
case 3: neighbor += new Vector2(-1, 0);
break;
}
//Ensures that end piece is not deleted
if (
(neighbor.X >= 0) &&
(neighbor.X < mazeWidth) &&
(neighbor.Y >= 0) &&
(neighbor.Y < mazeHeight)
)
{
//if cell was not visited
if (!MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited)
{
Random random = new Random();
MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited = true;
//if random number is >= a certain number, removes the walls on both ends
if (random.Next(20) >= 15 && removed <= 100)
{
//MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited = true;
MazeCells[(int)cell.X, (int)cell.Y].Walls[selectedNeighbor] = false;
MazeCells[(int)neighbor.X, (int)neighbor.Y].Walls[(selectedNeighbor + 2) % 4] = false;
removed++;
}
RandomWalls(neighbor);
}
}
}
}
I apologize for the lack of notes on the code, but this is what the maze end up looking like after it renders:

How to center a bunch of controls programmatically in c#

I'm pretty new to this community, and I have this app that adds controls programmatically.
I would like to center all of the added controls sort of like selecting them and pressing center on Visual Studio. And no I don't want to center each one aside.
Here's the code I used to get all the controls:
private void GetAllControl(Control c, List<Control> list)
{
//gets all controls and saves them to a list
foreach (Control control in c.Controls)
{
list.Add(control);
}
}
//And then call it like this
List<Control> list = new List<Control>();
GetAllControl(PNL_custom, list);
foreach (Play_panel m in list)
{
//And here I want to insert that center code
}
Thanks in advance,
VBTheory
Here's how to center the controls as a GROUP. It's almost the same as before except we compute how far the center of mass for the group has to move to become the center of the parent control. Then we iterate over all the controls and offset their locations by that much. This centers them all while maintaining their positions relative to each other:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
List<Control> list = new List<Control>();
GetAllControl(PNL_custom, list);
CenterControlsAsGroup(list, Direction.Both); // center group in the center of the parent
}
public enum Direction
{
Vertical,
Horizontal,
Both
}
private void CenterControlsAsGroup(List<Control> controls, Direction direction)
{
if (controls.Count > 1)
{
int xSum = 0;
int ySum = 0;
Point center;
foreach (Control ctl in controls)
{
center = new Point(ctl.Location.X + ctl.Width / 2, ctl.Location.Y + ctl.Height / 2);
xSum = xSum + center.X;
ySum = ySum + center.Y;
}
Point average = new Point(xSum / controls.Count, ySum / controls.Count);
center = new Point(controls[0].Parent.Width / 2, controls[0].Parent.Height / 2);
int xOffset = center.X - average.X;
int yOffset = center.Y - average.Y;
foreach (Control ctl in controls)
{
switch (direction)
{
case Direction.Vertical:
ctl.Location = new Point(ctl.Location.X + xOffset, ctl.Location.Y);
break;
case Direction.Horizontal:
ctl.Location = new Point(ctl.Location.X, ctl.Location.Y + yOffset);
break;
case Direction.Both:
ctl.Location = new Point(ctl.Location.X + xOffset, ctl.Location.Y + yOffset);
break;
}
}
}
}
private void GetAllControl(Control c, List<Control> list)
{
//gets all controls and saves them to a list
foreach (Control control in c.Controls)
{
list.Add(control);
}
}
}
"And no I don't want to center each one aside."
So you want to "Align" the List of Controls?...as in:
Format --> Align --> Centers
Format --> Align --> Middles
If yes , then compute the center of each control and add up the X, Y coords so you can compute an "average" point (the center of mass). Now you can iterate over the controls and use that as the aligning X or Y value, depending on your desired direction. Simply subtract half the width or height and keep the other value.
Something like:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
List<Control> list = new List<Control>();
GetAllControl(PNL_custom, list);
CenterControls(list, Direction.Vertical);
}
public enum Direction
{
Vertical,
Horizontal
}
private void CenterControls(List<Control> controls, Direction direction)
{
if (controls.Count > 1)
{
int xSum = 0;
int ySum = 0;
Point center;
foreach (Control ctl in controls)
{
center = new Point(ctl.Location.X + ctl.Width / 2, ctl.Location.Y + ctl.Height / 2);
xSum = xSum + center.X;
ySum = ySum + center.Y;
}
Point average = new Point(xSum / controls.Count, ySum / controls.Count);
foreach (Control ctl in controls)
{
switch (direction)
{
case Direction.Vertical:
ctl.Location = new Point(average.X - ctl.Width / 2, ctl.Location.Y);
break;
case Direction.Horizontal:
ctl.Location = new Point(ctl.Location.X, average.Y - ctl.Height / 2);
break;
}
}
}
}
private void GetAllControl(Control c, List<Control> list)
{
//gets all controls and saves them to a list
foreach (Control control in c.Controls)
{
list.Add(control);
}
}
}
Get the width and height of the control's container (which is either another control or the form). The coordinates of controls are distances in pixels, relative to the upper left corner of their containers (which is (0,0)). So all you have to do is set a control's x coordinate to be (form width - control width) / 2. Same goes for height.
All your controls will be added to a container (most likely the Form) though they could easily be in a group box etc.
To align them center inside the container you need to do a little maths and position them yourself :)
Before you can center the control in the container you need to find the midpoint of the container. This will be the container's width / 2 : container's height / 2.
I will use a single control called cmdButton1 to highlight - you will want to iterate through your list of controls and do this to all of them in turn.
int midParentX = cmdButton1.Parent.width / 2;
int midParentX = cmdButton1.Parent.height / 2;
Then you can position a control at this midpoint:
cmdButton1.Location.X = midParentX;
cmdButton1.Location.Y = midParentY;
However, your control (cmdButton in my example) is anchored at (0,0) being the top left corner of the control, so we need to move it back and up by half its own width and height
cmdButton1.Location.X -= (cmdButton1.width / 2);
cmdButton1.Location.Y -= (cmdButton1.height / 2);
To be more relevant:
foreach (Play_panel m in list)
{
int pX = m.Parent.width;
int pY = m.Parent.height;
m.Location.X = (pX / 2) - (m.width / 2);
m.Location.Y = (pY / 2) - (m.height / 2);
}
So i did it on this way:
public enum ArrangeOrientation : int {
None,
Horizonatal,
Vertical,
HorizontalGrid,
VerticalGrid,
TopLeftGrid,
TopRightGrid,
BottomLeftGrid,
BottomRightGrid
}
private void ArrangeButtons(List<Control> controls, List<Control> parents, ArrangeOrientation orientation, double shrinkFactor = 1d) {
if(controls == null) return;
if(parents == null) parents = new List<Control>();
List<Control> childs = new List<Control>();
Control parent = null;
foreach(Control ctrl in controls) {
if(parent == null && !parents.Contains(ctrl.Parent)) {
parents.Add(ctrl.Parent);
parent = ctrl.Parent;
}
if(parent == ctrl.Parent)
childs.Add(ctrl);
}
if(parent != null && childs.Count > 0) {
ArrangeControlsToGridLayout(childs, orientation, shrinkFactor);
ArrangeButtons(controls, parents, orientation, shrinkFactor);
}
}
private void ArrangeControlsToGridLayout(List<Control> controls, ArrangeOrientation orientation, double shrinkFactor = 1d) {
// do nothing if nothing set
if(orientation == ArrangeOrientation.None) return;
if(shrinkFactor == 0d|| shrinkFactor > 1d) shrinkFactor = 1d;
// buffer controls in separate list to avoid manipulating parameter
List<Control> ctrl = new List<Control>(controls.ToArray());
// remove invisible controls
int j = 0;
while(j < ctrl.Count) {
if(!ctrl[j].Visible) ctrl.RemoveAt(j);
else j++;
}
// loop arrangement
int count = ctrl.Count;
int xDelta, yDelta, xOffs, yOffs, y, x, columns, rows, parentWidth, parentHeight, xShrinkOffs, yShrinkOffs;
if(count >= 1) {
// parents size
parentWidth = ctrl[0].Parent.Width;
parentHeight = ctrl[0].Parent.Height;
// shrink factor offset
parentWidth = Convert.ToInt32(parentWidth * shrinkFactor);
parentHeight = Convert.ToInt32(parentHeight * shrinkFactor);
// shrink factor offset
xShrinkOffs = Convert.ToInt32((ctrl[0].Parent.Width - parentWidth) / 2d);
yShrinkOffs = Convert.ToInt32((ctrl[0].Parent.Height - parentHeight) / 2d);
// calculate columns rows grid layout
if(orientation == ArrangeOrientation.Horizonatal) {
rows = 1;
columns = count;
}
else if(orientation == ArrangeOrientation.Vertical) {
rows = count;
columns = 1;
}
else if(orientation == ArrangeOrientation.TopLeftGrid
|| orientation == ArrangeOrientation.TopRightGrid
|| orientation == ArrangeOrientation.BottomLeftGrid
|| orientation == ArrangeOrientation.BottomRightGrid) {
rows = 1;
columns = count;
}
else {
rows = Convert.ToInt32(Math.Floor(Math.Sqrt(count)));
if(Math.Sqrt(count) % 1d != 0d) rows++;
columns = count / rows + (count % rows != 0 ? 1 : 0);
}
if(orientation == ArrangeOrientation.HorizontalGrid) {
int swap = columns;
columns = rows;
rows = columns;
}
// calculate position offsets, grid distance
xDelta = parentWidth / count;
yDelta = parentHeight / count;
xOffs = xDelta / 2;
yOffs = yDelta / 2;
if(orientation == ArrangeOrientation.TopLeftGrid) {
}
else if(orientation == ArrangeOrientation.TopRightGrid) {
xOffs = parentWidth - xOffs;
xDelta = -xDelta;
}
else if(orientation == ArrangeOrientation.BottomLeftGrid) {
yOffs = parentHeight - yOffs;
yDelta = -yDelta;
}
else if(orientation == ArrangeOrientation.BottomRightGrid) {
xOffs = parentWidth - xOffs;
yOffs = parentHeight - yOffs;
xDelta = -xDelta;
yDelta = -yDelta;
}
else {
xDelta = parentWidth / columns;
yDelta = parentHeight / rows;
xOffs = xDelta / 2;
yOffs = yDelta / 2;
}
// fit controls in grid layout
Point pRoot = new Point(/*ctrl[0].Parent.Location.X + */xOffs, /*ctrl[0].Parent.Location.Y + */yOffs);
y = 0; x = 0;
for(int i = 0; i < count; i++) {
if(orientation == ArrangeOrientation.VerticalGrid) {
// actual x/y - points zero based index
y = Convert.ToInt32(Math.Floor((double)i % rows));
// next row? zero based index
if(i % rows == 0 && i != 0) x++;
}
else {
// actual x/y - points zero based index
x = Convert.ToInt32(Math.Floor((double)i % columns));
// next row? zero based index
if(i % columns == 0 && i != 0) y++;
if(orientation == ArrangeOrientation.TopLeftGrid
|| orientation == ArrangeOrientation.TopRightGrid
|| orientation == ArrangeOrientation.BottomLeftGrid
|| orientation == ArrangeOrientation.BottomRightGrid)
y = x;
} // assign controls to grid
ctrl[i].Location = new Point(pRoot.X + x * xDelta - ctrl[i].Size.Width / 2 + xShrinkOffs, pRoot.Y + y * yDelta - ctrl[i].Size.Height / 2 + yShrinkOffs);
}
}
}
When there are multiple controls,above code was placing all controls on top of each other.
All i am trying to do is to center all the controls inside a panel but to put them next to each other instead of putting one over the other.
Here is my modified code (FYI this will center controls in 1 line not multiple line):
public enum Direction
{
Vertical,
Horizontal,
Both
}
public void CenterControls(List<Control> controls, Direction direction)
{
if (controls.Count > 1)
{
int controls_sum_width = 0;
int controls_seperation = 20;
int parentwidth = 0;
Point center;
foreach (Control ctl in controls)
{
controls_sum_width = controls_sum_width + ctl.Width + controls_seperation;
}
Point Container_center = new Point(controls[0].Parent.Width / 2, controls[0].Parent.Height / 2);
parentwidth = controls[0].Parent.Width;
int xoffset = (parentwidth - controls_sum_width) / 2;
int Location_X = 0;
foreach (Control ctl in controls)
{
center = new Point( ctl.Width / 2, ctl.Height / 2);
int yOffset = Container_center.Y - center.Y;
switch (direction)
{
case Direction.Vertical:
ctl.Location = new Point(ctl.Location.X + xoffset, ctl.Location.Y);
break;
case Direction.Horizontal:
ctl.Location = new Point(ctl.Location.X, yOffset);
break;
case Direction.Both:
ctl.Location = new Point(Location_X + xoffset, yOffset);
break;
}
Location_X = Location_X + ctl.Width+ controls_seperation;
}
}
else
{
Point parent_center;
Point center;
parent_center = new Point(controls[0].Parent.Width / 2, controls[0].Parent.Height / 2);
center = new Point(controls[0].Location.X + controls[0].Width / 2, controls[0].Location.Y + controls[0].Height / 2);
int xOffset = parent_center.X - center.X;
int yOffset = parent_center.Y - center.Y;
switch (direction)
{
case Direction.Vertical:
controls[0].Location = new Point(controls[0].Location.X + xOffset, controls[0].Location.Y);
break;
case Direction.Horizontal:
controls[0].Location = new Point(controls[0].Location.X, controls[0].Location.Y + yOffset);
break;
case Direction.Both:
controls[0].Location = new Point(controls[0].Location.X + xOffset, controls[0].Location.Y + yOffset);
break;
}
}
}
public void GetAllControl(Control c, List<Control> list)
{
//gets all controls and saves them to a list
foreach (Control control in c.Controls)
{
list.Add(control);
}
}

Categories