====== Testing agents ======

===== Mock games =====

In order to test agents, you need to set up a "mock" game, place the agents in the situation you want to test, then run the game for a few rounds to see if they behave correctly. We wrote a module, ''/home/student/winterschool/project/pacman/testingTools.py'', that contains the function ''get_mock_game'' to set up a small-scale game. A complete example for testing a game is in ''/home/student/winterschool/project/pacman/test_game.py''.

<code python>
def get_mock_game(layout_txt, agents, first_agent=0):
    """Set up a mock game with given layout and agents.
    Input arguments:
    layout_txt -- a string with the layout of the maze (see layout.py)
    agents -- a list of instances of Agent , the agents that are going to play
              the mock game
    first_agent -- 0 is the red team starts, 1 otherwise
    
    Return (layout, game)
    layout -- an instance of layout.Layout, object representing the maze
    game -- instance of game.Game, with which you can manipulate the game
    """
</code>

The game object can be manipulated using three methods:
  - ''game._init_run()'': initialize the game, must be called to start the game
  - ''game._one_game_step()'': run one step of the game; the first time this function is called, the agent with index 0 is moved; the second time, the agent with index 1; and so on until all agents are moved, and the agent with index 0 is moved again.
  - ''game._end_run()'': end the game, can be called at the end of the game to clean up objects

===== Obtaining game states =====

In order to obtain the game state from the point of view of a particular agent, you should call ''game_state = game.state.makeObservation(agent_index)''. The returned game state is then equivalent to the one received by the agent with ID ''agent_index'' on its turn, including the masking of distant enemies. //Do not use ''game.state'' directly to request information about agents.// The information in ''game.state'' depends on the agent that is currently moving, and so direct requests to the object is prone to introduce bugs in the tests.

===== Example: GoEastAgent =====


Imagine you want to test an agent that always goes East:

<code python>
import basic_agents
from game import Directions

class GoEastAgent(basic_agents.BasicAgent):
    def choose_action(self, game_state):
        return Directions.EAST
</code>

In order to do this, we draw the game maze using symbols for walls (%), food (.), and agents (1,2 represent different agents, odd for one team and even for the other).

<code python>
import unittest
import basic_agents
from testingTools import get_mock_game
from goeast_agents import GoEastAgent

class GoEastTestCase(unittest.TestCase):
    def test_east(self):
        layout_txt = """%%%%%%%%
                        %     2%
                        %     .%
                        %1     %
                        %%%%%%%%
                        """
        # BasicAgent does nothing by default
        lt, game = get_mock_game(layout_txt, [GoEastAgent(0),
                                              basic_agents.BasicAgent(1)])
        game._init_run()
        
        # test that the start position is correct (unnecessary in general)
        game_state = game.state.makeObservation(0)
        assert game_state.getAgentPosition(0) == (1,1)
        game._one_game_step()
        # test that the agent really moved east!
        game_state = game.state.makeObservation(0)
        assert game_state.getAgentPosition(0) == (2,1)

if __name__=='__main__':
    unittest.main()
</code>