I am trying to create a chess board strategy application in WinForms c#.
Someone from here was gracious enough to help with this code.
When it is run, it does everything I wanted except that the sq.position values are wrong.
The value like A1 should be A7, A6 should be A2
How can I reverse the order of the number value in this code:
private void Test_Load(object sender, EventArgs e)
{
int blockSize = 70;
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.Black : 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);
}
}
}
private void squareMouseLeave(object sender, EventArgs e)
{
Panel p = (Panel)sender;
ChessSquare sq = (ChessSquare)p.Tag;
p.BackColor = sq.Color;
}
private 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);
}
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 + 1); }
}
public ChessSquare()
{ }
public ChessSquare(string letter, int number)
{
Letter = letter;
Number = number;
}
}
I am still very new to this type of programming....
Change this:
ChessSquare sq = new ChessSquare(((char)(65 + i)).ToString(), j);
to that:
ChessSquare sq = new ChessSquare(((char)(65 + i)).ToString(), 7 - j);
Update: Corrected! Thanks user2772713!
Related
the problem i'm facing right now is that i don't know how to check on the opponent's move which ships it sinks so i can display a message saying "Your ____ has sunk".
this is the code i have written
namespace Naval
{
public partial class Form2 : Form
{
const int Size_grid = 10;
const int picturebox = 50;
PictureBox[,] playerBoard = new PictureBox[Size_grid, Size_grid];
PictureBox[,] opponentBoard = new PictureBox[Size_grid, Size_grid];
int[,] playerShips = new int[Size_grid, Size_grid];
int[,] opponentShips = new int[Size_grid, Size_grid];
int[] Lengths = new int[] { 5, 4, 3, 2 };
//string[] Names = new string[] { "Αεροπλανοφόρο", "Αντιτορπιλικό", "Πολεμικό", "Υποβρύχιο" };
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
for (int row = 0; row < Size_grid; row++)
{
for (int col = 0; col < Size_grid; col++)
{
PictureBox playerPictureBox = new PictureBox();
playerPictureBox.Size = new Size(picturebox, picturebox);
playerPictureBox.Location = new Point(col * (picturebox + 10) + 185, row * (picturebox + 10) + 245);
playerPictureBox.Click += PictureBox_Click;
playerPictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
playerPictureBox.BackColor = Color.Gray;
panel1.Controls.Add(playerPictureBox);
playerBoard[row, col] = playerPictureBox;
}
}
for (int row = 0; row < Size_grid; row++)
{
for (int col = 0; col < Size_grid; col++)
{
PictureBox opponentPictureBox = new PictureBox();
opponentPictureBox.Size = new Size(picturebox, picturebox);
opponentPictureBox.Location = new Point(col * (picturebox + 10) + 1145, row * (picturebox + 10) + 245);
opponentPictureBox.Click += PictureBox_Click;
opponentPictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
opponentPictureBox.BackColor = Color.Gray;
panel1.Controls.Add(opponentPictureBox);
opponentBoard[row, col] = opponentPictureBox;
}
}
PlacePlayerShips(playerShips, Lengths);
PlaceOpponentShips(opponentShips, Lengths);
}
private void PictureBox_Click(object sender, EventArgs e)
{
PictureBox pictureBox = (PictureBox)sender;
int row = (pictureBox.Location.Y - 245) / (picturebox + 10);
int col = (pictureBox.Location.X - 1145) / (picturebox + 10);
if (pictureBox.Location.X >= 1145 && pictureBox.ImageLocation == null) // opponent board
{
if (row >= 0 && row < opponentShips.GetLength(0) && col >= 0 && col < opponentShips.GetLength(1))
{
if (opponentShips[row, col] > 0)
{
pictureBox.ImageLocation = "x.png";
}
else
{
pictureBox.ImageLocation = "-.png";
}
ComputerMove();
}
}
}
private void ComputerMove()
{
Random random = new Random();
int row = random.Next(Size_grid);
int col = random.Next(Size_grid);
while (playerBoard[row, col].ImageLocation != null)
{
row = random.Next(Size_grid);
col = random.Next(Size_grid);
}
if (playerShips[row, col] > 0)
{
playerBoard[row, col].ImageLocation = "x.png";
}
else
{
playerBoard[row, col].ImageLocation = "-.png";
}
}
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
private void PlacePlayerShips(int[,] playerShips, int[] shipLengths)
{
Random random = new Random(DateTime.Now.Millisecond);
foreach (int shipLength in shipLengths)
{
int row, col;
int direction = random.Next(2);
int placed = 0;
while (placed == 0)
{
if (direction == 0) // Horizontal
{
row = random.Next(Size_grid);
col = random.Next(Size_grid - shipLength + 1);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (playerShips[row, col + i] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
playerShips[row, col + i] = 1;
playerBoard[row, col + i].BackColor = Color.LightBlue;
}
}
}
else // Vertical
{
row = random.Next(Size_grid - shipLength + 1);
col = random.Next(Size_grid);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (playerShips[row + i, col] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
playerShips[row + i, col] = 1;
playerBoard[row + i, col].BackColor = Color.LightBlue;
}
}
}
// Change direction if ship couldn't be placed
if (placed == 0)
{
direction = (direction + 1) % 2;
}
}
}
}
private void PlaceOpponentShips(int[,] opponentShips, int[] shipLengths)
{
Random random = new Random(DateTime.Now.Millisecond);
;
foreach (int shipLength in shipLengths)
{
int row, col;
int direction = random.Next(2);
int placed = 0;
while (placed == 0)
{
if (direction == 0) // Horizontal
{
row = random.Next(Size_grid);
col = random.Next(Size_grid - shipLength + 1);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (opponentShips[row, col + i] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
opponentShips[row, col + i] = 1;
}
}
}
else // Vertical
{
row = random.Next(Size_grid - shipLength + 1);
col = random.Next(Size_grid);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (opponentShips[row + i, col] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
opponentShips[row + i, col] = 1;
}
}
}
// Change direction if ship couldn't be placed
if (placed == 0)
{
direction = (direction + 1) % 2;
}
}
}
}
private void label1_Click(object sender, EventArgs e)
{
}
int time = 0;
private void timer1_Tick(object sender, EventArgs e)
{
time++;
label42.Text= time.ToString();
}
private void timer2_Tick(object sender, EventArgs e)
{
label44.Text = " ";
timer2.Enabled = false;
}
}
}
i tried adding a switch with choices 1-4 but it didn't work i've also tried having a int[] ship Hits = new int[] {0,0,0,0} and just adding 1 every time a ship was hit but that didn't go as planned because i didn't know how to bind each item of the array to a ship . and i think that's about it
One approach that you might find helpful would be to bundle up all the information about a Ship into a class. This is an abstraction that could make it easier for displaying ship names when they are sunk. At the same time, use inheritance so that a Ship is still a PictureBox with all the functionality that implies.
Ship minimal class example
Member properties tell us what we need know about a ship. Use enum values to make the intent perfectly clear.
class Ship : PictureBox
{
#region P R O P E R T I E S
[Description("Type")]
public τύπος τύπος
{
get => _τύπος;
set
{
if (!Equals(_τύπος, value))
{
_τύπος = value;
switch (_τύπος)
{
case τύπος.Αεροπλανοφόρο: Image = Image.FromFile(Path.Combine(_imageDir, "aircraft-carrier.png")); break;
case τύπος.Αντιτορπιλικό: Image = Image.FromFile(Path.Combine(_imageDir, "destroyer.png")); break;
case τύπος.Πολεμικό: Image = Image.FromFile(Path.Combine(_imageDir, "military.png")); break;
case τύπος.Υποβρύχιο: Image = Image.FromFile(Path.Combine(_imageDir, "submarine.png")); break;
}
}
}
}
τύπος _τύπος = 0;
public bool Sunk { get; set; }
[Description("Flag")]
public σημαία σημαία
{
get => _σημαία;
set
{
_σημαία = value;
onUpdateColor();
}
}
σημαία _σημαία = σημαία.Player;
#endregion P R O P E R T I E S
private void onUpdateColor()
{
var color =
Sunk ? Color.Red :
σημαία.Equals(σημαία.Player) ?
Color.Navy :
Color.DarkOliveGreen;
for (int x = 0; x < Image.Width; x++) for (int y = 0; y < Image.Height; y++)
{
Bitmap bitmap = (Bitmap)Image;
if (bitmap.GetPixel(x, y).R < 0x80)
{
bitmap.SetPixel(x, y, color);
}
}
Refresh();
}
public Point[] Hits { get; set; } = new Point[0];
public override string ToString() =>
$"{σημαία} {τύπος} # {((TableLayoutPanel)Parent)?.GetCellPosition(this)}";
private readonly static string _imageDir =
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
}
Where enum values are:
enum Direction
{
Horizontal,
Vertical,
}
enum τύπος
{
[Description("Aircraft Carrier")]
Αεροπλανοφόρο = 5,
[Description("Destroyer")]
Αντιτορπιλικό = 4,
[Description("Military")]
Πολεμικό = 3,
[Description("Submarine")]
Υποβρύχιο = 2,
}
/// <summary>
/// Flag
/// </summary>
enum σημαία
{
Player,
Opponent,
}
Displaying ships names when they are sunk
When the inherited Ship version of PictureBox is clicked the information is now available.
private void onAnyShipClick(object sender, EventArgs e)
{
if (sender is Ship ship)
{
MessageBox.Show(ship.ToString());
}
}
Images credit: Robuart
Used under license.
I'm trying to give the letters in my richtextbox different colors for my subnet calculator, but the richtextbox doesn't change the colors until the 26th letter.
How it looks:
int iValueSm = trackBarSmMask.Value;
rtbScroll.Text = "";
rtbScroll.SelectionStart = rtbScroll.TextLength;
rtbScroll.SelectionLength = 0;
for (int i = 1; i <= iValueSm; i++)
{
rtbScroll.SelectionColor = Color.Blue;
rtbScroll.AppendText("N");
if (i%8==0 && i != 32)
{
rtbScroll.Text = rtbScroll.Text + ".";
}
}
for (int i = iValueSm+1; i <= 32; i++)
{
rtbScroll.SelectionColor = Color.Red;
rtbScroll.AppendText("H");
if (i % 8 == 0 && i != 32)
{
rtbScroll.Text = rtbScroll.Text + ".";
}
}
labelAmountNetID.Text = "/" + iValueSm.ToString();
Well, can be a lot of approaches to deal with this problem but here is one suggestion:
// Track bar definitions...
private void SetTrackBarVals()
{
trackBar1.Minimum = 0;
trackBar1.Maximum = 31;
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
var counter = 0;
var dotsCounter = 0;
rtbScroll.Text = "";
int iValueSm = trackBar1.Value + 1; // +1 because we start counting from 0
for (int i = 1; i <= 32; i++)
{
if (counter > 0 && counter % 8 == 0)
{
// new octet
rtbScroll.AppendText(".");
dotsCounter++;
}
if (i > iValueSm)
{
// It is red
rtbScroll.AppendText("H");
rtbScroll.SelectionStart = (i - 1) + dotsCounter;
rtbScroll.SelectionLength = 1 ;
rtbScroll.SelectionColor = Color.Red;
}
else
{
rtbScroll.AppendText("N");
}
counter++;
}
}
Anytime you set the .Text() property, you RESET all formatting back to black and white.
Here is how I'd write it using SelectedText:
private void Form1_Load(object sender, EventArgs e)
{
updateRTB();
}
private void trackBarSmMask_ValueChanged(object sender, EventArgs e)
{
updateRTB();
}
private void trackBarSmMask_Scroll(object sender, EventArgs e)
{
updateRTB();
}
private void updateRTB()
{
rtbScroll.Text = "";
rtbScroll.SelectionStart = 0;
rtbScroll.SelectionLength = 0;
int iValueSm = trackBarSmMask.Value;
labelAmountNetID.Text = "/" + iValueSm.ToString();
for (int i = 1; i <= 32; i++)
{
rtbScroll.SelectionColor = (i <= iValueSm) ? Color.Blue : Color.Red;
rtbScroll.SelectedText = (i <= iValueSm) ? "N" : "H";
if (i % 8 == 0 && i != 32)
{
rtbScroll.SelectionColor = Color.Black;
rtbScroll.SelectedText = ".";
}
}
}
I have a combobox which has values 4-9, and according to that value I want generate runtime labels and textboxes. When I click on 6 then the code can generate 6 labels and textboxes as required, but when I click on 5 again one label and textbox should disappear or if I click on 4 again 2 labels and textboxes should disappear....which is not happening. I have this code in c#. What changes should I make in this code? Is there any other way that I can do this code?
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.Text == "4")
{
checkBox1.Visible = true;
for (int i = 0; i < 4; i++)
{
addlabel(i);
}
for (int i1 = 0; i1 < 4; i1++)
{
addlabel1(i1);
}
}
if (comboBox1.Text == "5")
{
checkBox1.Visible = true;
for (int i = 0; i < 5; i++)
{
addlabel(i);
}
for (int i1 = 0; i1 < 5; i1++)
{
addlabel1(i1);
}
}
if (comboBox1.Text == "6")
{
checkBox1.Visible = true;
for (int i = 0; i < 6; i++)
{
addlabel(i);
}
for (int i1 = 0; i1 < 6; i1++)
{
addlabel1(i1);
}
}
}
void addlabel(int i)
{
int left = 70;
int top = 100;
int step_x = 80;
int step_y = 30;
new Label()
{
Name = $"label{i}",
Text = "Enter Subject:",
Location = new Point(left, top + step_y * i),
Parent = this,
};
left += step_x;
int left1 = 357;
int top1 = 100;
int step_x1 = 80;
int step_y1 = 30;
new Label()
{
Name = $"label{i}",
Text = "Total Marks:",
Location = new Point(left1, top1 + step_y1 * i),
Parent = this,
};
left1 += step_x1;
}
void addlabel1(int i1)
{
int left = 200;
int top = 100;
int step_x = 80;
int step_y = 30;
new TextBox()
{
Name = $"textbox{i1}",
Text = "",
Size = new Size(122, 20),
Location = new Point(left, top + step_y * i1),
Parent = this,
};
left += step_x;
int left1 = 480;
int top1 = 100;
int step_x1 = 80;
int step_y1 = 30;
new TextBox()
{
Name = $"textbox{i1}",
Text = "",
Size = new Size(122, 20),
Location = new Point(left1, top1 + step_y1 * i1),
Parent = this,
};
left1 += step_x1;
}
Any Suggestions? Help me out.
Try the following code:
public partial class Form1 : Form
{
private int prev = 0;
private Point lblLocation = new Point(70, 100);
private Point tbLocation = new Point(170, 100);
public Form1()
{
InitializeComponent();
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
int cur = Convert.ToInt32(comboBox1.SelectedItem);
int tmp = cur - prev;
if (tmp > 0)
{
// add new controls
for (int i = 1; i <= tmp; i++)
{
AddLabel(prev + i);
AddTextBox(prev + i);
lblLocation.Y += 30;
tbLocation.Y += 30;
}
prev = cur;
}
else
{
// remove controls
tmp = Math.Abs(tmp);
for(int i= 0; i < tmp; i++)
{
RemoveControl($"lbl{prev}");
RemoveControl($"tb{prev}");
lblLocation.Y -= 30;
tbLocation.Y -= 30;
prev--;
}
}
}
private void AddLabel(int i)
{
new Label()
{
Name = $"lbl{i}",
Text = $"lbl{i}",
Location = lblLocation,
Parent = this
};
}
private void AddTextBox(int i)
{
new TextBox()
{
Name = $"tb{i}",
Text = $"tb{i}",
Location = tbLocation,
Parent = this
};
}
private void RemoveControl(string name)
{
foreach (Control item in Controls.OfType<Control>())
{
if (item.Name == name)
{
Controls.Remove(item);
}
}
}
}
i have a code like this:
Label[,] Cell = new Label[8, 8];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
Cell[i, j] = new Label();
Cell[i, j].Text = (i + 1) + "" + (j + 1);
Cell[i, j].Location = new Point(j * 50 + 25, i * 50 + 25);
this.Controls.Add(Cell[i, j]);
Cell[i, j].Click += new System.EventHandler(lbl_click);
}
}
public void lbl_click(object sender, EventArgs e)
{
//I want having i & j here and work with them.
}
How can I access i and j variables from within the click event handler?
Using the Tag property
One option could be to Tag the label with the data you need to use.
For example, create a class to hold the data...
class TagData
{
public int I { get; set; }
public int J { get; set; }
}
In your loop...
Cell[i, j].Tag = new TagData() { I = i, J = j };
In the event handler...
public void lbl_click(object sender, EventArgs e)
{
Label label = sender as Label;
TagData tagData = label.Tag as TagData;
// Do something with tagData.I and tagData.J
}
Parsing the label Text
If you can assume that neither i or j would be more than a single digit each, then you could simply parse the Text. Like so:
public void lbl_click(object sender, EventArgs e)
{
Label label = sender as Label;
int i = int.Parse(label.Text[0]) - 1;
int j = int.Parse(label.Text[1]) - 1;
}
NOTE: The danger with more than a single digit for each is that without a separator you could not know if "123" was i = 1 or i = 12. You could of course work around this by using a separator, for example "12,3" but I wouldn't suggest having code that relies on specific UI design/formatting.
Ok thanks to musefan here is the solution with storing the coordinates in the Tag of the label. Winforms controls got a Property called Tag where you can store related Information.
Label[,] Cell = new Label[8, 8];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
Label tempLabel = new Label();
Cell[i,j] = tempLabel;
tempLabel.Text = (i + 1) + "" + (j + 1);
tempLabel.Location = new Point(j * 50 + 25, i * 50 + 25);
tempLabel.Click += new System.EventHandler(lbl_click);
tempLabel.Tag = new Tuple<int, int>(i, j);
this.Controls.Add(tempLabel);
}
}
public void lbl_click(object sender, EventArgs e)
{
Label label = sender as Label;
Tuple<int, int> position = label.Tag as Tuple<int, int>;
if(positon != null)
{
int i = position.Item1;
int j = position.Item2;
//do whatever with the coordinates
}
}
i've been trying to modify the program so that it could accept more than one data for a single alphabet character for example letter "A". there were some sort of ContainsKey function that allow only one key from keyboard to hold only one data. how to make it possible to hold more than one data?
I'm gonna make it very clear, this is an online OCR program using unsupervised neural network. when a user draw a character in the drawing space, they will have the option to add the character into the learning data to be train later. when they add a character, they have to define what character they just entered using the key on the keyboard. for example, they draw letter 'A' and a popup window will show up asking the user to enter the key from the keyboard for that letter.
the problem here, when there is already a letter 'A' in the learning data, i cannot add another letter 'A' bcause the key A is already hold the previous 'A'. i wanted to make the key A is able to hold more than one letter 'A'.
im gonna post the whole code for the program here and i hope u guys bear with me. this isnt my program, it is from Heaton Research and i just intend to modify it. thank in advance.
public partial class Form1 : Form
{
/**
* The downsample width for the application.
*/
const int DOWNSAMPLE_WIDTH = 10;
/**
* The down sample height for the application.
*/
const int DOWNSAMPLE_HEIGHT = 12;
private Bitmap entryImage;
private Graphics entryGraphics;
private int entryLastX;
private int entryLastY;
private Pen blackPen;
private bool[] downsampled;
private Dictionary<char, List<bool[]>> letterData = new Dictionary<Char, List<bool[]>>();
private double[][] trainingSet;
private SelfOrganizingMap network;
public Form1()
{
InitializeComponent();
blackPen = new Pen(Color.Black);
entryImage = new Bitmap(entry.Width, entry.Height);
entryGraphics = Graphics.FromImage(entryImage);
downsampled = new bool[Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH];
ClearEntry();
}
private void entry_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(entryImage, 0, 0);
Pen blackPen = new Pen(Color.Black);
g.DrawRectangle(blackPen, 0, 0, entry.Width - 1, entry.Height - 1);
}
private void btnDelete_Click(object sender, EventArgs e)
{
string str = (string)this.letters.Items[this.letters.SelectedIndex];
char ch = str[0];
this.letterData.Remove(ch);
this.letters.Items.Remove(str);
ClearEntry();
}
private void btnLoad_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Data File (*.dat)|*.dat";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
TextReader f = new StreamReader(openFileDialog1.FileName);
String line;
this.letterData.Clear();
this.letters.Items.Clear();
while ((line = f.ReadLine()) != null)
{
int sampleSize = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
char ch = char.ToUpper(line[0]);
bool[] sample = new bool[sampleSize];
int idx = 2;
for (int i = 0; i < sampleSize; i++)
{
if (line[idx++] == '1')
sample[i] = true;
else
sample[i] = false;
}
this.letterData.Add(ch, sample);
this.letters.Items.Add("" + ch);
}
f.Close();
}
MessageBox.Show(this, "File Loaded");
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
private void btnSave_Click(object sender, EventArgs e)
{
try
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "Data File (*.dat)|*.dat";
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
TextWriter f = new StreamWriter(saveFileDialog1.FileName);
int size = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
for (int i = 0; i < this.letters.Items.Count; i++)
{
char ch = ((string)this.letters.Items[i])[0];
bool[] data = this.letterData[ch];
f.Write(ch + ":");
for (int j = 0; j < size; j++)
{
f.Write(data[j] ? "1" : "0");
}
f.WriteLine("");
}
f.Close();
MessageBox.Show("File Saved");
}
}
catch (Exception e2)
{
MessageBox.Show("Error: " + e2.Message, "Training");
}
}
private void btnBeginTraining_Click(object sender, EventArgs e)
{
int inputCount = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
int letterCount = this.letters.Items.Count;
this.trainingSet = new double[letterCount][];
int index = 0;
foreach (char ch in this.letterData.Keys)
{
this.trainingSet[index] = new double[inputCount];
bool[] data = this.letterData[ch];
for (int i = 0; i < inputCount; i++)
{
this.trainingSet[index][i] = data[i] ? 0.5 : -0.5;
}
index++;
}
network = new SelfOrganizingMap(inputCount, letterCount, NormalizationType.Z_AXIS);
this.ThreadProc();
}
private void btnAdd_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
String Prompt = "Enter the letter you just draw (from the keyboard)";
String Title = "Letter definition Required";
String Default = " ";
Int32 XPos = ((SystemInformation.WorkingArea.Width / 2) - 200);
Int32 YPos = ((SystemInformation.WorkingArea.Height / 2) - 100);
bool valid = false;
for (int i = 0; i < this.downsampled.Length; i++)
{
if (this.downsampled[i])
{
valid = true;
}
}
if (!valid)
{
MessageBox.Show("Please draw a letter before adding it.");
return;
}
String Result = Microsoft.VisualBasic.Interaction.InputBox(Prompt, Title, Default, XPos, YPos);
if (Result != null)
{
Result = Result.ToUpper();
if (Result.Length == 0)
{
MessageBox.Show("Please enter a character.");
}
else if (Result.Length < 1)
{
MessageBox.Show("Please enter only a single character.");
}
//else if (this.letterData.ContainsKey(Result[0]))
//{
// MessageBox.Show("That letter is already defined, please delete first.");
//}
else
{
if (this.letterData.ContainsKey(Result[0]))
{
this.letterData[Result[0]].Add(this.downsampled);
}
else
{
this.letterData.Add(Result[0], new List<bool[]>() {this.downsampled});
}
this.letters.Items.Add(Result);
//this.letterData.Add(Result[0], this.downsampled);
this.ClearEntry();
}
}
}
private void btnRecognize_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
if (this.network == null)
{
MessageBox.Show("The program needs to be trained first");
return;
}
int sampleSize = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
double[] input = new double[sampleSize];
for (int i = 0; i < sampleSize; i++)
{
input[i] = this.downsampled[i] ? 0.5 : -0.5;
}
int best = this.network.Winner(input);
char[] map = mapNeurons();
this.result.Text = " " + map[best];
MessageBox.Show(" " + map[best] + " (Neuron #"
+ best + " fired)", "That Letter You Enter Is");
//ClearEntry();
}
private void btnClear_Click(object sender, EventArgs e)
{
ClearEntry();
}
private void btnSample_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
}
public void ClearEntry()
{
Brush whiteBrush = new SolidBrush(Color.White);
entryGraphics.FillRectangle(whiteBrush, 0, 0, entry.Width, entry.Height);
entry.Invalidate();
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
}
private void entry_MouseDown(object sender, MouseEventArgs e)
{
entry.Capture = true;
entryLastX = e.X;
entryLastY = e.Y;
}
private void entry_MouseUp(object sender, MouseEventArgs e)
{
entryGraphics.DrawLine(blackPen, entryLastX, entryLastY, e.X, e.Y);
entry.Invalidate();
entry.Capture = false;
}
private void entry_MouseMove(object sender, MouseEventArgs e)
{
if (entry.Capture == true)
{
entryGraphics.DrawLine(blackPen, entryLastX, entryLastY, e.X, e.Y);
entry.Invalidate();
entryLastX = e.X;
entryLastY = e.Y;
}
}
private void sample_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
int x, y;
int vcell = sample.Height / Form1.DOWNSAMPLE_HEIGHT;
int hcell = sample.Width / Form1.DOWNSAMPLE_WIDTH;
Brush whiteBrush = new SolidBrush(Color.White);
Brush blackBrush = new SolidBrush(Color.Black);
Pen blackPen = new Pen(Color.Black);
g.FillRectangle(whiteBrush, 0, 0, sample.Width, sample.Height);
for (y = 0; y < Form1.DOWNSAMPLE_HEIGHT; y++)
{
g.DrawLine(blackPen, 0, y * vcell, sample.Width, y * vcell);
}
for (x = 0; x < Form1.DOWNSAMPLE_WIDTH; x++)
{
g.DrawLine(blackPen, x * hcell, 0, x * hcell, sample.Height);
}
int index = 0;
for (y = 0; y < Form1.DOWNSAMPLE_HEIGHT; y++)
{
for (x = 0; x < Form1.DOWNSAMPLE_WIDTH; x++)
{
if (this.downsampled[index++])
{
g.FillRectangle(blackBrush, x * hcell, y * vcell, hcell, vcell);
}
}
}
g.DrawRectangle(blackPen, 0, 0, sample.Width - 1, sample.Height - 1);
}
private void letters_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.letters.SelectedIndex >= 0)
{
string str = (string)this.letters.Items[this.letters.SelectedIndex];
char ch = str[0];
this.downsampled = this.letterData[ch];
this.sample.Invalidate();
}
}
public void ThreadProc()
{
TrainSelfOrganizingMap train = new TrainSelfOrganizingMap(
this.network, this.trainingSet, TrainSelfOrganizingMap.LearningMethod.SUBTRACTIVE, 0.5);
int tries = 1;
do
{
train.Iteration();
this.txtTries.Text = "" + tries;
this.txtBestError.Text = "" + train.BestError;
this.txtLastError.Text = "" + train.TotalError;
tries++;
Application.DoEvents();
} while (train.TotalError > 0.01 && (tries <= 100));
MessageBox.Show("Training complete.");
}
/**
* Used to map neurons to actual letters.
*
* #return The current mapping between neurons and letters as an array.
*/
public char[] mapNeurons()
{
char[] map = new char[this.letters.Items.Count];
for (int i = 0; i < map.Length; i++)
{
map[i] = '?';
}
for (int i = 0; i < this.letters.Items.Count; i++)
{
double[] input = new double[Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH];
char ch = ((string)(this.letters.Items[i]))[0];
bool[] data = this.letterData[ch];
for (int j = 0; j < input.Length; j++)
{
input[j] = data[j] ? 0.5 : -0.5;
}
int best = this.network.Winner(input);
map[best] = ch;
}
return map;
}
}
Dictionary<> is created in a such way that you can access Key Value pair in most efficient way. Now in Dictionary<> you can not have two pairs with same key. To do so,
what you can do, you create a dictionary like Dictionary<char, List<bool[]>>, now in this dictionary you can store one key with more than one value.
Update
If you change the dictionary to Dictionary<char, List<bool[]>> then to store one key with more than one value you will have to as follows
private bool[] downsampled;
private Dictionary<char, List<bool[]>> letterData = new Dictionary<Char, List<bool[]>>();
//
// Your Code
//
if (Result != null)
{
Result = Result.ToUpper();
if (Result.Length == 0)
{
MessageBox.Show("Please enter a character.");
}
else if (Result.Length < 1)
{
MessageBox.Show("Please enter only a single character.");
}
else
{
if (this.letterData.ContainsKey(Result[0]))
{
this.letterData[Result[0]].Add(this.downsampled);
}
else
{
this.letterData.Add(Result[0], new List<bool[]>() { this.downsampled });
}
this.letters.Items.Add(Result);
this.ClearEntry();
}
}
If you want to string as key, instead of char, use Dictionary<string, List<bool[]>>.
Hope this answers your question.
Take a look at the Lookup class in .Net. This lets you have the same "key" value multiple times.