0

Recently we've been working with the Berkley Pacman AI course. We have to analyse what changing values of alpha, epsilon and gamma do to our AI.

To insert a command directly into CMD we tell CMD:

pacman.py -q -p PacmanQAgent -x 2000 -n 2010 -l smallGrid -a epsilon=0.08,alpha=0.3,gamma=0.7

Now, I want to run a series of tests where we change the values of these given variables. So I want to open up CMD, run a lot of commands (which are essentially the same) and save the output in a text file. I found some information on StackExchange, it gave me the following code:

string command = "pacman.py -q -p PacmanQAgent -x 2000 -n 2010 -l smallGrid -a epsilon=0.08,alpha=0.3,gamma=0.7";
Process.Start("CMD.exe", command);

Altough it opens up CMD, it seems not do anything. Also the directory of the CMD is the directory of my solution. This should be rather easy (Altough Windows APIs can be quite hard to work with)

Can anyone help, or give me a general solution?

Rich_Rich
  • 427
  • 3
  • 15
  • 1
    http://stackoverflow.com/questions/1469764/run-command-prompt-commands ? – FakeCaleb Dec 14 '16 at 14:58
  • Wait, what's your question? You stated a problem, but didn't state what you want to do. – Frecklefoot Dec 14 '16 at 14:59
  • 1
    Firstly, you don't really need to run cmd.exe - you can just run `pacman.py` directly. To set the working directory, look at the [ProcessStartInfo](https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo(v=vs.110).aspx) class. There is an overload of [Process.Start](https://msdn.microsoft.com/en-us/library/0w4h05yb(v=vs.110).aspx) that accepts one. – RB. Dec 14 '16 at 14:59
  • Look on MSDN at the [Process](https://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx) and [ProcessStartInfo](https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo(v=vs.110).aspx) classes. They should contain everything you need to know. – Matt Burland Dec 14 '16 at 14:59

2 Answers2

1

Try the ProcessStartInfo class. MSDN ProcessStartInfo

Since this is for an AI course. I would maybe make a PacmanArgument class. PacmanArgument would have properties for each possible commandline argument and a custom ToString method to call. It would make to easier to programatically generate the arguments for something like a genetic algorithm assuming the output can be read as fitness.

Main Function:

double MAX_EPSILON = 1; //I assume there are constraints
//create packman agent with initial values
PacmanAgent agent = new PackmanAgent(0,0,0) //epsilon,alpha,gamma
//create Process info 
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "pacman.py"
psi.WorkingDirectory = @"C:/FilePathToPacman"
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;

string output;
Console.WriteLine("***** Increasing Eplison Test *****");
while( agent.Epsilon =< MAX_EPSILON )
{
    psi.Arguments = agent.GetArgument();
    // Start the process with the info we specified.
    // Call WaitForExit and then the using-statement will close.
    using (Process process =  Process.Start(psi))
    {
        output = process.StandardOutput.ReadToEnd(); //pipe output to c# variable
        process.WaitForExit(); //wait for pacman to end
    }

    //Do something with test output
    Console.WriteLine("Epsilon: {0}, Alpha: {1}, Gamma: {2}",agent.Epsilon,agent.Alpha,agent.Gamma );
    Console.WriteLine("\t" + output);

    agent.IncrementEpsilon(0.05); //increment by desired value or default(set in IncrementEpsilon function)
}

Pacman Agent class:

public class PacmanAgent
{
    private string ArgumentBase = "-q -p PacmanQAgent -x 2000 -n 2010 -l smallGrid -a ";
    [Range(0, 1, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public double Epsilon { get; set; }
    [Range(0, 1, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public double Alpha { get; set; }
    [Range(0, 1, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public double Gamma { get; set; }

    public PacmanAgent(int epsilon, int alpha , int gamma )   
    {
         Epsilon = epsilon;
         Alpha = alpha; 
         Gamma = gamma; 
    }   

    public string GetArgument()
    {
        string argument = string.Format("{0} epsilon={1}, alpha={2}, gamma={3}", ArgumentBase, Epsilon, Alpha, Gamma)
        return argument
    }

    public void IncrementEpsilon(double i = 0.01)
    {
        Epsilon += i;
    }
    public void IncrementAlpha(double i = 0.01)
    {
        Alpha += i;
    }
    public void IncrementGamma(double i = 0.01)
    {
        Gamma += i;
    }
}

*I wrote this outside on an IDE so please excuse any syntax errors

Rich_Rich
  • 427
  • 3
  • 15
Jared Stroebele
  • 574
  • 6
  • 25
  • This is quite remarkable! I don't have time today to work on it, but makes alot of sense what I see. I could not have done this by myself as I have never worked with managing other processes with C# – Rich_Rich Dec 14 '16 at 22:47
  • Something wrong with the filepath now. Trying to figure it out. You also forgot to add `psi.UseShellExecute = false;` but fixed that now. – Rich_Rich Dec 20 '16 at 17:25
  • @RichardDirven Did this end up working for you? I have only worked with Processes a small amount recently and did not have anything setup to test this code on so I am curious. – Jared Stroebele Dec 30 '16 at 17:06
  • the code compiled, but didn't seem to do anything, other than just starting up the CMD. In the end I wrote two programs, one for creating a huge batch files with all the different epsilon, alpha and gamma values. Then I ran the batch, afterwards I wrote a program interpreting the output it gave me. – Rich_Rich Dec 30 '16 at 17:11
  • @RichardDirven Looks like if we incorporate [Run Python Script From C#](http://stackoverflow.com/questions/11779143/how-to-run-a-python-script-from-c) Set the file name to c:\python26\python.exe (or appropriate location) and the arguments to the whole command `pacman.py -q -p PacmanQAgent -x 2000 -n 2010 -l smallGrid -a epsilon=0.08,alpha=0.3,gamma=0.7` it may work – Jared Stroebele Dec 30 '16 at 17:37
0

You could first of all build a temporary batch file containing all your pacman.py commands. Do that using the standard approaches to creating a file in C#. Use the standard CMD.EXE pipe functionality to append to a file (myfile.txt below).

Your temporary .BAT file would be like:

cd \mydirectory
pacman.py -q -p PacmanQAgent -x 2000 -n 2010 -l smallGrid -a epsilon=0.08,alpha=0.3,gamma=0.7 >> myfile.txt
pacman.py -q -p PacmanQAgent -x 2000 -n 2010 -l smallGrid -a epsilon=0.08,alpha=0.3,gamma=0.7 >> myfile.txt
pacman.py -q -p PacmanQAgent -x 2000 -n 2010 -l smallGrid -a epsilon=0.08,alpha=0.3,gamma=0.7 >> myfile.txt

Then run it in a similar way to the approach you used already:

var command = "mytemp.bat"
processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
process = Process.Start(processInfo);
process.WaitForExit();

You can also make Process redirect it's standard output and read it into a string variable in C# if you don't want to pipe it in the batch file.

Alan B
  • 4,086
  • 24
  • 33
  • So then my program would also have to change the temporary bat file a couple of times? – Rich_Rich Dec 14 '16 at 15:50
  • I would envision building it on the fly as you need it, executing it, and deleting it afterwards. So you're opening a stream to a text file called 'myfile.bat', pumping in the CMD.EXE commands as above, closing it, then running it with Process.Start() – Alan B Dec 14 '16 at 16:41