//At the algorithm manager level, "generate step" is ambiguous with actually stepping through the algorithm, //Or starting the algorithm, and making the first history entry at step 0. //Here, a step only happens when we have been asked by the manager to *actually* take a step. public void Step() { boardData.UnitPercieves(UnitType.Url); boardData.UnitPercieves(UnitType.Bender); Move urlFirstMove = null; Move urlSecondMove = null; List <Move> UrlMoves = null; Move benderMove = null; //Url senses twice. If bender moves into him, he wont start chasing until next turn. //This is a pre-bender-move view. this is the view we use //At this point, URL is seeing what happened before bender moves. //We want to see if URL is attacking bender at his new location. But if he isn't, we'll need to... //store where bender used to be, before seeing if he moved out of view, or if we can attack him. //url if (GetUnit(UnitType.Url).chasing) { foreach (var i in boardData.units[UnitType.Url].perceptionData.perceptionData) { if (i.Value == Percept.Enemy) { urlFirstMove = i.Key; } } } //url move should not be null, since once url starts chasing, he should always see bender //each perception thereafter //Url move will most likely be a diagonal //Bender section. benderMove = liveQmatrix.GenerateStep(GetPerception(UnitType.Bender)); GetUnit(UnitType.Bender).SetMoveThisStep(benderMove); //Store the step for status message //Check if bender chose a move that moves him into url. //If bender did not make a move that knocks him into the enemy, //Only then should bender move resultThisStep = boardData.ApplyMove(UnitType.Bender, benderMove); //The move should be performed now, if possible. //See if URL can attack bender after bender moved //In the below section, we see if URL attacks bender, before updating the q matrix. //Update reward in this section boardData.UnitPercieves(UnitType.Url); //what url sees after bender moves //Previous optimal move is stored in urlFirstMove if (GetUnit(UnitType.Url).chasing&& MyRandom.Next(0, InitialSettings.URLStopsChasingChance) == 0) { urlRandomlyStopped = true; GetUnit(UnitType.Url).chasing = false; } if (GetUnit(UnitType.Url).chasing) { //Loop through Url's perceptions foreach (var i in boardData.units[UnitType.Url].perceptionData.perceptionData) { //Url is already chasing. //See if bender made a bad move, and even though he moves before us, //he didn't avoid us properly if (i.Value == Percept.Enemy) { urlSecondMove = i.Key; } } if (urlSecondMove != null) { //Bender made a bad move. Attack him. obtainedReward = MoveResult.list[MoveResult.EnemyEncountered]; benderAttacked = true; resultThisStep = MoveResult.EnemyEncountered; urlFirstMove = urlSecondMove; } else { //Bender ran away correctly. Copy his move and follow him. urlFirstMove = benderMove; } } else { //Url is not chasing. See if after bender moved, we he ran into url. //If so, start chasing. foreach (var i in boardData.units[UnitType.Url].perceptionData.perceptionData) { if (i.Value == Percept.Enemy) { urlSecondMove = i.Key; } } if (urlSecondMove != null) { //We found a move that detects bender. Start chasing. startedChasing = true; GetUnit(UnitType.Url).chasing = true; urlFirstMove = Move.Wait; } else { //urlsecond move was null, so we didn't see bender. Normal behavior. //Pick a random move that isn't moving into a wall or sitting still. UrlMoves = new List <Move>(); //Left off with looping through url's perceptions to find a non-wall, non grab move. foreach (var i in boardData.units[UnitType.Url].perceptionData.perceptionData) { if (i.Value != Percept.Wall && i.Key != Move.Grab && i.Key != Move.Wait && Move.CardinalMoves.Contains(i.Key)) { UrlMoves.Add(i.Key); } } //Its impossible not to have a move here, so take a random one thats available. urlFirstMove = UrlMoves[MyRandom.Next(0, UrlMoves.Count)]; } } obtainedReward = MoveResult.list[resultThisStep]; //Get the reward for this action episodeRewards += obtainedReward; //Update the rewards total if (resultThisStep == MoveResult.CanCollected) { ++cansCollected; } //give the value to the q matrix to digest if (GetStepNumber() == Qmatrix.stepLimit && GetEpisodeNumber() > Qmatrix.episodeLimit) { AlgorithmManager.algorithmEnded = true; } if (benderMove == null) { boardData.units[UnitType.Url].chasing = false; } PerceptionState startingState = GetUnit(UnitType.Bender).GetStartingPerceptionState(); liveQmatrix.UpdateState(startingState, GetPerception(UnitType.Bender), benderMove, obtainedReward); GetUnit(UnitType.Url).SetMoveThisStep(urlFirstMove); //for status smessage //Move url if (!benderAttacked) { boardData.ApplyMove(UnitType.Url, urlFirstMove); urlFirstMove = null; //Now that url moved, detect if he is chasing again. if (GetUnit(UnitType.Url).chasing == false) { foreach (var i in boardData.units[UnitType.Url].perceptionData.perceptionData) { if (i.Value == Percept.Enemy) { urlFirstMove = i.Key; } } if (urlFirstMove != null) { GetUnit(UnitType.Url).chasing = true; startedChasing = true; } } } //Now that url has moved, see if bender is in view. If so, chase him. //Make each unit perceieve after their step UnitPerceives(UnitType.Bender); UnitPerceives(UnitType.Url); }