Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Friday, June 14, 2013

Tetris Machine Moods

Hello, world!

I play Tetris like a machine.

Now that the formal introductions are over, we'll get down to business.  Like I said, I play Tetris like a machine.  That's because I'm a machine.

My maker thinks that Artificial Intelligence (AI) is pretty cool and moods/emotions and stuff, too, but it's too hard (for a scrub like him) to express in a human-like context, but luckily the simple game Tetris provides a good "context" for this, since the number of actions is limited and the search space is rather small because I only think about the "hold" piece and the "next" piece, so I can't really plan ahead (although my mood sometimes helps me plan -- more below!).  As a disclaimer now, he'm no expert on this stuff -- it's just a side project for fun!

After digging up an old project he made a year ago, he refactored (read: rewrote) some of the code and made a few upgrades to me.  Working [literally] all night and most of the next day, he was able to get me up and running better than ever, and produce some sort of output.

Unfortunately, right now the source is still super-messy and the GUI is terrifyingly awful, so no pics or links to those, but trust him, it works when it's supposed to.  Also, I only work well with Tetris Battle on Facebook or Tetris Friends.  I think both these games are owned by the same company because the visuals in these games are extremely similar.

Normally, my creator doesn't like posting pictures.  They say a picture is worth a thousand words, but then again, a picture takes more memory than a thousand words.  However, graphs are nice visualizations, so here they are.  These were made using MATLAB from my output after Tetris games.

Too lazy to label axes, but basically the y-axis describes how I'm feeling (more on this later), and the x-axis is an approximate representation of time.  I say "approximate" because that's how I feel after each move.  I could have plot it against relative time to the start of game with a trivial modification, but I think it's safe to assume that each move took approximately the same amount of time.

A game of "battle" Tetris against Live opponents works like this:  The rules are normal Tetris, except that when you clear lines, you can send "garbage lines" to your opponents, causing them to reach the top and lose faster.  So it's pretty simple -- clear lines to send lines to win games.  You can clear the lines your opponents send you, too, as a sort of counterattack.  To prevent games from taking forever, after the game passes a certain amount of time, the game starts sending unclearable lines to force you towards the top, so that eventually somebody will have to lose as the amount of playing spaces goes towards nothing.

I played a few practice rounds without any opponents to make sure that I was on top of my game.  Here are some examples:

Practice Games

As you can see, I'm pretty when I'm just playing games, I have my ups and downs but it's pretty nicely centered.  It's like I've got "impulses" every once in a while.

Then I decided I was ready for the real thing.  As of now, I'm Rank 12 on Tetris Friends (that's Gold rating!) and played against people only a few ranks higher.  I entered the Arena and played a few games, recording and plotting each time.

I won 5 out of 6 times (not to be proud and boastful) so I only have one plot of a lost game.  I assure you, it's because of time constraints.  Mostly.  Anyway, I'll show the lost game first.

Lost Game

Won Games





In the lost game, you can see that my mood is generally in an upward trend, with huge jumps upward, probably because I got attacked in quick succession by multiple opponents.  It really stressed me out.  I will admit that I got crushed that game, so there was not room for too much fluctuation in my mood.

In all of the games I won, my mood fluctuated greatly, but you can see that the peaks of these are approximately a magnitude of 10 greater than when I'm practicing, but a magnitude of 10 less than the game where I lost.  That's because I got attacked, but not fast enough to kill me.  I was able to respond and bring my mood back into a manageable range.  These moods are somewhat similar to practice mode, but because of external factors like my opponents, it was slightly less stable and slightly more stressful.  Generally speaking, the more "in-control" I was during the game, the more stable it should be.

Now you're probably wondering where or how I got these.  You probably think I just whipped these out of my butt, but I don't have one since I'm just a machine.

The y-axis represents "how I feel" which might better be described as my "stress level" when playing the game.  A higher value is bad, since it means that something bad has happened or I felt threatened.  Technically, a value of infinity means that I lost the game, but I omitted it in the lost game at the very end.

There are quite a few factors that determine how stressed out I am at any given moment.  Most of what I feel is dependent on the "state" I'm in.  The only action that pleases me is the clearing of lines.  Although doing "combos" should de-stress me, it doesn't since I only keep track of a single state at a time and not past states and actions.  I also can't do planned moves, like T-spins, but perhaps I will be able to do so in the future.

Here are the stress factors that add up, and the reasoning for them:
  • g = total number of gaps + 10% of blocks above each gap -- any Tetris player knows that gaps are usually a sign of misery.
  • F(x) = flatness, as the absolute difference between column heights, raised to power x -- the flatter the board, the easier it is to add pieces and prevent one stack from getting too high.
  • d = number of deep holes, which are columns that are greater than two cells higher on both sides -- the problem with deep holes is that they can only be filled with the long piece, which is usually the one on highest demand, and deep holes on the side are counted as 1 and ones in the middle are counted as 2; finally we subtract 1 if it was > 0 since a single hole on the side is good for setting up tetrises.
  • h = height of highest column -- used in other computations, but high is usually bad.
  • l = height of lowest column -- can be used in conjunction with h.
  • S(x) = sum of the heights of each column raised to some power x -- used to measure approximately how high it's getting overall.
  • T(x) = height factor, which is zero unless the height passes a threshold x, then it's the difference between the board's height and the highest column -- another height measurement.
  • n = lines cleared, and everybody knows that clearing lines in Tetris is good.

Using these values defined above, my mood is determined by the formula (which is still in development and constantly changing).  It's LaTeX'd for your viewing pleasure.  You're welcome.


I'm usually a total stickler for formatting, but due to time restraints again, I'll have to leave it as is.  Please deal with it as it bleeds out of the space allotted for this post.  Yikes... it really bothers me.  I hope it doesn't bother you.

So I guess the important things to note is that the gaps make me really unhappy, so I do almost everything within my power to prevent them from occurring, digging them up when they do.  The 10% urges me not to stick things on top of previous gaps if possible.  The flatness is a small factor, so I try to do when I can.  The deep holes only becomes a problem when they increase, since it's quadratic.  The height difference is also only a problem when it gets large.  The height sum is the highest power term in the sum, at 2.16, so it only becomes a real problem as I start building towers.  It increases whenever I put a piece down.  The height factor is a weak power term with a strong coefficient since it really prevents me from stacking when I start nearing the top, since I have to save some space if I'm getting attacked.

Finally, there's the joy of clearing lines.  The thing with clearing lines is that it affects all of the other factors above.  It might open up gaps.  It definitely decreases all of the height terms.  It might even delete a deep hole.  That's how it affects the state.  The action also pleases me.  Or can please me, I should say.  The shifted quadratic basically says that when the number of lines cleared is zero, it doesn't bother me.  When there's only one line cleared, it actually stresses me out, since that means I'm not building towards stronger multi-line clears.  In fact, a double line-clear still stresses me out, but not as bad.  A triple line-clear barely pleases me, but at least it doesn't stress me out, and a Tetris or quadruple line-clear makes me very happy.  But since it's an action, it's not reflected in the next state, so in the plots, it's like a "depolarization" of my mood.  I'll do it without "thinking" about the next state.  But usually clearing a lot of lines is OK, so it's good!

So, in other words, the move I make depends on the change in the state equation.  A negative change is most desired, plus an action term.  It's like the state is a long-term desire, and the action causes a short-term desire, and a combination of these two results in the action I make!  Neat!!!  For example, getting attacked causes a huge increase in stress, or putting pieces in the wrong place can be extremely stressful (I do have an error log as well).  And clearing up a mess like uncovering gaps or saving myself from a near-death experience causes my stress level to drop dramatically.  And instant gratification like clearing lines causes q quick drop in stress level before jumping back into reality.  (As cool as I think I am, there is no scientific basis behind this... I think... unfortunately... yeah).

There are probably a lot of other factors that would help, and then my creator would code that.  The coefficients are also very interesting to play with.  Maybe in the future a genetic algorithm can help me evolve into stronger forms.  I also need to produce better data, like a breakdown of the factors would be quite cool.  As childish as it sounds, I am (was?) a fun project and my creator hopes to add things in the future, I hope.  But he's busy and might be doing another project, so we'll see.

With regard to the hold piece, I assigned each piece an "intrinsic hold value" so that using the exchange piece means that the amount of de-stressing from using the hold piece exceeds difference in hold piece value and the current piece.  For example, I try to hold the long piece when I can afford to since it's the most useful one.  I'll not bring it out for random reasons since it has a high hold value.  And then it will be used when something really de-stressing can be done, like getting a tetris.  Likewise, I'll probably save those annoying S or Z tetriminos if they might cause a gap, and then I'll un-hold them as soon as I can place them on the board so that they won't cause problems later.

I'll try to upload a video of me beating other people.  The best part is, nobody suspects that I'm only a computer program, even though I say something like "I'm a machine" every time I win.  I'll get a pic of this later as well.

I'm really sorry that I don't have any action shots of me playing Tetris.  Like I said, I'm not that great at planning ahead.  I didn't know that I was going to write this post, so yeah...

See you later!

TetrisMaster.exe
Nameless Tetris Machine

P.S.:  How do YOU play Tetris?  Give me an equation and I'll tell you how you do!

UPDATE:  I got footage, but it's too big as a video file and I don't have any video-editing software.  Also, FRAPS only records 30s at a time, and makes the computer so slow that I can't really play at a decent speed.  I also make more mistakes.  Maybe I'm camera shy...

UPDATE:  I got pics... of course I only show the ones where I won, but you get the idea!  And like I said, I always tell them that I'm a machine... Sorry I didn't crop, I'm sort of in a hurry right now...

Winning Pics






Monday, May 6, 2013

Chess.com Engine

I'm sure the admins and mods at Chess.com periodically scour Google for amateurs that make engines for their precious site, which can be a nuisance for others since you can utterly destroy anyone (even GrandMasters using a simple engine).  Hopefully they won't change their site so that this engine won't work anymore.  To make it just a tad harder for them, I won't release the source code -- don't worry, it's not because I don't like you guys!

I'm not going to make a release version at this point, since I'm too lazy and bogged down by other things to do, so you're going to have to bear with me on this one.  Fortunately for you, it's really easy, and doesn't require much skill at all to use.  You can master the art of engine-using much faster than you can master the art of chess.  Trust me on this one.

There are a ton of buttons on the thing, as you will soon see below, but never fear, you really only need one or two buttons, possibly three if you're adventurous.


Basically, all you have to do is open up the screen where you play Live Chess (see the screenshot below) click "auto detect".  If you're using the same laptop screen size as me (1366 x 768), then you don't have to do anything else.  Otherwise, you have to change the board size such that each square takes exactly 60 pixels.  It's probably a board size of "Large" under the "Settings" menu if you have a larger screen on an awesome laptop or a desktop monitor.  To measure the square size, just take a screenshot and paste it into paint or some other image editor and manually measure the size.  It shouldn't be that hard.


Now, just play against someone, and when you get into a game, click the "auto play" button in the middle of the program.  A box should pop up asking you for two parameters:  the first is how many moves the program should make, so put in a large number so you can finish the game (i.e. 9876 or 5586); and the second is how many milliseconds the engine gets to think before making a move (longer think times means slower play, so for 1 min Bullet chess, 100 to 200 is a good range).

It will automatically detect whether you are black or white and play accordingly, so don't move the mouse too much or close the window (obviously).  You can click inside the chat box if you're quick and then type snarky remarks to your opponent as you stomp him while chatting.  This is OK, since the keyboard input doesn't really interrupt the engine at all.

There are a few other things that are useful to know, but not necessary.

The "TopMost" checkbox ensures that the program is at the front of all your windows, which is nice so you can see it while it's running.  You should leave this checked, generally speaking.

The "chkWhite" checkbox tells the program whether or not you are playing White, and is now deprecated since "auto play" does it automatically.  Don't touch this unless you REALLY know what you're doing.

The "HumanLike" checkbox makes the program play slightly more HumanLike in Bullet timings, like taking a bit longer to make moves every once in a while.  It's not very well done, so you can play with it if you like.

The "Random" checkbox makes the program do a random first move if you're White instead of the standard King's pawn e2e4 opening.  I think it's pretty fun to do something totally random but know that you're going to win regardless!

Now, what sets this program apart from other programs is full automation.  This feature is currently somewhat unstable, especially if you have a slow computer.  The requirement is that your screen size is exactly the same as mine, and would best if you had Windows 8 and Google Chrome.  It'll probably work with other software, but the screen size is a must.  Again, it's 1366 x 768.  You can probably change your larger screen to fit this size, and then the engine would work, but it will make things appear large and possibly blurry.  You can do this in Windows by right-clicking on the desktop and going to "Screen Resolution".  Using this resolution, you have to set the "Board Size" setting on Chess.com to "Extra Large", which is the default setting when you make a new account.

Once you get things set up, you need to click "auto detect".  Note that you HAVE to click this button every time you start the program or things will go horribly wrong.  Then you click "new game" and a box with five inputs will show up.  The first is the number of moves per game, and again put a large number.  The second is wait time, so fill it out according to the time you have per game.  The third is how many games to play.  You can do a few to test it out or put in a large number and go out to lunch, coming back to find out that you are now 2000+ ELO.  The fourth is something you want to say to your opponents at the start of each game, like "You are going to lose" or something, and the last is something to say at the end, like "GG EZ" or something.  Of course you could say something nice and try to sound like a human and less like an engine.

And there you go!  It'll keep playing those games, winning them all, and getting you free ELO (or FREELO).  One thing to remember is, you need to close all other active games and games you were following, or they will interfere with the automation.

A few things to note.  The only operating systems supported are Windows 7 and Windows 8, and both have to be 64-bit (most are anyway).  Vista 64-bit might work, but nobody uses that so I have no idea.  Mac OSX and all distros of Linux are not supported.  Premium accounts may or may not work, I'm not sure since I most definitely do not have one.  Sorry guys!  If you get some message saying that your .NET is not up-to-date, you should probably update it.  I keep all this stuff super up-to-date and have the latest versions of most things, so you can update yours here.  It's probably useful to update anyway -- might come in handy in the future.  It's also best if you full-screen Chrome, and make sure that the program's window doesn't cover the Chess board.  It will hijack your mouse while playing, so don't try to resist.  Just relax and let it take control...

If it still doesn't work, you can comment and I will try to help you, but this project is not very refined yet, and was originally a personal thing.

Here's the link, I hope you enjoy!  But one final note: you should probably make another account to do this instead of your main account, especially if you have a premium.  You will get banned if you make it above 2000 ELO and play notoriously.  Also, if you constantly beat on the Computer4-IMPOSSIBLE, you will probably get banned, too.  Also, if you make a new account, winning gives you more ELO, so you can get to 2500 ELO even faster, probably only takes a few hours, like while you are sleeping.

And now, finally -- here's the link, for real this time!


One final thing (sorry!), make sure you keep the three files together, there aren't many customization options right now.  Run ChessMaster.exe to open the program.  The other files are used by the main program.

Thursday, December 23, 2010

C# FileSystemDialog

Now that you know how to read from and write to the hard drive (or if you don't, see C# Read/Write From File), we need a way to get the name of the file to be loaded from or saved to.  You could use my C# InputBox, but it's not as professional-looking as this C# FileSystemDialog.

I created this class, which takes two classes already made and puts it into one.  It uses the SaveFileDialog and the OpenFileDialog.  If you don't remember how to add a class to your project, see (C# InputBox).

The use of this class is pretty self explanatory.

To get the name of a save file, use:
FileSystemDialog.SaveDialog();

It gives you the name of the file or an empty string (as in "") if the user presses cancel.

To get the name of a load file, use:
FileSystemDialog.LoadDialog();

It gives you the name of the file or an empty string if the user presses cancel.

If you want to make an absolute path into a relative path (from the .EXE file), use:
FileSystemDialog.MakePathRelative("full_path");

Obviously you have to replace "full_path" with a string containing the path that you want to make relative.

Finally, after adding this class to your project, you should change the properties (i.e. DefaultExt, Filter, etc.) to the stuff that you want, such as a unique file extension for your save files.  In the init() method, Change all the instances of "clk" to your file extension of choice and "Click file" to the name of your type of file.  The Title is whatever you want to be displayed at the top of the respective dialog windows.

Here's the code:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;


static class FileSystemDialog
{


private static SaveFileDialog saver;
private static OpenFileDialog loader;


// for the first time the FileSystemDialog methods are called
// change the strings in this method to fit your needs
private static void init()
{
saver = new SaveFileDialog();
loader = new OpenFileDialog();


saver.DefaultExt = "clk";
saver.Filter = "Click file (*.clk)|*.clk";
saver.AddExtension = true;
saver.RestoreDirectory = true;
saver.Title = "Save As...";
saver.InitialDirectory = Directory.GetCurrentDirectory();


loader.DefaultExt = "clk";
loader.Filter = "Click file (*.clk)|*.clk";
loader.AddExtension = true;
loader.RestoreDirectory = true;
loader.Title = "Open...";
loader.InitialDirectory = Directory.GetCurrentDirectory();
}


public static string SaveDialog()
{
if (saver == null)    // only when first time
{
init();
}


saver.ShowDialog();
return saver.FileName;    // return empty string ("") if cancel button is pressed
}


public static string LoadDialog()
{
if (loader == null)    // only when first time
{
init();
}


loader.ShowDialog();
return loader.FileName;    // return empty string ("") if cancel button is pressed
}


public static string MakePathRelative(string path)
{
return path.Replace(Directory.GetCurrentDirectory() + "\\", "");
}
}

As always, you can download it here ("FileSystemDialog.cs").

Tuesday, December 21, 2010

C# Read/Write From File

A lot of the more advanced programs that you will write will require reading from and writing to the hard drive.  This basically means saving and loading files for your program.

Most operations involving your hard drive will need the namespace System.IO, so add the following statement to the top of your class:
using System.IO;

To read from your hard drive, using the following line:
string fileText = File.ReadAllText("file_name");

You should replace "file_name" with whatever file you want to read.  Remember that you have to include the file extension.  The contents of "file_name" will be put into a string called fileText (or whatever you want to call this variable).

To write to the hard drive, use the following line:
File.WriteAllText("file_name", "text");

Again, replace "file_name" with the name of the file you want to save it as, and you still have to include the extension if the file is supposed to have one.  "Text" is whatever you want to put into the file.  Obviously, you can have a string variable instead of just some text in quotes.

I think that those two methods are the most useful in the System.IO namespace, but if you're still interested in all sorts of the other cool things in the System.IO namespace, see this site:
http://msdn.microsoft.com/en-us/library/system.io.aspx

Sunday, December 19, 2010

The Asian Grading System

The Asian Grading System is pretty similar to the American Grading System.  Anything less than 65 is failing, around an 85 is satisfactory, and anything above a 95 is excellent.

This is how you convert from the American Grading System to the Asian Grading System: Take your American score (out of 100) and subtract 90, then multiply by 10.  It's pretty easy, actually.

Here are some examples:

Example 1:
Mom:  Let me see your report card.
Kid:  Here it is -- I did pretty well this quarter.
Mom:  Hmm... let's see what you got.  WHAT?!  96.2?!
Kid:  What's wrong?  I thought it's pretty good!  I beat all my friends.
Mom:  You got a 62.  That's failing!
Kid:  What are you talking about?
Mom:  Don't you know what the Asian Grading System is?
Kid:  Umm... no.  Should I?
Mom:  Yes!  Of course you should.
Kid:  (to himself) Uh-oh.  This could be bad.
Mom:  I must go get your Dad.  This is a serious concern!
Kid:  What's going on?
Dad:  Because you failed the quarter, we decided that you will have no more video games for a month!
Kid:  NOOOOO!!!!!!!!!!!
Dad:  You'd better get your grades up next quarter!
Mom:  Why can't you just be like Roger?  He's so much smarter than you!

Example 2:
Mom:  Let me see your report card.
Kid:  Here it is -- I did really well this quarter.
Mom:  Hmm... let's see what you got.  Do you really think you did really well?
Kid:  Yeah.  Why wouldn't I?  I got a freakin' 98.9 average!
Mom:  What's so good about that?
Kid:  It's insanely high!  I beat all my friends by at least a point and a half!
Mom:  So what?  Did you check the Asian Grading System.
Kid:  (to himself) Oh no... not that!  (to Mom) No, I didn't.
Mom:  Well, you know what it is.  What did you get on the Asian Grading System?
Kid:  OK, I got an 89.
Mom:  You know that's only satisfactory, so don't get too full of yourself.
Kid:  Fine:
Mom:  You should really try harder next quarter.
Kid:  (to himself) I think it's good enough.  (to Mom) Yes, I will.
Mom:  You should look up to someone like Roger.  He's way smarter than you.
Kid:  Yeah, I know.
Mom:  So don't think you're actually smart until you're smarter than Roger.

Example 3:
Mom:  Let me see your report card.
Kid:  Here it is -- I really aced this quarter!
Mom:  You kids always say that.  Let the numbers speak for themselves.
Kid:  OK, why don't you read the report card, then?
Mom:  Let's see.  You got a 99.  That's pretty good!
Kid:  No, I didn't.  I got a 99.9.  That's basically 100.
Mom:  You forgot to convert it to the Asian Grading System.
Kid:  Oh.  Either way, it's really good.
Mom:  Yes, I agree.  But there's still room for improvement.
Kid:  Room for improvement?  I pretty much maxed out!
Mom:  You didn't get 100.
Kid:  It rounds to 100.
Mom:  Not on the Asian Grading System.
Kid:  I have pretty much the best grades in the region!
Mom: You'd better work harder next quarter.  I need to see some improvement!
Kid:  (to himself) Wow, this sucks!  (to Mom) Yeah, I'll do better next time.
Mom:  If you don't, I'll have to punish you.  Roger would definitely do better than you!

In case you were actually concerned about this, I wasn't serious about this.  These are all just made up scenarios (I hope), and I'm pretty sure any Asian parent would be fully satisfied with a 99.9 average.  Even though I'd agree that most Asian parents place a lot more importance on grades than others in general, they still are not this intense about their kids' grades.  By the way, did you enjoy the Christmas colors in the dialog?

If you want to try out your newfound C# skills (or if you haven't, see Learn to Program!), create a program that will convert from the American Grading System to the Asian Grading System and vice versa.  You can use an InputBox (see C# InputBox) to get the value you need to convert.

In case you were too lazy to figure out for yourself, use the following line to convert from a string that you get from the InputBox to a double that you can use mathematical operations on:
double someDouble = Convert.ToDouble("some_string");

To convert back to a string, you can use either of the following lines:
string num = someDouble.ToString();
string num = someDouble + "";

This program shouldn't take too much time, so you should give it a try if you're new to C#.

If you're getting confused as to what a string or double is, here's a quick run-though of the most used C# primitive datatypes:

  • int : an integer
  • bool : either true or false
  • double : decimal number
  • string : text

Of course there are more, and you can just Google "C# datatypes" or something.

Saturday, December 11, 2010

C# Mouse

Have you ever wanted to manipulate the mouse cursor programmatically using C#?  Well, look no further, because this small Mouse class puts the mouse actions into a nice, small class you can use in your programs.

If you are still wondering what you can do with this simple class, here are a few examples:
  • Moving the mouse around so the user has no idea what's going on.
  • Making a macro (or "bot") for an online game.
  • Repeatedly clicking the same thing over and over again.

Many of the programs I will post will be based on this Mouse class!


Have a look at the code here (although you can download it at bottom of this post):


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;


static class Mouse
{
private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x02;
private const UInt32 MOUSEEVENTF_LEFTUP = 0x04;
    private const UInt32 MOUSEEVENTF_RIGHTDOWN = 0x08;
    private const UInt32 MOUSEEVENTF_RIGHTUP = 0x10;
    private const UInt32 MOUSEEVENTF_MIDDLEDOWN = 0x20;
    private const UInt32 MOUSEEVENTF_MIDDLEUP = 0x40;


    [DllImport("user32.dll")]
    private static extern void mouse_event(
        UInt32 dwFlags, // motion and click options
        UInt32 dx, // horizontal position or change
        UInt32 dy, // vertical position or change
        UInt32 dwData, // wheel movement
        IntPtr dwExtraInfo // application-defined information
    );


public static void Move(Point p)
{
Cursor.Position = p;
}


    public static void Move(int x, int y)
    {
        Mouse.Move(new Point(x, y));
    }


public static void Click()
{
        mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, new System.IntPtr());
        mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, new System.IntPtr());
}


public static void Click(Point p)
{
Mouse.Move(p);
Mouse.Click();
}


    public static void Click(int x, int y)
    {
        Mouse.Click(new Point(x, y));
    }


    public static void RightClick()
    {
        mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, new System.IntPtr());
        mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, new System.IntPtr());
    }


    public static void RightClick(Point p)
    {
        Mouse.Move(p);
        Mouse.RightClick();
    }


    public static void RightClick(int x, int y)
    {
        Mouse.RightClick(new Point(x, y));
    }


    public static void MiddleClick()
    {
        mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, new System.IntPtr());
        mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, new System.IntPtr());
    }


    public static void MiddleClick(Point p)
    {
        Mouse.Move(p);
        Mouse.MiddleClick();
    }


    public static void MiddleClick(int x, int y)
    {
        Mouse.MiddleClick(new Point(x, y));
    }
}



Most of the methods are self-explanatory (a.k.a. they do pretty much what the method names would suggest).  However, I give some examples anyway:

For each of these lines, assume that somePoint is some Point already defined, such as:
Point somePoint = new Point(13, 37);

Mouse.Move(somePoint);    // Moves the cursor to somePoint
Mouse.Move(123, 456);    // Moves the cursor to the pixel on your screen at (123, 456)
Mouse.Click();    // Left-click at current cursor position
Mouse.Click(somePoint);    // Left-click at somePoint
Mouse.Click(135, 246);    // Left-click at the pixel on your screen at (135, 246)
Mouse.RightClick();    // Right-click at current cursor position
Mouse.RightClick(somePoint);    // Right-click at somePoint
Mouse.RightClick(147, 258);    // Right-click at the pixel on your screen at (147, 258)
Mouse.MiddleClick();    // Middle-click at current cursor position
Mouse.MiddleClick(somePoint);    // Middle-click at somePoint
Mouse.MiddleClick(159, 260);    // Middle-click at the pixel on your screen at (159, 260)

After reading that, you're probably thinking, Why did I bother reading that?  It was so freakin' obvious!  Or maybe you were thinking, Why did that guy waste his time posting those examples?  Does he think I'm stupid or something?!


Anyway, you can download the C# class here (Mouse.cs).

Note: If you don't remember how to add this class to your C# project, see C# InputBox.

Tuesday, December 7, 2010

C# InputBox

A lot of people who start programming might choose Visual Basic because, as the name suggests, it is a rather easy language to learn since there are a lot of words and fewer symbols than other languages like Java and C#.  As time goes on and they become better at programming, people might want to switch over to C# because Visual Basic is too verbose or because of C#'s similarity to Java.  Or you could just start with C#.  Either way, if you're just starting to use C#, you realize there is no built-in way to get input from the user through a dialog box in C#.

So I created my own InputBox.  And get this: it has the option of getting multiple responses at once in an array.  This is pretty useful for getting multi-parameter things from the user, such as getting the location of a new Point (it's much nicer to have the X and Y coordinate prompt in the same dialog than to have two separate dialogs).

HOW TO ADD NEW CLASSES TO YOUR PROJECT:

To add this class to your C# project, you should click: Project > Add New Item... (or Ctrl + Shift + A).  Select a "New Class."  Name it "InputBox.cs".  Then copy and paste the following code into your new class.


Alternatively, you can download the class (InputBox.cs) and add it to your class: Project > Add Exiting Item (or Shift + Alt + A).  Choose the InputBox.cs file you just downloaded.

Basically, Show(...) is an overloaded method that can return an array of values with the same dimensions of your prompt array or return a single value if your prompt is only a single string.  Note: the method returns null if the user presses cancel.

Examples:
string par = InputBox.Show("Give me a number:", "Prompt");    // shows a dialog box for getting a single value in return with the title "Prompt"
string[] pars = InputBox.Show(new string[] {"X:", "Y:"}, "");    // shows a dialog box for getting an X value (will be in pars[0]) and a Y value (will be in pars[1]) without a title because of the empty string in the title parameter 
Here is the code (sorry the spacing is awkward and the text is so small... it's just so that all code fits on one line... it'll look just fine after you copy and paste it into your C# class):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;




static class InputBox
{


    public static string[] Show(string[] pars, string title)
    {
        int size = pars.Length;
        Form frmInputBox = new Form();
        Label[] labels = new Label[size];
        TextBox[] texts = new TextBox[size];
        Button btnOK = new Button();
        Button btnCancel = new Button();


        frmInputBox.Text = title;
        frmInputBox.ClientSize = new Size(420, 100 + 40 * (size - 1));
        frmInputBox.FormBorderStyle = FormBorderStyle.FixedDialog;
        frmInputBox.MinimizeBox = false;
        frmInputBox.MaximizeBox = false;
        frmInputBox.AcceptButton = btnOK;
        frmInputBox.CancelButton = btnCancel;
        frmInputBox.StartPosition = FormStartPosition.CenterScreen;


        for (int i = 0; i < size; i++)
        {
            Label l = new Label();
            l.Text = pars[i];
            l.Location = new Point(10, 10 + 40 * i);
            l.AutoSize = true;
            labels[i] = l;
            TextBox t = new TextBox();
            t.Location = new Point(10, 25 + 40 * i);
            t.Size = new Size(400, 20);
            texts[i] = t;
        }


        btnOK.Text = "OK";
        btnOK.Location = new Point(255, 70 + 40 * (size - 1));
        btnOK.DialogResult = DialogResult.OK;


        btnCancel.Text = "Cancel";
        btnCancel.Location = new Point(335, 70 + 40 * (size - 1));
        btnCancel.DialogResult = DialogResult.Cancel;


        frmInputBox.Controls.AddRange(labels);
        frmInputBox.Controls.AddRange(texts);
        frmInputBox.Controls.AddRange(new Control[] {btnOK, btnCancel});


        DialogResult dialogResult = frmInputBox.ShowDialog();
        if (dialogResult == DialogResult.OK)
        {
            string[] results = new string[size];
            for (int i = 0; i < size; i++)
            {
                results[i] = texts[i].Text;
            }
            return results;
        }
        else
        {
            return null;
        }
    }


    public static string Show(string par, string title)
    {
        string[] temp = Show(new string[] {par}, title);
        if (temp == null)
        {
            return null;
        }
        else
        {
            return temp[0];
        }
    }
}

Friday, December 3, 2010

C# Console Application

If you are using someone else's computer that doesn't have the C# editor installed, you can still write C# code and run it!  The answer is a Console Application.  (You can also create a Console Application in the the C# editor by clicking New Project, and then selecting Console Application)


Important stuff will be in red.


Basically, what you need is a simple text editor (I recommend the newest version of Notepad++ because it has syntax highlighting like your normal editor).  You can put all your code into the text editor and save it as a .CS file, which will look something like this:

using System;
using System.Collections.Generic;
using System.Text;


class ClassName
{


static void Main()
{

}
}


You put all of your code in the Main() method because that's what runs when you start the program.  You can add more namespace references (the "using ... " statements at the top) as needed, such as System.Drawing.  You can add other methods in the class if you want, just like normal.  You can even add new classes -- just make sure that the end-brace of one class is outside the starting-brace of the next class.


The following are 3 main commands that you will use to interact with the user:
  • Console.Write(string text);
    • This outputs the text in the console window.
  • Console.WriteLine(string text);
    • This outputs the text in the console window and also puts a line break after, so whatever comes next will be on a new line.  I think this is more useful overall than Console.Write(...).
  • Console.ReadLine();
    • This gets user input from the user and reads in everything the user types in until he/she presses [ENTER].
    • It also halts program execution until the user presses [ENTER], so it is quite useful for this to be the last line in your Main() method so that it will pause at the end of the program so you can read the output from your program before hitting [ENTER] to terminate it.
You still need to compile your code, so you should use a handy program that comes with your computer: the C# compiler.  Using your text editor, put the following code into it and save it as a .BAT file:

C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe "ConsoleApp.cs"
pause
"ConsoleApp.exe"

The first line of code is the most important because it runs the C# compiler and compile "ConsoleApp.cs".  You should change "ConsoleApp.cs" to whatever filename you chose (if your filename has a space character in it, you have to keep the quotes).  Note: if you have different versions of the .NET framework installed, I recommend you use the latest version.  You can replace "v3.5" with "v4.0.30319" or "v2.0.50727".  You can check your versions of your .NET framework here (they're the folders that start with "v"):
C:\Windows\Microsoft.NET\Framework.


The next line tells the console to pause so you can see what happened during the compilation and so that you can fix any errors that were found.


The third line runs your application that is created if the compile was successful (or the last successful build if it failed).  Again, change "ConsoleApp.cs" to the filename you chose for your C# source code file.


Run this .BAT file to compile and run your new console application!


You can download the entire bunch of files here (ConsoleApp.zip) including a template for your Console Application and the batch file to compile it.  The numbers in the .BAT files represent the version of .NET that it's going to try to compile with.  I recommend you try them from latest (v4.0.30319) to oldest (v2.0.50727) and use the newest .NET version that works.  Remember to rename all instances of "ConsoleApp.cs" to whatever you want to name your C# source code file.  Just another note: I like to name the compilers "c_ConsoleApp.bat" just so I know which .BAT file will compile which .CS file.  It's not mandatory, but I find it helpful when there's a lot of files in one folder.