Pages

Subscribe:

Ads 468x60px

Monday, 12 September 2011

Puzzle Control

In this application I had combined the power of C# and AI in order to solve the "puzzle problem".

I created a puzzle control which can be personalized. One can specify the number of lines and columns of the puzzle, the puzzle color, the numbers font.




The advantage of a control is that it can be hosted by a form or by InternetExplorer. The algorithm used to solve the puzzle problem is BeamSearch (the euristic function is the straight line distance).
I developed a class PuzzleControl : Control which contains a set of properties which allow to personalize the puzzle as shown in the figure above.
public int Linespublic int Columnspublic Size SquareSizepublic int PenWidthpublic Color PenColorpublic int BorderWidthpublic Color BorderColorpublic Font NumberFontpublic Color NumberColor
As I mentioned before, I used BeamSearch algorithm to find the solution of the puzzle(the sequence of moves to get to final state). Initially, I used A* algorithm but it wasn't the best solution because of memory requirement.

A variable "Queue" is used to record unexpanded nodes. I limited the size of "Queue" (the best 20 nodes) in order to save memory. A node contains the state of puzzle ( a matrix with the numbers) and a list of moves (moves of blank) that have been done to that state.
The PuzzleControl includes operations such as: Init, Shuffle(right click on the control), Solve and StopSolve. So, the puzzle can be solved by a human player or by computer. If someone try to resolve the puzzle and need some help, he can ask computer and after a couple of help moves he can select "Computer-> Stop" from menu and continue resolve the puzzle by himself.

Note 1 : In order to move a piece of the puzzle, click the left button of the mouse on the surface of that piece. The piece will change the place with the blank. Only the pieces next to the blank can be moved.

Note 2 : Sometimes it will take more to resolve the puzzle (for the computer), because of the large number of moves that need to be done to the final solution.
Shuffled puzzle

Lingo Game in C#

It is a Lingo game developed in C#. It is based upon Game Show Network's Lingo but has a few modifications to it.

chessy Online Game

Introduction:    
The attached project is a chess game that can be played by two users online as well as on the network. This game is being developed using GDI+, multithreading, and networking classes provided by the .NET Framework class library.


Move the pieces by dragging and dropping the pieces.   



Memory Game Programming




Introduction:
This is a memory game where you can use your favorite pictures (.bmp, jpg, gif). Therefore you specify the directory/ies where the desired images are contained in the settings (Settings/Customize../Add). You can also make some other customizations like how many cards are displayed on the screen, or how the pictures are rendered (clip off an area to fit into the cards or stretch/shrink them). To start the game, choose One or Two Player Game in the Game menu (F1 or F2)
Classes:
GameForm.cs .. 

contains the Game Panel and the main code for playing.. For displaying the cards i used normal buttons which are created dynamically (the number is specified in settings).. There are timers for delays (eg. showing a card for about one second when it is opened).. When a new game is started, it selects randomly pictures from the specified directory/ies and loads it using the ImageContainer class
ImageContainer.cs ..

For loading the images on start and storing it in an array. I have implemented three modes for loading..

AddImageClipped .. an area of button size is cut out of the picture.. therefore i used native calls to demonstrate Windows GDI calls in C# (although i'm sure there is a simpler function somewhere in GDI+ which does the same).. the code for clipping is in ClipImage:
private Image ClipImage(Image source, int nDestWidth, int nDestHeight, int x, int y) 
{
Image image;
Bitmap bitmap;
int hbitmap1, hbitmap2; int hDC1, hDC2, screenDC; int res;// Convert a loaded image object to a 32 bit handle in order to use it with GDIbitmap = (Bitmap)source;
hbitmap1 = (
int)bitmap.GetHbitmap(); // Create compatible (memory) device contextshDC1 = CreateCompatibleDC(0);
res = SelectObject(hDC1, hbitmap1);
hDC2 = CreateCompatibleDC(0);
screenDC = GetDC(0);
// Create target bitmap (in memory)hbitmap2 = CreateCompatibleBitmap(screenDC, nDestWidth, nDestHeight);
res = SelectObject(hDC2, hbitmap2); 
// Copy from source device context to target device contextres = BitBlt(hDC2, x, y, nDestWidth, nDestHeight, hDC1, 0, 0, SRCCOPY);// Convert back 32-bit handle to imageimage = Image.FromHbitmap(new IntPtr(hbitmap2));// Free resourcesres = DeleteObject(hbitmap1);
res = DeleteObject(hbitmap2);
res = DeleteDC(hDC1);
res = DeleteDC(hDC2);
res = ReleaseDC(0, screenDC);
// new Image objectreturn image;
}

AddImageStretched .. the source picture 
is stretched or shrinked to button size before it is added to the ImageContainer this i have implemented with GDI+ and it looks much simpler then AddImageClipped
destImage = 
new Bitmap(destWidth, destHeight); // create new bitmap in memory with button width/heightg = System.Drawing.Graphics.FromImage(destImage); // get a drawing context from this bitmapg.DrawImage(source, 0,0,destWidth, destHeight); // draw the source image into target bitmap, impicitly stretching it to its sizedata.Add(destImage); // add to my image container
AddImageStretched with aspect ratio.. 
this is intended to remain the relationship between width and height, but it does look strange with some pictures (don't know why)
Player.cs .. just stores some information about the current player
Settings.cs .. its a serializable 
class to store the customizations you made.. it is used by GameForm to determine which directory/ies to use etc. Loading and Saving works with an object stream:
public static Settings Load(string path) 
{ 
try 
{
FileStream s = 
new FileStream(path, FileMode.Open);
IFormatter f = 
new BinaryFormatter();
Settings loadedSettings = f.Deserialize(s) 
as Settings;
s.Close();
return loadedSettings; 
}
catch (FileNotFoundException e) 
{
string fault = e.GetBaseException().ToString();return new Settings();
} 
}
public bool Save(string path)
{
try 
{
FileStream s = 
new FileStream(path, FileMode.Create);
IFormatter f = 
new BinaryFormatter();
f.Serialize(s, 
this);
s.Close(); 
return true;
}
catch (IOException) 
{
return false;
}
}
SettingsForm.cs .. the form where you can make your customizations.. Uses a settings-object to get the settings from a file and store it back. it also calls the DirectoryForm when you choose the Add or Change button
DirectoryForm.cs .. A directory dialog to choose a directory from a local drive.. I have used a tree list view for displaying the directories (i thought it would be better to implement my own dialog because i did not find a DirList control like I knew it from VB6)
Used:
I used Visual Studio. NET Beta 2 for developing it, but recompiled it under Visual Studio.NET Final (the source is compatible with both versions, but the .exe runs only under the final version)
Have fun..

Shuffle Game for Beginners



This code sample is a GDI+ shuffle game aimed for beginners. Attached zip file includes the exe and the Shuffle.cs file. 



using System; using System.Drawing; using System.WinForms; using System.Collections; namespace ShuffleGame 
{ 
public class Shuffle:Form 
{ 
private Label lbl1= new Label(); private Label lbl2= new Label(); private Label lbl3= new Label(); private Label lbl4= new Label(); private Label lbl5= new Label(); private Label lbl6= new Label(); private Label lbl7= new Label(); private Label lbl8= new Label(); private Label lblBlank= new Label(); private int[,] pos= {{0,0,0},{0,0,0},{0,0,0}}; private int ar,ac; private int Hits; private Label lblHits = new Label(); private Hashtable value = new Hashtable(); public static int Main(string [] args) 
{ 
Application.Run(
new Shuffle()); return 0; 
} 
public Shuffle() 
{ 
ar=2; 
ac=2; 
Hits=0; 
this.Text="Shuffle Game"; this.BackColor=Color.RoyalBlue; this.Size=new Size(310,370); 
lbl1.Text="1"; 
//lbl1.Location=new Point(0,0); lbl1.BackColor=Color.LightGray; 
lbl1.Size= 
new Size(90,90); 
lbl1.Font=
new Font("Times New Roman",14); 
lbl2.Text="2"; 
//lbl2.Location=new Point(100,0); lbl2.BackColor=Color.LightGray; 
lbl2.Size= 
new Size(90,90); 
lbl2.Font=
new Font("Times New Roman",14); 
lbl3.Text="3"; 
//lbl3.Location=new Point(200,0); lbl3.BackColor=Color.LightGray; 
lbl3.Size= 
new Size(90,90); 
lbl3.Font=
new Font("Times New Roman",14); 
lbl4.Text="4"; 
//lbl4.Location=new Point(0,100); lbl4.BackColor=Color.LightGray; 
lbl4.Size= 
new Size(90,90); 
lbl4.Font=
new Font("Times New Roman",14); 
lbl5.Text="5"; 
//lbl5.Location=new Point(100,100); lbl5.BackColor=Color.LightGray; 
lbl5.Size= 
new Size(90,90); 
lbl5.Font=
new Font("Times New Roman",14); 
lbl6.Text="6"; 
//lbl6.Location=new Point(200,100); lbl6.BackColor=Color.LightGray; 
lbl6.Size= 
new Size(90,90); 
lbl6.Font=
new Font("Times New Roman",14); 
lbl7.Text="7"; 
//lbl7.Location=new Point(0,200); lbl7.BackColor=Color.LightGray; 
lbl7.Size= 
new Size(90,90); 
lbl7.Font=
new Font("Times New Roman",14); 
lbl8.Text="8"; 
//lbl8.Location=new Point(100,200); lbl8.BackColor=Color.LightGray; 
lbl8.Size= 
new Size(90,90); 
lbl8.Font=
new Font("Times New Roman",14); 
lblBlank.Location=
new Point(200,200); 
lblBlank.Size=
new Size(90,90); 
PlaceRandom(); 
lblHits.Location=
new Point(0,310); 
lblHits.Text="Hits so far ---> " +Hits.ToString(); 
lblHits.BackColor=Color.LightGray; 
lblHits.Size=
new Size(350,40); this.Controls.Add(lbl1); this.Controls.Add(lbl2); this.Controls.Add(lbl3); this.Controls.Add(lbl4); this.Controls.Add(lbl5); this.Controls.Add(lbl6); this.Controls.Add(lbl7); this.Controls.Add(lbl8); this.Controls.Add(lblHits); this.Controls.Add(lblBlank); this.MouseDown += new MouseEventHandler(Win_Click); this.KeyDown+=new KeyEventHandler(Win_KeyDown); 
} 
private void Win_Click(Object sender, MouseEventArgs e) 
{ 
Random rnd=
new Random(); 
MessageBox.Show(rnd.Next(8).ToString()); 
MessageBox.Show("Hello"); 
} 
private void Win_KeyDown(Object sender, KeyEventArgs k) 
{ 
int temp; switch(k.KeyCode.ToInt32()) 
{ 
case 38: //"Up" if(ar<2) 
{ 
temp=pos[ar,ac]; 
pos[ar,ac]=pos[ar+1,ac]; 
pos[ar+1,ac]=temp; 
Swap(pos[ar,ac],temp); 
ar++; 
Hits++; 
} 
break; case 37: //"Left" if(ac<2) 
{ 
temp=pos[ar,ac]; 
pos[ar,ac]=pos[ar,ac+1]; 
pos[ar,ac+1]=temp; 
Swap(pos[ar,ac],temp); 
ac++; 
Hits++; 
} 
break; case 39: //"Right" if(ac>0) 
{ 
temp=pos[ar,ac]; 
pos[ar,ac]=pos[ar,ac-1]; 
pos[ar,ac-1]=temp; 
Swap(pos[ar,ac],temp); 
ac--; 
Hits++; 
} 
break; case 40: //"Down" if(ar>0) 
{ 
temp=pos[ar,ac]; 
pos[ar,ac]=pos[ar-1,ac]; 
pos[ar-1,ac]=temp; 
Swap(pos[ar,ac],temp); 
ar--; 
Hits++; 
} 
break; 
} 
lblHits.Text="Hits so far ---> " +Hits.ToString(); 
Boolean same=
true; 
String arrEle=""; 
for(int ctr=1,i=0;i<3;i++) 
{ 
for(int j=0;j<3;j++,ctr++) 
{ 
/*if(j==2 && i==2) 
{ 
if(pos[i,j]==0) 
same=true; 
break; 
} 
else if(pos[i,j]!=ctr) 
{ 
same=false; 
break; 
}*/
 if(pos[i,j]!=ctr) 
{ 
same=
false; break; 
} 
arrEle=arrEle+"\t"+pos[i,j]; 
} 
arrEle=arrEle+"\n"; 
} 
if(same) 
{ 
MessageBox.Show("You have finished the game in " + Hits.ToString() + " hits","End of Game",2); 
} 
} 
private void Swap(int vNum, int blank) 
{ 
Point temp; 
switch(vNum) 
{ 
case 1: 
temp=lbl1.Location; 
lbl1.Location=lblBlank.Location; 
lblBlank.Location=temp; 
break; case 2: 
temp=lbl2.Location; 
lbl2.Location=lblBlank.Location; 
lblBlank.Location=temp; 
break; case 3: 
temp=lbl3.Location; 
lbl3.Location=lblBlank.Location; 
lblBlank.Location=temp; 
break; case 4: 
temp=lbl4.Location; 
lbl4.Location=lblBlank.Location; 
lblBlank.Location=temp; 
break; case 5: 
temp=lbl5.Location; 
lbl5.Location=lblBlank.Location; 
lblBlank.Location=temp; 
break; case 6: 
temp=lbl6.Location; 
lbl6.Location=lblBlank.Location; 
lblBlank.Location=temp; 
break; case 7: 
temp=lbl7.Location; 
lbl7.Location=lblBlank.Location; 
lblBlank.Location=temp; 
break; case 8: 
temp=lbl8.Location; 
lbl8.Location=lblBlank.Location; 
lblBlank.Location=temp; 
break; 
} 
} 
private void PlaceRandom() 
{ 
int r,c; 
r=10;c=10; 
int i=0; 
ar=0; 
ac=0; 
Random rnd= 
new Random(); int val; while(i<8) 
{ 
val=rnd.Next(9).ToInt32(); 
if(numNotExists(val)==true && val>0) 
{ 
pos[ar,ac]=val; 
switch(val) 
{ 
case 1: 
lbl1.Location=
new Point(c,r); break; case 2: 
lbl2.Location=
new Point(c,r); break; case 3: 
lbl3.Location=
new Point(c,r); break; case 4: 
lbl4.Location=
new Point(c,r); break; case 5: 
lbl5.Location=
new Point(c,r); break; case 6: 
lbl6.Location=
new Point(c,r); break; case 7: 
lbl7.Location=
new Point(c,r); break; case 8: 
lbl8.Location=
new Point(c,r); break; default: 
} 
c+=100; 
ac++; 
if(ac>2) 
{ 
ac=0; 
ar++; 
} 
if(c>300) 
{ 
c=10; 
r+=100; 
} 
i++; 
} 
else continue; 
} 
lblBlank.Location=
new Point(c,r); 
pos[2,2]=9; 
} 
private Boolean numNotExists(int num) 
{ 
for(int i=0;i<3;i++) for(int j=0;j<3;j++) 
{ 
if(pos[i,j]==num) return false; 
} 
return true; 
} 
} 
}