Quick Links
Advanced Section
Learn how to take your simulation to the next step using Traversecraft with this tutorial.
Import required modules¶
Let's start by importing the required module form the main library.
It's always a good idea to check whether the library is installed or not. The below command will install the library if the library is not already installed.
!pip install -i https://test.pypi.org/simple/ TraverseCraft
Looking in indexes: https://test.pypi.org/simple/ Requirement already satisfied: TraverseCraft in /media/srajan/Data/Project/LibraryTests/envs/lib/python3.8/site-packages (0.8.5) Requirement already satisfied: prettytable in /media/srajan/Data/Project/LibraryTests/envs/lib/python3.8/site-packages (from TraverseCraft) (0.7.3.dev122)
Let's import Grid World and Grid Agent¶
we will import the CreateGridWorld
class from the world
module and GridAgent
class from the agent
module.
Note: It is very important to call the right agent for the given world, otherwise the module will through an error. Each world behave differently and each agent is tailored for that world only.
Remark: Don't worry if during the importing the library prints the OS Type. Actually the library uses some internal variables which are OS depended. It is necessary that the os type printed and your OS type matches. If it does't match please report this.
from traverseCraft.world import CreateGridWorld
from traverseCraft.agent import GridAgent
OS Type: Linux
Create a Grid World¶
Let's start with creating a 10 x 10 Grid world. But this time we will not use the default settings and will customize our world. We will make the following changes:
cellSize
: Controls the size of each cell in the grid.pathColor
: Set's the color of all the cells where the agent can move.blockColor
: Set's the color of all the cells where the agent can not move.goalColor
: Set the color of all the goal states.
we will set the following color for each type of cell:- Path: green color
- Block: red color
- Goal: gray color
# First let's Create a grid world object!
gridWorld = CreateGridWorld(worldName="Custom Grid World", rows=10, cols=10, cellSize=30, pathColor="green", blockColor="red", goalColor="gray")
Compile our Grid World¶
It is always a good idea to compile the world before doing any changes or modifications into the world.
Note: It is recommended to do all the changes in the world after compiling the world. Although you can change the world even before the compilation but then the world will show some partial information before compiling the world takes place.
Warning: Don't worry if the window showed up. Please don't destroy the window. This is due to the fact that the cell in jupyter notebook is running the process and the frame generated will reflect all the changes done after this point. If you destroy the window then it will show error.
gridWorld.constructWorld()
Add Block and Goal States¶
You may be wondering what the goal and block states were in the previous section. So the main goal of this library is to run simulations right!. Thus it make sense that the simulated world should have some cells which are walls or block or restricted areas which are the block cells and there should also some goal states which are the goal cells.
Note: a world can have none block states but it must have at least 1 goal state. Also a world can have more than 1 goal state and can also have more than 1 block states. But make the goal state can't be a block state.
By default the goal state will be the bottom right corner cell.
We will change the goal state and set some cells to be the block states.
- The block state cells are [[2,2], [3,6], [1,1], [7,8], [9,1], [0,5]]
- The goal state cells are [[5,6], [9,1]]
To achieve this we will use the setBlockPath()
and setGoalState()
methods.
Note: onces you execute the below command you will see the window opened after the world compilation will reflect all the changes. This way you can verify the changes in your world.
# Block cells
blockCells = [[2,2], [3,6], [1,1], [7,8], [9,1], [0,5]]
gridWorld.setBlockPath(blockCells)
# Goal cells
goalCells = [[5,6], [9,1]]
gridWorld.setGoalState(goalCells)
Undo a Change¶
Assume you want to set another set of cells as block or goal states, then one way is to simple run the setBlockPath()
or setGoalState()
method again with the new set of cells coordinates to refresh the block or goal state cells.
Note: when you rerun the method, it will reset the state to the new set of cells, it will not extend or add the cells to the previously existing cells.
let's refresh the block and goal state¶
- add [[0,3], [7,0]] to our existing block state.
- add [[0, 9], [7, 6]] to our existing goal state.
The changes will be reflected in the window.
# extend the block cells
blockCells.extend([[0,3], [7, 0]])
gridWorld.setBlockPath(blockCells)
# extend the goal cells
goalCells.extend([[0,9], [7,6]])
gridWorld.setGoalState(goalCells)
Warning: You can toggle between the block state and path state, But once a cell is set to goal state you can not change the state of the cell.
Let's see some basic information about our Grid World!¶
you can use a simple print()
statement or you can use the builtin function aboutWorld()
to get the world information as a string.
print(gridWorld)
+-------------------------+------------------------------------------------------------------+ | Attribute | Value | +-------------------------+------------------------------------------------------------------+ | World Name | Custom Grid World | | Rows | 10 | | Columns | 10 | | Cell Size | 30 | | Cell Padding | 2 | | Window Size | 402x357 | | Goal Cells | [[5, 6], [9, 1], [0, 9], [7, 6]] | | Block Cells | [[2, 2], [3, 6], [1, 1], [7, 8], [9, 1], [0, 5], [0, 3], [7, 0]] | | Path Color | green | | Block Color | red | | Goal Color | gray | | Border Width | 1 | | Button Background Color | #7FC7D9 | | Button Foreground Color | #332941 | | Button Text | Start Agent | | Text Font | Helvetica | | Text Size | 24 | | Text Weight | bold | +-------------------------+------------------------------------------------------------------+
help(gridWorld)
Help on CreateGridWorld in module traverseCraft.world object: class CreateGridWorld(builtins.object) | CreateGridWorld(worldName: str, rows: int, cols: int, cellSize: int = 20, pathColor: str = 'gray', blockColor: str = 'red', goalColor: str = 'green', cellPadding: int = 2, borderWidth: int = 1, buttonBgColor: str = '#7FC7D9', buttonFgColor: str = '#332941', textFont: str = 'Helvetica', textSize: int = 24, textWeight: str = 'bold', buttonText: str = 'Start Agent', logoPath: str = None) | | Class representing the world created using Grids. | | Attributes: | setOfCoordinates (List[List[int]]): A list of coordinates. | coordinate (List[int]): A list representing a coordinate. | worldID (str): The ID of the world. | | Args: | _worldName (str): The name of the world. | _rows (int): The number of rows in the world. (Between 0 and 50) | _cols (int): The number of columns in the world. (Between 0 and 50) | _logoPath (str): The path to the logo image. | _world (List[List[int]]): A 2D list representing the world. | _blockCells (setOfCoordinates): A set of coordinates representing the block cells. | _cellSize (int): The size of each cell in pixels.Defaults to 10. (Between 10 and 60) | _pathColor (str): The color of the path cells. Defaults to "gray". | _cellPadding (int): The padding around each cell in pixels. Defaults to 2. | _blockColor (str): The color of the block cells. Defaults to "red". | _borderWidth (int): The width of the cell borders in pixels. Defaults to 1. | _goalColor (str): The color of the goal cells. Defaults to "green". | _goalCells (setOfCoordinates): A set of coordinates representing the goal cells. | _buttonBgColor (str): The background color of the button. Defaults to "#7FC7D9". | _buttonFgColor (str): The foreground color of the button. Defaults to "#332941". | _textFont (str): The font of the button text. Defaults to "Helvetica". | _textSize (int): The size of the button text. Defaults to 24. | _textWeight (str): The weight of the button text. Defaults to "bold". | _buttonText (str): The text displayed on the button. Defaults to "Start Agent". | _root (Tk): The root window of the world. | _agent (Agent): The agent object. | _logoPath (str): The path to the logo image. | | Methods defined here: | | __init__(self, worldName: str, rows: int, cols: int, cellSize: int = 20, pathColor: str = 'gray', blockColor: str = 'red', goalColor: str = 'green', cellPadding: int = 2, borderWidth: int = 1, buttonBgColor: str = '#7FC7D9', buttonFgColor: str = '#332941', textFont: str = 'Helvetica', textSize: int = 24, textWeight: str = 'bold', buttonText: str = 'Start Agent', logoPath: str = None) | Initializes the Grid World. | | __str__(self) | Describes the attributes of the world. | | Parameters: | None | | Returns: | function(): The attributes of the world. | | aboutWorld(self) | Describes the attributes of the world. | | Parameters: | None | | Returns: | str: The attributes of the world. | | constructWorld(self) | Constructs the world by creating and arranging cells in the GUI. | If the goal cells are not set, it creates a goal cell at the bottom-right corner of the grid. | It also creates cells for each row and column in the grid, and binds a left-click event to toggle the cells. | Finally, it creates a "Start Agent" button at the bottom of the grid. | | Parameters: | None | | Returns: | None | | setAgent(self, agent) | Set the agent for the world. | | Parameters: | agent (Agent): The agent object to set. | | Returns: | None | | setBlockPath(self, blockCells: List[List[int]]) | Adds block cells to the world grid. | | Parameters: | blockCells (setOfCoordinates): A set of coordinates representing the block cells. | | Returns: | None | | setGoalState(self, goalState: List[List[int]]) | Adds the goal state to the world grid. | | Parameters: | goalState (setOfCoordinates): A set of coordinates representing the goal state. | | Returns: | None | | showWorld(self) | Displays the world. | | Parameters: | None | | Returns: | None | | summary(self) | Generates a summary of the world. | | Parameters: | None | | Returns: | str: The summary of the world. | | updateWorld(self) | Updates the world by positioning the cells in a grid layout and updating the root window. | | This method iterates over each cell in the world and positions it in a grid layout using the row and column indices. | It also updates the root window to reflect any changes made to the world. | | Note: | - The cells are positioned using the `grid` method with the specified row and column indices. | - The `sticky` parameter is set to "nsew" to make the cells stick to all sides of their respective grid cells. | - The `padx` and `pady` parameters specify the padding around each cell. | | Parameters: | None | Returns: | None | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) | | ---------------------------------------------------------------------- | Data and other attributes defined here: | | coordinate = typing.List[int] | The central part of internal API. | | This represents a generic version of type 'origin' with type arguments 'params'. | There are two kind of these aliases: user defined and special. The special ones | are wrappers around builtin collections and ABCs in collections.abc. These must | have 'name' always set. If 'inst' is False, then the alias can't be instantiated, | this is used by e.g. typing.List and typing.Dict. | | setOfCoordinates = typing.List[typing.List[int]] | The central part of internal API. | | This represents a generic version of type 'origin' with type arguments 'params'. | There are two kind of these aliases: user defined and special. The special ones | are wrappers around builtin collections and ABCs in collections.abc. These must | have 'name' always set. If 'inst' is False, then the alias can't be instantiated, | this is used by e.g. typing.List and typing.Dict. | | worldID = 'GRIDWORLD'
Let's create our agent which will interact with the world.¶
We will create a grid agent with the following custom settings.
agentColor
: set the color of the cell where the agent is present.heatMapView
: set True or False to decide whether to see the heatmap in realtime in simulation or not.agentPos
: set the beginning cell coordinates of the agent.
we will set the values to the following:
- agentColor: aqua
- heatMapView: False(to only see the simulation)
- agentPos: (4,4)
startState = (4,4)
gridAgent = GridAgent(agentName="Grid Agent", world=gridWorld, agentColor="aqua", heatMapView=False, agentPos=startState)
You can see the agent position get reflected in the window.
Let's see some basic information about our grid Agent
.¶
you can use a simple print()
statement or you can use the builtin function aboutAgent()
to get the agent information as a string.
print(gridAgent)
+----------------+-------------------+ | Attribute | Value | +----------------+-------------------+ | Agent Name | Grid Agent | | Agent Color | aqua | | World Name | Custom Grid World | | World ID | GRIDWORLD | | Start Position | (4, 4) | +----------------+-------------------+
Connect Our Agent with the World¶
Now, we have our world ready and constructed and we also have our agent ready, but the world doesn't know the agent and the agent does't know the world. We have to connect the agent with the world. We will use the .setAgent()
method of the world to connect the agent with the world.
gridWorld.setAgent(gridAgent)
Algorithm¶
Now, we have connected the agent with the world, but we did not told the agent what to do in the world.
The agent have a method setAlgorithmCallBack()
which takes a function as a argument.
This function will be run during the simulation.
Note: Make sure that the function you are passing in the
setAlgorithmCallBack()
method does not take any argument.
Let's first create our Algorithm that will move the agent.¶
We will write a simple DFS algorithm to move our agent, and our main goal will be to get to any goal state.
Some Useful methods¶
checkGoalState()
method is use to check whether the given coordinate is a goal state or not.checkBlockState()
method is use to check whether the given coordinate is a block state or not.moveAgent()
this method will return False if it is not possible to move the agent to the given cell coordinates or will move the agent and return True if it is possible. We can also control the delay in the movement using thedelay
parameter.
DFS Algorithm¶
def dfs(agent, i, j, visited):
if(agent.checkGoalState(i, j)):
return True
if(visited[i][j]):
return False
visited[i][j] = True
# move up
if(i > 0 and not visited[i-1][j] and agent.moveAgent(i-1, j)):
if(dfs(agent, i-1, j, visited)):
return True
agent.moveAgent(i, j)
# move down
if(i < 9 and not visited[i+1][j] and agent.moveAgent(i+1, j)):
if(dfs(agent, i+1, j, visited)):
return True
agent.moveAgent(i, j)
# move left
if(j > 0 and not visited[i][j-1] and agent.moveAgent(i, j-1)):
if(dfs(agent, i, j-1, visited)):
return True
agent.moveAgent(i, j)
# move right
if(j < 9 and not visited[i][j+1] and agent.moveAgent(i, j+1)):
if(dfs(agent, i, j+1, visited)):
return True
agent.moveAgent(i, j)
return False
We will use the dfs Algorithm in the main callback function¶
Remember: Since the call back function will only accept a function with no arguments, thus it is always a good idea to create another function which takes the arguments and use that function in the call back function.
def toDo():
visited = [[False for _ in range(10)] for _ in range(10)]
print("Agent Started moving around the world!")
if(dfs(gridAgent, startState[0], startState[1], visited)):
print("Agent reached the goal state!")
else:
print("Agent could not reach the goal state!")
We are ready with our algorithm¶
Lets set the algorithm to tell the agent what to do.
gridAgent.setAlgorithmCallBack(toDo)
Display the world and Start the Simulation!¶
Now, we are all set. We will first show the world using the showWorld()
method and then on the world there is a button at the bottom to start the simulation.
Fun Fact: You can click on any non goal cell to toggle between block and path state.
Warning: Always make sure that the method
showWorld()
is called when you are ready to simulate, because after this no change can be made on the world or the agent.
gridWorld.showWorld()
Agent Started moving around the world! Agent reached the goal state!
In the window You can see that, this time no heatmap is forming where the agent is going. This happened because we switch off this feature also by simple changing the value of heatMapView
to False
during the grid agent object creation.
You can also see there is a slight delay in the movement of the agent, this is also a feature of agent, you can control the delay while calling the moveAgent
method by the parameter delay
.
Let's see the summary¶
The agent and the world keep some records, that we can generate and see.
The Agent have information about the time taken to run the whole simulation.¶
We can see this information using the summary
method.
print(gridAgent.summary())
+--------------+---------------------------+ | Attribute | Value | +--------------+---------------------------+ | Start Time | Wed, 19 Jun 2024 18:14:15 | | End Time | Wed, 19 Jun 2024 18:14:39 | | Elapsed Time | 23.1 sec | +--------------+---------------------------+
The World have information about the visited count after the whole simulation.¶
We can see this information using the summary
method.
print(gridWorld.summary())
+------+---+---+---+---+---+---+---+---+---+---+ | Cell | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +------+---+---+---+---+---+---+---+---+---+---+ | 0 | 2 | 2 | 2 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | | 1 | 2 | 0 | 1 | 1 | 2 | 0 | 0 | 0 | 0 | 0 | | 2 | 2 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | | 3 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | | 4 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | | 5 | 1 | 2 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | | 6 | 1 | 2 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | | 7 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | | 8 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | | 9 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | +------+---+---+---+---+---+---+---+---+---+---+
help(gridAgent)
Help on GridAgent in module traverseCraft.agent object: class GridAgent(builtins.object) | GridAgent(world, agentName: str, agentColor: str = 'blue', heatMapView: bool = True, heatMapColor: str = '#FFA732', agentPos: tuple = (0, 0), heatGradient: float = 0.05) | | The Grid Agent class. | | Parameters: | - world (CreateGridWorld): The grid world object in which the agent operates. | - agentName (str): The name of the agent. | - agentColor (str, optional): The color of the agent. Defaults to "blue". | - heatMapView (bool, optional): Whether to enable the heat map view. Defaults to True. | - heatMapColor (str, optional): The color of the heat map. Defaults to "#FFA732". | - agentPos (tuple, optional): The initial position of the agent. Defaults to (0, 0). | - heatGradient (float, optional): The gradient value for the heat map. Defaults to 0.05. | | Attributes: | _worldObj (CreateGridWorld): The grid world object. | _worldID (str): The ID of the world. | _root (Tk): The root Tkinter object from the grid world. | _agentName (str): The name of the agent. | _agentColor (str): The color of the agent. | _heatMapView (bool): Indicates if the heat map view is enabled. | _heatMapColor (str): The color of the heat map. | _heatMapBaseColor (str): The base color of the heat map. | _heatGradient (float): The gradient value for the heat map. | _startState (tuple): The initial position of the agent. | _currentPosition (tuple): The current position of the agent. | _startTime (float): The start time of the agent. | _endTime (float): The end time of the agent. | algorithmCallBack (function): Callback function for the agent's algorithm. | | Methods defined here: | | __init__(self, world, agentName: str, agentColor: str = 'blue', heatMapView: bool = True, heatMapColor: str = '#FFA732', agentPos: tuple = (0, 0), heatGradient: float = 0.05) | Initialize self. See help(type(self)) for accurate signature. | | __str__(self) | Describes the attributes of the world. | | Parameters: | None | | Returns: | function(): The attributes of the world. | | aboutAgent(self) | Prints information about the agent. | | Parameters: | None | | Returns: | str: A string containing information about the agent. | | checkBlockState(self, i, j) | Check the state of a block in the world. | | Parameters: | i (int): The row index of the block. | j (int): The column index of the block. | | Returns: | bool: True if the block is empty (-1), False otherwise. | | checkGoalState(self, i, j) | Check if the given position (i, j) is a goal state. | | Parameters: | i (int): The row index of the position. | j (int): The column index of the position. | | Returns: | bool: True if the position is a goal state, False otherwise. | | getHeatMapColor(self, value: float) | Maps a value to a color on a heat map. | | Args: | value (float): The value to be mapped. | | Returns: | tuple: The RGB color tuple representing the mapped value on the heat map. | | moveAgent(self, i, j, delay: float = 0.5) | Moves the agent to the specified position (i, j) on the grid. | | Args: | i (int): The row index of the target position. | j (int): The column index of the target position. | delay (int, optional): The delay in seconds before moving the agent. Defaults to 1. | | Returns: | bool: True if the agent successfully moves to the target position, False otherwise. | | runAlgorithm(self) | Executes the algorithm callback function. | | Raises: | ValueError: If the algorithm callback function is not set. | | setAlgorithmCallBack(self, algorithmCallBack) | Set the callback function for the algorithm. | | Parameters: | algorithmCallBack (function): The callback function to be set. | | Returns: | None | | setStartState(self, i: int, j: int) | Sets the start state of the agent to the specified position (i, j). | | Args: | i (int): The row index of the start position. | j (int): The column index of the start position. | | Raises: | ValueError: If the specified start position is invalid. | | summary(self) | Returns a summary of the agent run. | | Parameters: | None | Returns: | str: A summary of the agent run. | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined)
This covers all the required features and knowledge required to create simulations for Grid World.
Next, please refer the API Reference section for more details regarding each class and methods.
Thanks!