I'm creating a WPF application with a menu, when clicked on menuItem I want to show NQueens (another project) in my Window (plugin). I've placed an NQueens.dll in my CurrentDirectory to work with. To make this work I've created an assembly object to load the classes and created an instance of Nqueens.Nqueen and invoked the methods.
The NQueens project consists of a class NQueen.cs and a MainWindow.
namespace NQueens
{
public class NQueen
{
public static bool berekenQueens(int Row, int N, bool[,] bord)
{
if (Row >= N) return true; //stopconditie
for (int Col = 0; Col < N; Col++)
{
//Q toevoegen
bord[Row, Col] = true;
//Q + Q volgende Row controleren
if (bordValidatie(Row, Col, bord, N) && berekenQueens(Row + 1, N, bord))
{
return true;
}
//Q verwijderen indien niet door controle
bord[Row, Col] = false;
}
return false;
}
private static bool bordValidatie(int currentRow, int currentCol, bool[,] currentBord, int N)
{
int colstep = 1;
for (int i = currentRow - 1; i >= 0; i--)
{
//rechte lijn
if (currentBord[i, currentCol])
return false;
//linker diagonaal
if (currentCol - colstep >= 0)
{
if (currentBord[i, currentCol - colstep])
return false;
}
//rechter diagonaal
if (currentCol + colstep < N)
{
if (currentBord[i, currentCol + colstep])
return false;
}
colstep += 1;
}
return true;
}
}
}
MainWindow.xaml.cs
namespace NQueens
{
public partial class MainWindow : Window
{
public int iN { get { return Convert.ToInt32(txtN.Text); } set { txtN.Text = "" + value; } }
private bool[,] spelbord;
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
spelbord = new bool[iN, iN];
NQueen.berekenQueens(0, iN, spelbord);
visualise(iN, spelbord);
}
private void visualise(int N, bool[,] bord)
{
gridTekenen();
for (int row = 0; row < N; row++)
{
for (int col = 0; col < N; col++)
{
Rectangle rect = new Rectangle();
rect.Stretch = Stretch.Fill;
TextBlock txtB = new TextBlock();
if (spelbord[row, col])
{
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Colors.LightGreen;
rect.Fill = mySolidColorBrush;
txtB.Text = "Q";
}
rect.SetValue(Grid.ColumnProperty, col);
rect.SetValue(Grid.RowProperty, row);
txtB.SetValue(Grid.ColumnProperty, col);
txtB.SetValue(Grid.RowProperty, row);
gridPaneel.Children.Add(rect);
gridPaneel.Children.Add(txtB);
}
}
}
private void gridTekenen()
{
gridPaneel.ShowGridLines = true;
int grooteGrid = int.Parse(txtN.Text);
RowDefinition rowDef;
ColumnDefinition colDef;
for (int i = 0; i < grooteGrid; i++)
{
rowDef = new RowDefinition();
GridLengthConverter myGridLengthConverter = new GridLengthConverter();
GridLength gl1 = (GridLength)myGridLengthConverter.ConvertFromString(150 + "*");
rowDef.Height = gl1;
colDef = new ColumnDefinition();
colDef.Width = gl1;
gridPaneel.RowDefinitions.Add(rowDef);
gridPaneel.ColumnDefinitions.Add(colDef);
}
}
}
}
Code in WPF application when clicked on the menuItem.
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
// Create an assembly object to load our classes
string path = System.Environment.CurrentDirectory + "\\NQueens.dll";
Assembly ass = Assembly.LoadFile(path);
Console.WriteLine(path);
Type objType = ass.GetType("NQueens.NQueen");
// Create an instace of NQueens.NQueen
var instance = Activator.CreateInstance(objType);
// public static bool berekenQueens(int Row, int N, bool[,] bord)
var result = objType.InvokeMember("berekenQueens",BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public,
null, instance, new object[] { 1, /* Row */ 1, /* N */ new bool[,] { {true,false} } /* bord */
});
// private static bool bordValidatie(int currentRow, int currentCol, bool[,] currentBord, int N)
var result2 = objType.InvokeMember("bordValidatie", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic,
null, instance, new object[] { 1, /* Row */ 1, /* N */ new bool[,] { {true,false} } /* bord */, 1
});
}
I do not know what to do now. How can I show the NQueen program in my current Window when clicked on the menuItem.
NQueen class should be any kind of wpf control descendant. If it's a simple class, it cannot communicate with its container.
So you should instanciate NQueens.MainWindow instead of NQueens.NQueen and call the Show method.
Related
I'm trying to resize my control and maintain they're current position. I've tried doing it by keeping the original proportion in list and comparing it and resizing it accordingly whenever the size of the form is changed.
The result http://prntscr.com/bc796l -> http://prntscr.com/bc79a2
Can you guide me where my problem is or suggest a different approach
private void Form_Resize(object sender, EventArgs e)
{
Control.ControlCollection controls = Controls;
List<Size> newSizes = new List<Size>();
for (int j = 0; j < controls.Count; j++)
{
int widthProportion = Bounds.Width / controls[j].Width;
int heightProportion = Bounds.Height/controls[j].Height;
string controlName = controlProportions[j].Item1;
int originalWidthProportion = controlProportions[j].Item2;
int originalHeightProportion = controlProportions[j].Item3;
if (controls[j].Name == controlName)
{
if (widthProportion > originalWidthProportion)
{
while (widthProportion > originalWidthProportion)
{
originalWidthProportion++;
}
}
else if (widthProportion < originalWidthProportion)
{
while (widthProportion < originalWidthProportion)
{
originalWidthProportion--;
}
}
if (heightProportion > originalHeightProportion)
{
while (heightProportion > originalHeightProportion)
{
originalHeightProportion++;
}
}
else if (heightProportion < originalHeightProportion)
{
while (heightProportion < originalHeightProportion)
{
originalHeightProportion--;
}
}
newSizes.Add(new Size(Bounds.Width/originalWidthProportion, Bounds.Height/originalHeightProportion));
controlProportions[j] = new Tuple<string, int, int>(controls[j].Name, originalWidthProportion,
originalHeightProportion);
}
}
for (int j = 0; j < controls.Count; j++)
{
controls[j].Size = newSizes[i];
}
}
That's how I originally populate the list :
private static readonly List<Tuple<string,int, int>> controlProportions = new List<Tuple<string,int, int>>();
private void SetControlProportions()
{
Control.ControlCollection controls = Controls;
foreach (Control control in controls)
{
int heightProportion = Bounds.Height / control.Height;
int widthProportion = Bounds.Width / control.Width;
controlProportions.Add(new Tuple<string, int, int>(control.Name,widthProportion, heightProportion));
}
}
I am making an application in which I want to add buttons on panel from my main form dynamically. If I have 10 items in List then that many buttons will be generate on panel from main form. But when I try to do that one then it shows me error that Control.Invoke required.
Please anyone suggest me how to add controls...??
private void CheckOrderListEntry(Workorder workorder)
{
int ticketID = workorder.TicketID;
int index = 0;
int lastIndex = _workorderList.Count;
bool isExist = false;
for (index = 0; index < lastIndex; index++)
{
int existingTicektId = _workorderList[index].TicketID;
if (ticketID == existingTicektId)
{
_workorderList[index] = workorder;
isExist = true;
break;
}
}
if (!isExist)
{
_workorderList.Add(workorder);
}
ListEventChangeHandler();
}
public void ListEventChangeHandler()
{
_orderBtn = new Button[_workorderList.Count];
int index = 0;
int lastIndex = _orderBtn.Length;
for (; index < lastIndex; index++)
{
Workorder workorder = _workorderList[index];
_orderBtn[index] = new Button();
_orderBtn[index].Name = String.Format("{0}", index);
_orderBtn[index].Text = String.Format("Order #: {0} Source: {1} Desination: {2}", workorder.TicketID, workorder.PickupAddress, workorder.DropoffAddress);
_orderBtn[index].BackColor = Color.SteelBlue;
_orderBtn[index].ForeColor = Color.White;
_orderBtn[index].Font = new Font("Tahoma", 16, FontStyle.Regular);
_orderBtn[index].Click += new EventHandler(OrderBtnClick);
}
UpdatePanel(_orderBtn);
}
public delegate void UpdateAcceptOrderPanel(Button[] btn);
public void UpdatePanel(Button[] btn)
{
try
{
if (this.InvokeRequired)
{
UpdateAcceptOrderPanel updateMyPanel = new UpdateAcceptOrderPanel(UpdatePanel);
this.Invoke(updateMyPanel, btn);
}
else
{
AddButtonOnPanel(btn);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void AddButtonOnPanel(Button[] btn)
{
for (int index = 0; index < btn.Length; index++)
{
this.acceptOrderPanle.Controls.Add(btn[index]);
}
}
I'm not very good on delegates, but this is the way I would do your UpdatePanel method ...
public void UpdatePanel(Panel panel, Button button)
{
if(panel.InvokeRequired)
{
panel.Invoke(new Action<Panel,Button>(UpdatePanel), new object[] {panel, button});
}
else
{
panel.Controls.Add(button);
}
}
hope this help ...
I have been trying to create a chess strategy application. I seem to be having issues with trying to get the label1 control to populate during run time. I am actually pretty new to the idea of dynamically creating events like 'mouse enter, mouse leave' How do I get the label to show the coordinates in the mouse enter event
int currentXposition, currentYposition;
const string positionLabel = "Current Position: ";
private void Test_Load(object sender, EventArgs a)
{
var temp=Color.Transparent; //Used to store the old color name of the panels before mouse events
var colorName = Color.Red; //Color used to highlight panel when mouse over
int numBlocks = 8; //Used to hold the number of blocks per row
int blockSize=70;
//Initialize new array of Panels new
string[,] Position = new string[8, 8];
Panel[,] chessBoardPanels = new Panel[numBlocks, numBlocks];
string Alphabet = "A,B,C,D,E,F,G,H";
string Numbers ="1,2,3,4,5,6,7,8";
string[] alphaStrings = Numbers.Split(',');
string[] numStrings=Numbers.Split(',');
// b = sub[0];
int FirstValue, SecondValue;
//Store Position Values
for (int firstValue = 0; firstValue < 8; ++firstValue)
{
FirstValue = Alphabet[firstValue];
for (int SecValue = 0; SecValue < 8; ++SecValue)
{
SecondValue = Numbers[SecValue];
Position[firstValue, SecValue] = alphaStrings[firstValue] + numStrings[SecValue];
}
}
//Loop to create panels
for (int iRow = 0; iRow < numBlocks; iRow++)
for (int iColumn = 0; iColumn < numBlocks; iColumn++)
{
Panel p = new Panel();
//set size
p.Size = new Size(blockSize, blockSize);
//set back colour
p.BackColor = (iRow + (iColumn % 2)) % 2 == 0 ? Color.Black : Color.White;
//set location
p.Location = new Point(blockSize *iRow+15, blockSize * iColumn+15);
chessBoardPanels[iRow, iColumn] = p;
chessBoardPanels[iRow,iColumn].MouseEnter += (s,e) =>
{
currentXposition = iRow;
currentYposition = iColumn;
var oldColor = (s as Panel).BackColor;
(s as Panel).BackColor = colorName;
temp = oldColor;
label1.Text = Position[iRow, iColumn];
};
chessBoardPanels[iRow, iColumn].MouseLeave += (s, e) =>
{
(s as Panel).BackColor = temp;
};
groupBox1.Controls.Add(p);
}
}
Try this.. It was not populating because of a out of range.. iRow always = 8...
Add this class to your project.
public class ChessSquare
{
public string Letter { get; set; }
public int Number { get; set; }
public Color Color { get; set; }
public string Position
{
get { return string.Format("{0}{1}", Letter, Number); }
}
public ChessSquare()
{
}
public ChessSquare(string letter, int number)
{
Letter = letter;
Number = number;
}
}
Replace the FormLoad method with this:
int blockSize = 20;
Panel[,] chessBoardPanels = new Panel[8, 8];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
ChessSquare sq = new ChessSquare(((char)(65+i)).ToString(), j);
sq.Color = (i + (j % 2)) % 2 == 0 ? Color.AliceBlue : Color.White;
Panel p = new Panel()
{ Size = new Size(blockSize, blockSize),
BackColor = sq.Color,
Tag = sq,
Location = new Point(blockSize * i + 15, blockSize * j+15),
};
p.MouseEnter+=new EventHandler(squareMouseEnter);
p.MouseLeave += new EventHandler(squareMouseLeave);
chessBoardPanels[i, j] = p;
groupBox1.Controls.Add(p);
}
}
And add those two methods to your code:
void squareMouseEnter(object sender, EventArgs e)
{
Panel p = (Panel)sender;
ChessSquare sq = (ChessSquare)p.Tag;
p.BackColor = Color.Aqua;
label1.Text = string.Format("Current position: {0}", sq.Position);
}
void squareMouseLeave(object sender, EventArgs e)
{
Panel p = (Panel) sender;
ChessSquare sq = (ChessSquare)p.Tag;
p.BackColor = sq.Color;
}
I there are several ways of doing it... This one is pretty straight forward.
Good day to all,
I've been working on a C# Sudoku Solver application but I sincerely underestimated the difficulty of the algorithms to solve a sudoku. I've been searching the web for possible algorithms that I could implement, but I've had no luck finding an easy algorithm that I can get my head around.
I found an algorithm that may work in my application, however this person is using a single-dimensional array to work it out.
I've tried to change it to make it work with a multidimensional array, but I can't get it to work properly.
Could anybody give me advice or show me how I could change the code so that it works with a multidimensional array(int[,])? I just can't seem to find it on my own. The code is found here: http://blah.winsmarts.com/2007-1-sudoku_solver_in_c-.aspx
If you have another algorithm that would work with an int[,], that's also wonderful of course.
Help would be greatly appreciated since I've been searching for a long time.
Thanks in advance!
The code you linked already logically uses a 2D array, it just uses a 1D array as a backing. Change this:
private int[] vals = new int[81];
public int this[int row, int column]
{
get { return vals[FindIndex(row, column)]; }
set
{
vals[FindIndex(row, column)] = value;
}
}
private int FindIndex(int row, int column)
{
return (((column - 1) * 9) + row - 1);
}
To:
private int[,] vals = new int[9,9];
public int this[int row, int column]
{
get { return vals[row - 1, column - 1]; }
set
{
vals[row - 1, column - 1] = value;
}
}
(The - 1's are necessary with the rest of the current code because row and column start at 1 instead of 0.)
Recursive backtracking , brute force, algorithm.
public class SudokoSolver
{
private readonly Grid _grid;
public SudokoSolver(Grid grid)
{
_grid = grid;
_grid.Validate();
}
public int?[,] SolvePuzzle()
{
Solve();
Console.WriteLine(_grid.Assigns + " tries total.");
return _grid.Data;
}
private bool Solve()
{
int row, col;
if (!_grid.FindUnassignedLoc(out row, out col))
{
return true;
}
for (int num = 1; num <= 9; num++)
{
if (_grid.NoConflicts(row, col, num))
{
_grid.Assign(row, col, num);
if (Solve())
{
return true;
}
_grid.Unassign(row, col);
}
}
return false;
}
public int?[,] Data
{
get { return _grid.Data; }
}
}
public class Grid
{
public int?[,] Data { get; private set; }
private int _curC = 0;
private int _curR = 0;
private int _assigns = 0;
public Grid(int?[,] data)
{
Data = data ?? new int?[9,9];
}
public bool FindUnassignedLoc(out int row, out int col)
{
while (Data[_curR, _curC].HasValue)
{
_curC++;
if (_curC == 9)
{
_curR++;
_curC = 0;
}
if (_curR == 9)
{
row = -1;
col = -1;
return false;
}
}
row = _curR;
col = _curC;
return true;
}
public bool NoConflicts(int row, int col, int num)
{
for (int r = 0; r < 9; ++r)
{
if (Data[r, col] == num)
{
return false;
}
}
for (int c = 0; c < 9; c++)
{
if (Data[row, c] == num)
{
return false;
}
}
int fromC = 3 * (col/3);
int fromR = 3 * (row / 3);
for (int c = fromC; c < fromC + 3; c++)
{
for (int r = fromR; r < fromR + 3; r++)
{
if (Data[r, c] == num)
{
return false;
}
}
}
return true;
}
public void Assign(int row, int col, int num)
{
_assigns++;
Data[row, col] = num;
}
public void Unassign(int row, int col)
{
Data[row, col] = null;
_curC = col;
_curR = row;
}
public int Assigns
{
get { return _assigns; }
}
public void Validate()
{
if (Data.Length != 81)
{
throw new Exception("Invalid dimentions!");
}
if (!IsLegal())
{
throw new Exception("Illigal numbers populated!");
}
}
public bool IsLegal()
{
var container = new HashSet<int>();
//vertical check
for (int c = 0; c < 9; ++c)
{
container.Clear();
for (int r = 0; r < 9; ++r)
{
if (Data[r, c].HasValue)
{
if (container.Contains(Data[r, c].Value))
{
return false;
}
container.Add(Data[r, c].Value);
}
}
}
// horizontal check
for (int r = 0; r < 9; ++r)
{
container.Clear();
for (int c = 0; c < 9; ++c)
{
if (Data[r, c].HasValue)
{
if (container.Contains(Data[r, c].Value))
{
return false;
}
container.Add(Data[r, c].Value);
}
}
}
// square check
var topLeftCorners = new List<Tuple<int, int>>
{
new Tuple<int, int>(0,0),
new Tuple<int, int>(0,3),
new Tuple<int, int>(0,6),
new Tuple<int, int>(3,0),
new Tuple<int, int>(3,3),
new Tuple<int, int>(3,6),
new Tuple<int, int>(6,0),
new Tuple<int, int>(6,3),
new Tuple<int, int>(6,6)
};
foreach (var topLeftCorner in topLeftCorners)
{
int fromC = topLeftCorner.Item2;
int fromR = topLeftCorner.Item1;
container.Clear();
for (int c = fromC; c < fromC + 3; c++)
{
for (int r = fromR; r < fromR + 3; r++)
{
if (Data[r, c].HasValue)
{
if (container.Contains(Data[r, c].Value))
{
return false;
}
container.Add(Data[r, c].Value);
}
}
}
}
return true;
}
}
I have the multi-dimensional array originalArray[X_VECTOR, Y_VECTOR] of MyButtons.
MyButton is simple created class (maybe unnecessary):
class MyButton : Button
{
private int[] id;
public MyButton()
{
id = new int[2];
}
public int[] ID
{
get
{
return id;
}
set
{
id = value;
}
}
}
In loop we fill the array of buttons:
public void fillArray() {
originalArray = new MyButton[X_VECTOR, Y_VECTOR];
int count_buttons = 0;
for (int i = 0; i < X_VECTOR; ++i)
{
for (int j = 0; j < Y_VECTOR; ++j)
{
count_buttons++;
MyButton btn = new MyButton();
btn.Name = "btn " + count_buttons;
btn.ID[0] = i;
btn.ID[1] = j;
originalArray[i, j] = btn;
}
}
}
Now, we would like to move button to right side after click in array:
protected void MyBtnClick(object sender, EventArgs e) {
if (sender != null) {
MyButton myclickbutton = (MyButton)sender;
int x = myclickbutton.ID[0];
int y = myclickbutton.ID[1];
MyButton temp = originalArray[x, y];
temp.Location = new Point(curr_pos_x + 55, curr_pos_y);
temp.ID[0] = x;
temp.ID[1] = y + 1; // new coordinate y
originalArray[x, y + 1] = temp;
temp = null;
// originalArray[x, y] = null;
}
}
NULL is not set. What I'm going wrong?
I need this ilustration:
BEFORE CLICK:
originalArray[0,0] = btn instance;
originalArray[0,1] = null;
AFTER CLICK:
originalArray[0,0] = null;
originalArray[0,1] = btn instance;
EDIT:
When I tried this:
protected void MyBtnClick(object sender, EventArgs e) {
if (sender != null) {
MyButton myclickbutton = (MyButton)sender;
int x = myclickbutton.ID[0];
int y = myclickbutton.ID[1];
myclickbutton.Location = new Point(curr_pos_x + 55, curr_pos_y);
myclickbutton.ID[0] = x;
myclickbutton.ID[1] = y + 1;
originalArray[x, y + 1] = myclickbutton;
originalArray[x, y] = null;
}
}
That maybe OK, but when I was testing this
if ((originalArray[i, j].Name == testArray[i, j].Name)) ...
This line gets me NullReferenceException.
This function I same like fillArray above, and this I call in constructor:
public void createTestArray() {
testArray = new MyButton[X_VECTOR, Y_VECTOR];
int count_buttons = 0;
for (int i = 0; i < X_VECTOR; ++i)
{
for (int j = 0; j < Y_VECTOR; ++j)
{
count_buttons++;
MyButton btn = new MyButton();
btn.Name = "btn " + count_buttons;
testArray[i, j] = btn;
}
}
}
You made one of items of array to be null, now you go through all of them, null items throw you an exception. Just check if item is not null before names are compared and you will not get an exception
You're getting a message saying Null is not set. You have commented out the line that returns the original x and y entry in the multi-dimensional array to null. What you've got at the moment is:
originalArray[0,0] = btn instance;
originalArray[0,1] = temp;
Remove the comments from your last line and you should erase btn instance in 0,0.