making the robocode robot work

In previous posts in this series I've been exploring acceptance testing my robocode robot. I've passed an acceptance test that ensures it never gets disabled at the start but I still have once acceptance test that is failing.
Some time ago, I wrote the following acceptance test:

In a one round battle, fighting against a single robot that does not move, the slayer robot should win.

I've yet to pass this test - I found a random seed that ensures the battle is a draw if my robot does not move and as yet I have not issued a single command to the robot.
So here's my first steps into doing just that.

I'm starting with the specifications for my RobotEngine - at the moment this takes in one ImAnObserver in the constructor, so I add a new specification for multiple observers shown at the bottom of the following code:

    public class when_initialising_a_robot_engine : with_a_robot_engine
    {
        Because of = () => robotEngine.Initialise(robot);

        It should_tell_the_statistics_writer_to_ensure_we_have_clean_statistics = () =>
            statisticsManager.AssertWasCalled(s => s.EnsureWeStartWithCleanStatistics());

        It should_ensure_that_we_have_something_to_observe_the_start_of_each_turn = () =>
            robotEngine.AtTheStartOfEachTurn.ShouldNotBeNull();

        It should_ask_the_first_observer_to_observe = () =>
            firstObserver.AssertWasCalled(o => o.Observe(robotEngine));

        It should_ask_the_second_observer_to_observe = () =>                  <---
           secondObserver.AssertWasCalled(o => o.Observe(robotEngine));       <---
    }

The RobotEngine changes accordingly:

        public RobotEngine(IManageStatistics statisticsManager, 
                           IEnumerable<ImAnObserver> observers)
        {
            this.statisticsManager = statisticsManager;
            this.observers = observers;
        }

        public void Initialise(ImARobot robot)
        {
            this.robot = robot;
            statisticsManager.EnsureWeStartWithCleanStatistics();
            CreateObservableForTheStartOfEachTurnFromTheRobot(robot);
            foreach (var observer in observers)
            {
                observer.Observe(this);
            }
        }

Now that every observer gets an opportunity to subscribe to rx observables, I can create myself a new observable that will activate the first commands on the first few turns - here is the StartOfTheBattleObserver class specification:

    public class when_at_the_start_of_the_battle : with_a_start_of_battle_observer
    {
        Establish context = () =>
        {
            statusAtTheStartOfTheTurn = new StatusAtTheStartOfATurn { TurnNumber = 1 };
            statusAtTheStartOfATurnEvent.Stub(s => s.EventArgs)
                                        .Return(statusAtTheStartOfTheTurn);

            startOfTheTurnObservable = Observable.Return(statusAtTheStartOfATurnEvent);

            robotEngine.Stub(e => e.AtTheStartOfEachTurn).Return(startOfTheTurnObservable);
        };

        Because of = () => observer.Observe(robotEngine);

        It should_subscribe_to_the_observable_and_recognise_the_first_turn = () =>
            observer.RecognisedTheFirstTurn.ShouldBeTrue();
    }

    public class with_a_start_of_battle_observer
    {
     Establish context = () =>
        {
            statusAtTheStartOfATurnEvent = 
                MockRepository.GenerateStub<IEvent<StatusAtTheStartOfATurn>>();
            robotEngine = MockRepository.GenerateStub<ImARobotEngine>();
            observer = new StartOfTheBattleObserver();
        };

        protected static StatusAtTheStartOfATurn statusAtTheStartOfTheTurn;
        protected static IEvent<StatusAtTheStartOfATurn> statusAtTheStartOfATurnEvent;
        protected static IObservable<IEvent<StatusAtTheStartOfATurn>> startOfTheTurnObservable;
        protected static ImARobotEngine robotEngine;
        protected static StartOfTheBattleObserver observer;
    }

I'm creating a new observable in my set up that has turn number 1 in the status and am using the same eventing and observable as the last observer - the start of the turn observable. I then assert against a property on the observer - RecognisedTheFirstTurn.
Here's how I get this to pass:

    public class StartOfTheBattleObserver : ImAnObserver
    {
        public void Observe(ImARobotEngine robotEngine)
        {
            robotEngine.AtTheStartOfEachTurn.Where(x => x.EventArgs.TurnNumber ==1)
                       .Subscribe(x => RecognisedTheFirstTurn = true);
        }

        public bool RecognisedTheFirstTurn { get; private set; }
    }

The next step is to issue an instruction to the robot itself, but this observer has no knowledge of the robot instance - this is purposeful. So I need a hook in the robot engine for it to issue instructions and I add that in the specification:

    public class when_at_the_start_of_the_battle : with_a_start_of_battle_observer
    {
        Establish context = () =>
        {
            statusAtTheStartOfTheTurn = new StatusAtTheStartOfATurn { TurnNumber = 1 };
            statusAtTheStartOfATurnEvent.Stub(s => s.EventArgs)
                                        .Return(statusAtTheStartOfTheTurn);

            startOfTheTurnObservable = Observable.Return(statusAtTheStartOfATurnEvent);

            robotEngine.Stub(e => e.AtTheStartOfEachTurn).Return(startOfTheTurnObservable);
            robotEngine.Stub(e => e.IssueInstructionsToRobot(null))
                       .IgnoreArguments().Do(RecordInstruction);
        };

        It should_subscribe_to_the_observable_and_recognise_the_first_turn = () =>
            observer.RecognisedTheFirstTurn.ShouldBeTrue();

        It should_issue_instructions_for_the_robot_engine_to_look_for_enemies = () =>
            ShouldHaveIssuedInstruction(x => x.LookForEnemies());

        static void ShouldHaveIssuedInstruction(Action<ImARobot> expectedInstruction)
        {
            var robot = MockRepository.GenerateStub<ImARobot>();
            if(instructionSentToRobotEngine!=null)
                instructionSentToRobotEngine(robot);
            robot.AssertWasCalled(expectedInstruction);
        }

        static Action<Action<ImARobot>> RecordInstruction = i => 
                                             instructionSentToRobotEngine = i;
        
        static Action<ImARobot> instructionSentToRobotEngine;
    }

On the RobotEngine interface, this specification has driven a new signature for issuing robot instructions... this can be seen in the stubbing of the robot engine:  there is a new method  IssueInstructionToRobot(Action<ImARobot> instruction).

In this stubbed method I'm recording the action that was sent in by providing the two members at the bottom of the specification.

In my assertion I am then applying this action to the robot stub and asserting that a certain instruction was issued - the LookForEnemies instruction. Here is the implementation code:

    public class StartOfTheBattleObserver : ImAnObserver
    {
        public void Observe(ImARobotEngine robotEngine)
        {
            HaveNotLookedForEnemies = true;

            robotEngine.AtTheStartOfEachTurn.Where(x => x.EventArgs.TurnNumber < 10  
                                                              && HaveNotLookedForEnemies)
                       .Subscribe(x =>
                        {
                           RecognisedTheFirstTurn = true;
                           robotEngine.IssueInstructionsToRobot(r => r.LookForEnemies());
                           HaveNotLookedForEnemies = false;
                        });
        }

        protected bool HaveNotLookedForEnemies { get; private set; }

        public bool RecognisedTheFirstTurn { get; private set; }
    }

    public interface ImARobotEngine
    {
        void Initialise(ImARobot robot);

        void IssueInstructionsToRobot(Action<ImARobot> instruction);

        IObservable<IEvent<StatusAtTheStartOfATurn>> AtTheStartOfEachTurn { get; }
    }

    public interface ImARobot
    {
        event EventHandler<StatusAtTheStartOfATurn> StartOfEveryTurn;
        void LookForEnemies();
    }

I've now got an observer that reacts to turn number one (in fact the code above shows a more progressed version where I wrote an additional specification to ensure this happens regardless of whether my robot skips a few turns, or something else untoward happens).
It issues instruction to the robot to look for enemies.

The last part of this implementation is to issue that command in the robot and I do this directly without a specification as it is in my robot adapter layer that speaks directly to robocode:

    public class SlayerRobot : Robot, ImARobot
    {

        public void LookForEnemies()
        {
            TurnRadarRight(360);
        }

        public override void OnScannedRobot(ScannedRobotEvent evnt)
        {
            Fire(1);
        }
    }

So now in theory I'm ready to go and should have my robot firing when it scans other robots.

When I run the battle, my robot scans as shown below, so the observable is being picked up and the instruction is being issued to the robot:

scanning

However, the robot never fires!

I get one 360 rotation of the radar and then the robot is dormant for the rest of the round.
In the next post I'll illustrate the cause and move onto addressing this.



0 comments: