public static int Execute(string path) { if (string.IsNullOrWhiteSpace(path)) { return(-1); } var considered = 0; var deleted = 0; var map = new HashSet <string>(); foreach (var kvp in AITraining.GetTrainingFiles(path)) { considered++; if (kvp.Value <= 0) { // remove inputs that had no kills Console.WriteLine("Removed {0}", kvp.Key); File.Delete(kvp.Key); deleted++; } } Console.WriteLine("Removed {0} of {1} files", deleted, considered); return(deleted); }
public shootMup() { InitializeComponent(); try { SuspendLayout(); // initial setup AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; ClientSize = new System.Drawing.Size(1484, 1075); Name = "shootMup"; Text = "shootMup"; DoubleBuffered = true; // generate players var human = new ShootMPlayer() { Name = "You" }; var players = new Player[100]; for (int i = 0; i < players.Length; i++) { players[i] = new SimpleAI() { Name = string.Format("ai{0}", i) } } ; // generate the world World = WorldGenerator.Generate(WorldType.Random, PlayerPlacement.Borders, human, ref players); // if we are training for AI, then capture telemetry World.OnBeforeAction += AITraining.CaptureBefore; World.OnAfterAction += AITraining.CaptureAfter; World.OnDeath += (elem) => { if (elem is Player) { var winners = new List <string>(); // capture the winners foreach (var player in players) { winners.Add(string.Format("{0} [{1}]", player.Name, player.Kills)); } AITraining.CaptureWinners(winners); } }; UI = new UIHookup(this, World); } finally { ResumeLayout(false); } }
private void PlayerDied(Element element) { // check for winner/death (element may be any element that can take damage) if (element is Player) { // check how many players are still alive int alive = 0; var toplayers = new Dictionary <string, int>(); Player lastAlive = null; foreach (var player in Players) { toplayers.Add(player.Name, player.Kills); if (!player.IsDead) { alive++; lastAlive = player; } } Alive = alive; var winners = toplayers.OrderByDescending(kvp => kvp.Value).Select(kvp => string.Format("{0} [{1}]", kvp.Key, kvp.Value)).ToArray(); if (element.Id == Human.Id || (alive == 1 && !Human.IsDead)) { if (Constants.CaptureAITrainingData) { AITraining.CaptureWinners(winners); } PlayerRank = alive; Menu = new Finish() { Kills = Human.Kills, Ranking = PlayerRank, Winner = (alive == 1) ? Human.Name : "", TopPlayers = winners }; ShowMenu(); if (OnEnd != null) { OnEnd(); } } else if (alive == 1) { if (Constants.CaptureAITrainingData) { AITraining.CaptureWinners(winners); } Menu = new Finish() { Kills = Human.Kills, Ranking = PlayerRank, Winner = lastAlive.Name, TopPlayers = winners }; ShowMenu(); if (OnEnd != null) { OnEnd(); } } } }
private void AIMove(object state) { // block usage if a menu is being displayed if (Map.IsPaused) { return; } // move the AI int index = (int)state; Stopwatch timer = new Stopwatch(); timer.Start(); if (Players[index] is AI) { AI ai = Players[index] as AI; float xdelta = 0; float ydelta = 0; float angle = 0; // the timer is reentrant, so only allow one instance to run if (System.Threading.Interlocked.CompareExchange(ref ai.RunningState, 1, 0) != 0) { return; } if (ai.IsDead) { // drop the current players goodies Map.Drop(ai); ai.SwitchWeapon(); Map.Drop(ai); // stop the timer AITimers[index].Dispose(); return; } // NOTE: Do not apply the ZoomFactor (as it distorts the AI when debugging) - TODO may want to allow this while parachuting // TODO will likely want to translate into a copy of the list with reduced details List <Element> elements = Map.WithinWindow(ai.X, ai.Y, Constants.ProximityViewWidth, Constants.ProximityViewHeight).ToList(); var angleToCenter = Collision.CalculateAngleFromPoint(ai.X, ai.Y, Background.X, Background.Y); var inZone = Background.Damage(ai.X, ai.Y) > 0; if (Constants.CaptureAITrainingData) { // capture what the ai sees AITraining.CaptureBefore(ai, elements, angleToCenter, inZone); } // get action from AI var action = ai.Action(elements, angleToCenter, inZone, ref xdelta, ref ydelta, ref angle); // turn ai.Angle = angle; // perform action bool result = false; Type item = null; switch (action) { case ActionEnum.Drop: item = Map.Drop(ai); result |= (item != null); ai.Feedback(action, item, result); break; case ActionEnum.Pickup: item = Map.Pickup(ai); result |= (item != null); ai.Feedback(action, item, result); break; case ActionEnum.Reload: var reloaded = ai.Reload(); result |= (reloaded == AttackStateEnum.Reloaded); ai.Feedback(action, reloaded, result); break; case ActionEnum.Attack: var attack = Map.Attack(ai); result |= attack == AttackStateEnum.FiredAndKilled || attack == AttackStateEnum.FiredWithContact || attack == AttackStateEnum.MeleeAndKilled || attack == AttackStateEnum.MeleeWithContact; ai.Feedback(action, attack, result); break; case ActionEnum.SwitchWeapon: var swap = ai.SwitchWeapon(); result |= swap; ai.Feedback(action, null, result); break; case ActionEnum.Move: case ActionEnum.None: break; default: throw new Exception("Unknown ai action : " + action); } // have the AI move float oxdelta = xdelta; float oydelta = ydelta; var moved = Map.Move(ai, ref xdelta, ref ydelta); ai.Feedback(ActionEnum.Move, null, moved); // ensure the player stays within the map if (ai.X < 0 || ai.X > Map.Width || ai.Y < 0 || ai.Y > Map.Height) { System.Diagnostics.Debug.WriteLine("Out of bounds"); } if (ai.RecordTraining) { // capture what the ai sees AITraining.CaptureAfter(ai, action, oxdelta, oydelta, angle, action == ActionEnum.None || action == ActionEnum.Move ? moved : result); } // set state back to not running System.Threading.Volatile.Write(ref ai.RunningState, 0); } timer.Stop(); if (timer.ElapsedMilliseconds > 100) { System.Diagnostics.Debug.WriteLine("**AIMove Duration {0} ms", timer.ElapsedMilliseconds); } }
public void KeyPress(char key) { // inputs that are accepted while a menu is displaying if (Map.IsPaused) { switch (key) { // menu case Constants.Esc: HideMenu(); break; } return; } // menu if (key == Constants.Esc) { ShowMenu(); return; } // for training we track the human movements (as the supervised set) if (Human.RecordTraining) { // capture what the user sees List <Element> elements = Map.WithinWindow(Human.X, Human.Y, Constants.ProximityViewWidth, Constants.ProximityViewHeight).ToList(); var angleToCenter = Collision.CalculateAngleFromPoint(Human.X, Human.Y, Background.X, Background.Y); var inZone = Background.Damage(Human.X, Human.Y) > 0; AITraining.CaptureBefore(Human, elements, angleToCenter, inZone); } // handle the user input ActionEnum action = ActionEnum.None; bool result = false; float xdelta = 0; float ydelta = 0; switch (key) { // move case Constants.Down: case Constants.Down2: case Constants.DownArrow: ydelta = 1; break; case Constants.Left: case Constants.Left2: case Constants.LeftArrow: xdelta = -1; break; case Constants.Right: case Constants.Right2: case Constants.RightArrow: xdelta = 1; break; case Constants.Up: case Constants.Up2: case Constants.UpArrow: ydelta = -1; break; case Constants.Switch: action = ActionEnum.SwitchWeapon; result = SwitchWeapon(Human); break; case Constants.Pickup: case Constants.Pickup2: action = ActionEnum.Pickup; result = Pickup(Human); break; case Constants.Drop3: case Constants.Drop2: case Constants.Drop4: case Constants.Drop: action = ActionEnum.Drop; result = Drop(Human); break; case Constants.Reload: case Constants.MiddleMouse: action = ActionEnum.Reload; result = Reload(Human); break; case Constants.Space: case Constants.LeftMouse: action = ActionEnum.Attack; result = Attack(Human); break; case Constants.RightMouse: // use the mouse to move in the direction of the angle float r = (Human.Angle % 90) / 90f; xdelta = 1 * r; ydelta = 1 * (1 - r); if (Human.Angle > 0 && Human.Angle < 90) { ydelta *= -1; } else if (Human.Angle > 180 && Human.Angle <= 270) { xdelta *= -1; } else if (Human.Angle > 270) { ydelta *= -1; xdelta *= -1; } break; } // if a move command, then move if (xdelta != 0 || ydelta != 0) { action = ActionEnum.Move; result = Move(Human, xdelta, ydelta); } // for training we track the human movements (as the supervised set) if (Human.RecordTraining) { // capture the result AITraining.CaptureAfter(Human, action, xdelta, ydelta, Human.Angle, result); } }
public static int Serialize(string path, string type, int remaining) { // validate type var action = ActionEnum.None; switch (type.ToLower()) { case "angle": action = ActionEnum.Attack; break; case "xy": action = ActionEnum.Move; break; } if (remaining < 0) { remaining = Int32.MaxValue; } // load each model and then give a few predictions and check the results var duplicates = new HashSet <int>(); using (var writer = File.CreateText(Path.Combine(path, "data.csv"))) { foreach (var kvp in AITraining.GetTrainingFiles(path)) { var file = kvp.Key; var count = kvp.Value; if (remaining <= 0) { break; } if (count > 0) { foreach (var d in AITraining.GetTraingingData(file)) { if (remaining <= 0) { break; } if (d.Result && d.Z == 0) { var dm = d.AsModelDataSet(); var hash = dm.ComputeHash(); // check type if (action != ActionEnum.None && action != (ActionEnum)d.Action) { continue; } // void duplicates if (duplicates.Contains(hash)) { continue; } // write to disk for (int i = 0; i < dm.Features(); i++) { writer.Write("{0},", dm.Feature(i)); } var outcome = dm.Action; switch (action) { case ActionEnum.Move: outcome = dm.MoveAngle; break; case ActionEnum.Attack: outcome = dm.FaceAngle; break; } writer.WriteLine("{0}", outcome); // update remaining--; duplicates.Add(hash); } } } } } // using writer return(0); }
public static int Check(string type, string path) { // load each model and then give a few predictions and check the results var rand = new Random(); var data = new List <TrainingData>(); var done = false; foreach (var kvp in AITraining.GetTrainingFiles(path)) { if (done) { break; } var file = kvp.Key; var count = kvp.Value; if (count > 0) { foreach (var d in AITraining.GetTraingingData(file)) { if (done) { break; } if (d.Result && d.Z == 0) { // sample ~15% if (rand.Next() % 6 == 0) { // test data set data.Add(d); } if (data.Count > 1000) { done = true; } } } } } foreach (var modelType in new ModelValue[] { ModelValue.Action, ModelValue.XY, ModelValue.Angle } ) { var map = new Dictionary <string, int>(); var modelPath = ""; if (modelType == ModelValue.Action) { modelPath = string.Format("action.{0}.model", type); } else if (modelType == ModelValue.XY) { modelPath = string.Format("xy.{0}.model", type); } else if (modelType == ModelValue.Angle) { modelPath = string.Format("angle.{0}.model", type); } else { throw new Exception("Unknown model type : " + modelType); } Model model = null; if (type.Equals("ml", StringComparison.OrdinalIgnoreCase)) { model = new ModelMLNet(Path.Combine(path, modelPath)); } else { model = new ModelOpenCV(Path.Combine(path, modelPath)); } var delta = 0d; var count = 0; var timer = new Stopwatch(); timer.Start(); foreach (var d in data) { var key = ""; if (false && modelType == ModelValue.XY) { float xdelta, ydelta; model.Predict(d.AsModelDataSet(), out xdelta, out ydelta); delta += Math.Abs(xdelta - d.Xdelta); delta += Math.Abs(ydelta - d.Ydelta); count += 2; key = string.Format("{0},{1} {2},{3}", Math.Round(d.Xdelta, 1), Math.Round(d.Ydelta, 1), Math.Round(xdelta, 1), Math.Round(ydelta, 1)); } else { var value = model.Predict(d.AsModelDataSet()); if (modelType == ModelValue.Action) { delta += Math.Abs(value - (float)d.Action); key = string.Format("{0},{1}", d.Action, Math.Round(value)); } else if (modelType == ModelValue.Angle) { delta += Math.Abs(value - d.Angle); key = string.Format("{0},{1}", Math.Round(d.Angle), Math.Round(value)); } else if (modelType == ModelValue.XY) { var moveAngle = Collision.CalculateAngleFromPoint(0, 0, d.Xdelta, d.Ydelta); delta += Math.Abs(value - moveAngle); key = string.Format("{0},{1}", Math.Round(moveAngle), Math.Round(value)); } } if (!map.ContainsKey(key)) { map.Add(key, 0); } map[key]++; } timer.Stop(); Console.WriteLine("{0} has an average delta of {1:f2}. This ran in {2}ms or {3:f2}ms per prediction", modelType, delta / (double)count, timer.ElapsedMilliseconds, (float)timer.ElapsedMilliseconds / (float)data.Count); foreach (var kvp in map.OrderByDescending(k => k.Value)) { Console.WriteLine("\t{0}\t{1}", kvp.Key, kvp.Value); } } return(0); }
public static int TrainAndEvaulate(string type, string path) { if (string.IsNullOrWhiteSpace(path)) { return(-1); } // 1 in x of these will be picked up (the smaller the number the more of them var takeOnly = 0; var rand = new Random(); var actionData = new DataSet() { TrainingCountMax = 150000 }; var xyData = new DataSet() { TrainingCountMax = 10000 }; var angleData = new DataSet() { TrainingCountMax = 150000 }; int trainingCount = 0, testCount = 0; var lastFile = ""; var duplicates = new HashSet <int>(); foreach (var kvp in AITraining.GetTrainingFiles(path)) { var file = kvp.Key; var count = kvp.Value; lastFile = file; if (count > 0) { // for debugging if (takeOnly > 0 && --takeOnly == 0) { break; } // once enough data has been gathered, break if (actionData.TrainingCountMax + xyData.TrainingCountMax + angleData.TrainingCountMax == 0) { break; } foreach (var d in AITraining.GetTraingingData(file)) { if (d.Result) { var dm = d.AsModelDataSet(); var hash = dm.ComputeHash(); // void duplicates if (duplicates.Contains(hash)) { continue; } // sample ~15% for test if (rand.Next() % 6 == 0) { // test data set testCount++; if (actionData.TrainingCountMax > 0) { actionData.Test.Add(dm); } switch ((ActionEnum)d.Action) { case ActionEnum.Attack: if (angleData.TrainingCountMax > 0) { angleData.Test.Add(dm); } break; case ActionEnum.Move: if (xyData.TrainingCountMax > 0) { xyData.Test.Add(dm); } break; } } else { // training data set trainingCount++; if (actionData.TrainingCountMax > 0) { actionData.Training.Add(dm); actionData.TrainingCountMax--; } switch ((ActionEnum)d.Action) { case ActionEnum.Attack: if (angleData.TrainingCountMax > 0) { angleData.Training.Add(dm); angleData.TrainingCountMax--; } break; case ActionEnum.Move: if (xyData.TrainingCountMax > 0 && !duplicates.Contains(hash)) { xyData.Training.Add(dm); xyData.TrainingCountMax--; } break; } } // add as a potential collision duplicates.Add(hash); } // is result } // foreach TrainingData } // if count > 0 } // foreach file Console.WriteLine("Last file considered {0}", lastFile); Console.WriteLine("Training data set ({0} items) and test data set ({1} items)", trainingCount, testCount); Console.WriteLine(" Training: Action({0}) XY({1}) Angle({2})", actionData.Training.Count, xyData.Training.Count, angleData.Training.Count); Console.WriteLine(" Test: Action({0}) XY({1}) Angle({2})", actionData.Test.Count, xyData.Test.Count, angleData.Test.Count); // train shootMup.Bots.Model actions = null; if (type.Equals("ml", StringComparison.OrdinalIgnoreCase)) { actions = new ModelMLNet(actionData.Training, ModelValue.Action); } else { actions = new ModelOpenCV(actionData.Training, ModelValue.Action); } actions.Save(Path.Combine(path, string.Format("action.{0}.model", type))); // evaluate var eval = actions.Evaluate(actionData.Test, ModelValue.Action); Console.WriteLine("Actions RMS={0} R^2={1}", eval.RMS, eval.RSquared); // train shootMup.Bots.Model xy = null; if (type.Equals("ml", StringComparison.OrdinalIgnoreCase)) { xy = new ModelMLNet(xyData.Training, ModelValue.XY); } else { xy = new ModelOpenCV(xyData.Training, ModelValue.XY); } xy.Save(Path.Combine(path, string.Format("xy.{0}.model", type))); // evaluate eval = xy.Evaluate(xyData.Test, ModelValue.XY); Console.WriteLine("XY RMS={0} R^2={1}", eval.RMS, eval.RSquared); // train shootMup.Bots.Model angle = null; if (type.Equals("ml", StringComparison.OrdinalIgnoreCase)) { angle = new ModelMLNet(angleData.Training, ModelValue.Angle); } else { angle = new ModelOpenCV(angleData.Training, ModelValue.Angle); } angle.Save(Path.Combine(path, string.Format("angle.{0}.model", type))); // evaluate eval = angle.Evaluate(angleData.Test, ModelValue.Angle); Console.WriteLine("Angle RMS={0} R^2={1}", eval.RMS, eval.RSquared); return(0); }