|
Britbot
|
00001 #region Usings 00002 00003 using System; 00004 using System.Collections.Generic; 00005 using System.Diagnostics; 00006 using System.Threading; 00007 using System.Threading.Tasks; 00008 using Britbot.Fallback; 00009 using Pirates; 00010 00011 #endregion 00012 00013 namespace Britbot 00014 { 00018 public class Bot : IPirateBot 00019 { 00020 #region Static Fields & Consts 00021 00025 private static Dictionary<Pirate, Direction> _movesDictionary = new Dictionary<Pirate, Direction>(); 00026 00030 private static Dictionary<Pirate, Direction> _fallbackMoves = new Dictionary<Pirate, Direction>(); 00031 00035 private static Task _commanderTask; 00036 00040 private static Task _fallbackTask; 00041 00042 #endregion 00043 00044 #region Fields & Properies 00045 00049 public static IPirateGame Game { get; private set; } 00050 00051 #endregion 00052 00053 #region Interface Implementations 00054 00059 public void DoTurn(IPirateGame state) 00060 { 00061 //update the game so other classes will get updated data 00062 Bot.Game = state; 00063 00064 bool commanderOk = false; 00065 00066 try 00067 { 00068 /* 00069 * NOTE: I changed the commander and Group classes so the do not move anything by themselves, they just return 00070 * moving instructions in the form of a Dictionary<Pirate,Direction>. This is because we do not want to abort the commander 00071 * after it moved couple of pirates but not all of them 00072 */ 00073 //run the commander and check if it returned true (so it went OK) 00074 commanderOk = Bot.ExecuteBot(); 00075 } 00076 catch (Exception ex) //catch any FATAL errors from the ExecuteBot method 00077 { 00078 Logger.Write("=================BOT ERROR=====================", true); 00079 Logger.Write("Bot almost crashed because of exception: " + ex.Message, true); 00080 00081 //print the exception stack trace 00082 StackTrace exTrace = new StackTrace(ex, true); 00083 StackFrame frame = exTrace.GetFrame(0); 00084 Logger.Write( 00085 string.Format("The exception was thrown from method {0} at file {1} at line #{2}", frame.GetMethod(), 00086 frame.GetFileName(), frame.GetFileLineNumber()), true); 00087 00088 Logger.Write("=================BOT ERROR=====================", true); 00089 } 00090 finally //whatever has happened there, move pirates so we will not crash 00091 { 00092 //Actually move stuff 00093 if (commanderOk) //if the commander was OK, use its results 00094 Mover.MoveAll(Bot._movesDictionary); 00095 else //else use the fallback results 00096 Mover.MoveAll(Bot._fallbackMoves); 00097 } 00098 } 00099 00100 #endregion 00101 00106 private static bool ExecuteBot() 00107 { 00108 //clear the last moves 00109 Bot._fallbackMoves.Clear(); 00110 Bot._movesDictionary.Clear(); 00111 00112 //setup time check flag 00113 bool onTime = false; 00114 00115 //setup time remaining 00116 int time = Bot.Game.TimeRemaining(); 00117 00118 //setup safe timeout 00119 int safeTimeout = (int)(time * 0.65); 00120 CancellationTokenSource cancellationSource = new CancellationTokenSource(safeTimeout); 00121 00122 //Commander task setup and start 00123 Bot._commanderTask = 00124 Task.Factory.StartNew(() => 00125 { 00126 try 00127 { 00128 Bot._movesDictionary = Commander.Play(cancellationSource.Token, out onTime); 00129 } 00130 catch (Exception ex) 00131 { 00132 Logger.Write("TOP LEVEL EXCEPTION WAS CAUGHT ON THE COMMANDER TASK ON TURN " + 00133 Bot.Game.GetTurn(), true); 00134 Logger.Write(ex.ToString(), true); 00135 } 00136 }); 00137 00138 //Fallback task setup and start 00139 Bot._fallbackTask = 00140 Task.Factory.StartNew(() => 00141 { 00142 try 00143 { 00144 Bot._fallbackMoves = FallbackBot.GetFallbackTurns(cancellationSource.Token); 00145 } 00146 catch (Exception ex) 00147 { 00148 Logger.Write("TOP LEVEL EXCEPTION WAS CAUGHT ON THE FALLBACK TASK ON TURN " + 00149 Bot.Game.GetTurn(), true); 00150 Logger.Write(ex.ToString(), true); 00151 } 00152 }); 00153 00154 //Wait for the tasks until the same timeout is over. 00155 //bloacks this thread until safeTimeout elapses 00156 Task.WaitAll(new Task[] {Bot._commanderTask, Bot._fallbackTask}, safeTimeout); 00157 00158 //if it's stuck... 00159 if (!onTime) 00160 { 00161 Logger.Write("=================TIMEOUT=======================", true); 00162 Logger.Write("Commander timed out or errorer, switching to fallback code", true); 00163 Logger.Write("Time remaining: " + Bot.Game.TimeRemaining()); 00164 Logger.Write("=================TIMEOUT=======================", true); 00165 } 00166 00167 //do some profiling 00168 Logger.Profile(); 00169 00170 //return if the commander is on time / error status 00171 return onTime; 00172 } 00173 } 00174 }
1.7.6.1