Alex Regueiro avatar Alex Regueiro committed c2e7c60

Added framework for bots.

Comments (0)

Files changed (28)

 #!/bin/sh
 
-./bin/Icfp2011.Icrs.Player.exe $@
+./bin/Icfp2011.Icrs.Player.exe bin/Bots/Icfp2011.Icrs.RandomBot.exe $@

src/Bots/Icfp2011.Icrs.RandomBot/Icfp2011.Icrs.RandomBot.csproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Icfp2011.Icrs.Bots.RandomBot</RootNamespace>
+    <AssemblyName>Icfp2011.Icrs.Bots.RandomBot</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject />
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="RandomBot.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Icfp2011.Icrs.Bot\Icfp2011.Icrs.Bot.csproj">
+      <Project>{64BFF89A-9A0F-4573-A969-C684BCF31556}</Project>
+      <Name>Icfp2011.Icrs.Bot</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\Icfp2011.Icrs\Icfp2011.Icrs.csproj">
+      <Project>{B6E191D7-3CB2-4364-A9CB-921CA49E1F4C}</Project>
+      <Name>Icfp2011.Icrs</Name>
+      <Private>False</Private>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

src/Bots/Icfp2011.Icrs.RandomBot/Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ICFP 2011 ICRS Random Bot")]
+[assembly: AssemblyDescription("Bot that just does random actions")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("ICRS Team")]
+[assembly: AssemblyProduct("ICFP 2011 ICRS")]
+[assembly: AssemblyCopyright("Copyright © ICRS Team 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f89827a4-fc3e-4346-a155-a702a5da8c50")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.*")]
+//[assembly: AssemblyFileVersion("1.0")]

src/Bots/Icfp2011.Icrs.RandomBot/RandomBot.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Icfp2011.Icrs.Bot
+{
+    public abstract class RandomBot
+    {
+        public RandomBot()
+        {
+        }
+
+        // TODO: random bot
+    }
+}

src/Bots/Icfp2011.Icrs.RandomBot/app.config

+<?xml version="1.0"?>
+<configuration>
+<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>

src/ICFP-2011.sln

 		..\run = ..\run
 	EndProjectSection
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{E35086CE-C47F-49E0-8A82-CBE385D925C5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Icfp2011.Icrs.Bot", "Icfp2011.Icrs.Bot\Icfp2011.Icrs.Bot.csproj", "{64BFF89A-9A0F-4573-A969-C684BCF31556}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Icfp2011.Icrs.RandomBot", "Bots\Icfp2011.Icrs.RandomBot\Icfp2011.Icrs.RandomBot.csproj", "{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		{1413FC5A-C10C-459E-A9F7-40C0CBCFD184}.Release|Mixed Platforms.Build.0 = Release|x86
 		{1413FC5A-C10C-459E-A9F7-40C0CBCFD184}.Release|x86.ActiveCfg = Release|x86
 		{1413FC5A-C10C-459E-A9F7-40C0CBCFD184}.Release|x86.Build.0 = Release|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Debug|Mixed Platforms.Build.0 = Debug|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Debug|x86.ActiveCfg = Debug|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Debug|x86.Build.0 = Debug|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Release|Any CPU.ActiveCfg = Release|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Release|Mixed Platforms.Build.0 = Release|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Release|x86.ActiveCfg = Release|x86
+		{64BFF89A-9A0F-4573-A969-C684BCF31556}.Release|x86.Build.0 = Release|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Debug|Mixed Platforms.Build.0 = Debug|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Debug|x86.ActiveCfg = Debug|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Debug|x86.Build.0 = Debug|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Release|Any CPU.ActiveCfg = Release|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Release|Mixed Platforms.Build.0 = Release|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Release|x86.ActiveCfg = Release|x86
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF}.Release|x86.Build.0 = Release|x86
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{4E5EB807-424B-4302-BEAC-BBA1F7F68CAF} = {E35086CE-C47F-49E0-8A82-CBE385D925C5}
+	EndGlobalSection
 EndGlobal

src/Icfp2011.Icrs.Arbiter/Program.cs

                     return Properties.Settings.Default.ExitCodeNotEnoughArgs;
                 }
 
-                return Properties.Settings.Default.ExitCodeFatalError;
+                return Properties.Settings.Default.ExitCodeSuccess;
             }
 #if !DEBUG
             catch (Exception ex)
             }
         }
 
-#if TEST
-        // TODO: temp
-        public static void RunTestMatch()
-        {
-            var match = new LtgMatch();
-            var propSlots = match.GetProponentSlots();
-            var oppSlots = match.GetOpponentSlots();
-
-            propSlots[0].ApplyRight(propSlots, oppSlots, LtgCards.Help);
-            propSlots[0].ApplyRight(propSlots, oppSlots, LtgCards.Zero);
-            propSlots[0].ApplyLeft(propSlots, oppSlots, LtgCards.KCombinator);
-        }
-#endif
-
         public static void RunMatch()
         {
             try
                     {
                         try
                         {
-                            PerformCardAction(match, Console.In, false);
+                            DoAction(match, Console.In, false);
                         }
                         catch (FormatException)
                         {
                             if (lightInterface)
-                                Console.Error.WriteLine("(cannot parse!)");
+                                Console.Out.WriteLine("(cannot parse!)");
                             else
-                                Console.Error.WriteLine("Error reading input.");
+                                Console.Error.WriteLine("Error reading last input.");
                             continue;
                         }
                         break;
                     }
-                    if (!NextTurn(match, false))
+                    if (!NextTurn(match))
                         break;
                 }
             }
                     while (true)
                     {
                         StartTurn(match);
-                        PerformCardAction(match, playerAProcess.StandardOutput, true);
-                        if (!NextTurn(match, false))
+                        DoAction(match, playerAProcess.StandardOutput, true);
+                        if (!NextTurn(match))
                             break;
                     }
                 }
                     while (true)
                     {
                         StartTurn(match);
-                        PerformCardAction(match, playerAProcess.StandardOutput, true);
-                        PerformCardAction(match, playerBProcess.StandardOutput, true);
-                        if (!NextTurn(match, true))
+                        DoAction(match, playerAProcess.StandardOutput, true);
+                        DoAction(match, playerBProcess.StandardOutput, true);
+                        if (!NextTurn(match))
                             break;
                     }
                 }
             }
         }
 
-        private static bool NextTurn(LtgMatch match, bool switchTurns)
+        private static bool NextTurn(LtgMatch match)
         {
-            var success = match.NextTurn(switchTurns);
+            var success = match.NextTurn();
 
             if (lightInterface)
             {
             return success;
         }
 
-        private static void PerformCardAction(LtgMatch match, TextReader reader, bool echoInput)
+        private static void DoAction(LtgMatch match, TextReader reader, bool echoInput)
         {
             var propSlots = match.GetProponentSlots();
             var oppSlots = match.GetOpponentSlots();
             {
                 Console.Out.WriteLine("*** player {0}'s turn, with slots:",
                     (int)match.CurrentPlayer);
+#if DEBUG
                 for (int i = 0; i < propSlots.Length; i++)
                 {
                     var slot = propSlots[i];
                         continue;
                     Console.Out.WriteLine("{0}={{{1},{2}}}", i, slot.Vitality, funcText);
                 }
+#endif
                 Console.Out.WriteLine("(slots {{{0},{1}}} are omitted)",
                     LtgMatch.InitialVitality, initialFuncText);
             }
             oldSlotsPlayerA = match.SlotsPlayerA.CloneAll();
             oldSlotsPlayerB = match.SlotsPlayerB.CloneAll();
 
+            match.StartPlayerTurn();
+
             // Read card action from input stream and perform it.
             var action = ReadCardAction(reader, echoInput);
             var actionSlot = propSlots[action.SlotIndex];
-            var applySuccess = false;
+            LtgException result;
+            actionSlot.DoAction(propSlots, oppSlots, action, out result);
             if (action.ApplicationOrder == LtgCardApplicationOrder.Left)
             {
-                applySuccess = actionSlot.ApplyLeft(propSlots, oppSlots, action.Card);
                 if (!lightInterface)
                 {
                     Console.Out.WriteLine("player {0} applied card {1} to slot {2}",
             }
             else if (action.ApplicationOrder == LtgCardApplicationOrder.Right)
             {
-                applySuccess = actionSlot.ApplyRight(propSlots, oppSlots, action.Card);
                 if (!lightInterface)
                 {
                     Console.Out.WriteLine("player {0} applied slot {2} to card {1}",
                 throw new InvalidOperationException("Invalid card application order.");
             }
 
+            match.EndPlayerTurn();
+
             if (lightInterface)
             {
-                if (applySuccess)
+                if (result == null)
                 {
                     Console.Out.Write("(ok)");
                 }
                 else
                 {
-                    Console.Out.Write("(error)");
+                    Console.Out.Write("(error: {0})", result.ErrorType);
                 }
 
+#if DEBUG
                 OutputSlotChanges(match, LtgPlayer.PlayerA);
                 OutputSlotChanges(match, LtgPlayer.PlayerB);
+#endif
             }
             else
             {
-                if (applySuccess)
+                if (result == null)
                 {
                     //
                 }
                 else
                 {
-                    Console.Out.WriteLine("Exception");
+                    Console.Out.WriteLine("Exception: {0}", GetLtgExceptionName(result.ErrorType));
                     Console.Out.WriteLine("slot {0} reset to {1}", action.SlotIndex, initialFuncText);
                 }
             }
         }
 
+        private static string GetLtgExceptionName(LtgExceptionType type)
+        {
+            switch (type)
+            {
+                case LtgExceptionType.Overflow:
+                    return "Native.AppLimitExceeded";
+                default:
+                    return "Native.Error";
+            }
+        }
+
+#if DEBUG
         private static void OutputSlotChanges(LtgMatch match, LtgPlayer player)
         {
             LtgSlot[] newSlots;
                 throw new ArgumentException("Invalid player.", "player");
             }
 
-            var firstChange = true;
-            for (int i = 0; i < newSlots.Length; i++)
             {
-                if (newSlots[i].Value == oldSlots[i].Value)
-                    continue;
+                // Output changes in values of slots.
+                var firstChange = true;
+                for (int i = 0; i < newSlots.Length; i++)
+                {
+                    if (newSlots[i].Value == oldSlots[i].Value)
+                        continue;
 
-                if (firstChange)
+                    if (firstChange)
+                    {
+                        Console.Out.WriteLine();
+                        firstChange = false;
+                    }
+
+                    Console.Out.Write(GetPlayerChar(player));
+                    Console.Out.Write(i);
+                    Console.Out.Write("={0}", GetValueText(match, newSlots[i]));
+                    Console.Out.Write(" ");
+                }
+            }
+
+            {
+                // Output changes in vitalities of slots.
+                var firstChange = true;
+                for (int i = 0; i < newSlots.Length; i++)
                 {
-                    Console.Out.WriteLine();
-                    firstChange = false;
+                    if (newSlots[i].Vitality == oldSlots[i].Vitality)
+                        continue;
+
+                    if (firstChange)
+                    {
+                        Console.Out.WriteLine();
+                        firstChange = false;
+                    }
+
+                    Console.Out.Write(GetPlayerChar(player));
+                    Console.Out.Write(i);
+                    Console.Out.Write("={0}", newSlots[i].Vitality);
+                    Console.Out.Write(" ");
                 }
-
-                Console.Out.Write(GetPlayerChar(player));
-                Console.Out.Write(i);
-                Console.Out.Write("={0}", GetValueText(match, newSlots[i]));
-                Console.Out.Write(" ");
             }
         }
 
 
             var testMatch = match;
             var evalDepth = 0;
-            var evaluator = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+            var evaluator = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
                 {
                     var func = arg as LtgFunction;
                     var name = arg.ToName();
                 });
 
             var success = evaluator.Evaluate(ref evalDepth,
-                testMatch.GetProponentSlots(), testMatch.GetOpponentSlots(), val);
+                testMatch.GetProponentSlots(), testMatch.GetOpponentSlots(), val, false);
             return sb.ToString();
         }
+#endif
 
         private static char GetPlayerChar(LtgPlayer player)
         {
         {
             var action = new LtgAction();
 
+            if (lightInterface && !Environment.UserInteractive)
+            {
+                var parts = Console.In.ReadLine().Split(' ');
+                action.ApplicationOrder = (LtgCardApplicationOrder)int.Parse(parts[0]);
+                action.Card = LtgCards.FromName(parts[0]);
+                action.SlotIndex = int.Parse(parts[0]);
+            }
+
             Action readSlotNumber = () =>
                 {
                     if (!lightInterface)
-                        Console.Out.WriteLine("slot number?");
+                        Console.Out.WriteLine("slot no?");
                     action.SlotIndex = int.Parse(ReadValue(reader, echoInput));
                 };
             Action readCardNumber = () =>
             }
             else
             {
-                throw new InvalidOperationException();
+                throw new InvalidOperationException("Invalid application order.");
             }
 
             return action;
                 {
                     var key = Console.ReadKey(true);
                     var chr = key.KeyChar;
-                    if (chr == ' ')
+
+                    if (chr == ' ' || chr == '\r' || chr == '\n')
                     {
-                        Console.Write(chr);
+                        Console.Write(' ');
                         break;
                     }
-                    if (chr == '\r' || chr == '\n')
-                        continue;
+                    Console.Write(chr);
                     if (chr == '\b')
                     {
                         if (sb.Length == 0)
                             continue;
+                        Console.Write(' ');
+                        Console.Write('\b');
                         sb.Remove(sb.Length - 1, 1);
                     }
                     else
                     {
                         sb.Append(chr);
                     }
-                    Console.Write(chr);
                 }
                 value = sb.ToString();
             }
                 value = reader.ReadLine();
             }
 
-            if (string.IsNullOrEmpty(value))
+            if (value == null || value.ToLowerInvariant() == "q")
                 throw new PlayerProgramTerminatedException();
             if (echoInput)
             {

src/Icfp2011.Icrs.Arbiter/Properties/Settings.Designer.cs

         
         [global::System.Configuration.ApplicationScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("Not enough arguments.")]
+        [global::System.Configuration.DefaultSettingValueAttribute("Not enough arguments were specified to to the program.")]
         public string MessageNotEnoughArgs {
             get {
                 return ((string)(this["MessageNotEnoughArgs"]));

src/Icfp2011.Icrs.Arbiter/Properties/Settings.settings

       <Value Profile="(Default)">Fatal error: {0}</Value>
     </Setting>
     <Setting Name="MessageNotEnoughArgs" Type="System.String" Scope="Application">
-      <Value Profile="(Default)">Not enough arguments.</Value>
+      <Value Profile="(Default)">Not enough arguments were specified to to the program.</Value>
     </Setting>
     <Setting Name="ExitCodeSuccess" Type="System.Int32" Scope="Application">
       <Value Profile="(Default)">0</Value>

src/Icfp2011.Icrs.Arbiter/app.config

         <value>Fatal error: {0}</value>
       </setting>
       <setting name="MessageNotEnoughArgs" serializeAs="String">
-        <value>Not enough arguments.</value>
+        <value>Not enough arguments were specified to to the program.</value>
       </setting>
       <setting name="ExitCodeSuccess" serializeAs="String">
         <value>0</value>

src/Icfp2011.Icrs.Bot/Icfp2011.Icrs.Bot.csproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{64BFF89A-9A0F-4573-A969-C684BCF31556}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Icfp2011.Icrs.Bot</RootNamespace>
+    <AssemblyName>Icfp2011.Icrs.Bot</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject />
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="LtgBot.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Icfp2011.Icrs\Icfp2011.Icrs.csproj">
+      <Project>{B6E191D7-3CB2-4364-A9CB-921CA49E1F4C}</Project>
+      <Name>Icfp2011.Icrs</Name>
+      <Private>False</Private>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

src/Icfp2011.Icrs.Bot/LtgBot.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Icfp2011.Icrs.Bot
+{
+    public abstract class LtgBot
+    {
+        public LtgBot()
+        {
+        }
+
+        // TODO: bot interface
+    }
+}

src/Icfp2011.Icrs.Bot/Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ICFP 2011 ICRS Bot interface")]
+[assembly: AssemblyDescription("Host and plugin interface for bot system")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("ICRS Team")]
+[assembly: AssemblyProduct("ICFP 2011 ICRS")]
+[assembly: AssemblyCopyright("Copyright © ICRS Team 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f89827a4-fc3e-4346-a155-a702a5da8c50")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.*")]
+//[assembly: AssemblyFileVersion("1.0")]

src/Icfp2011.Icrs.Bot/app.config

+<?xml version="1.0"?>
+<configuration>
+<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>

src/Icfp2011.Icrs.Player/Icfp2011.Icrs.Player.csproj

     </None>
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\Icfp2011.Icrs.Bot\Icfp2011.Icrs.Bot.csproj">
+      <Project>{64BFF89A-9A0F-4573-A969-C684BCF31556}</Project>
+      <Name>Icfp2011.Icrs.Bot</Name>
+      <Private>False</Private>
+    </ProjectReference>
     <ProjectReference Include="..\Icfp2011.Icrs\Icfp2011.Icrs.csproj">
       <Project>{B6E191D7-3CB2-4364-A9CB-921CA49E1F4C}</Project>
       <Name>Icfp2011.Icrs</Name>
+      <Private>False</Private>
     </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

src/Icfp2011.Icrs.Player/Program.cs

 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
+using System.Reflection;
 using System.Text;
 
 namespace Icfp2011.Icrs.Player
 {
+    using Bot;
+
     internal static class Program
     {
-        public static void Main(string[] args)
+        private static LtgBot bot;
+
+        // arg 0 = path to bot file
+        // arg 1 = 0/1 indicating which player this is
+        public static int Main(string[] args)
         {
             try
             {
-#if DEBUG
-                //Debugger.Launch();
+#if LAUNCH_DEBUG
+                Debugger.Launch();
 #endif
 
                 Console.Out.NewLine = "\n";
 
-                // TODO: temporary
+                if (args.Length < 2)
+                {
+                    Console.Error.WriteLine(Properties.Settings.Default.MessageNotEnoughArgs);
+                    return Properties.Settings.Default.ExitCodeNotEnoughArgs;
+                }
 
-                WriteCardAction(new LtgAction()
-                    {
-                        ApplicationOrder = LtgCardApplicationOrder.Right,
-                        SlotIndex = 0,
-                        Card = LtgCards.SCombinator,
-                    });
-                WriteCardAction(new LtgAction()
-                    {
-                        ApplicationOrder = LtgCardApplicationOrder.Right,
-                        SlotIndex = 0,
-                        Card = LtgCards.Get,
-                    });
-                WriteCardAction(new LtgAction()
-                    {
-                        ApplicationOrder = LtgCardApplicationOrder.Right,
-                        SlotIndex = 0,
-                        Card = LtgCards.ICombinator,
-                    });
-                WriteCardAction(new LtgAction()
-                    {
-                        ApplicationOrder = LtgCardApplicationOrder.Right,
-                        SlotIndex = 0,
-                        Card = LtgCards.Zero,
-                    });
+                var botProgramPath = args[0];
+                LoadBot(botProgramPath); ;
 
-                //WriteCardAction(new LtgAction()
-                //    {
-                //        ApplicationOrder = LtgCardApplicationOrder.Right,
-                //        SlotIndex = 0,
-                //        Card = LtgCards.Help,
-                //    });
-                //WriteCardAction(new LtgAction()
-                //    {
-                //        ApplicationOrder = LtgCardApplicationOrder.Right,
-                //        SlotIndex = 0,
-                //        Card = LtgCards.Zero,
-                //    });
-                //WriteCardAction(new LtgAction()
-                //    {
-                //        ApplicationOrder = LtgCardApplicationOrder.Left,
-                //        SlotIndex = 0,
-                //        Card = LtgCards.KCombinator,
-                //    });
+                var programPlayer = (LtgPlayer)int.Parse(args[1]);
+                RunPlayer(programPlayer);
+
+                return Properties.Settings.Default.ExitCodeSuccess;
             }
 #if !DEBUG
             catch (Exception ex)
             }
         }
 
+        private static void LoadBot(string path)
+        {
+            // TODO: load bot
+        }
+
+        private static void RunPlayer(LtgPlayer player)
+        {
+            var match = new LtgMatch();
+
+            if (player != match.CurrentPlayer)
+                DoOpponentAction(match);
+            while (true)
+            {
+                match.StartPlayerTurn();
+                DoProponentAction(match);
+                match.EndPlayerTurn();
+
+                match.StartPlayerTurn();
+                DoOpponentAction(match);
+                match.EndPlayerTurn();
+
+                match.NextTurn();
+            }
+        }
+
+        private static void DoProponentAction(LtgMatch match)
+        {
+            // TODO: player move
+        }
+
+        private static void DoOpponentAction(LtgMatch match)
+        {
+            match.StartPlayerTurn();
+
+            var action = ReadCardAction();
+            var propSlots = match.GetProponentSlots();
+            var oppSlots = match.GetOpponentSlots();
+            var slot = propSlots[action.SlotIndex];
+            LtgException result;
+            slot.DoAction(propSlots, oppSlots, action, out result);
+        }
+
         private static void WriteCardAction(LtgAction action)
         {
-            Action writeSlotNumber = () =>
-                {
-                    Console.Out.WriteLine(action.SlotIndex);
-                };
-            Action writeCardNumber = () =>
-                {
-                    Console.Out.WriteLine(action.Card.ToName());
-                };
+            Action writeSlotNumber = () => Console.Out.WriteLine(action.SlotIndex);
+            Action writeCardNumber = () => Console.Out.WriteLine(action.Card.ToName());
 
             Console.Out.WriteLine((int)action.ApplicationOrder);
             if (action.ApplicationOrder == LtgCardApplicationOrder.Left)
                 throw new ArgumentException("Invalid action.", "action");
             }
         }
+
+        private static LtgAction ReadCardAction()
+        {
+            var action = new LtgAction();
+
+            Action readSlotNumber = () => action.SlotIndex = int.Parse(Console.In.ReadLine());
+            Action readCardNumber = () => action.Card = LtgCards.FromName(Console.In.ReadLine());
+
+            action.ApplicationOrder = (LtgCardApplicationOrder)int.Parse(Console.In.ReadLine());
+            if (action.ApplicationOrder == LtgCardApplicationOrder.Left)
+            {
+                readCardNumber();
+                readSlotNumber();
+            }
+            else if (action.ApplicationOrder == LtgCardApplicationOrder.Right)
+            {
+                readSlotNumber();
+                readCardNumber();
+            }
+            else
+            {
+                throw new InvalidOperationException("Invalid application order.");
+            }
+
+            return action;
+        }
     }
 }

src/Icfp2011.Icrs.Player/Properties/AssemblyInfo.cs

 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
 [assembly: AssemblyTitle("ICFP 2011 ICRS Player")]
-[assembly: AssemblyDescription("Player program")]
+[assembly: AssemblyDescription("Player program for arbitrary bots")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("ICRS Team")]
 [assembly: AssemblyProduct("ICFP 2011 ICRS")]

src/Icfp2011.Icrs.Player/Properties/Settings.Designer.cs

                 return ((string)(this["MessageFatalError"]));
             }
         }
+        
+        [global::System.Configuration.ApplicationScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("1")]
+        public int ExitCodeFatalError {
+            get {
+                return ((int)(this["ExitCodeFatalError"]));
+            }
+        }
+        
+        [global::System.Configuration.ApplicationScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("0")]
+        public int ExitCodeSuccess {
+            get {
+                return ((int)(this["ExitCodeSuccess"]));
+            }
+        }
+        
+        [global::System.Configuration.ApplicationScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("Not enough arguments were specified to to the program.")]
+        public string MessageNotEnoughArgs {
+            get {
+                return ((string)(this["MessageNotEnoughArgs"]));
+            }
+        }
+        
+        [global::System.Configuration.ApplicationScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("2")]
+        public int ExitCodeNotEnoughArgs {
+            get {
+                return ((int)(this["ExitCodeNotEnoughArgs"]));
+            }
+        }
     }
 }

src/Icfp2011.Icrs.Player/Properties/Settings.settings

     <Setting Name="MessageFatalError" Type="System.String" Scope="Application">
       <Value Profile="(Default)">Fatal error: {0}</Value>
     </Setting>
+    <Setting Name="ExitCodeFatalError" Type="System.Int32" Scope="Application">
+      <Value Profile="(Default)">1</Value>
+    </Setting>
+    <Setting Name="ExitCodeSuccess" Type="System.Int32" Scope="Application">
+      <Value Profile="(Default)">0</Value>
+    </Setting>
+    <Setting Name="MessageNotEnoughArgs" Type="System.String" Scope="Application">
+      <Value Profile="(Default)">Not enough arguments were specified to to the program.</Value>
+    </Setting>
+    <Setting Name="ExitCodeNotEnoughArgs" Type="System.Int32" Scope="Application">
+      <Value Profile="(Default)">2</Value>
+    </Setting>
   </Settings>
 </SettingsFile>

src/Icfp2011.Icrs.Player/app.config

       <setting name="MessageFatalError" serializeAs="String">
         <value>Fatal error: {0}</value>
       </setting>
+      <setting name="ExitCodeFatalError" serializeAs="String">
+        <value>1</value>
+      </setting>
+      <setting name="ExitCodeSuccess" serializeAs="String">
+        <value>0</value>
+      </setting>
+      <setting name="MessageNotEnoughArgs" serializeAs="String">
+        <value>Not enough arguments were specified to to the program.</value>
+      </setting>
+      <setting name="ExitCodeNotEnoughArgs" serializeAs="String">
+        <value>2</value>
+      </setting>
     </Icfp2011.Icrs.Player.Properties.Settings>
   </applicationSettings>
 </configuration>

src/Icfp2011.Icrs/Icfp2011.Icrs.csproj

   <ItemGroup>
     <Compile Include="LtgAction.cs" />
     <Compile Include="LtgCards.cs" />
+    <Compile Include="LtgException.cs" />
     <Compile Include="LtgFunction.cs" />
     <Compile Include="LtgMatch.cs" />
     <Compile Include="LtgNumber.cs" />

src/Icfp2011.Icrs/LtgCards.cs

     {
         public static readonly LtgValue Zero = new LtgNumber(0);
 
-        public static readonly LtgFunction ICombinator = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction ICombinator = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
                 return arg;
             });
 
-        public static readonly LtgFunction Succ = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Succ = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
                 var n = arg as LtgNumber;
                 if (n == null)
-                    return null;
+                    throw new LtgException(LtgExceptionType.NotNumber);
                 return new LtgNumber(Math.Min(n.Number + 1, LtgUtilities.MaxNumber));
             });
 
-        public static readonly LtgFunction Dbl = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Dbl = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
                 var n = arg as LtgNumber;
                 if (n == null)
-                    return null;
+                    throw new LtgException(LtgExceptionType.NotNumber);
                 return new LtgNumber(Math.Min(n.Number * 2, LtgUtilities.MaxNumber));
             });
 
-        public static readonly LtgFunction Get = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Get = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
                 var i = arg as LtgNumber;
                 if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
-                    return null;
+                    throw new LtgException(LtgExceptionType.NotSlotNumber);
                 var ps = propSlots[i.Number];
                 if (!ps.IsAlive)
-                    return null;
+                    throw new LtgException(LtgExceptionType.NotAlive);
                 return ps.Value;
             });
 
-        public static readonly LtgFunction Put = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Put = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
                 return ICombinator;
             });
 
-        public static readonly LtgFunction SCombinator = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction SCombinator = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
-                return new LtgFunction(SCombinator, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) =>
+                return new LtgFunction(SCombinator, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2, reverseMode2) =>
                     {
-                        return new LtgFunction(SCombinator, new[] { arg, arg2 }, (depth3, propSlots3, oppSlots3, arg3) =>
+                        return new LtgFunction(SCombinator, new[] { arg, arg2 }, (depth3, propSlots3, oppSlots3, arg3, reverseMode3) =>
                             {
                                 var f = arg as LtgFunction;
                                 if (f == null)
-                                    return null;
+                                    throw new LtgException(LtgExceptionType.NotFunction);
 
                                 var g = arg2 as LtgFunction;
                                 if (g == null)
-                                    return null;
+                                    throw new LtgException(LtgExceptionType.NotFunction);
 
-                                var h = f.Evaluate(ref depth3, propSlots, oppSlots, arg3);
-                                var y = g.Evaluate(ref depth3, propSlots, oppSlots, arg3);
-                                return h.Evaluate(ref depth3, propSlots, oppSlots, y);
+                                var h = f.Evaluate(ref depth3, propSlots, oppSlots, arg3, reverseMode);
+                                var y = g.Evaluate(ref depth3, propSlots, oppSlots, arg3, reverseMode);
+                                return h.Evaluate(ref depth3, propSlots, oppSlots, y, reverseMode);
                             });
                     });
             });
 
-        public static readonly LtgFunction KCombinator = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction KCombinator = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
-                return new LtgFunction(KCombinator, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) => arg);
+                return new LtgFunction(KCombinator, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2, reverseMode2) => arg);
             });
 
-        public static readonly LtgFunction Inc = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Inc = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
                 var i = arg as LtgNumber;
                 if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
-                    return null;
+                    throw new LtgException(LtgExceptionType.NotSlotNumber);
                 var ps = propSlots[i.Number];
-                if (ps.Vitality > 0 && ps.Vitality < LtgUtilities.MaxVitality)
-                    ps.Vitality++;
+                if (ps.Vitality > 0)
+                {
+                    if (reverseMode)
+                    {
+                        ps.Vitality--;
+                    }
+                    else
+                    {
+                        if (ps.Vitality < LtgUtilities.MaxVitality)
+                            ps.Vitality++;
+                    }
+                }
 
                 return LtgCards.ICombinator;
             });
 
-        public static readonly LtgFunction Dec = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Dec = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
                 var i = arg as LtgNumber;
                 if (i == null || i.Number < 0 || i.Number >= oppSlots.Length)
-                    return null;
+                    throw new LtgException(LtgExceptionType.NotSlotNumber);
                 var os = oppSlots[oppSlots.Length - 1 - i.Number];
                 if (os.Vitality > 0)
-                    os.Vitality--;
+                {
+                    if (reverseMode)
+                    {
+                        if (os.Vitality < LtgUtilities.MaxVitality)
+                            os.Vitality++;
+                    }
+                    else
+                    {
+                        os.Vitality--;
+                    }
+                }
 
                 return LtgCards.ICombinator;
             });
 
-        public static readonly LtgFunction Attack = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Attack = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
-                return new LtgFunction(Attack, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) =>
+                return new LtgFunction(Attack, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2, reverseMode2) =>
                 {
-                    return new LtgFunction(Attack, new[] { arg, arg2 }, (depth3, propSlots3, oppSlots3, arg3) =>
+                    return new LtgFunction(Attack, new[] { arg, arg2 }, (depth3, propSlots3, oppSlots3, arg3, reverseMode3) =>
                         {
                             var i = arg as LtgNumber;
                             if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
-                                return null;
+                                throw new LtgException(LtgExceptionType.NotSlotNumber);
                             var ps = propSlots[i.Number];
 
                             var j = arg2 as LtgNumber;
                             if (j == null || j.Number < 0 || j.Number >= oppSlots2.Length)
-                                return null;
+                                throw new LtgException(LtgExceptionType.NotSlotNumber);
                             var os = oppSlots[oppSlots.Length - 1 - j.Number];
 
                             var n = arg3 as LtgNumber;
                             if (n == null || n.Number > ps.Vitality)
-                                return null;
+                                throw new LtgException(LtgExceptionType.NotEnoughVitality);
 
                             ps.Vitality = ps.Vitality - n.Number;
-                            os.Vitality = Math.Max(os.Vitality - (n.Number * 9 / 10), 0);
+                            if (reverseMode)
+                            {
+                                if (os.Vitality > 0)
+                                    os.Vitality = Math.Min(os.Vitality + (n.Number * 9 / 10), LtgUtilities.MaxVitality);
+                            }
+                            else
+                            {
+                                os.Vitality = Math.Max(os.Vitality - (n.Number * 9 / 10), 0);
+                            }
 
                             return LtgCards.ICombinator;
                         });
                 });
             });
 
-        public static readonly LtgFunction Help = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Help = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
-                return new LtgFunction(Help, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) =>
+                return new LtgFunction(Help, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2, reverseMode2) =>
                 {
-                    return new LtgFunction(Help, new[] { arg, arg2 }, (depth3, propSlots3, oppSlots3, arg3) =>
+                    return new LtgFunction(Help, new[] { arg, arg2 }, (depth3, propSlots3, oppSlots3, arg3, reverseMode3) =>
                     {
                         var i = arg as LtgNumber;
                         if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
-                            return null;
+                            throw new LtgException(LtgExceptionType.NotSlotNumber);
                         var ps1 = propSlots[i.Number];
 
                         var j = arg2 as LtgNumber;
                         if (j == null || j.Number < 0 || j.Number >= propSlots2.Length)
-                            return null;
+                            throw new LtgException(LtgExceptionType.NotSlotNumber);
                         var ps2 = propSlots[j.Number];
 
                         var n = arg3 as LtgNumber;
                         if (n == null || n.Number > ps1.Vitality)
-                            return null;
+                            throw new LtgException(LtgExceptionType.NotEnoughVitality);
 
                         ps1.Vitality = ps1.Vitality - n.Number;
-                        ps2.Vitality = Math.Min(ps2.Vitality + (n.Number * 11 / 10), LtgUtilities.MaxVitality);
+                        if (reverseMode)
+                        {
+                            if (ps2.Vitality > 0)
+                                ps2.Vitality = Math.Max(ps2.Vitality - (n.Number * 11 / 10), 0);
+                        }
+                        else
+                        {
+                            ps2.Vitality = Math.Min(ps2.Vitality + (n.Number * 11 / 10), LtgUtilities.MaxVitality);
+                        }
 
                         return LtgCards.ICombinator;
                     });
                 });
             });
 
-        public static readonly LtgFunction Copy = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Copy = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
                 var i = arg as LtgNumber;
                 if (i == null || i.Number < 0 || i.Number >= oppSlots.Length)
-                    return null;
+                    throw new LtgException(LtgExceptionType.NotSlotNumber);
                 var os = oppSlots[i.Number];
 
                 return os.Value;
             });
 
-        public static readonly LtgFunction Revive = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Revive = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
                 var i = arg as LtgNumber;
                 if (i == null || i.Number < 0 || i.Number >= propSlots.Length)
-                    return null;
+                    throw new LtgException(LtgExceptionType.NotSlotNumber);
                 var ps = propSlots[i.Number];
                 if (ps.Vitality <= 0)
                     ps.Vitality = 1;
                 return LtgCards.ICombinator;
             });
 
-        public static readonly LtgFunction Zombie = new LtgFunction((depth, propSlots, oppSlots, arg) =>
+        public static readonly LtgFunction Zombie = new LtgFunction((depth, propSlots, oppSlots, arg, reverseMode) =>
             {
-                return new LtgFunction(Zombie, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2) =>
+                return new LtgFunction(Zombie, new[] { arg }, (depth2, propSlots2, oppSlots2, arg2, reverseMode2) =>
                     {
                         var i = arg as LtgNumber;
                         if (i == null || i.Number < 0 || i.Number >= oppSlots.Length)
-                            return null;
+                            throw new LtgException(LtgExceptionType.NotSlotNumber);
                         var os = oppSlots[oppSlots.Length - 1 - i.Number];
                         if (os.IsAlive)
-                            return null;
+                            throw new LtgException(LtgExceptionType.NotDead);
                         os.Vitality = -1;
 
                         return LtgCards.ICombinator;

src/Icfp2011.Icrs/LtgException.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Icfp2011.Icrs
+{
+    public class LtgException : Exception
+    {
+        public LtgException(LtgExceptionType type)
+            : base()
+        {
+            this.ErrorType = type;
+        }
+
+        public LtgExceptionType ErrorType
+        {
+            get;
+            private set;
+        }
+    }
+
+    public enum LtgExceptionType
+    {
+        CannotApplyNumber,
+        Overflow,
+        NotAlive,
+        NotDead,
+        NotEnoughVitality,
+        NotNumber,
+        NotFunction,
+        NotSlotNumber,
+    }
+}

src/Icfp2011.Icrs/LtgFunction.cs

 {
     public class LtgFunction : LtgValue
     {
-        private Func<int, LtgSlot[], LtgSlot[], LtgValue, LtgValue> func;
+        private LtgFunc func;
 
 #if DEBUG
         private LtgFunction parentFunc;
 #endif
 
 #if DEBUG
-        public LtgFunction(LtgFunction parentFunc, IList<LtgValue> args, Func<int, LtgSlot[], LtgSlot[], LtgValue, LtgValue> func)
+        public LtgFunction(LtgFunction parentFunc, IList<LtgValue> args, LtgFunc func)
             : this(func)
         {
             this.parentFunc = parentFunc;
             this.args = args;
         }
 #else
-        public LtgFunction(LtgFunction parentFunc, IList<LtgValue> args, Func<int, LtgSlot[], LtgSlot[], LtgValue, LtgValue> func)
+        public LtgFunction(LtgFunction parentFunc, IList<LtgValue> args, LtgFunc func)
             : this(func)
         {
         }
 #endif
 
-        public LtgFunction(Func<int, LtgSlot[], LtgSlot[], LtgValue, LtgValue> func)
+        public LtgFunction(LtgFunc func)
         {
             this.func = func;
         }
         }
 #endif
 
-        public Func<int, LtgSlot[], LtgSlot[], LtgValue, LtgValue> Function
+        public LtgFunc Function
         {
             get { return this.func; }
         }
 
-        public override LtgValue Evaluate(ref int depth, LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue arg)
+        public delegate LtgValue LtgFunc(int depth, LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue arg,
+            bool reverseMode);
+
+        public override LtgValue Evaluate(ref int depth, LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue arg,
+            bool reverseMode)
         {
             if (depth > LtgUtilities.MaxEvaluationDepth)
-                return null;
+                throw new LtgException(LtgExceptionType.Overflow);
 
             depth++;
-            return this.func(depth, propSlots, oppSlots, arg);
+            return this.func(depth, propSlots, oppSlots, arg, reverseMode);
         }
     }
 }

src/Icfp2011.Icrs/LtgMatch.cs

 {
     public class LtgMatch
     {
+        const string messageInvalidPlayer = "Invalid player.";
+
         public const int NumSlots = 256;
         public const int InitialVitality = 10000;
         public const int MaxNumTurns = 100000;
         private int turnNumber;
 
         public LtgMatch()
+            : this(new LtgSlot[NumSlots], new LtgSlot[NumSlots], LtgPlayer.PlayerA, 1)
         {
-            this.slotsPlayerA = new LtgSlot[NumSlots];
-            this.slotsPlayerB = new LtgSlot[NumSlots];
-
-            this.curPlayer = LtgPlayer.PlayerA;
-            this.turnNumber = 1;
-
             Initialize();
         }
 
-        private LtgMatch(LtgSlot[] slotsPlayerA, LtgSlot[] slotsPlayerB, LtgPlayer curPlayer)
+        private LtgMatch(LtgSlot[] slotsPlayerA, LtgSlot[] slotsPlayerB, LtgPlayer curPlayer, int turnNumber)
         {
             this.slotsPlayerA = slotsPlayerA;
             this.slotsPlayerB = slotsPlayerB;
             this.curPlayer = curPlayer;
+            this.turnNumber = turnNumber;
         }
 
         public LtgSlot[] SlotsPlayerA
             get { return this.turnNumber; }
         }
 
+        public void StartPlayerTurn()
+        {
+            var propSlots = GetProponentSlots();
+            var oppSlots = GetOpponentSlots();
+
+            for (int i = 0; i < propSlots.Length; i++)
+            {
+                var slot = propSlots[i];
+                if (slot.Vitality == -1)
+                {
+                    try
+                    {
+                        var depth = 0;
+                        slot.Value = slot.Value.Evaluate(ref depth, propSlots, oppSlots, LtgCards.ICombinator, true);
+                    }
+                    catch (LtgException)
+                    { }
+                    slot.Vitality = 0;
+                    slot.Value = LtgCards.ICombinator;
+                }
+            }
+        }
+
+        public void EndPlayerTurn()
+        {
+            this.curPlayer = GetOtherPlayer(this.curPlayer);
+        }
+
+        // Returns whether match can continue.
+        public bool NextTurn()
+        {
+            this.turnNumber++;
+            return this.turnNumber < MaxNumTurns;
+        }
+
         private void Initialize()
         {
             for (int i = 0; i < NumSlots; i++)
 
         public LtgSlot[] GetProponentSlots()
         {
-            if (this.curPlayer == LtgPlayer.PlayerA)
-                return this.slotsPlayerA;
-            else if (this.curPlayer == LtgPlayer.PlayerB)
-                return this.slotsPlayerB;
-            else
-                throw new InvalidOperationException();
+            return GetSlots(this.curPlayer);
         }
 
         public LtgSlot[] GetOpponentSlots()
         {
-            if (this.curPlayer == LtgPlayer.PlayerA)
-                return this.slotsPlayerB;
-            else if (this.curPlayer == LtgPlayer.PlayerB)
-                return this.slotsPlayerA;
-            else
-                throw new InvalidOperationException();
+            return GetSlots(GetOtherPlayer(this.curPlayer));
         }
 
-        // Returns whether match can continue.
-        public bool NextTurn(bool switchTurns)
+        public LtgSlot[] GetSlots(LtgPlayer player)
         {
-            if (switchTurns)
-            {
-                if (this.curPlayer == LtgPlayer.PlayerA)
-                    this.curPlayer = LtgPlayer.PlayerB;
-                else if (this.curPlayer == LtgPlayer.PlayerB)
-                    this.curPlayer = LtgPlayer.PlayerA;
-                else
-                    throw new InvalidOperationException();
-            }
+            if (player == LtgPlayer.PlayerA)
+                return this.slotsPlayerA;
+            else if (player == LtgPlayer.PlayerB)
+                return this.slotsPlayerB;
+            else
+                throw new ArgumentException(messageInvalidPlayer, "player");
+        }
 
-            this.turnNumber++;
-            return this.turnNumber < MaxNumTurns;
+        public LtgPlayer GetOtherPlayer(LtgPlayer player)
+        {
+            if (player == LtgPlayer.PlayerA)
+                return LtgPlayer.PlayerB;
+            else if (player == LtgPlayer.PlayerB)
+                return LtgPlayer.PlayerA;
+            else
+                throw new ArgumentException(messageInvalidPlayer, "player");
         }
 
         public LtgMatch Clone()
             return new LtgMatch(
                 this.slotsPlayerA.CloneAll(),
                 this.slotsPlayerB.CloneAll(),
-                this.curPlayer
+                this.curPlayer,
+                this.turnNumber
                 );
         }
     }

src/Icfp2011.Icrs/LtgNumber.cs

             get { return this.num; }
         }
 
-        public override LtgValue Evaluate(ref int depth, LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue arg)
+        public override LtgValue Evaluate(ref int depth, LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue arg, 
+            bool reverseMode)
         {
-            //Debug.Fail("Cannot compose numbers.");
-            return null;
+            throw new LtgException(LtgExceptionType.CannotApplyNumber);
         }
     }
 }

src/Icfp2011.Icrs/LtgSlot.cs

         public int Vitality
         {
             get { return this.vitality; }
-            set { this.vitality = value; }
+            internal set { this.vitality = value; }
         }
 
         public LtgValue Value
         {
             get { return this.value; }
+            internal set { this.value = value; }
         }
 
-        public bool ApplyLeft(LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue card)
+        public void DoAction(LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgAction action, out LtgException result)
         {
-            var depth = 0;
-            PerformAutomaticApplication(propSlots);
-            this.value = card.Evaluate(ref depth, propSlots, oppSlots, this.value);
-            if (this.value == null)
+            if (action.ApplicationOrder == LtgCardApplicationOrder.Left)
+                ApplyLeft(propSlots, oppSlots, action.Card, out result);
+            else if (action.ApplicationOrder == LtgCardApplicationOrder.Right)
+                ApplyRight(propSlots, oppSlots, action.Card, out result);
+            else
+                throw new ArgumentException("Invalid card application order.", "action");
+        }
+
+        public void ApplyLeft(LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue card, out LtgException result)
+        {
+            result = null;
+            try
+            {
+                if (!this.IsAlive)
+                    throw new LtgException(LtgExceptionType.NotAlive);
+                var depth = 0;
+                this.value = card.Evaluate(ref depth, propSlots, oppSlots, this.value, false);
+            }
+            catch (LtgException exLtg)
             {
                 this.value = LtgCards.ICombinator;
-                return false;
+                result = exLtg;
             }
-            return true;
         }
 
-        public bool ApplyRight(LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue card)
+        public void ApplyRight(LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue card, out LtgException result)
         {
-            var depth = 0;
-            PerformAutomaticApplication(propSlots);
-            this.value = this.value.Evaluate(ref depth, propSlots, oppSlots, card);
-            if (this.value == null)
+            result = null;
+            try
+            {
+                if (!this.IsAlive)
+                    throw new LtgException(LtgExceptionType.NotAlive);
+                var depth = 0;
+                this.value = this.value.Evaluate(ref depth, propSlots, oppSlots, card, false);
+            }
+            catch (LtgException exLtg)
             {
                 this.value = LtgCards.ICombinator;
-                return false;
+                result = exLtg;
             }
-            return true;
-        }
-
-        private void PerformAutomaticApplication(LtgSlot[] propSlots)
-        {
-            // TODO
         }
 
         public LtgSlot Clone()

src/Icfp2011.Icrs/LtgValue.cs

         }
 
         // Returns null when error occurs.
-        public abstract LtgValue Evaluate(ref int depth, LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue arg);
+        public abstract LtgValue Evaluate(ref int depth, LtgSlot[] propSlots, LtgSlot[] oppSlots, LtgValue arg,
+            bool reverseMode);
     }
 }
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.