diff --git a/Algorithms/.gitignore b/Algorithms/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..5f2c97937124264fdebf3602664c58bc39290ee6
--- /dev/null
+++ b/Algorithms/.gitignore
@@ -0,0 +1,30 @@
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+.idea/
+
+# Generated files
+.idea/**/contentModel.xml
+
+.DS_Store
+__pycache__/
+
+
+# Extra
+./build
+./obj
+./Logs
+./Library
+./Temp
+./ProjectSettings
+
+
+# algorithms
+*.tour
+*.par
+*.tsp 
+
+
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/EnvChannel.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/EnvChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..89909eccb160d3bebb15087e72541ddbdd4ce2fd
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/EnvChannel.py
@@ -0,0 +1,45 @@
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from EnvironmentData import EnvironmentData
+
+"""
+class that processes information from SideChannel EnvChannel
+"""
+
+class EnvChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("621f0a70-4f87-11ea-a6bf-784f4387d1f7")) #must coincide with ChannelId set in c#
+        self.EnvData = EnvironmentData() # object that stores info on environment
+
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        data = msg.read_string()
+        environment_info = json.loads(data)
+
+        self.EnvData.matrix = environment_info["matrixLayout"]
+        self.EnvData.rotation = environment_info["rotationRobot"]
+        self.EnvData.action_size = environment_info["sizeOfAction"]
+        self.EnvData.observation_size = environment_info["sizeOfObservation"]
+        self.EnvData.number_of_robots = environment_info["numberOfRobotsInEnv"]
+        self.EnvData.number_of_current_tasks = environment_info["numberOfCurrentTasks"]
+        self.EnvData.can_go_backwards = environment_info["backwards"]
+        self.EnvData.random_tasks = environment_info["tasksGeneratedRandomly"]
+        self.EnvData.instance_ids = environment_info["instanceIDSRobots"]
+
+        self.EnvData.set_initial_nodes_dictionary(environment_info["initialNodesOfRobots"])
+        self.EnvData.set_tasks_to_be_assigned(environment_info["currentTasks"])
+        self.EnvData.set_assigned_tasks()
+
+    def send_string(self, data: str) -> None:
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/EnvironmentData.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/EnvironmentData.py
new file mode 100644
index 0000000000000000000000000000000000000000..5156f445b07ce2351c4b0dcd5ea506e3135bf990
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/EnvironmentData.py
@@ -0,0 +1,92 @@
+# stores data on environment
+# initialized when initial data is being sent through EnvChannel
+import json
+import numpy as np
+
+from Node import Node
+
+import ta_task
+from ta_state import Location
+
+
+class EnvironmentData:
+
+    def __init__(self):
+        self.matrix = None
+        self.rotation = None
+        self.action_size = None
+        self.observation_size = None
+        self.number_of_robots = None
+        self.number_of_current_tasks = None
+        self.can_go_backwards = None
+        self.random_tasks = None  # if set to true random tasks will be send whenever a task has been completed,
+        # otherwise all tasks self.tasks_to_be_assigned
+
+        self.instance_ids = []
+        self.current_nodes_dictionary = {} # dictionary instance_id -> current node
+        self.tasks_to_be_assigned = [] # tasks that are still to be assigned
+        self.assigned_tasks_dictionary = {} # dictionary instance_id -> assigned task
+
+        self.task_side_channel = None
+
+    #########################################
+    ## methods used by EnvChannel to initialize attributes:
+    #########################################
+
+    # set_initial_nodes_dictionary
+    # set_tasks_to_be_assigned
+    # set_assigned_tasks
+
+    # given a correct string containing array of nodes
+    def set_initial_nodes_dictionary(self, initial_nodes):
+        for i in range(self.number_of_robots):
+            self.current_nodes_dictionary[self.instance_ids[i]] = Node(initial_nodes[i]["GridPosition"]["Row"],
+                                                      initial_nodes[i]["GridPosition"]["Column"],
+                                                      initial_nodes[i]["Degrees"])
+
+    # given a correct json_string containing array of tasks
+    def set_tasks_to_be_assigned(self, tasks):
+        for i in range(self.number_of_current_tasks):
+            pickup = Location(tasks[i]["PickUp"]["Column"],
+                              tasks[i]["PickUp"]["Row"], 0)
+            delivery = Location(
+                tasks[i]["Delivery"]["Column"], tasks[i]["Delivery"]["Row"], 0)
+            releaseTime = tasks[i]["ReleaseTime"]
+            new_task = ta_task.Task(ta_task.CURRENT_TASK_ID, releaseTime,
+                            pickup, delivery, None)
+            ta_task.CURRENT_TASK_ID += 1
+            self.tasks_to_be_assigned.append(new_task)
+
+    # initialize dictionary robot instance_id -> task (None)
+    def set_assigned_tasks(self):
+        for i in range(self.number_of_robots):
+            self.assigned_tasks_dictionary[self.instance_ids[i]] = None
+
+    #########################################
+    ## methods used to update environment info
+    #########################################
+
+    # when a task is assigned to a robot, it has to be added to self.assigned_tasks
+    # and removed from self.tasks_to_be_assigned
+    # info has to be sent to unity via the correct channel
+    def assign_task(self, robot_instanceID, task):
+        self.assigned_tasks_dictionary[robot_instanceID] = task
+        self.tasks_to_be_assigned.remove(task)
+        taskDict = {"Task": {
+            "PickUp": {"Column": str(task.pickup_endpoint.col), "Row": str(task.pickup_endpoint.row)},
+            "Delivery": {"Column": str(task.delivery_endpoint.col), "Row": str(task.delivery_endpoint.row)},
+            "ReleaseTime": str(task.release_time)},
+                    "InstanceID": int(robot_instanceID)}
+
+        self.task_side_channel.send_string(json.dumps(taskDict))
+
+    # when a new task is available it is added to tasks_to_be_assigned
+    # a check is made whether there are still tasks that can be added, but this should not be happening (diagnostical)
+    def add_task_to_tasks_to_be_assigned(self, task):
+        if len(self.tasks_to_be_assigned) == self.number_of_current_tasks:
+            raise Exception("cannot add more tasks")
+        self.tasks_to_be_assigned.append(task)
+
+    # when a robot has finished his task it has to be removed from assigned_tasks
+    def task_done(self, instance_id):
+        self.assigned_tasks_dictionary[instance_id] = None
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH-2_USER_GUIDE.pdf b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH-2_USER_GUIDE.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..5b6edc40d0d640399ffdb78307263c7c0707b534
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH-2_USER_GUIDE.pdf differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH-3_PARAMETERS.pdf b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH-3_PARAMETERS.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..7642480b7ccc43f184818f62829ad0dd75c2f6cd
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH-3_PARAMETERS.pdf differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH-3_REPORT.pdf b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH-3_REPORT.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..cf04bb69d91ea29d79a7ba8880cd3d3899747dd1
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH-3_REPORT.pdf differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH_Genetic.pdf b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH_Genetic.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..db5d376fdd3ce0725a2905312762e8f5ae416fb1
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH_Genetic.pdf differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH_REPORT.pdf b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH_REPORT.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..333e254a7f1a76a951240626f1ba8fc830bdd99e
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/LKH_REPORT.pdf differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/POPMUSIC_REPORT.pdf b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/POPMUSIC_REPORT.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..c957427ad8c7ddac33947df6d525f39226d2574c
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/POPMUSIC_REPORT.pdf differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/TSPLIB_DOC.pdf b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/TSPLIB_DOC.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..c109b3a0ea7c35ea91f59eccb9e034202a6238a9
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/DOC/TSPLIB_DOC.pdf differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKH-3.exe b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKH-3.exe
new file mode 100644
index 0000000000000000000000000000000000000000..132733fbc6ddd5fbfaec3b2fc792f8404e1b4fd6
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKH-3.exe differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKHWin-3.0.6-WinChanges.zip b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKHWin-3.0.6-WinChanges.zip
new file mode 100644
index 0000000000000000000000000000000000000000..4d8fdea33ef7ea8799b4f8abcd1e82276180bd25
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKHWin-3.0.6-WinChanges.zip differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKH_linux b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKH_linux
new file mode 100644
index 0000000000000000000000000000000000000000..8a9ab0d5394332e166a8332d956afb089a077bfa
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKH_linux differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/Makefile b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..4849d972907664b17c5bd9310455084e203789cd
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/Makefile
@@ -0,0 +1,4 @@
+all:
+	make -C SRC
+clean:
+	make -C SRC clean
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/README.txt b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..30c5f622fa2b23276bac3aa5d21169249fc738d5
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/README.txt
@@ -0,0 +1,146 @@
+LKH is an implementation of the Lin-Kernighan traveling salesman heuristic.
+
+The code is distributed for research use. The author reserves all rights to 
+the code.
+
+
+INSTRUCTIONS FOR INSTALLATION: (Version 3.0.3 - July 2018)
+-----------------------------
+
+The software is available in gzipped tar format:
+
+	LKH-3.0.3.tgz	(approximately 2.3 MB)
+
+Download the software and execute the following UNIX commands:
+
+  	tar xvfz LKH-3.0.3.tgz
+   	cd LKH-3.0.3
+	make
+
+An executable file called LKH will now be available in the directory LKH-3.0.3.
+
+To test the installation run the program by typing ./LKH pr2392.par. 
+Then press return. The program should now solve a TSP instance with 2392 nodes.
+
+For testing the installation on an mTSP problem, type ./LKH whizzkids96.par.
+Then press return.
+
+A two-level tree is used as the default tour representation. 
+A three-level tree representation may be used instead by compiling the
+source code with the compiler option 
+
+	-DTHREE_LEVEL_TREE
+
+Just edit the first line in SRC/Makefile and execute the commands
+
+	make clean
+	make
+
+CHANGES IN VERSION 3.0.3:
+-------------------------
+
+Candidate sets may now be created by means of POPMUSIC by giving the following
+specification in the parameter file for LKH:
+
+	CANDIDATE_SET_TYPE = POPMUSIC
+
+The value of the parameter MAX_CANDIDATES is used to trim the candidate set.
+There are, however, some other POPMUSIC related parameters. If not specified,
+they will take their default values. These parameters are:
+
+    POPMUSIC_SAMPLE_SIZE = <int>  
+    Sample size.
+    Default: 10.
+
+    POPMUSIC_SOLUTIONS = <int> 
+    Number of solutions to generate.
+    Default: 50.
+
+    POPMUSIC_MAX_NEIGHBORS = <int>
+    Maximum number of nearest neighbors used as candidates in iterated 3-opt for
+    POPMUSIC.
+    Default: 5.
+
+    POPMUSIC_TRIALS = <int>
+    Number of trials used in iterated 3-opt for POPMUSIC. 
+    If the value is zero, the number of trials is the size of the subpath
+    to be optimized.
+    Default: 1.
+
+    POPMUSIC_INITIAL_TOUR = { YES | NO }
+    Specifies whether the first generated POPMUSIC tour is used as
+    initial tour for Lin-Kernighan.
+    Default: NO.
+
+CHANGES IN VERSION 3.0.2:
+-------------------------
+
+Tours may now be recombined by GPX2 (Generalized Partition Crossover 2) 
+instead of IPT (Iterative Partial Transcription). 
+
+GPX2 is used by giving the following specification in the parameter file:
+
+	RECOMBINATION = GPX2
+
+The possible settings are:
+
+	RECOMBINATION = { IPT | GPX2 } 
+
+IPT is default.
+
+	
+CHANGES IN VERSION 3.0.1:
+-------------------------
+
+    New problem type: TSPDL (traveling salesman with draft limits)
+
+NEW IN VERSION 3.0:
+-------------------
+	
+New parameter keywords:
+
+	BWTSP = <integer> <integer> [ <integer> ]
+	DEPOT = <integer>
+	MAKESPAN = { YES | NO }	MTSP_MIN_SIZE = <integer>
+	MTSP_MAX_SIZE = <integer>
+	MTSP_OBJECTIVE = [ MINMAX | MINMAX_SIZE | MINSUM ]
+	MTSP_RESULT_FILE = <string>
+	SINTEF_RESULT_FILE = <string>
+	SALESMEN = <integer>
+	SCALE = <integer>
+	VEHICLES : <integer>
+
+	New initial tour algorithms:
+	CVRPR
+	MTSP
+	SOP 
+
+New TSPLIB format keywords:
+
+The specification part: 
+
+	CAPACITY : <integer>
+	DEMAND_DIMENSION : <integer>
+	DISTANCE : <real>
+	GRID_SIZE : <real>
+	RISK_THRESHOLD : <integer>
+	SALESMEN : <integer>
+	SCALE : <integer> 
+	SERVICE_TIME_SECTION 
+	VEHICLES : <integer>
+
+	New edge weight types:	
+	EXACT_2D
+	EXACT_3D 
+	FLOOR_2D
+	FLOOR_3D
+	TOR_2D
+	TOR_3D 
+
+The data part: 
+
+	BACKHAUL_SECTION
+	DEMAND_SECTION
+	DEPOT_SECTION
+	PICKUP_AND_DELIVERY_SECTION
+	TIME_WINDOW_SECTION
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/SRC.zip b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/SRC.zip
new file mode 100644
index 0000000000000000000000000000000000000000..4dd16c6a5d327c5bac3f7b15a7a7888013e22a2e
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/SRC.zip differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Node.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Node.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2bb07c8fdf941ab68a8e8c87e8478b6d2e79aba
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Node.py
@@ -0,0 +1,39 @@
+# Class Node represent nodes in the graph. Every node contains a
+# position (x,y) in the grid
+# and a rotation in degree where
+# 0 = North
+# 90 = East
+# 280 = South
+# 270 = West
+# all degrees must be between 0 and 360
+
+# attributes are set to private such that they cannot be overwritten and there is no problem with the hash
+
+class Node:
+    def __init__(self,x,y,g):
+        self._x = x
+        self._y = y
+        self._g = g
+
+    @property
+    def x(self):
+        return self._x
+
+    @property
+    def y(self):
+        return self._y
+
+    @property
+    def g(self):
+        return self._g
+
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.x == other.x and self.y == other.y and self.g == other.g
+
+
+    def __hash__(self):
+        return (((self.x * 397) ** self.y) * 397) **self.g
+
+    def __str__(self):
+        return "[(" + str(self.x) + ", " + str(self.y) + ")" + "," + str(self.g) + "]"
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/PickupAndDeliveryChannel.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/PickupAndDeliveryChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..c7b40e6db4ea21d3a9eb72b29558fe4b9260ddfb
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/PickupAndDeliveryChannel.py
@@ -0,0 +1,36 @@
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+"""
+class that processes information from SideChannel EnvChannel
+"""
+
+NEW_TASKS = []
+
+
+# Create the StringLogChannel class
+class PaDChannel(SideChannel):
+
+    def __init__(self) -> None:
+        # must coincide with ChannelId set in c#
+        super().__init__(uuid.UUID("621f0a70-4f87-11ea-a6bf-784f4387d1f8"))
+
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        data = msg.read_string()
+        print(f"Received info from side channel: {data}")
+        args = data.split(" ")
+        NEW_TASKS.append(args[1:])
+        print(f"New Task({args[1]}, {args[2]}, {args[3]})")
+
+    def send_string(self, data: str) -> None:
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Pipfile b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Pipfile
new file mode 100644
index 0000000000000000000000000000000000000000..9b2afe2db3b43b974e3fc2244ddb1076119118dc
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Pipfile
@@ -0,0 +1,15 @@
+[[source]]
+url = "https://pypi.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+networkx = "==2.5"
+mlagents = "==0.23.0"
+mlagents-envs = "==0.23.0"
+numpy = "*"
+
+[dev-packages]
+
+[requires]
+python_version = "3.6"
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Pipfile.lock b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Pipfile.lock
new file mode 100644
index 0000000000000000000000000000000000000000..b182fb88a1831f2730b6e59774e840f5498a278a
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Pipfile.lock
@@ -0,0 +1,528 @@
+{
+    "_meta": {
+        "hash": {
+            "sha256": "7d5bfdeb402549418fd529d32756528fb1c7c6815d55687f16e3784120edf6c8"
+        },
+        "pipfile-spec": 6,
+        "requires": {
+            "python_version": "3.6"
+        },
+        "sources": [
+            {
+                "name": "pypi",
+                "url": "https://pypi.org/simple",
+                "verify_ssl": true
+            }
+        ]
+    },
+    "default": {
+        "absl-py": {
+            "hashes": [
+                "sha256:62bd4e248ddb19d81aec8f9446b407ff37c8175c2ba88266a7afa9b4ce4a333b",
+                "sha256:6953272383486044699fd0e9f00aad167a27e08ce19aae66c6c4b10e7e767793"
+            ],
+            "version": "==0.13.0"
+        },
+        "attrs": {
+            "hashes": [
+                "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
+                "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+            "version": "==21.2.0"
+        },
+        "cached-property": {
+            "hashes": [
+                "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130",
+                "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"
+            ],
+            "markers": "python_version < '3.8'",
+            "version": "==1.5.2"
+        },
+        "cachetools": {
+            "hashes": [
+                "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001",
+                "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"
+            ],
+            "markers": "python_version ~= '3.5'",
+            "version": "==4.2.2"
+        },
+        "cattrs": {
+            "hashes": [
+                "sha256:616972ae3dfa6e623a40ad3cb845420e64942989152774ab055e5c2b2f89f997",
+                "sha256:b7ab5cf8ad127c42eefd01410c1c6e28569a45a255ea80ed968511873c433c7a"
+            ],
+            "version": "==1.0.0"
+        },
+        "certifi": {
+            "hashes": [
+                "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee",
+                "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"
+            ],
+            "version": "==2021.5.30"
+        },
+        "chardet": {
+            "hashes": [
+                "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
+                "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+            "version": "==4.0.0"
+        },
+        "cloudpickle": {
+            "hashes": [
+                "sha256:3a32d0eb0bc6f4d0c57fbc4f3e3780f7a81e6fee0fa935072884d58ae8e1cc7c",
+                "sha256:9bc994f9e9447593bd0a45371f0e7ac7333710fcf64a4eb9834bf149f4ef2f32"
+            ],
+            "markers": "python_version >= '3.5'",
+            "version": "==1.6.0"
+        },
+        "dataclasses": {
+            "hashes": [
+                "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf",
+                "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"
+            ],
+            "markers": "python_version < '3.7'",
+            "version": "==0.8"
+        },
+        "decorator": {
+            "hashes": [
+                "sha256:6e5c199c16f7a9f0e3a61a4a54b3d27e7dad0dbdde92b944426cb20914376323",
+                "sha256:72ecfba4320a893c53f9706bebb2d55c270c1e51a28789361aa93e4a21319ed5"
+            ],
+            "markers": "python_version >= '3.5'",
+            "version": "==5.0.9"
+        },
+        "google-auth": {
+            "hashes": [
+                "sha256:9266252e11393943410354cf14a77bcca24dd2ccd9c4e1aef23034fe0fbae630",
+                "sha256:c7c215c74348ef24faef2f7b62f6d8e6b38824fe08b1e7b7b09a02d397eda7b3"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
+            "version": "==1.32.1"
+        },
+        "google-auth-oauthlib": {
+            "hashes": [
+                "sha256:09832c6e75032f93818edf1affe4746121d640c625a5bef9b5c96af676e98eee",
+                "sha256:0e92aacacfb94978de3b7972cf4b0f204c3cd206f74ddd0dc0b31e91164e6317"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==0.4.4"
+        },
+        "grpcio": {
+            "hashes": [
+                "sha256:0e193feaf4ebc72f6af57d7b8a08c0b8e43ebbd76f81c6f1e55d013557602dfd",
+                "sha256:118479436bda25b369e2dc1cd0921790fbfaea1ec663e4ee7095c4c325694495",
+                "sha256:1f79d8a24261e3c12ec3a6c25945ff799ae09874fd24815bc17c2dc37715ef6c",
+                "sha256:26af85ae0a7ff8e8f8f550255bf85551df86a89883c11721c0756b71bc1019be",
+                "sha256:278e131bfbc57bab112359b98930b0fdbf81aa0ba2cdfc6555c7a5119d7e2117",
+                "sha256:2a179b2565fa85a134933acc7845f9d4c12e742c802b4f50bf2fd208bf8b741e",
+                "sha256:3a25e1a46f51c80d06b66223f61938b9ffda37f2824ca65749c49b758137fac2",
+                "sha256:3db0680fee9e55022677abda186e73e3c019c59ed83e1550519250dc97cf6793",
+                "sha256:3e85bba6f0e0c454a90b8fea16b59db9c6d19ddf9cc95052b2d4ca77b22d46d6",
+                "sha256:3eb960c2f9e031f0643b53bab67733a9544d82f42d0714338183d14993d2a23c",
+                "sha256:419af4f577a3d5d9f386aeacf4c4992f90016f84cbceb11ecd832101b1f7f9c9",
+                "sha256:44efa41ac36f6bcbf4f64d6479b3031cceea28cf6892a77f15bd1c22611bff9d",
+                "sha256:4bc60f8372c3ab06f41279163c5d558bf95195bb3f68e35ed19f95d4fbd53d71",
+                "sha256:4c19578b35715e110c324b27c18ab54a56fccc4c41b8f651b1d1da5a64e0d605",
+                "sha256:532ab738351aad2cdad80f4355123652e08b207281f3923ce51fb2b58692dd4c",
+                "sha256:549beb5646137b78534a312a3b80b2b8b1ea01058b38a711d42d6b54b20b6c2b",
+                "sha256:59f5fb4ba219a11fdc1c23e17c93ca3090480a8cde4370c980908546ffc091e6",
+                "sha256:5efa68fc3fe0c439e2858215f2224bfb7242c35079538d58063f68a0d5d5ec33",
+                "sha256:5ff4802d9b3704e680454289587e1cc146bb0d953cf3c9296e2d96441a6a8e88",
+                "sha256:6a225440015db88ec4625a2a41c21582a50cce7ffbe38dcbbb416c7180352516",
+                "sha256:6d898441ada374f76e0b5354d7e240e1c0e905a1ebcb1e95d9ffd99c88f63700",
+                "sha256:6e137d014cf4162e5a796777012452516d92547717c1b4914fb71ce4e41817b5",
+                "sha256:6edf68d4305e08f6f8c45bfaa9dc04d527ab5a1562aaf0c452fa921fbe90eb23",
+                "sha256:72e8358c751da9ab4f8653a3b67b2a3bb7e330ee57cb26439c6af358d6eac032",
+                "sha256:77054f24d46498d9696c809da7810b67bccf6153f9848ea48331708841926d82",
+                "sha256:7adfbd4e22647f880c9ed86b2be7f6d7a7dbbb8adc09395808cc7a4d021bc328",
+                "sha256:87b4b1977b52d5e0873a5e396340d2443640ba760f4fa23e93a38997ecfbcd5b",
+                "sha256:889518ce7c2a0609a3cffb7b667669a39b3410e869ff38e087bf7eeadad62e5d",
+                "sha256:89af675d38bf490384dae85151768b8434e997cece98e5d1eb6fcb3c16d6af12",
+                "sha256:8ab27a6626c2038e13c1b250c5cd22da578f182364134620ec298b4ccfc85722",
+                "sha256:8ccde1df51eeaddf5515edc41bde2ea43a834a288914eae9ce4287399be108f5",
+                "sha256:947bdba3ebcd93a7cef537d6405bc5667d1caf818fa8bbd2e2cc952ec8f97e09",
+                "sha256:96d78d9edf3070770cefd1822bc220d8cccad049b818a70a3c630052e9f15490",
+                "sha256:a433d3740a9ef7bc34a18e2b12bf72b25e618facdfd09871167b30fd8e955fed",
+                "sha256:a77d1f47e5e82504c531bc9dd22c093ff093b6706ec8bcdad228464ef3a5dd54",
+                "sha256:b1624123710fa701988a8a43994de78416e5010ac1508f64ed41e2577358604a",
+                "sha256:b16e1967709392a0ec4b10b4374a72eb062c47c168a189606c9a7ea7b36593a8",
+                "sha256:b5ea9902fc2990af993b74862282b49ae0b8de8a64ca3b4a8dda26a3163c3bb4",
+                "sha256:c323265a4f18f586e8de84fda12b48eb3bd48395294aa2b8c05307ac1680299d",
+                "sha256:c83481501533824fe341c17d297bbec1ec584ec46b352f98ce12bf16740615c4",
+                "sha256:cd7ddb5b6ffcbd3691990df20f260a888c8bd770d57480a97da1b756fb1be5c0",
+                "sha256:cddd61bff66e42ef334f8cb9e719951e479b5ad2cb75c00338aac8de28e17484",
+                "sha256:cf6c3bfa403e055380fe90844beb4fe8e9448edab5d2bf40d37d208dbb2f768c",
+                "sha256:d4179d96b0ce27602756185c1a00d088c9c1feb0cc17a36f8a66eec6ddddbc0c",
+                "sha256:d49f250c3ffbe83ba2d03e3500e03505576a985f7c5f77172a9531058347aa68",
+                "sha256:dcfcb147c18272a22a592251a49830b3c7abc82385ffff34916c2534175d885e",
+                "sha256:ddd33c90b0c95eca737c9f6db7e969a48d23aed72cecb23f3b8aac009ca2cfb4",
+                "sha256:e4a8a371ad02bf31576bcd99093cea3849e19ca1e9eb63fc0b2c0f1db1132f7d",
+                "sha256:e891b0936aab73550d673dd3bbf89fa9577b3db1a61baecea480afd36fdb1852",
+                "sha256:e90cda2ccd4bdb89a3cd5dc11771c3b8394817d5caaa1ae36042bc96a428c10e",
+                "sha256:ff9ebc416e815161d89d2fd22d1a91acf3b810ef800dae38c402d19d203590bf"
+            ],
+            "version": "==1.38.1"
+        },
+        "h5py": {
+            "hashes": [
+                "sha256:02c391fdb980762a1cc03a4bcaecd03dc463994a9a63a02264830114a96e111f",
+                "sha256:1cd367f89a5441236bdbb795e9fb9a9e3424929c00b4a54254ca760437f83d69",
+                "sha256:1cdfd1c5449ca1329d152f0b66830e93226ebce4f5e07dd8dc16bfc2b1a49d7b",
+                "sha256:1e2516f190652beedcb8c7acfa1c6fa92d99b42331cbef5e5c7ec2d65b0fc3c2",
+                "sha256:236ac8d943be30b617ab615c3d4a4bf4a438add2be87e54af3687ab721a18fac",
+                "sha256:2e37352ddfcf9d77a2a47f7c8f7e125c6d20cc06c2995edeb7be222d4e152636",
+                "sha256:80c623be10479e81b64fa713b7ed4c0bbe9f02e8e7d2a2e5382336087b615ce4",
+                "sha256:ba71f6229d2013fbb606476ecc29c6223fc16b244d35fcd8566ad9dbaf910857",
+                "sha256:cb74df83709d6d03d11e60b9480812f58da34f194beafa8c8314dbbeeedfe0a6",
+                "sha256:dccb89358bc84abcd711363c3e138f9f4eccfdf866f2139a8e72308328765b2c",
+                "sha256:e33f61d3eb862614c0f273a1f993a64dc2f093e1a3094932c50ada9d2db2170f",
+                "sha256:f89a3dae38843ffa49d17a31a3509a8129e9b46ece602a0138e1ed79e685c361",
+                "sha256:fea05349f63625a8fb808e57e42bb4c76930cf5d50ac58b678c52f913a48a89b"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==3.1.0"
+        },
+        "idna": {
+            "hashes": [
+                "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
+                "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+            "version": "==2.10"
+        },
+        "importlib-metadata": {
+            "hashes": [
+                "sha256:079ada16b7fc30dfbb5d13399a5113110dab1aa7c2bc62f66af75f0b717c8cac",
+                "sha256:9f55f560e116f8643ecf2922d9cd3e1c7e8d52e683178fecd9d08f6aa357e11e"
+            ],
+            "markers": "python_version < '3.8'",
+            "version": "==4.6.1"
+        },
+        "markdown": {
+            "hashes": [
+                "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49",
+                "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==3.3.4"
+        },
+        "mlagents": {
+            "hashes": [
+                "sha256:06e7b7d4b5ae46213d6bf52be9b17770ba305b58138423630070dee4acbe9406",
+                "sha256:1103dfcaa4b08b5705b59b03bf893aa79d1ccc08bc2eac0bbe77154d353f8f14"
+            ],
+            "index": "pypi",
+            "version": "==0.23.0"
+        },
+        "mlagents-envs": {
+            "hashes": [
+                "sha256:0bd06c704c3cc384c6852138dc865fd5cfb4f0fddd69a8ccee28c457cd80bdfb",
+                "sha256:472adf39a6fb66750749e619077e3d8ce51afa8b90d00f93960c18d467ed40ef"
+            ],
+            "index": "pypi",
+            "version": "==0.23.0"
+        },
+        "networkx": {
+            "hashes": [
+                "sha256:7978955423fbc9639c10498878be59caf99b44dc304c2286162fd24b458c1602",
+                "sha256:8c5812e9f798d37c50570d15c4a69d5710a18d77bafc903ee9c5fba7454c616c"
+            ],
+            "index": "pypi",
+            "version": "==2.5"
+        },
+        "numpy": {
+            "hashes": [
+                "sha256:0172304e7d8d40e9e49553901903dc5f5a49a703363ed756796f5808a06fc233",
+                "sha256:34e96e9dae65c4839bd80012023aadd6ee2ccb73ce7fdf3074c62f301e63120b",
+                "sha256:3676abe3d621fc467c4c1469ee11e395c82b2d6b5463a9454e37fe9da07cd0d7",
+                "sha256:3dd6823d3e04b5f223e3e265b4a1eae15f104f4366edd409e5a5e413a98f911f",
+                "sha256:4064f53d4cce69e9ac613256dc2162e56f20a4e2d2086b1956dd2fcf77b7fac5",
+                "sha256:4674f7d27a6c1c52a4d1aa5f0881f1eff840d2206989bae6acb1c7668c02ebfb",
+                "sha256:7d42ab8cedd175b5ebcb39b5208b25ba104842489ed59fbb29356f671ac93583",
+                "sha256:965df25449305092b23d5145b9bdaeb0149b6e41a77a7d728b1644b3c99277c1",
+                "sha256:9c9d6531bc1886454f44aa8f809268bc481295cf9740827254f53c30104f074a",
+                "sha256:a78e438db8ec26d5d9d0e584b27ef25c7afa5a182d1bf4d05e313d2d6d515271",
+                "sha256:a7acefddf994af1aeba05bbbafe4ba983a187079f125146dc5859e6d817df824",
+                "sha256:a87f59508c2b7ceb8631c20630118cc546f1f815e034193dc72390db038a5cb3",
+                "sha256:ac792b385d81151bae2a5a8adb2b88261ceb4976dbfaaad9ce3a200e036753dc",
+                "sha256:b03b2c0badeb606d1232e5f78852c102c0a7989d3a534b3129e7856a52f3d161",
+                "sha256:b39321f1a74d1f9183bf1638a745b4fd6fe80efbb1f6b32b932a588b4bc7695f",
+                "sha256:cae14a01a159b1ed91a324722d746523ec757357260c6804d11d6147a9e53e3f",
+                "sha256:cd49930af1d1e49a812d987c2620ee63965b619257bd76eaaa95870ca08837cf",
+                "sha256:e15b382603c58f24265c9c931c9a45eebf44fe2e6b4eaedbb0d025ab3255228b",
+                "sha256:e91d31b34fc7c2c8f756b4e902f901f856ae53a93399368d9a0dc7be17ed2ca0",
+                "sha256:ef627986941b5edd1ed74ba89ca43196ed197f1a206a3f18cc9faf2fb84fd675",
+                "sha256:f718a7949d1c4f622ff548c572e0c03440b49b9531ff00e4ed5738b459f011e8"
+            ],
+            "index": "pypi",
+            "version": "==1.18.5"
+        },
+        "oauthlib": {
+            "hashes": [
+                "sha256:42bf6354c2ed8c6acb54d971fce6f88193d97297e18602a3a886603f9d7730cc",
+                "sha256:8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==3.1.1"
+        },
+        "pillow": {
+            "hashes": [
+                "sha256:063d17a02a0170c2f880fbd373b2738b089c6adcbd1f7418667bc9e97524c11b",
+                "sha256:1037288a22cc8ec9d2918a24ded733a1cc4342fd7f21d15d37e6bbe5fb4a7306",
+                "sha256:25f6564df21d15bcac142b4ed92b6c02e53557539f535f31c1f3bcc985484753",
+                "sha256:28f184c0a65be098af412f78b0b6f3bbafd1614e1dc896e810d8357342a794b7",
+                "sha256:3251557c53c1ed0c345559afc02d2b0a0aa5788042e161366ed90b27bc322d3d",
+                "sha256:331f8321418682386e4f0d0e6369f732053f95abddd2af4e1b1ef74a9537ef37",
+                "sha256:333313bcc53a8a7359e98d5458dfe37bfa301da2fd0e0dc41f585ae0cede9181",
+                "sha256:34ce3d993cb4ca840b1e31165b38cb19c64f64f822a8bc5565bde084baff3bdb",
+                "sha256:490c9236ef4762733b6c2e1f1fcb37793cb9c57d860aa84d6994c990461882e5",
+                "sha256:519b3b24dedc81876d893475bade1b92c4ce7c24b9b82224f0bd8daae682e039",
+                "sha256:53f6e4b73b3899015ac4aa95d99da0f48ea18a6d7c8db672e8bead3fb9570ef5",
+                "sha256:561339ed7c324bbcb29b5e4f4705c97df950785394b3ac181f5bf6a08088a672",
+                "sha256:6f7517a220aca8b822e25b08b0df9546701a606a328da5bc057e5f32a3f9b07c",
+                "sha256:713b762892efa8cd5d8dac24d16ac2d2dbf981963ed1b3297e79755f03f8cbb8",
+                "sha256:72858a27dd7bd1c40f91c4f85db3b9f121c8412fd66573121febb00d074d0530",
+                "sha256:778a819c2d194e08d39d67ddb15ef0d32eba17bf7d0c2773e97bd221b2613a3e",
+                "sha256:803606e206f3e366eea46b1e7ab4dac74cfac770d04de9c35319814e11e47c46",
+                "sha256:856fcbc3201a6cabf0478daa0c0a1a8a175af7e5173e2084ddb91cc707a09dd1",
+                "sha256:8f65d2a98f198e904dbe89ecb10862d5f0511367d823689039e17c4d011de11e",
+                "sha256:94db5ea640330de0945b41dc77fb4847b4ab6e87149126c71b36b112e8400898",
+                "sha256:950e873ceefbd283cbe7bc5b648b832d1dcf89eeded6726ebec42bc7d67966c0",
+                "sha256:a7beda44f177ee602aa27e0a297da1657d9572679522c8fb8b336b734653516e",
+                "sha256:aef0838f28328523e9e5f2c1852dd96fb85768deb0eb8f908c54dad0f44d2f6f",
+                "sha256:b42ea77f4e7374a67e1f27aaa9c62627dff681f67890e5b8f0c1e21b1500d9d2",
+                "sha256:bccd0d604d814e9494f3bf3f077a23835580ed1743c5175581882e7dd1f178c3",
+                "sha256:c2d78c8230bda5fc9f6b1d457c7f8f3432f4fe85bed86f80ba3ed73d59775a88",
+                "sha256:c3529fb98a40f89269175442c5ff4ef81d22e91b2bdcbd33833a350709b5130c",
+                "sha256:cc8e926d6ffa65d0dddb871b7afe117f17bc045951e66afde60eb0eba923db9e",
+                "sha256:ce90aad0a3dc0f13a9ff0ab1f43bcbea436089b83c3fadbe37c6f1733b938bf1",
+                "sha256:cec702974f162026bf8de47f6f4b7ce9584a63c50002b38f195ee797165fea77",
+                "sha256:d9ef8119ce44f90d2f8ac7c58f7da480ada5151f217dc8da03681b73fc91dec3",
+                "sha256:eccaefbd646022b5313ca4b0c5f1ae6e0d3a52ef66de64970ecf3f9b2a1be751",
+                "sha256:fb91deb5121b6dde88599bcb3db3fdad9cf33ff3d4ccc5329ee1fe9655a2f7ff",
+                "sha256:fc25d59ecf23ea19571065306806a29c43c67f830f0e8a121303916ba257f484"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==8.3.0"
+        },
+        "protobuf": {
+            "hashes": [
+                "sha256:13ee7be3c2d9a5d2b42a1030976f760f28755fcf5863c55b1460fd205e6cd637",
+                "sha256:145ce0af55c4259ca74993ddab3479c78af064002ec8227beb3d944405123c71",
+                "sha256:14c1c9377a7ffbeaccd4722ab0aa900091f52b516ad89c4b0c3bb0a4af903ba5",
+                "sha256:1556a1049ccec58c7855a78d27e5c6e70e95103b32de9142bae0576e9200a1b0",
+                "sha256:26010f693b675ff5a1d0e1bdb17689b8b716a18709113288fead438703d45539",
+                "sha256:2ae692bb6d1992afb6b74348e7bb648a75bb0d3565a3f5eea5bec8f62bd06d87",
+                "sha256:2bfb815216a9cd9faec52b16fd2bfa68437a44b67c56bee59bc3926522ecb04e",
+                "sha256:4ffbd23640bb7403574f7aff8368e2aeb2ec9a5c6306580be48ac59a6bac8bde",
+                "sha256:59e5cf6b737c3a376932fbfb869043415f7c16a0cf176ab30a5bbc419cd709c1",
+                "sha256:6902a1e4b7a319ec611a7345ff81b6b004b36b0d2196ce7a748b3493da3d226d",
+                "sha256:6ce4d8bf0321e7b2d4395e253f8002a1a5ffbcfd7bcc0a6ba46712c07d47d0b4",
+                "sha256:6d847c59963c03fd7a0cd7c488cadfa10cda4fff34d8bc8cba92935a91b7a037",
+                "sha256:72804ea5eaa9c22a090d2803813e280fb273b62d5ae497aaf3553d141c4fdd7b",
+                "sha256:7a4c97961e9e5b03a56f9a6c82742ed55375c4a25f2692b625d4087d02ed31b9",
+                "sha256:85d6303e4adade2827e43c2b54114d9a6ea547b671cb63fafd5011dc47d0e13d",
+                "sha256:8727ee027157516e2c311f218ebf2260a18088ffb2d29473e82add217d196b1c",
+                "sha256:99938f2a2d7ca6563c0ade0c5ca8982264c484fdecf418bd68e880a7ab5730b1",
+                "sha256:9b7a5c1022e0fa0dbde7fd03682d07d14624ad870ae52054849d8960f04bc764",
+                "sha256:a22b3a0dbac6544dacbafd4c5f6a29e389a50e3b193e2c70dae6bbf7930f651d",
+                "sha256:a38bac25f51c93e4be4092c88b2568b9f407c27217d3dd23c7a57fa522a17554",
+                "sha256:a981222367fb4210a10a929ad5983ae93bd5a050a0824fc35d6371c07b78caf6",
+                "sha256:ab6bb0e270c6c58e7ff4345b3a803cc59dbee19ddf77a4719c5b635f1d547aa8",
+                "sha256:c56c050a947186ba51de4f94ab441d7f04fcd44c56df6e922369cc2e1a92d683",
+                "sha256:e76d9686e088fece2450dbc7ee905f9be904e427341d289acbe9ad00b78ebd47",
+                "sha256:ebcb546f10069b56dc2e3da35e003a02076aaa377caf8530fe9789570984a8d2",
+                "sha256:f0e59430ee953184a703a324b8ec52f571c6c4259d496a19d1cabcdc19dabc62",
+                "sha256:ffea251f5cd3c0b9b43c7a7a912777e0bc86263436a87c2555242a348817221b"
+            ],
+            "version": "==3.17.3"
+        },
+        "pyasn1": {
+            "hashes": [
+                "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
+                "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
+                "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
+                "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
+                "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
+                "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
+                "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
+                "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
+                "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
+                "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
+                "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
+                "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2",
+                "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"
+            ],
+            "version": "==0.4.8"
+        },
+        "pyasn1-modules": {
+            "hashes": [
+                "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
+                "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
+                "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
+                "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
+                "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
+                "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
+                "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
+                "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
+                "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
+                "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
+                "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
+                "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
+                "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
+            ],
+            "version": "==0.2.8"
+        },
+        "pyyaml": {
+            "hashes": [
+                "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf",
+                "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696",
+                "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393",
+                "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77",
+                "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922",
+                "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5",
+                "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8",
+                "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10",
+                "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc",
+                "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018",
+                "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e",
+                "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253",
+                "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347",
+                "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183",
+                "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541",
+                "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb",
+                "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185",
+                "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc",
+                "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db",
+                "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa",
+                "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46",
+                "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122",
+                "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b",
+                "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63",
+                "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df",
+                "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc",
+                "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247",
+                "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6",
+                "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
+            "version": "==5.4.1"
+        },
+        "requests": {
+            "hashes": [
+                "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
+                "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+            "version": "==2.25.1"
+        },
+        "requests-oauthlib": {
+            "hashes": [
+                "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
+                "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a",
+                "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"
+            ],
+            "version": "==1.3.0"
+        },
+        "rsa": {
+            "hashes": [
+                "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2",
+                "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==4.7.2"
+        },
+        "six": {
+            "hashes": [
+                "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
+                "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+            "version": "==1.16.0"
+        },
+        "tensorboard": {
+            "hashes": [
+                "sha256:e167460085b6528956b33bab1c970c989cdce47a6616273880733f5e7bde452e"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+            "version": "==2.5.0"
+        },
+        "tensorboard-data-server": {
+            "hashes": [
+                "sha256:809fe9887682d35c1f7d1f54f0f40f98bb1f771b14265b453ca051e2ce58fca7",
+                "sha256:d8237580755e58eff68d1f3abefb5b1e39ae5c8b127cc40920f9c4fb33f4b98a",
+                "sha256:fa8cef9be4fcae2f2363c88176638baf2da19c5ec90addb49b1cde05c95c88ee"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==0.6.1"
+        },
+        "tensorboard-plugin-wit": {
+            "hashes": [
+                "sha256:2a80d1c551d741e99b2f197bb915d8a133e24adb8da1732b840041860f91183a"
+            ],
+            "version": "==1.8.0"
+        },
+        "torch": {
+            "hashes": [
+                "sha256:2e49cac969976be63117004ee00d0a3e3dd4ea662ad77383f671b8992825de1a",
+                "sha256:38d67f4fb189a92a977b2c0a38e4f6dd413e0bf55aa6d40004696df7e40a71ff",
+                "sha256:422e64e98d0e100c360993819d0307e5d56e9517b26135808ad68984d577d75a",
+                "sha256:5d76c255a41484c1d41a9ff570b9c9f36cb85df9428aa15a58ae16ac7cfc2ea6",
+                "sha256:6652a767a0572ae0feb74ad128758e507afd3b8396b6e7f147e438ba8d4c6f63",
+                "sha256:a3793dcceb12b1e2281290cca1277c5ce86ddfd5bf044f654285a4d69057aea7",
+                "sha256:af464a6f4314a875035e0c4c2b07517599704b214634f4ed3ad2e748c5ef291f",
+                "sha256:d241c3f1c4d563e4ba86f84769c23e12606db167ee6f674eedff6d02901462e3",
+                "sha256:dd2fc6880c95e836960d86efbbc7f63d3287f2e1893c51d31f96dbfe02f0d73e",
+                "sha256:de84b4166e3f7335eb868b51d3bbd909ec33828af27290b4171bce832a55be3c",
+                "sha256:e000b94be3aa58ad7f61e7d07cf379ea9366cf6c6874e68bd58ad0bdc537b3a7",
+                "sha256:f0aaf657145533824b15f2fd8fde8f8c67fe6c6281088ef588091f03fad90243"
+            ],
+            "markers": "platform_system != 'Windows'",
+            "version": "==1.7.1"
+        },
+        "typing-extensions": {
+            "hashes": [
+                "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497",
+                "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342",
+                "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"
+            ],
+            "markers": "python_version < '3.8'",
+            "version": "==3.10.0.0"
+        },
+        "urllib3": {
+            "hashes": [
+                "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4",
+                "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
+            "version": "==1.26.6"
+        },
+        "werkzeug": {
+            "hashes": [
+                "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42",
+                "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==2.0.1"
+        },
+        "wheel": {
+            "hashes": [
+                "sha256:78b5b185f0e5763c26ca1e324373aadd49182ca90e825f7853f4b2509215dc0e",
+                "sha256:e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e"
+            ],
+            "markers": "python_version >= '3'",
+            "version": "==0.36.2"
+        },
+        "zipp": {
+            "hashes": [
+                "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3",
+                "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==3.5.0"
+        }
+    },
+    "develop": {}
+}
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Readme.md b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..27b0b6a9b6d66f7bb0a3362c55c262f091326e68
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/Readme.md
@@ -0,0 +1,94 @@
+# Task-Allocation and Prioritized pathplanning (TA-Prioritized)
+
+The Task-Allocation and Prioritized pathplanning (TA-Prioritized) algorithm is a centralized algorithm for the offline variant of the MAPD problem.
+
+In the offline variant of the MAPD problem the following is supported:
+- Using tasks from a taskslist with releaseTimes 
+- Tested from 1 agent up untill 50 agents (significant lag for larger amount of agents)
+
+Not supported:
+- Randomly generated tasks (randomTasks = True)
+- Tasklists without releaseTimes
+
+## Running the algorithm
+
+1. Install the virtual environment
+    - 'pipenv install'
+2. Setup the LKH-3 TSP solver (see "LKH-3 TSP Solver" section)
+3. Setup lkh.config (see below)
+4. Run the "centralized_decisionmaker_shortest_path.py" file
+4. Start the game inside the Unity editor
+
+## Working of the algorithm
+
+This implementation is a modified version of the implementation available at: https://github.com/Pieter-Cawood/M-TA-Prioritized-MAPD
+
+This implementation is based on the "Task and Path Planning for Multi-Agent Pickup and Delivery" paper (http://idm-lab.org/bib/abstracts/papers/aamas19a.pdf).
+An explanation of the algorithm is available at:
+    - Section 3 and 4 of the "Task and Path Planning for Multi-Agent Pickup and Delivery" paper
+    - Section 2.2.2 of the paper provided in the "paper" 
+    
+General working of the algorithm:
+    - The algorithm uses the LKH-3 TSP Solver to generate task sequences for the agents:
+        * Each agent gets an ordered list of tasks (or no tasks at all)
+        * The agent needs to execute these tasks in the provided order
+    - The algorithm plans 1 path for each agent to execute its whole task set:
+        * Each agent gets one path that allows it to execute all its tasks in the correct order
+        => In order to minimize the amount of timesteps needed to solve the problem the algorithm uses the Prioritized Pathplanning method to always plan longer paths first
+        => This is done to avoid making the longer paths even longer by waiting to avoid collisions (see papers for a more detailed explanation)
+    - Once all the agents have their path they start following that path
+        * In each timestep each agent moves one step following its path
+
+## (IMPORTANT) LKH-3 TSP Solver
+
+- This algorithm uses a modified version of the original LKH-3 TSP solver (original: http://akira.ruc.dk/~keld/research/LKH-3/) to generate task sequences. The source code (and an executable for Linux and Windows) can be found in the LKH3 directory. A visual studio project for Windows is added as LKHwin-3.0.6-WinChanges.
+- By default the algorithm computes new task sequences using the LKH-3 solver every time the algorithm is ran
+- The algorithm supports using pre-computed task sequences (as this process can be slow for larger task sets) (see "Generating pre-computed task sequences" section)
+
+### Setup of LKH-3 TSP Solver
+
+- The source code (and an executable for Linux and Windows) are provided in the LKH-3 directory
+- If the provided executable is not supported by your machine (error when trying to run the LKH-3 executable) you can compile a new executable on a Unix/Linux machine using the following commands:
+    * cd LKH3
+    * make
+- On Windows machines you need to create an .exe file using the visual studio project provided in the LKH3/SRC directory
+
+### Running algorithm without using pre-computed task sequences
+- Set the lkh.conf file as follows:
+    * tourFile = None
+    * path = specify path to LKH3 solver (can found in directory LKH3, Linux: LKH_linux, Windows: LKH-3.exe)
+    * lkhMaxTime = The maximum time (in seconds) that should be used by the LKH-3 TSP solver to compute task sequences (default: 500)
+- Run the main file centralized_decisionmaker_shortest_path.py directly.
+
+### Running algorithm using pre-computed task sequences
+- Set the lkh.conf file as follows:
+    * tourFile = None.
+    * path = specify path to LKH3 solver (can found in directory LKH3, Linux: LKH_linux, Windows: LKH-3.exe)
+    * lkhMaxTime = The maximum time (in seconds) that should be used by the LKH-3 TSP solver to compute task sequences (default: 500)
+- Compute tour file using generate_tour_file.py
+    * Add the path to the problem file (config file warehouse) and the file containing the tasks in generate_tour_file.py.
+    * run generate_tour_file.py, a tour file will have been generated and added in LKH3/TOUR. Each tour file created will have a unique name.
+- Set the lkh.conf file as follows:
+    * tourFile = path to tour file computed in previous step.
+    * path = path to LKH3 solver (Linux: LKH_linux, Windows: LKH-3.exe)
+    * lkhMaxTime = The maximum time (in seconds) that should be used by the LKH-3 TSP solver to compute task sequences (default: 500)
+- Run the main file centralized_decisionmaker_shortest_path.py
+
+## Overview of the provided files
+
+Main file:
+- centralized_decisionmaker_shortest_path.py: Main file that runs the algorithm
+
+Task Allocation and Prioritized Pathplanning:
+- ta_agent.py: Agent that are executing tasks
+- ta_system.py: System allocates tasks and plans paths for agents
+- ta_task.py: Pickup and delivery tasks
+- ta_world.py: Class that reads and stores the warehouse environment
+
+A-star:
+- ta_astar.py: A-Star algorithm
+- ta_state.py: Contains Location and state classes used for the path planning
+
+LKH-3:
+- lkh.py: Class that computes task sequences using the LKH-3 TSP solver
+- lkh.conf: Configuration file for the LKH-3 TSP solver
\ No newline at end of file
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/TaskSideChannel.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/TaskSideChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e86f1a0f43763e5ee775f1063422926c5a64297
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/TaskSideChannel.py
@@ -0,0 +1,41 @@
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+import ta_task
+from ta_state import Location
+
+
+class TaskSideChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("c11ab982-82b8-4194-b387-3bd0fe9ebdc7")) #must coincide with ChannelId set in c#
+        self.environment_data = None #info on the environment
+
+    # channel receives new tasks that have to be assigned
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        data = msg.read_string()
+        new_task = json.loads(data)
+        new_task = new_task["task"]
+        task_to_add = ta_task.Task(ta_task.CURRENT_TASK_ID,
+                           Location(new_task["PickUp"]["Column"],
+                                    new_task["PickUp"]["Row"], 0),
+                           Location(new_task["Delivery"]["Column"], new_task["Delivery"]["Row"], 0),
+                                   new_task["ReleaseTime"],
+                           None)
+        ta_task.CURRENT_TASK_ID += 1
+        # add task to task to be assigned
+        self.environment_data.add_task_to_tasks_to_be_assigned(task_to_add)
+
+    # channel sends information when a task has been assigned (to which robot)
+    def send_string(self, data: str) -> None:
+
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/centralized_decisionmaker_shortest_path.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/centralized_decisionmaker_shortest_path.py
new file mode 100644
index 0000000000000000000000000000000000000000..2cc18a3d799b06749b833e0bd27ddaf0a71dda98
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/centralized_decisionmaker_shortest_path.py
@@ -0,0 +1,209 @@
+from mlagents_envs.environment import ActionTuple, UnityEnvironment
+import EnvChannel
+import TaskSideChannel
+import PickupAndDeliveryChannel as PADEC
+import numpy as np
+import os
+import time
+
+from Node import Node
+
+import configparser
+
+from lkh import LKH
+
+# from pickup_and_delivery.task import Task
+from ta_system import System as TA_System
+from ta_state import Location
+from ta_agent import Agent
+
+# as long as simulation_going is true, new actions will be generated
+simulation_going = True
+
+# Load the side channels and Unity environment.
+envChannel = EnvChannel.EnvChannel()
+taskChannel = TaskSideChannel.TaskSideChannel()
+# Open unity and press play to execute
+env = UnityEnvironment(file_name=None, side_channels=[
+                       envChannel, taskChannel])
+env.reset() # reset the environment
+
+# Specify the used behaviour name for steering the agent
+behavior_names = list(env.behavior_specs.keys())
+behavior_name = behavior_names[0]
+
+# info obtained from environment
+environment_info = envChannel.EnvData
+# set up links between task side channel and environment info
+environment_info.task_side_channel = taskChannel
+taskChannel.environment_data = environment_info
+
+##--------##
+## Agents ##
+##--------##
+
+# Create all the agents
+agentsList = []
+for robot_id, start_node in environment_info.current_nodes_dictionary.items():
+    # Convert the Node that represents the agent's starting position to a Location
+    robot_position = Location(start_node.y, start_node.x, start_node.g)
+    # Create agent
+    agentsList.append(Agent(robot_id, robot_position))
+
+##-------##
+## Tasks ##
+##-------##
+
+# Retrieve all tasks
+tasksList = environment_info.tasks_to_be_assigned
+
+##-----------------------------##
+## LKH3-Solver: Task sequences ##
+##-----------------------------##
+
+## Create the LKH class so that the problem (and parameter) files for the LKH3 solver can be generated
+lkh = LKH(environment_info.matrix, tasksList, agentsList)
+# File that contains all the task sequences: can either be pre-computed or can be computed on the fly
+lkhFile = lkh.get_task_sequences()
+
+##--------##
+## System ##
+##--------##
+
+# Initialize system
+system = TA_System(environment_info.matrix, environment_info.rotation, agentsList, tasksList, lkhFile)
+
+##---------------##
+## Path Planning ##
+##---------------##
+
+# Retrieve all agents from the system
+agents_list = system.world.agents
+# Retrieve all paths from the system
+agent_paths = system.get_paths()
+
+##-------------##
+## Follow Path ##
+##-------------##
+
+# Keep track of current timestep
+actions_requested_in_timestep = 0
+timestep = 0
+
+# Keep track of tasks that need to be assigned in Unity
+to_assign_tasks = []
+
+# Assign all agents to their first task in Unity
+for a_id, agent in agents_list.items():
+    # Agent has at least one task
+    if len(agent.taskSet) > 0:
+        # Get the agent's first task
+        next_task = agent.taskSet[0]
+        # Assign the first task to the agent in Unity
+        environment_info.assign_task(
+            a_id, system.tasks[next_task.id])
+
+while simulation_going:    
+    # Get information on the agents that request an action
+    decision_steps, terminal_steps = env.get_steps(behavior_name)
+    agents = decision_steps.agent_id
+    observation = decision_steps.obs[0][0]
+
+    # Actions that will be sent to Unity
+    actions = []
+    action_tuple = ActionTuple()  # actions to send to unity
+
+    # Assign tasks in Unity for agents that are waiting for a new task assignment
+    for agent_tuple in to_assign_tasks:
+        # Extract the needed information from the tupple
+        agent_id = agent_tuple[0]
+        task = agent_tuple[1]
+        # Assign the task to the agent in Unity
+        environment_info.assign_task(agent_id, task)
+        # Remove the task from the tupple list to avoid assigning the same task to the same agent more than once
+        to_assign_tasks.remove(agent_tuple)
+
+    ##--------------##
+    ## Observations ##
+    ##--------------##
+
+    # get observations per robot and store in dictionary observations[instance_id] -> observation
+    observations = {}
+    for i in range(environment_info.number_of_robots):
+        observation_i = observation[i * environment_info.observation_size:
+                                    i * environment_info.observation_size + environment_info.observation_size]
+        observations[observation_i[0]] = observation_i[1:]
+    
+    # Create an action for all agents that request an action
+    for robot_id_unity in observations:   
+        
+        ##--------------##
+        ## OBSERVATIONS ##
+        ##--------------##
+        
+        # robot_id_unity = list(agents_list.keys())[i]
+        # Collect agent's observations        
+        observation = observations[robot_id_unity]
+
+        # Extract observations
+        # robot_id_unity = observation[0] # robot id in unity used to get correct precomputed path
+        robot_pos_x = observation[1]
+        robot_pos_y = observation[0]
+        robot_rot = observation[2]
+        # Convert coordinates to position
+        robot_position = Location(robot_pos_x, robot_pos_y, robot_rot)
+        
+        ##-------------##
+        ## FOLLOW PATH ##
+        ##-------------##
+
+        # Get the pre-computed path of the agent
+        path = agent_paths[robot_id_unity]
+
+        next_pos = None
+
+        # Check if agent still needs to move
+        if timestep <= agents_list[robot_id_unity].final_action:
+            # Agent has not yet reached the end of its path: get the next position of the agent
+            next_pos = path[timestep]
+        else:
+            # Agent has reached the end of its path: stay parked at its parking location
+            next_pos = Location(robot_pos_x, robot_pos_y, robot_rot)
+
+        # Convert Position to Node
+        next_action = Node(next_pos.row, next_pos.col, next_pos.rotation)
+
+        # Check whether agent needs to pickup/deliver
+        pickup_action = 0
+        delivery_action = 0
+        if next_pos.to_pickup:
+            # Agent has to pick up his task
+            pickup_action = 1
+        elif next_pos.to_deliver:
+            # Agent has to deliver his task
+            delivery_action = 1
+            # Remove the task that was delivered from the taskSet
+            agents_list[robot_id_unity].taskSet = agents_list[robot_id_unity].taskSet[1:]
+            # Get the task set of the agent
+            tasks = agents_list[robot_id_unity].taskSet
+            # If there are remaining tasks assign the next one to the agent:
+            if (len(tasks) > 0):
+                # Get the agent's next task
+                next_task = tasks[0]
+                # Do not assign the task directly as the agent has not yet delivered it's task, add it to a list so that it will be assigned in the next timestep
+                to_assign_tasks.append((robot_id_unity, system.tasks[next_task.id]))
+
+        # Send action to agent in Unity
+        actions.extend([robot_id_unity, next_action.x, next_action.y, next_action.g, pickup_action, delivery_action])
+
+    timestep += 1
+            
+    # Send actions to Unity
+    actions = np.array(actions)
+    actions.resize(1, environment_info.number_of_robots * environment_info.action_size)
+    action_tuple.add_discrete(actions)
+
+    env.set_actions(behavior_name, action_tuple)
+    env.step()
+
+
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/generate_tour_file.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/generate_tour_file.py
new file mode 100644
index 0000000000000000000000000000000000000000..7d0ea098ee7a2035f446ce5d87daab0b52cf063b
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/generate_tour_file.py
@@ -0,0 +1,65 @@
+import os
+import json
+import numpy as np
+
+from lkh import Agent, LKH
+from ta_world import Location
+from ta_task import Task
+
+#problemFile = "C:/Users/Marjon/Documents/Toolbox_MAS/pick-up-and-delivery/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/warehousejson.txt"
+#tasksFile = "C:/Users/Marjon/Documents/Toolbox_MAS/pick-up-and-delivery/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/tasks_releasetime.txt"
+
+problemFile ="../../../PickUpandDelivery/ConfigurationFiles/Offline_Centralized/warehousejson.txt"
+tasksFile = "../../../PickUpandDelivery/ConfigurationFiles/Offline_Centralized/tasks_releasetime.txt"
+
+
+print(os.path.isfile(problemFile))
+print(os.path.isfile(tasksFile))
+
+environment = None
+agentsList = []
+tasksList = []
+
+with open(problemFile) as envFile:
+    envData = json.load(envFile)
+
+    environment = np.array(envData["Matrix"])
+
+    agents = envData["InitialNodes"]
+
+    for a in agents:
+        col = a["GridPosition"]["Column"]
+        row = a["GridPosition"]["Row"]
+        rot = a["Degrees"]
+
+        loc = Location(col, row, rot)
+
+        agentsList.append(Agent(loc))
+
+with open(tasksFile) as tasksFile:
+
+    tasksData = json.load(tasksFile)
+
+    taskID = 1
+
+    for task in tasksData:
+
+        pickup = Location(task['PickUp']["Column"],
+                          task['PickUp']["Row"],
+                          0)
+
+        delivery = Location(task['Delivery']["Column"],
+                            task['Delivery']["Row"],
+                            0)
+
+        releaseTime = task['ReleaseTime']
+
+        tasksList.append(Task(taskID, releaseTime, pickup, delivery, None))
+
+        taskID += 1
+
+lkh = LKH(environment, tasksList, agentsList)
+
+lkhFile = lkh.get_task_sequences()
+
+print(f"Computed task sequences saved: {lkhFile}")
\ No newline at end of file
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/lkh.conf b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/lkh.conf
new file mode 100644
index 0000000000000000000000000000000000000000..0fc64fae722c355ffd40ecd05ec99f5f2c091b3e
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/lkh.conf
@@ -0,0 +1,6 @@
+[lkh]
+#tourFile=None
+path=C:/Users/Marjon/Documents/Toolbox_MAS/pick-up-and-delivery/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/LKH-3.exe
+lkhMaxTime=500
+
+tourFile=LKH3/TOUR/LKH_2021_08_12-12_29_43.tour
\ No newline at end of file
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/lkh.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/lkh.py
new file mode 100644
index 0000000000000000000000000000000000000000..33bc318348a49021335998965a55aff962976cd1
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/lkh.py
@@ -0,0 +1,262 @@
+import numpy as np
+import configparser
+import os
+import time
+import sys
+import json
+
+from ta_task import Task
+# from position import Position, dist
+from ta_world import Location
+
+def dist(loc1, loc2):
+    return abs(loc1.col - loc2.col) + abs(loc1.row - loc2.row)
+
+##-----------##
+## CONSTANTS ##
+##-----------##
+
+# Dummy agents only used to calculate the distances in the graph
+class Agent:
+    def __init__(self, pos):
+        # Dummy agents only have a position
+        self.parking_location = pos
+
+##--------##
+## System ##
+##--------##
+
+class LKH:
+    def __init__(self, environment, tasks, agentsList):
+        # Keep track of the agents and the amount of agents
+        self.agents = agentsList
+
+        # Keep track of all endpoints in the environment
+        self.task_endpoints = dict()
+        # Initialize environment
+        self.init_env(environment)
+
+        # Keep track of tasks in the task set
+        self.tasks = tasks
+        # Initialize tasks
+        self.load_tasks()
+
+    def init_env(self, env):
+        # Keep track of task endpoints
+        n_endpoints = 0
+        for y in range(len(env)):
+            for x in range(len(env[0])):
+                if env[y][x] == 3:
+                    self.task_endpoints[(x, y)] = n_endpoints
+                    n_endpoints += 1
+
+    ##-------##
+    ## TASKS ##
+    ##-------##
+
+    def load_tasks(self):
+        for task in self.tasks:
+            pickup_id = self.task_endpoints[(
+                task.pickup_endpoint.col, task.pickup_endpoint.row)]
+            task.pickup_id = pickup_id
+            delivery_id = self.task_endpoints[(
+                task.delivery_endpoint.col, task.delivery_endpoint.row)]
+            task.delivery_id = delivery_id
+
+    ##-------##
+    ## LKH-3 ##
+    ##-------##
+    
+    def get_task_sequences(self):
+
+        ##----------------##
+        ## Initialization ##
+        ##----------------##
+
+        print(f"Current directory: {os.getcwd()}")
+
+        # Create a configParser to read the config file
+        config = configparser.ConfigParser()
+        # Read the config file
+        config.read("lkh.conf")
+
+        # Extract information needed from config file
+        # Path to pre-computed .tour file OR None (default: None)
+        tour_file_path = config["lkh"]["tourFile"]
+        lkh_path = config["lkh"]["path"]  # Path to the LKH solver (default: /LKH3/LKH)
+        # Maximum time (in seconds) that is going to be used by the LKH3 solver to compute task sequences (default: 500)
+        lkh_time = config["lkh"]["lkhMaxTime"]
+
+        if tour_file_path != "None":
+            # Use a pre-computed .tour file (contains pre-computed task sequences)
+            return tour_file_path
+        
+        # First compute the task sequences using the LKH3 solver, then return the created .tour file
+
+        ## Generate a unique filename for the generated problem, parameter and .tour files
+        timestr = time.strftime("%Y_%m_%d-%H_%M_%S")
+        lkh_filename = "LKH_" + timestr
+
+        ## Create problem and parameter files
+        self.generate_problem_files(lkh_filename)
+
+        ##------------##
+        ## Run solver ##
+        ##------------##
+
+        ## Run the LKH-3 algorithm to generate .tour file
+        print("\n\n[LKH3] Generating task sequences:\n")
+        os.system(lkh_path + " " + "LKH3/PROBLEM/" + lkh_filename + ".par")
+        print("\n\n[LKH3] Task sequences generated")
+
+        ##---------------##
+        ## Return result ##
+        ##---------------##
+
+        # Save the path of the newly created .tour file
+        lkhFile = "LKH3/TOUR/" + lkh_filename + ".tour"
+        return lkhFile
+
+        
+
+    def generate_problem_files(self, lkhFileName):
+
+        ##-------------------------------------##
+        ## Create graph to calculate sequences ##
+        ##-------------------------------------##
+
+        n_tasks = len(self.tasks)
+        n_agents = len(self.agents)
+        n_nodes = n_tasks + n_agents
+        edge_weights = np.zeros((n_nodes, n_nodes))
+
+        # Edge
+        for k in range(n_agents):
+            for i in range(n_tasks):
+                task = self.tasks[i]
+                agent = self.agents[k]
+                # Edges from tasks to agents
+                edge_weights[n_agents +
+                             i][k] = dist(task.pickup_endpoint, task.delivery_endpoint)
+                # Edges from agents to tasks
+                edge_weights[k][n_agents+i] = max(
+                    dist(agent.parking_location, task.pickup_endpoint), task.release_time)
+
+        for i in range(n_tasks):
+            for j in range(n_tasks):
+                if (i != j):
+                    taski = self.tasks[i]
+                    taskj = self.tasks[j]
+                    # Edges between tasks
+                    d = dist(taski.pickup_endpoint, taski.delivery_endpoint) + \
+                        dist(taski.delivery_endpoint, taskj.pickup_endpoint)
+                    edge_weights[n_agents+i][n_agents+j] = d
+
+        #---------------------#
+        # Create problem file #
+        #---------------------#
+
+        problemFileName = "LKH3/PROBLEM/" + lkhFileName + ".tsp"
+        problemFile = open(problemFileName, "w")
+        problemFile.write("NAME: MAPD\n")
+        problemFile.write("TYPE: TSPTW\n")
+        problemFile.write(f"DIMENSION: {n_nodes}\n")
+        problemFile.write("EDGE_WEIGHT_TYPE: EXPLICIT\n")
+        problemFile.write("DISPLAY_DATA_TYPE: NO_DISPLAY\n")
+        problemFile.write("EDGE_WEIGHT_FORMAT: FULL_MATRIX\n")
+        problemFile.write("EDGE_WEIGHT_SECTION\n")
+        for i in range(n_nodes):
+            for j in range(n_nodes):
+                problemFile.write(f"{str(int(edge_weights[i][j]))} ")
+            problemFile.write("\n")
+        problemFile.write("TIME_WINDOW_SECTION\n")
+        for i in range(n_agents):
+            problemFile.write(f"{i+1} -1 {10000} 0 0 0\n")
+        for i in range(n_tasks):
+            task = self.tasks[i]
+            problemFile.write(
+                f"{i+1+n_agents} {task.release_time} {10000} {dist(task.pickup_endpoint, task.delivery_endpoint)} {task.pickup_id} {task.delivery_id}\n")
+
+        #-----------------------#
+        # Create parameter file #
+        #-----------------------#
+
+        parameterFileName = "LKH3/PROBLEM/" + lkhFileName + ".par"
+        parFile = open(parameterFileName, "w")
+        parFile.write("SPECIAL\n")
+        parFile.write("PROBLEM_FILE = " + problemFileName + "\n")
+        parFile.write("MAX_TRIALS = 100000\nTIME_LIMIT = 1000\n")
+        parFile.write("RUNS = 1\n")
+        parFile.write("TRACE_LEVEL = 1\n")
+        parFile.write("TOUR_FILE = LKH3/TOUR/" + lkhFileName + ".tour\n")
+        parFile.write("MAKESPAN = YES\n")
+
+# environmentFile = None
+# tasksFile = None
+
+#TODO: remove commented code
+
+# if __name__ == '__main__':
+#
+#     if (len(sys.argv) != 3):
+#         print("Incorrect number of arguments: 'python lkh.py <problemFile> <tasksFile>'")
+#         problemFile = "C:/Users/Marjon/Documents/Toolbox_MAS/pick-up-and-delivery/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/warehousejson.txt"
+#         tasksFile = "C:/Users/Marjon/Documents/Toolbox_MAS/pick-up-and-delivery/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/tasks_releasetime.txt"
+#     else:
+#         problemFile = str(sys.argv[1])
+#         tasksFile = str(sys.argv[2])
+#
+#     print(f"Problem file: {problemFile}")
+#     print(f"Tasks file: {tasksFile}")
+#
+#     environment = None
+#     agentsList = []
+#     tasksList = []
+#
+#     with open(problemFile) as envFile:
+#         envData = json.load(envFile)
+#
+#         environment = np.array(envData["Matrix"])
+#
+#         agents = envData["InitialNodes"]
+#
+#         for a in agents:
+#             col = a["GridPosition"]["Column"]
+#             row = a["GridPosition"]["Row"]
+#             rot = a["Degrees"]
+#
+#             loc = Location(col, row, rot)
+#
+#             agentsList.append(Agent(loc))
+#
+#     with open(tasksFile) as tasksFile:
+#
+#         tasksData = json.load(tasksFile)
+#
+#         taskID = 1
+#
+#         for task in tasksData:
+#
+#             pickup = Location(task['PickUp']["Column"],
+#                               task['PickUp']["Row"],
+#                               0)
+#
+#             delivery = Location(task['Delivery']["Column"],
+#                                 task['Delivery']["Row"],
+#                                 0)
+#
+#             releaseTime = task['ReleaseTime']
+#
+#             tasksList.append(Task(taskID, releaseTime, pickup, delivery, None))
+#
+#             taskID += 1
+#
+#     lkh = LKH(environment, tasksList, agentsList)
+#
+#     lkhFile = lkh.get_task_sequences()
+#
+#     print(f"Computed task sequences saved: {lkhFile}")
+
+
+
+
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/paper/Bachelorthesis.pdf b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/paper/Bachelorthesis.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..e9bf4fce9fccb3903a7f502782e4292f8c59e23d
Binary files /dev/null and b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/paper/Bachelorthesis.pdf differ
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_agent.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..2203d79e507a49fa2b88204e085a6ee591d4a4a2
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_agent.py
@@ -0,0 +1,27 @@
+"""
+Created on Sat Apr 18 11:45:41 2020
+
+@author: Pieter Cawood
+
+"""
+
+GLOBAL_MAX_AGENT_TIME = 2500
+
+class Agent(object):
+    def __init__(self, _id, parking_location):
+        self.id = _id
+        self.parking_location = parking_location
+        self.path = {}
+        self.max_time = GLOBAL_MAX_AGENT_TIME
+        self.pos = parking_location
+        self.next_endpoint = None
+        self.time_at_goal = 0
+
+        self.final_action = 0
+
+        self.taskSet = []
+
+        self.tasksPlanning = []
+
+
+
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_astar.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_astar.py
new file mode 100644
index 0000000000000000000000000000000000000000..c15b674e09b720dae7cb101a40699b6b8b0bf74c
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_astar.py
@@ -0,0 +1,154 @@
+"""
+Created on Wed Apr 22 07:43:03 2020
+
+@author: Pieter Cawood
+
+"""
+from heapq import *
+from ta_state import *
+from ta_world import MAPNODETYPES
+
+def rotation_steps(rotation, start_rotation, end_rotation):
+    n_rotations = int(360/rotation)
+    return int(abs(end_rotation-start_rotation)/rotation)
+    
+
+
+def get_heuristic(start_location, goal_location, rotation):
+    # Admissible heuristic - manhattan distance
+    return abs(start_location.col - goal_location.col) + abs(start_location.row - goal_location.row) + rotation_steps(rotation, start_location.rotation, goal_location.rotation)
+
+def get_old_heuristic(start_location, goal_location):
+    # Admissible heuristic - manhattan distance
+    return abs(start_location.col - goal_location.col) + abs(start_location.row - goal_location.row)
+
+
+class AStar:
+    def __init__(self, world, _rotation):
+        self.dim_x = world.width
+        self.dim_y = world.height
+        self.obstacles = {}
+        self.other_agent_paths = []
+
+        self.rotation = _rotation
+
+    def state_possible(self, current_state, new_state):
+        # Check not parking or wall
+        not_obstacle = False
+        if (new_state.location.col, new_state.location.row) not in self.obstacles:
+            not_obstacle = True
+        return 0 <= new_state.location.col < self.dim_x and 0 <= new_state.location.row < self.dim_y \
+               and not_obstacle and not self.is_collision(current_state, new_state)
+
+    def is_collision(self, current_state, new_state): 
+        for other_agent_path in self.other_agent_paths:
+            # Vertex collision
+            if new_state.time in other_agent_path:
+                if other_agent_path[new_state.time].row == new_state.location.row and other_agent_path[new_state.time].col == new_state.location.col:
+                    return True
+            # Edge collision
+            if new_state.time in other_agent_path and current_state.time in other_agent_path:
+                if other_agent_path[new_state.time].row == current_state.location.row and \
+                    other_agent_path[new_state.time].col == current_state.location.col and \
+                        other_agent_path[current_state.time].row == new_state.location.row and \
+                            other_agent_path[current_state.time].col == new_state.location.col:
+                    return True
+        return False
+
+    def get_neighbours(self, current_state):
+        neighbours = []
+        neighbour_time_step = current_state.time + 1
+        # Wait in state
+        new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row, current_state.location.rotation))
+        if self.state_possible(current_state, new_state):
+            neighbours.append(new_state)
+
+        # Add rotation
+        new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row, (current_state.location.rotation+self.rotation) % 360))
+        if self.state_possible(current_state, new_state):
+            neighbours.append(new_state)
+        # Remove rotation
+        new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row, (current_state.location.rotation-self.rotation) % 360))
+        if self.state_possible(current_state, new_state):
+            neighbours.append(new_state)
+
+        ##  Move in specific directions
+        if current_state.location.rotation == 0:
+            # Move down
+            new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row - 1, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)        
+        elif current_state.location.rotation == 90:
+            # Move right
+            new_state = State(neighbour_time_step, Location(current_state.location.col + 1, current_state.location.row, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)
+        elif current_state.location.rotation == 180:
+            # Move up
+            new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row + 1, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)
+        elif current_state.location.rotation == 270:
+            new_state = State(neighbour_time_step, Location(current_state.location.col - 1, current_state.location.row, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)
+                 
+        return neighbours
+
+    def create_obstacles(self, world, other_agent_paths, remaining_parking, timestep):
+        # Map blocked cells
+        for element in world:
+            if world[element] == MAPNODETYPES.WALL:
+                self.obstacles[(element[0], element[1])] = True
+                    
+        # Other agents' parking locations
+        for location in remaining_parking:
+            self.obstacles[(location.col, location.row)] = True
+
+        short_paths = []
+        t = timestep
+        for path in other_agent_paths:
+            new_path = dict()
+            t = timestep
+            while t in path:
+                new_path[t] = path[t]
+                t += 1
+            short_paths.append(new_path)
+        self.other_agent_paths = short_paths
+
+    def search(self, time_step, start_location, goal_location, other_agent_paths, world, parking_locations, agent,
+               release_time=0, find_step = 0):
+        self.create_obstacles(world, other_agent_paths, parking_locations, time_step)
+        initial_state = State(time_step, start_location)
+        came_from = {}
+        open_list = [initial_state]
+        closed_set = set()
+        initial_state.g_score = 0
+        # initial_state.f_score = get_heuristic(start_location, goal_location, self.rotation)
+        initial_state.f_score = get_old_heuristic(start_location, goal_location)
+        while open_list:
+            current = heappop(open_list)
+            # If agent is at the goal location
+            if current.location == goal_location:
+                # Agent cannot move during pickup/delivery, needs at least 2 timesteps at the goal location
+                if current in came_from and came_from[current].location == goal_location:
+                    # If not yet release time hold and run search
+                    if not current.time < release_time:
+                        new_path = [current]
+                        while current in came_from:
+                            current = came_from[current]
+                            new_path.append(current)
+                        return new_path[::-1]
+            # Continue looking for the goal location
+            closed_set |= {current}
+            neighbours = self.get_neighbours(current)
+            neighbour: State
+            for neighbour in neighbours:
+                # Only explore new states
+                if (neighbour not in closed_set) and (neighbour not in open_list):
+                    came_from[neighbour] = current
+                    neighbour.g = current.g + 1
+                    # neighbour.f = neighbour.g + get_heuristic(neighbour.location, goal_location, self.rotation)
+                    neighbour.f = neighbour.g + get_old_heuristic(neighbour.location, goal_location)
+                    heappush(open_list, neighbour)
+        return False
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_state.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_state.py
new file mode 100644
index 0000000000000000000000000000000000000000..5ad98faed2d5c8a149f7671e2ce84702c0db5604
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_state.py
@@ -0,0 +1,56 @@
+"""
+Created on Sat Apr 18 10:45:11 2020
+
+@author: Pieter Cawood
+
+"""
+
+def h(pos1, pos2):
+    return abs(pos1.col - pos2.col) + abs(pos1.row - pos2.row)
+
+class Location(object):
+    def __init__(self, col, row, rotation):
+        self.col = col
+        self.row = row
+        self.rotation = rotation
+
+        # Relevant information for pickup and delivery actions
+        self.task_id = None
+        self.to_pickup = False
+        self.to_deliver = False
+
+    def __eq__(self, other):
+        return self.col == other.col and self.row == other.row and self.rotation == other.rotation
+
+    def __hash__(self):
+        return hash(str(self.col) + "_" + str(self.row) + "_" + str(self.rotation))
+
+    def __str__(self):
+        return str((self.col, self.row, self.rotation))
+
+    # Better information for debugging
+    def __repr__(self):
+        return f"Location({self.col}, {self.row}, {self.rotation})"
+
+
+class State(object):
+    def __init__(self, time, location):
+        self.time = time
+        self.location = location
+        self.g = 0
+        self.f = 0
+
+    def __eq__(self, other):
+        return self.time == other.time and self.location == other.location
+
+    def __hash__(self):
+        return hash(str(self.time) + str(self.location.col) + str(self.location.row))
+
+    def __str__(self):
+        return str((self.time, self.location.col, self.location.row))
+
+    def __lt__(self, other):
+        if self.f < other.f:
+            return True
+        else:
+            return False
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_system.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_system.py
new file mode 100644
index 0000000000000000000000000000000000000000..e36ec78cd4c83668bdbb577597cc9509120962e0
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_system.py
@@ -0,0 +1,261 @@
+"""
+Created on Sat Apr 18 11:11:10 2020
+
+@author: Pieter Cawood
+"""
+import time
+from ta_world import *
+from ta_task import *
+from ta_astar import AStar
+from queue import Queue
+from itertools import combinations
+import concurrent.futures
+
+GLOBAL_MAX_AGENT_TIME = 2500
+
+def plan_path(world, rotation, agent, time_step, release_time=0, find_step=0):
+        a_star = AStar(world, rotation)
+        other_agent_paths = []
+        parking_locations = []
+
+        # Add other agent paths
+        for agent_id in world.agents:
+            if agent_id != agent.id:
+                other_agent_paths.append(world.agents[agent_id].path)
+                parking_locations.append(world.agents[agent_id].parking_location)
+        start_location = agent.path[time_step]
+        goal_location = agent.next_endpoint
+
+        # Non dummy path, add release time to hold pickup
+        new_path = a_star.search(time_step, start_location, goal_location, other_agent_paths, world, parking_locations,
+                                agent, release_time, find_step)
+        # Could not find path
+        if not new_path:
+            return False
+
+        # Update agent path
+        for state in new_path:
+            world.agents[agent.id].path[state.time] = state.location
+
+        world.agents[agent.id].time_at_goal = time_step + len(new_path) - 1
+        return world.agents[agent.id].time_at_goal
+
+def copy_queue(queue):
+        result = Queue()
+        for entry in queue.queue:
+            result.put(entry)
+        return result
+
+def calculate_execution_time(world, rotation, agent_id, tsp_seqs):
+        # print(f"Calculating execution time of agent: {agent_id}")
+        time_step = 0
+        new_start_step = -1
+        while True:
+            new_start_step += 1
+            time_step = new_start_step
+            if agent_id not in tsp_seqs:
+                tsp_seqs[agent_id] = Queue()
+            seq = copy_queue(tsp_seqs[agent_id])
+            path_failed = False
+            for seq_task in range(seq.qsize()):
+                task = seq.get()
+                # To pickup position
+                world.agents[agent_id].next_endpoint = task.pickup_endpoint
+                time_step = plan_path(world, rotation, world.agents[agent_id], time_step, task.release_time, 1)
+                if not time_step:
+                    path_failed = True
+                    break
+                # To delivery position
+                world.agents[agent_id].next_endpoint = task.delivery_endpoint
+                time_step = plan_path(world, rotation, world.agents[agent_id], time_step, 0, 2)
+                if not time_step:
+                    path_failed = True
+                    break
+                if not path_failed:
+                    break
+            # Move agent path back to parking position
+            for t_step in range(GLOBAL_MAX_AGENT_TIME):
+                world.agents[agent_id].path[t_step] = world.agents[agent_id].parking_location
+            return time_step
+
+class System:
+    def __init__(self, env, rotation, agentsList, taskList, sequence_file_path):
+        self.env = env
+        self.rotation = rotation
+        self.agentsList = agentsList
+        self.taskList = taskList
+        self.sequence_file_path = sequence_file_path
+
+        self.world = None
+        self.tasks = None
+
+        self.paths = dict()
+
+        self.makespan = 0
+
+        self.main()
+
+
+    def load_files(self):
+        world = World(self.env, self.agentsList)
+        self.world = world
+        tasks = TaskDict(self.taskList, world)
+        self.tasks = tasks
+        agent_tour_dict = TourDict(
+            self.sequence_file_path, self.agentsList, tasks)
+        return world, tasks, agent_tour_dict
+
+
+    def find_agent_path(self, world, rotation, agent, time_step, release_time=0, find_step=0):
+        a_star = AStar(world, rotation)
+        other_agent_paths = []
+        parking_locations = []
+
+        # Add other agent paths
+        for agent_id in world.agents:
+            if agent_id != agent.id:
+                other_agent_paths.append(world.agents[agent_id].path)
+                parking_locations.append(world.agents[agent_id].parking_location)
+        start_location = agent.path[time_step]
+        goal_location = agent.next_endpoint
+
+        # Non dummy path, add release time to hold pickup
+        new_path = a_star.search(time_step, start_location, goal_location, other_agent_paths, world, parking_locations,
+                                agent, release_time, find_step)
+        # Could not find path
+        if not new_path:
+            return False
+
+        # Update agent path
+        for state in new_path:
+            world.agents[agent.id].path[state.time] = state.location
+
+        world.agents[agent.id].time_at_goal = time_step + len(new_path) - 1
+        return world.agents[agent.id].time_at_goal
+
+
+    def test_paths(self, world):
+        for agent_1, agent_2 in combinations(world.agents, 2):
+            for time_step in world.agents[agent_1].path:
+                if time_step > max(world.agents[agent_2].path):
+                    break
+                # Vertex collision between any two agents
+                if world.agents[agent_1].path[time_step] == world.agents[agent_2].path[time_step]:
+                    print("Agent #" + str(agent_1) + ",#" + str(agent_2) + " vertex collision at " +
+                        str(world.agents[agent_1].path[time_step]) + " t:" + str(time_step))
+                    return False
+                # Edge collision between any two agents
+                elif (time_step + 1 in world.agents[agent_1].path) and (time_step + 1 in world.agents[agent_2].path):
+                    if (world.agents[agent_1].path[time_step] == world.agents[agent_2].path[time_step + 1]) and \
+                            (world.agents[agent_2].path[time_step] == world.agents[agent_1].path[time_step + 1]):
+                        print("Agent #" + str(agent_1) + ",#" + str(agent_2) + " edge collision at " +
+                            str(world.agents[agent_1].path[time_step]) + "-" +
+                            str(world.agents[agent_2].path[time_step]) + " t:" + str(time_step))
+                        return False
+        return True
+
+
+
+    def main(self):
+        world, tasks, tsp_seqs = self.load_files()
+        make_span = 0
+        last_sim_step = 0
+        closed_list = {}
+        time_start = time.perf_counter()
+        for next_agent in world.agents:
+            time_agent_start = time.perf_counter()
+            max_len = 0
+            priority_id = -1
+            print(f"Determining execution times for remaining agents: ", end='')
+            '''
+            Calculate agents execution time for their paths
+            Initialise path to parking position once complete
+            '''
+            estimated_times = []
+            threads = []
+            remainingAgents = []
+
+            for agent_id in world.agents:
+                if agent_id not in closed_list:
+                    remainingAgents.append(agent_id)
+
+            if len(remainingAgents) > 1:
+                with concurrent.futures.ThreadPoolExecutor() as executor:
+                    for agent_id in remainingAgents:
+                        print(agent_id, end=',')
+                        future = executor.submit(calculate_execution_time, world, self.rotation, agent_id, tsp_seqs)
+                        threads.append((future, agent_id))
+                print("")
+
+                for threadTuple in threads:
+                    timestep = threadTuple[0].result()
+                    estimated_times.append((timestep, threadTuple[1]))
+                largest_exec = max(estimated_times, key=lambda t: t[0])
+                max_len = largest_exec[0]
+                priority_id = largest_exec[1] 
+            else:
+                priority_id = remainingAgents[0]                  
+            # print(f"Calculating actual for {priority_id}")
+            # Expand _id: highest execution time
+            closed_list[priority_id] = True
+            # print(f"Agent {priority_id} is now in closed list")
+            '''
+            Calculate actual prioritized agent path
+            '''
+            new_start_step = -1
+            while True:
+                new_start_step += 1
+                time_step = new_start_step
+                seq = copy_queue(tsp_seqs[priority_id])
+                path_failed = False
+                for next_task in range(tsp_seqs[priority_id].qsize()):
+                    task = seq.get()
+                    # To pickup position
+                    world.agents[priority_id].next_endpoint = task.pickup_endpoint
+                    time_step = self.find_agent_path(world, self.rotation, world.agents[priority_id], time_step, task.release_time, 3)
+                    world.agents[priority_id].path[time_step].task_id = task.id
+                    world.agents[priority_id].path[time_step].to_pickup = True
+                    if not time_step:
+                        path_failed = True
+                        break
+                    # To delivery position
+                    world.agents[priority_id].next_endpoint = task.delivery_endpoint
+                    time_step = self.find_agent_path(world, self.rotation, world.agents[priority_id], time_step, 0, 4)
+                    world.agents[priority_id].path[time_step].task_id = task.id
+                    world.agents[priority_id].path[time_step].to_deliver = True
+                    if not time_step:
+                        path_failed = True
+                        break
+                    task.delivered = time_step
+                    world.agents[priority_id].taskSet.append(task)
+                if not path_failed:
+                    break
+            # Record make_span before parking travel
+            make_span = max(make_span, world.agents[priority_id].time_at_goal)
+            time_agent_stop = time.perf_counter()
+            print("\t* Agent #" + str(priority_id) + " execution time: " + str(
+            world.agents[priority_id].time_at_goal) + " (calc :" + str(
+            round(((time_agent_stop - time_agent_start) / 60), 1)) + " mins)")
+            # End - Travel back to parking
+            world.agents[priority_id].next_endpoint = world.agents[priority_id].parking_location
+            self.find_agent_path(world, self.rotation, world.agents[priority_id], time_step)
+            last_sim_step = max(last_sim_step, world.agents[priority_id].time_at_goal)
+            world.agents[priority_id].final_action = last_sim_step
+
+        time_stop = time.perf_counter()
+        print("Make_span of :" + str(make_span))
+        self.makespan = make_span
+        print("Runtime of :" + str(round(((time_stop - time_start) / 60), 1)) + " minutes")
+        for a_id, a in world.agents.items():
+            self.paths[a_id] = a.path
+
+    def get_paths(self):
+        return self.paths
+
+    def get_parking_locations(self):
+        agents = self.world.agents
+        parking_locations = dict()
+        for a_id, agent in agents.items():
+            parking_pos = agent.parking_location
+            parking_locations[parking_pos] = a_id
+        return parking_locations
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_task.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_task.py
new file mode 100644
index 0000000000000000000000000000000000000000..87abad263c228fe56cb021979dbe4bf4d2d39226
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_task.py
@@ -0,0 +1,100 @@
+"""
+Created on Sat Apr 18 12:51:32 2020
+
+@author: Pieter Cawood
+"""
+from queue import Queue
+import os
+
+CURRENT_TASK_ID = 0
+
+
+class Task(object):
+    def __init__(self, task_id, release_time, endpoint_pickup, endpoint_delivery, world):
+        self.id = task_id
+        self.assigned_agent = None
+        self.release_time = release_time
+        self.pickup_endpoint = endpoint_pickup
+        self.delivery_endpoint = endpoint_delivery
+
+        self.delivered = None
+
+        self.pickup_id = None
+        self.delivery_id = None
+
+    def service_time(self):
+        if self.delivered is not None:
+            return (self.delivered - self.release_time)
+        else:
+            return None
+
+
+# With key of task_id to pair with TaskSequence
+class TaskDict(dict):
+    def __init__(self, taskList, world):
+        self.load_tasks(taskList, world)
+
+    def load_tasks(self, taskList, world):
+        
+        for t in taskList:
+            self[t.id] = t
+
+
+        # task_id = 0
+        # for t in taskList:
+        #     task_releaseTime = t[0]
+        #     task_pickup = t[1]
+        #     task_delivery = t[2]
+
+        #     self[task_id] = Task(task_id, task_releaseTime, task_pickup, task_delivery, world)
+        #     task_id += 1
+        print(f"(2/3) Tasks loaded")
+
+
+# With key of seq id (max is agent count) to load all tasks
+# Seq_id is initially agent listed in tour file
+class TourDict(dict):
+    def __init__(self, tour_file_path, agent_count, tasks_dict):
+        self.load_file(tour_file_path, agent_count, tasks_dict)
+
+    def load_file(self, tour_file_path, agentsList, tasks_dict):
+        agent_count = len(agentsList)
+        file = open(tour_file_path, "r")
+#        file = open("C:/Users/Marjon/Documents/Toolbox_MAS/mvpwarehouse/Algorithm_TA_Prioritized/LKH3/TOUR/LKH_2021_07_08-15_00_44.tour", "r")
+        if not file.mode == 'r':
+            print("Could not open " + tour_file_path)
+        else:
+            tour_data = file.readlines()
+            tour_section = False
+            agent_sequence = None
+            agent_number = 1
+            ez = 0
+            for line in tour_data:
+                if "-1" in line:  # end of data
+                    if agent_sequence.qsize():
+                        agent = agentsList[agent_number-1]
+                        a_id = agent.id
+                        self[a_id] = agent_sequence
+                        tour_section = False
+                if tour_section:
+                    line_val = int(line)
+                    if line_val <= agent_count:  # line listed an agent number
+                        # print(f"Reading sequence of agent: {ez} / {agent_count}")
+                        if agent_sequence.qsize():  # Store previous agent queue
+                            # print(f"Saved sequence for agent {agent_number} with size {agent_sequence.qsize()}")
+                            agent = agentsList[agent_number-1]
+                            a_id = agent.id
+                            self[a_id] = agent_sequence
+                            agent_sequence = Queue()  # Create new agent queue
+                            agent_number = line_val
+                        ez += 1
+                    else:
+                        # Line listed as task number, subtract agent count
+                        task_id = line_val - agent_count - 1
+                        agent_sequence.put(tasks_dict[task_id])
+                        # Set initial agent to tsp seq
+                        tasks_dict[task_id].seq_id = agent_number
+                if "TOUR_SECTION" in line:  # start of data next line
+                    tour_section = True
+                    agent_sequence = Queue()
+        print(f"(3/3) Sequences loaded")
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_world.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_world.py
new file mode 100644
index 0000000000000000000000000000000000000000..bb39f9cc548bfacb46aefb85c9b4e91cf5ee52a4
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/ta_world.py
@@ -0,0 +1,67 @@
+"""
+Created on Sat Apr 18 10:49:17 2020
+
+@author: Pieter Cawood
+
+"""
+from enum import Enum
+from ta_agent import *
+from ta_state import *
+
+
+class MAPNODETYPES(Enum):
+    PARKING = 0
+    PATH = 1
+    WALL = 2
+    TASK_ENDPOINT = 3
+
+
+# Loads map. parking and endpoints are numbered in sequence loaded.
+# Task endpoints numbered from agent_number + 1
+class World(dict):
+    def __init__(self, env, agentsList):
+        self.agents = dict()
+        self.endpoints = dict()
+        self.parking_locations = dict()
+        self.width = 0  # Map width
+        self.height = 0  # Map height
+        self.load_map(env)
+        self.load_agents(env, agentsList)
+
+    def load_agents(self, env, agentsList):
+        for agent in agentsList:
+            agent_col = agent.parking_location.col
+            agent_row = agent.parking_location.row
+            if env[agent_row][agent_col] != 2:
+                raise Exception('Agent {} has an invalid parking location: {}'.format(agent.id, agent.parking_location))
+            self.agents[agent.id] = agent
+            agent.path[0] = agent.parking_location
+            self.parking_locations[agent.id] = agent.parking_location
+
+    def load_map(self, env):
+        parking_count = 1
+        endpoint_count = 0
+        for row in range(len(env)):
+            for col in range(len(env[0])):
+                node = None
+                if env[row][col] == 0:
+                    # Node is a path
+                    node = MAPNODETYPES.PATH
+                elif env[row][col] == 2:
+                    # Node is a parking location (non-task endpoint)
+                    node = MAPNODETYPES.PARKING
+                elif env[row][col] == 1:
+                    # Node is a wall
+                    node = MAPNODETYPES.WALL
+                elif env[row][col] == 3:
+                    # Node is a pickup/delivery location (task endpoint)
+                    node = MAPNODETYPES.TASK_ENDPOINT
+                    self.endpoints[endpoint_count] = Location(col, row, 0)
+                    endpoint_count += 1
+                if node is not None:
+                    # Add node to this collection
+                    self[col, row] = node
+        self.width = len(env[0])
+        self.height = len(env)
+        print(f"(1/3) Map loaded")
+        print(f"Created {parking_count} agents")
diff --git a/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/test.py b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..5afca52772df1cee7078faa5fac96a39cd7a9421
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/test.py
@@ -0,0 +1,15 @@
+import os
+
+#total = "C:/Users/Marjon/Documents/Toolbox_MAS/pick-up-and-delivery/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized/LKH3/TOUR/LKH_2021_08_11-16_23_20.tour"
+#start = "C:/Users/Marjon/Documents/Toolbox_MAS/pick-up-and-delivery/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized"
+
+total = "C:/Users/Marjon/Documents/Toolbox_MAS/pick-up-and-delivery/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/warehousejson.txt"
+start = "C:/Users/Marjon/Documents/Toolbox_MAS/pick-up-and-delivery/Algorithms/Offline_Centralized/Algorithm_TA_Prioritized"
+
+#print(os.path.relpath(total, start))
+
+test = "../../../PickUpandDelivery/ConfigurationFiles/Offline_Centralized/warehousejson.txt"
+
+print(os.path.isfile(test))
+
+print(os.path.isfile("LKH3/LKH-3.exe"))
\ No newline at end of file
diff --git a/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/EnvChannel.py b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/EnvChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..64ab52f3d9eba835313576996a986084d4dc6233
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/EnvChannel.py
@@ -0,0 +1,61 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from EnvironmentData import EnvironmentData
+
+"""
+class that processes information from SideChannel EnvChannel: stores all incoming information
+in an instance of class EnvironmentData
+"""
+
+class EnvChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("621f0a70-4f87-11ea-a6bf-784f4387d1f7")) #must coincide with ChannelId set in c#
+        self.envData = EnvironmentData() # object that stores info on environment
+
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        data = msg.read_string()
+        environment_info = json.loads(data)
+
+        self.envData.matrix = environment_info["matrixLayout"]
+        self.envData.rotation = environment_info["rotationRobot"]
+        self.envData.size_of_action = environment_info["sizeOfAction"]
+        self.envData.size_of_observation = environment_info["sizeOfObservation"]
+        self.envData.number_of_robots = environment_info["numberOfRobotsInEnv"]
+        self.envData.number_of_current_tasks = environment_info["numberOfCurrentTasks"]
+        self.envData.can_go_backwards = environment_info["backwards"]
+        self.envData.random_tasks = environment_info["tasksGeneratedRandomly"]
+        self.envData.instance_ids = environment_info["instanceIDSRobots"]
+
+        self.envData.set_initial_nodes_dictionary(environment_info["initialNodesOfRobots"])
+        self.envData.set_tasks_to_be_assigned(environment_info["currentTasks"])
+        self.envData.set_assigned_tasks()
+
+    def send_string(self, data: str) -> None:
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/EnvironmentData.py b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/EnvironmentData.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e8e71e36be0c96182a7480803290e2edbaccb2f
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/EnvironmentData.py
@@ -0,0 +1,99 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+stores data on environment
+instance methods that initialize environment (used by EnvChannel)
+- set_initial_nodes_dictionary(initial_nodes): initializes current_nodes_dictionary
+containing current(next) nodes for each of the robots
+- set_tasks_to_be_assigned(tasks): initialize tasks_to_be_assigned: tasks that have to be assigned
+- set_assigned_tasks(): initialize assigned_tasks_dictionary containing
+ for every robot the current assigned task
+
+instance methods that update environment info
+- assign_task(robot_instanceID, task): assign task to a given robot
+- add_task_to_tasks_to_be_assigned(task): append a new task to tasks_to_be_assigned
+- task_done(instance_id): remove task from robot that was assigned this task
+"""
+
+
+from Node import Node
+from Task import Position, Task
+
+
+class EnvironmentData:
+
+    def __init__(self):
+        self.matrix = None
+        self.rotation = None
+        self.size_of_action = None
+        self.size_of_observation = None
+        self.number_of_robots = None
+        self.number_of_current_tasks = None
+        self.can_go_backwards = None
+        self.random_tasks = None  # if set to true random tasks will be send whenever a task has been completed,
+        # otherwise all tasks self.tasks_to_be_assigned
+
+        self.instance_ids = []
+        self.current_nodes_dictionary = {} # dictionary instance_id -> current node
+        self.tasks_to_be_assigned = [] # tasks that are still to be assigned
+        self.assigned_tasks_dictionary = {} # dictionary instance_id -> assigned task
+
+
+    #########################################
+    ## methods used by EnvChannel to initialize attributes:
+    #########################################
+
+    # given a correct string containing array of nodes
+    def set_initial_nodes_dictionary(self, initial_nodes):
+        for i in range(self.number_of_robots):
+            self.current_nodes_dictionary[self.instance_ids[i]] = Node(initial_nodes[i]["GridPosition"]["Row"],
+                                                      initial_nodes[i]["GridPosition"]["Column"],
+                                                      initial_nodes[i]["Degrees"])
+
+    # given a correct json_string containing array of tasks
+    def set_tasks_to_be_assigned(self, tasks):
+        for i in range(self.number_of_current_tasks):
+            pickup = Position(tasks[i]["PickUp"]["Row"], tasks[i]["PickUp"]["Column"])
+            delivery = Position(tasks[i]["Delivery"]["Row"], tasks[i]["Delivery"]["Column"])
+            release = tasks[i]["ReleaseTime"]
+            self.tasks_to_be_assigned.append(Task(pickup, delivery, release))
+
+    # initialize dictionary robot instance_id -> task (None)
+    def set_assigned_tasks(self):
+        for i in range(self.number_of_robots):
+            self.assigned_tasks_dictionary[self.instance_ids[i]] = None
+
+    #########################################
+    ## methods used to update environment info
+    #########################################
+
+    # when a task is assigned to a robot, it has to be added to self.assigned_tasks
+    # and removed from self.tasks_to_be_assigned
+    def assign_task(self, robot_instanceID, task):
+        self.assigned_tasks_dictionary[robot_instanceID] = task
+        self.tasks_to_be_assigned.remove(task)
+
+    # when a new task is available it is added to tasks_to_be_assigned
+    # a check is made whether there are still tasks that can be added, but this should not be happening (diagnostical)
+    def add_task_to_tasks_to_be_assigned(self, task):
+        if len(self.tasks_to_be_assigned) == self.number_of_current_tasks:
+            raise Exception("cannot add more tasks")
+        self.tasks_to_be_assigned.append(task)
+
+    # when a robot has finished his task it has to be removed from assigned_tasks
+    def task_done(self, instance_id):
+        self.assigned_tasks_dictionary[instance_id] = None
diff --git a/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/EnvironmentManager.py b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/EnvironmentManager.py
new file mode 100644
index 0000000000000000000000000000000000000000..d830bee18b18943dfe19075de04c1083c021f727
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/EnvironmentManager.py
@@ -0,0 +1,203 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""'
+Class that contains and manages the information on the environment.
+- Initializes and holds information on the environment (EnvData).
+- Contains a reference to the sidechannel (EnvChannel).
+- Contains a reference to the sidechannel (TaskChannel).
+- Contains a reference to the unity environment (UnityEnv).
+Has instance methods
+- reset() which resets the environment.
+- step() which assigns tasks, computes a new action based on observation from the unity environment
+ and sends actions back to unity, updates info environment when a task has finished
+- close() which closes the environment/
+
+Has also some auxilary instance methods:
+- assign_new_task() which finds a new task and a robot that is free, then calls
+assign_task_to_robot(robot_instanceID, task)
+- compute_path(current_node, task) which computes paths starting in current_node completing a certain task
+- initialize_shortest_paths() which initializes a dictionary containing the paths robots are following
+- assign_task_to_robot(robot_instanceID, task) which assigns task to a robot with given instance ID,
+updates EnvData and sends information on assignment back to Unity
+
+Note that this a toy example. No checks are done on collisions.
+"""
+
+
+import json
+
+from mlagents_envs.base_env import ActionTuple
+
+from Graph import Graph
+from Node import Node
+
+import numpy as np
+
+
+class EnvironmentManager:
+
+    def __init__(self, envData, unityEnv, envChannel, taskChannel):
+        self.envData = envData
+        self.unityEnv = unityEnv
+        self.envChannel = envChannel
+        self.taskChannel = taskChannel
+
+        # IMPORTANT: sends info through envChannel, to be called before setting up connection envData an taskChannel
+        self.reset()
+
+        # taskChannel needs info on envData
+        self.taskChannel.environment_data = envData
+
+        # behavior name for agent
+        self.behavior_name = list(unityEnv.behavior_specs.keys())[0]
+
+        # graph that is used for computing paths
+        self.graph = Graph(envData.matrix, envData.rotation, envData.can_go_backwards)
+
+        # for every robot with instanceID id shortest_paths[id] gives the shortest path to
+        # its currently assigned task
+        self.shortest_paths = {}
+
+        self.initialize_shortest_paths()
+
+    # step in the environment
+    # 1) checks if new tasks can be assigned
+    # 2) collect observations
+    # 3) compute new actions
+    # 4) send actions back to Unity
+    def step(self):
+        self.assign_new_task()
+
+        # get information from the agent that requests an action
+        decision_steps, terminal_steps = self.unityEnv.get_steps(self.behavior_name)
+
+        # decision_steps.obs is a list of numpy arrays, first dimension corresponds to the number of agents that has requested
+        # a decision (here 1), the observation of the agent is the first element
+        observation = decision_steps.obs[0][0]
+
+        print("----------------------------------------")
+
+
+        actions = []  # long list of all actions
+        action_tuple = ActionTuple()  # actions to send to unity
+
+        # get observations per robot and store in dictionary observations[instance_id] -> observation
+        observations = {}
+        for i in range(self.envData.number_of_robots):
+            observation_i = observation[i * self.envData.size_of_observation:
+                                        i * self.envData.size_of_observation + self.envData.size_of_observation]
+            observations[observation_i[0]] = observation_i[1:]
+
+        # create an action for all robots and send at once to unity
+        for robot_id_unity in observations:
+
+            obs = observations[robot_id_unity]
+            print("robot " + str(robot_id_unity) + " at node [(" + str(obs[0]) + "," + str(obs[1]) + ")," + str(
+                obs[2]) + "]")
+
+            path = self.shortest_paths[robot_id_unity]
+            # if path is empty, then robot should stay at same node
+            if len(path) == 0:
+                actions.extend([robot_id_unity, obs[0], obs[1], obs[2], 0, 0])
+            # if path is not empty we get next action from shortest path
+            else:
+                next_action = path[0]  # is node or "pickup" or "deliver"
+                if next_action == "pickup":
+                    actions.extend([robot_id_unity, obs[0], obs[1], obs[2], 1, 0])
+                elif next_action == "deliver":
+                    actions.extend([robot_id_unity, obs[0], obs[1], obs[2], 0, 1])
+                    self.envData.assigned_tasks_dictionary[robot_id_unity] = None
+                else:
+                    actions.extend([robot_id_unity, next_action.x, next_action.y, next_action.g, 0, 0])
+                    # update current node
+                    self.envData.current_nodes_dictionary[robot_id_unity] = Node(next_action.x, next_action.y,
+                                                                                     next_action.g)
+                # update path
+                self.shortest_paths[robot_id_unity] = path[1:]
+
+        # add action to action_tuple and set the actions
+        actions = np.array(actions)
+        actions.resize(1, self.envData.size_of_action * self.envData.number_of_robots)
+        action_tuple.add_discrete(actions)
+
+        self.unityEnv.set_actions(self.behavior_name, action_tuple)
+        self.unityEnv.step() # send actions to unity and wait until a new decision is requested
+
+
+
+
+    # reset the environment
+    def reset(self):
+        self.unityEnv.reset()
+
+    # close the environment
+    def close(self):
+        self.close()
+
+    # assigns the next available task to an idle robot, if possible
+    def assign_new_task(self):
+        # check if there are tasks that have to be assigned
+        # if this is the case, get first task and assign to available robot
+        if len(self.envData.tasks_to_be_assigned) != 0:
+            task = self.envData.tasks_to_be_assigned[0]
+            # get available robot
+            for robot_id in self.envData.instance_ids:
+                if self.envData.assigned_tasks_dictionary[robot_id] is None:
+                     # robot is free: assign task to robot and break out of for loop
+                    self.assign_task_to_robot(robot_id, task)
+                    break
+
+
+    # compute path from current_node that finishes given task
+    # for test purposes pick up and delivery need to have rotation 0
+    # at pick up delivery robot stays at same node
+    # returns a sequence of nodes and pick up/delivery actions
+    def compute_path(self, current_node, task):
+        path1 = self.graph.computeShortestPath(current_node,
+                                          Node(task.PickUp.Row, task.PickUp.Column, 0))
+        path1 = path1[1:]
+        path2 = self.graph.computeShortestPath(Node(task.PickUp.Row, task.PickUp.Column, 0),
+                                          Node(task.Delivery.Row, task.Delivery.Column, 0))
+        path2 = path2[1:]
+
+        return path1 + ["pickup"] + path2 + ["deliver"]
+
+
+    # for every robot initially there is an empty path to be followed
+    def initialize_shortest_paths(self):
+        for robot_id in self.envData.instance_ids:
+            self.shortest_paths[robot_id] = []
+
+    def assign_task_to_robot(self, robot_instanceID, task):
+        # update envData
+        self.envData.assign_task(robot_instanceID, task)
+        # compute path for robot
+        self.shortest_paths[robot_instanceID] = \
+            self.compute_path(self.envData.current_nodes_dictionary[robot_instanceID],task)
+        # send info to unity
+        taskDict = {"Task": {
+                        "PickUp": {"Row": task.PickUp.Row, "Column": task.PickUp.Column},
+                        "Delivery": {"Row": task.Delivery.Row, "Column": task.Delivery.Column},
+                        "ReleaseTime": task.ReleaseTime},
+                    "InstanceID": robot_instanceID}
+        self.taskChannel.send_string(json.dumps(taskDict))
+
+
+
+
+
+
diff --git a/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Graph.py b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Graph.py
new file mode 100644
index 0000000000000000000000000000000000000000..69e03b997172dae6855dca7f06890606239e7063
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Graph.py
@@ -0,0 +1,126 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+from networkx import DiGraph, shortest_path
+from Node import Node
+
+"""
+Class Graph creates a graph based on matrix, deviation (unit of rotation) and whether robots can move backwards).
+Its nodes contain position in the grid and orientation wrt north (see class <c>Node</c>).
+Networkx package as underlying data structure.
+"""
+
+class Graph:
+    def __init__(self, matrix, deviation, cangobackwards):
+        self.matrix = matrix
+        self.number_of_rows = len(matrix)
+        self.number_of_columns = len(matrix[0])
+        self.deviation = deviation
+        self.cangobackwards = cangobackwards
+        self.graph = DiGraph()
+
+        for i in range(self.number_of_rows):
+            for j in range(self.number_of_columns):
+                # we have to add nodes to the graph when we encounter a number different than 1
+                if matrix[i][j] != 1:
+                    self.addEdgesByRotation(i, j)
+                    self.addEdgesByMovingForward(i,j)
+
+    def addEdgesByRotation(self, row, column):
+        degree = 0
+        while degree < 360:
+            newnode = Node(row, column, degree)
+
+            # add all edges from newnode staying at the same position (row, number), i.e. rotation
+
+            # rotate left
+            rotateLeftNode = Node(row, column, get_degree_in_range_0_360(degree - self.deviation))
+            self.graph.add_edge(newnode, rotateLeftNode)
+
+            # rotate right
+            rotateRightNode = Node(row, column, get_degree_in_range_0_360(degree + self.deviation))
+            self.graph.add_edge(newnode, rotateRightNode)
+
+            degree += self.deviation
+
+    def addEdgesByMovingForward(self, row, column):
+        # check left
+        if column > 0 and self.matrix[row][column-1] != 1:
+            # we can move forward if we have degree 270
+            currentnode = Node(row, column, 270)
+            neighbourleft = Node(row, column-1, 270)
+            self.graph.add_edge(currentnode, neighbourleft)
+            # we can move backward if we have degree 90
+            if self.cangobackwards:
+                currentnode = Node(row, column, 90)
+                neighbourleft = Node(row, column-1, 90)
+                self.graph.add_edge(currentnode, neighbourleft)
+
+        # check right
+        if column < self.number_of_columns -1 and self.matrix[row][column+1] != 1:
+            # we can move forward if we have degree 90
+            currentnode = Node(row, column, 90)
+            neighbourright = Node(row, column+1, 90)
+            self.graph.add_edge(currentnode, neighbourright)
+            # we can move backward if we have degree 270
+            if self.cangobackwards:
+                currentnode = Node(row, column, 270)
+                neighbourright = Node(row, column+1, 270)
+                self.graph.add_edge(currentnode, neighbourright)
+
+        # check up
+        if row > 0 and self.matrix[row-1][column] != 1:
+            # we can move forward if we have degree 0
+            currentnode = Node(row, column, 0)
+            neighbourup = Node(row-1, column, 0)
+            self.graph.add_edge(currentnode, neighbourup)
+            # we can move backward if we have degree 180
+            if self.cangobackwards:
+                currentnode = Node(row, column, 180)
+                neighbourup = Node(row-1, column, 180)
+                self.graph.add_edge(currentnode, neighbourup)
+
+        # check down
+        if row < self.number_of_rows-1 and self.matrix[row+1][column] != 1:
+            # we can move forward if we have degree 180
+            currentnode = Node(row, column, 180)
+            neighbourdown = Node(row+1, column, 180)
+            self.graph.add_edge(currentnode, neighbourdown)
+            # we can move backward if we have degree 0
+            if self.cangobackwards:
+                currentnode = Node(row, column, 0)
+                neighbourdown = Node(row+1, column, 0)
+                self.graph.add_edge(currentnode, neighbourdown)
+
+    def computeShortestPath(self, start_node, end_node):
+        #compute shortest path from start_node to end_node: return a list
+        return shortest_path(self.graph, start_node, end_node)
+
+def get_degree_in_range_0_360(degree):
+    rest = degree % 360
+    if rest < 0:
+        return rest + 360
+    return rest
+
+
+
+
+
+
+
+
+
+
diff --git a/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Node.py b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Node.py
new file mode 100644
index 0000000000000000000000000000000000000000..126684f885f63b51edcd2b6684d26d7a847c51af
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Node.py
@@ -0,0 +1,57 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+Class Node represent nodes in the graph. Every node contains a
+position (x,y) in the grid
+and a rotation in degree where
+0 = North
+90 = East
+280 = South
+270 = West
+all degrees must be between 0 and 360
+
+attributes are set to private such that they cannot be overwritten and there is no problem with the hash
+"""
+
+class Node:
+    def __init__(self,x,y,g):
+        self._x = x
+        self._y = y
+        self._g = g
+
+    @property
+    def x(self):
+        return self._x
+
+    @property
+    def y(self):
+        return self._y
+
+    @property
+    def g(self):
+        return self._g
+
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.x == other.x and self.y == other.y and self.g == other.g
+
+
+    def __hash__(self):
+        return (((self.x * 397) ** self.y) * 397) **self.g
+
+    def __str__(self):
+        return "[(" + str(self.x) + ", " + str(self.y) + ")" + "," + str(self.g) + "]"
diff --git a/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Pipfile b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Pipfile
new file mode 100644
index 0000000000000000000000000000000000000000..2cf8108a7836978e89ef3320e61b72d3c4eb3be6
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Pipfile
@@ -0,0 +1,14 @@
+[[source]]
+url = "https://pypi.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+networkx = "==2.5"
+mlagents = "==0.23.0"
+mlagents-envs = "==0.23.0"
+
+[dev-packages]
+
+[requires]
+python_version = "3.6"
diff --git a/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Task.py b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Task.py
new file mode 100644
index 0000000000000000000000000000000000000000..23aa3d5b09f76858f524061f0050f39d9e914fe0
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/Task.py
@@ -0,0 +1,51 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+Class Task represents tasks which consist of 2 positions: a pickup and a delivery position and a release time.
+"""
+class Task:
+    def __init__(self, pos1, pos2, release):
+        self.PickUp = pos1
+        self.Delivery = pos2
+        self.ReleaseTime = release
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.PickUp == other.PickUp and\
+               self.Delivery == other.Delivery and self.ReleaseTime == other.ReleaseTime
+
+    def __hash__(self):
+        hash_code = hash(self.PickUp)
+        hash_code = (hash_code * 397) ** hash(self.Delivery)
+        hash_code = (hash_code * 397) ** hash(self.ReleaseTime)
+        return hash_code
+
+    def __str__(self):
+        return "[" + str(self.PickUp) + ", " + str(self.Delivery) + "]" + str(self.ReleaseTime)
+
+class Position:
+    def __init__(self, x, y):
+        self.Row = x
+        self.Column = y
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.Row == other.Row and self.Column == other.Column
+
+    def __hash__(self):
+        return ((self.Row * 397) ** self.Column) * 397
+
+    def __str__(self):
+        return "(" + str(self.Row) + ", " + str(self.Column) + ")"
diff --git a/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/TaskSideChannel.py b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/TaskSideChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..6b5d1fba25f4def24a809c0552ee719bd7bef553
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/TaskSideChannel.py
@@ -0,0 +1,50 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from Task import Task, Position
+
+"""
+Class that processes info from the TaskSideChannel.
+- sends assignment of tasks to robots
+"""
+
+
+class TaskSideChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("c11ab982-82b8-4194-b387-3bd0fe9ebdc7")) #must coincide with ChannelId set in c#
+        self.environment_data = None #info on the environment
+
+    # channel receives new tasks that have to be assigned
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        print(msg.read_string())
+
+    # channel sends information when a task has been assigned (to which robot)
+    def send_string(self, data: str) -> None:
+
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/main.py b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..bf0312bb53a914f0169c5b6fb6d78efb87298b3c
--- /dev/null
+++ b/Algorithms/Offline_Centralized/Algorithm_test_toyexample_offline_centralized/main.py
@@ -0,0 +1,44 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+Main file that controls and decision making
+This is a toy example!
+Uses EnvironmentManager who assigns tasks in order to available agents
+and then computes shortest paths, no check on collisions.
+"""
+
+from mlagents_envs.environment import UnityEnvironment
+import EnvChannel, TaskSideChannel
+import EnvironmentManager
+
+# as long as simulation_going is true, new actions will be generated
+
+simulation_going = True
+
+# setup side channels and unity environment
+envChannel = EnvChannel.EnvChannel()
+taskChannel = TaskSideChannel.TaskSideChannel()
+env = UnityEnvironment(file_name=None, side_channels=[envChannel, taskChannel])
+
+# set up environment manager
+envManager = EnvironmentManager.EnvironmentManager(envChannel.envData, env, envChannel, taskChannel)
+
+
+while simulation_going:
+    envManager.step()
+
+envManager.close()
diff --git a/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/EnvChannel.py b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/EnvChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6d62add37419b9cfe1ddb9b07a70b150a07a6d7
--- /dev/null
+++ b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/EnvChannel.py
@@ -0,0 +1,63 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from EnvironmentData import EnvironmentData
+
+"""
+class that processes information from SideChannel EnvChannel: stores all incoming information
+in an instance of class EnvironmentData
+"""
+
+
+class EnvChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("621f0a70-4f87-11ea-a6bf-784f4387d1f7")) #must coincide with ChannelId set in c#
+        self.envData = EnvironmentData() # object that stores info on environment
+
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        data = msg.read_string()
+        environment_info = json.loads(data)
+
+        self.envData.matrix = environment_info["matrixLayout"]
+        self.envData.rotation = environment_info["rotationRobot"]
+        self.envData.size_of_action = environment_info["sizeOfAction"]
+        self.envData.size_of_observation = environment_info["sizeOfObservation"]
+        self.envData.number_of_robots = environment_info["numberOfRobotsInEnv"]
+        self.envData.number_of_current_tasks = environment_info["numberOfCurrentTasks"]
+        self.envData.can_go_backwards = environment_info["backwards"]
+        self.envData.random_tasks = environment_info["tasksGeneratedRandomly"]
+        self.envData.instance_ids = environment_info["instanceIDSRobots"]
+
+        self.envData.set_initial_nodes_dictionary(environment_info["initialNodesOfRobots"])
+        self.envData.set_tasks_to_be_assigned(environment_info["currentTasks"])
+        self.envData.set_assigned_tasks()
+
+    def send_string(self, data: str) -> None:
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/EnvironmentData.py b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/EnvironmentData.py
new file mode 100644
index 0000000000000000000000000000000000000000..be6a9c1e66b598ea49fd5fba407962fc81bc9581
--- /dev/null
+++ b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/EnvironmentData.py
@@ -0,0 +1,102 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+stores data on environment
+instance methods that initialize environment (used by EnvChannel)
+- set_initial_nodes_dictionary(initial_nodes): initializes current_nodes_dictionary
+containing current(next) nodes for each of the robots
+- set_tasks_to_be_assigned(tasks): initialize tasks_to_be_assigned: tasks that have to be assigned
+- set_assigned_tasks(): initialize assigned_tasks_dictionary containing
+ for every robot the current assigned task
+
+instance methods that update environment info
+- assign_task(robot_instanceID, task): assign task to a given robot
+- add_task_to_tasks_to_be_assigned(task): append a new task to tasks_to_be_assigned
+- task_done(instance_id): remove task from robot that was assigned this task
+"""
+
+
+import json
+
+from Node import Node
+from Task import Position, Task
+
+
+class EnvironmentData:
+
+    def __init__(self):
+        self.matrix = None
+        self.rotation = None
+        self.size_of_action = None
+        self.size_of_observation = None
+        self.number_of_robots = None
+        self.number_of_current_tasks = None
+        self.can_go_backwards = None
+        self.random_tasks = None  # if set to true random tasks will be send whenever a task has been completed,
+        # otherwise all tasks self.tasks_to_be_assigned
+
+        self.instance_ids = []
+        self.current_nodes_dictionary = {} # dictionary instance_id -> current node
+        self.tasks_to_be_assigned = [] # tasks that are still to be assigned
+        self.assigned_tasks_dictionary = {} # dictionary instance_id -> assigned task
+
+
+    #########################################
+    ## methods used by EnvChannel to initialize attributes:
+    #########################################
+
+    # given a correct string containing array of nodes
+    def set_initial_nodes_dictionary(self, initial_nodes):
+        for i in range(self.number_of_robots):
+            self.current_nodes_dictionary[self.instance_ids[i]] = Node(initial_nodes[i]["GridPosition"]["Row"],
+                                                      initial_nodes[i]["GridPosition"]["Column"],
+                                                      initial_nodes[i]["Degrees"])
+
+    # given a correct json_string containing array of tasks
+    def set_tasks_to_be_assigned(self, tasks):
+        for i in range(self.number_of_current_tasks):
+            pickup = Position(tasks[i]["PickUp"]["Row"], tasks[i]["PickUp"]["Column"])
+            delivery = Position(tasks[i]["Delivery"]["Row"], tasks[i]["Delivery"]["Column"])
+            release = tasks[i]["ReleaseTime"]
+            self.tasks_to_be_assigned.append(Task(pickup, delivery, release))
+
+    # initialize dictionary robot instance_id -> task (None)
+    def set_assigned_tasks(self):
+        for i in range(self.number_of_robots):
+            self.assigned_tasks_dictionary[self.instance_ids[i]] = None
+
+    #########################################
+    ## methods used to update environment info
+    #########################################
+
+    # when a task is assigned to a robot, it has to be added to self.assigned_tasks
+    # and removed from self.tasks_to_be_assigned
+    # info has to be sent to unity via the correct channel
+    def assign_task(self, robot_instanceID, task):
+        self.assigned_tasks_dictionary[robot_instanceID] = task
+        self.tasks_to_be_assigned.remove(task)
+
+    # when a new task is available it is added to tasks_to_be_assigned
+    # a check is made whether there are still tasks that can be added, but this should not be happening (diagnostical)
+    def add_task_to_tasks_to_be_assigned(self, task):
+        if len(self.tasks_to_be_assigned) == self.number_of_current_tasks:
+            raise Exception("cannot add more tasks")
+        self.tasks_to_be_assigned.append(task)
+
+    # when a robot has finished his task it has to be removed from assigned_tasks
+    def task_done(self, instance_id):
+        self.assigned_tasks_dictionary[instance_id] = None
diff --git a/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/EnvironmentManager.py b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/EnvironmentManager.py
new file mode 100644
index 0000000000000000000000000000000000000000..910a3108999159afa39573e29a13b95d94465168
--- /dev/null
+++ b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/EnvironmentManager.py
@@ -0,0 +1,196 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""'
+Class that contains and manages the information on the environment.
+- Initializes and holds information on the environment (EnvData).
+- Contains a reference to the sidechannel (EnvChannel).
+- Contains a reference to the sidechannel (TaskChannel).
+- Contains a reference to the unity environment (UnityEnv).
+Has instance methods
+- reset() which resets the environment.
+- step() which assigns tasks, computes a new action based on observation from the unity environment
+ and sends actions back to unity, updates info environment when a task has finished
+- close() which closes the environment/
+
+Has also some auxiliary instance methods:
+- assign_new_task() which finds a new task and a robot that is free, then calls
+assign_task_to_robot(robot_instanceID, task)
+- compute_path(current_node, task) which computes paths starting in current_node completing a certain task
+- initialize_shortest_paths() which initializes a dictionary containing the paths robots are following
+- assign_task_to_robot(robot_instanceID, task) which assigns task to a robot with given instance ID,
+updates EnvData and sends information on assignment back to Unity
+
+Note that this a toy example. No checks are done on collisions.
+"""
+
+import json
+
+from mlagents_envs.base_env import ActionTuple
+
+from Graph import Graph
+from Node import Node
+
+import numpy as np
+
+
+class EnvironmentManager:
+
+    def __init__(self, envData, unityEnv, envChannel, taskChannel):
+        self.envData = envData
+        self.unityEnv = unityEnv
+        self.envChannel = envChannel
+        self.taskChannel = taskChannel
+
+        # IMPORTANT: sends info through envChannel, to be called before setting up connection envData an taskChannel
+        self.reset()
+
+        # taskChannel needs info on envData
+        self.taskChannel.environment_data = envData
+
+        # behavior name for agent
+        self.behavior_name = list(unityEnv.behavior_specs.keys())[0]
+
+        # graph that is used for computing paths
+        self.graph = Graph(envData.matrix, envData.rotation, envData.can_go_backwards)
+
+        # for every robot with instanceID id shortest_paths[id] gives the shortest path to
+        # its currently assigned task
+        self.shortest_paths = {}
+
+        self.initialize_shortest_paths()
+
+    # step in the environment
+    # 1) checks if new tasks can be assigned
+    # 2) collect observations
+    # 3) compute new actions
+    # 4) send actions back to Unity
+    def step(self):
+        self.assign_new_task()
+
+        # get information from the agent that requests an action
+        decision_steps, terminal_steps = self.unityEnv.get_steps(self.behavior_name)
+
+        print("request is being made by")
+        agents = decision_steps.agent_id
+        print(str(len(agents)) + " agents")
+
+        # decision_steps.obs is a list of numpy arrays, first dimension corresponds to the number of agents that has requested
+        # a decision (here len(agents))
+        observations = decision_steps.obs
+
+        print("----------------------------------------")
+
+
+        actions = []  # long list of all actions
+        action_tuple = ActionTuple()  # actions to send to unity
+
+        # create an action for all agents that request an action
+        for i in range(len(agents)):
+            observation = observations[0][i]  # observation of current agent
+            robot_id_unity = observation[0]
+            row = observation[1]
+            column = observation[2]
+            degrees = observation[3]
+
+            print("robot " + str(robot_id_unity) + " at node [(" + str(row) + "," + str(column) + ")," + str(
+                degrees) + "]")
+
+            path = self.shortest_paths[robot_id_unity]
+
+            # if path is empty, then robot should stay at same node
+            if len(path) == 0:
+                actions.extend([row, column, degrees, 0, 0])
+            # if path is not empty we get next action from shortest path
+            else:
+                next_action = path[0]  # is a node or "pickup" or "deliver"
+                if next_action == "pickup":
+                    actions.extend([row, column, degrees, 1, 0])
+                elif next_action == "deliver":
+                    actions.extend([row, column, degrees, 0, 1])
+                    self.envData.assigned_tasks_dictionary[robot_id_unity] = None
+                else:
+                    actions.extend([next_action.x, next_action.y, next_action.g, 0, 0])
+                    # update current node
+                    self.envData.current_nodes_dictionary[robot_id_unity] = Node(next_action.x, next_action.y,
+                                                                                     next_action.g)
+                # update path
+                self.shortest_paths[robot_id_unity] = path[1:]
+
+        # add action to action_tuple and set the actions
+        actions = np.array(actions)
+        actions.resize(len(agents), self.envData.size_of_action)
+        action_tuple.add_discrete(actions)
+
+        self.unityEnv.set_actions(self.behavior_name, action_tuple)
+        self.unityEnv.step() # send actions to unity and wait until a new decision is requested
+
+    # reset the environment
+    def reset(self):
+        self.unityEnv.reset()
+
+    # close the environment
+    def close(self):
+        self.close()
+
+    # assigns the next available task to an idle robot, if possible
+    def assign_new_task(self):
+        # check if there are tasks that have to be assigned
+        # if this is the case, get first task and assign to available robot
+        if len(self.envData.tasks_to_be_assigned) != 0:
+            task = self.envData.tasks_to_be_assigned[0]
+            # get available robot
+            for robot_id in self.envData.instance_ids:
+                if self.envData.assigned_tasks_dictionary[robot_id] is None:
+                     # robot is free: assign task to robot and break out of for loop
+                    self.assign_task_to_robot(robot_id, task)
+                    break
+
+
+    # compute path from current_node that finishes given task
+    # for test purposes pick up and delivery need to have rotation 0
+    # at pick up delivery robot stays at same node
+    # returns a sequence of nodes and pick up/delivery actions
+    def compute_path(self, current_node, task):
+        path1 = self.graph.computeShortestPath(current_node,
+                                          Node(task.PickUp.Row, task.PickUp.Column, 0))
+        path1 = path1[1:]
+        path2 = self.graph.computeShortestPath(Node(task.PickUp.Row, task.PickUp.Column, 0),
+                                          Node(task.Delivery.Row, task.Delivery.Column, 0))
+        path2 = path2[1:]
+
+        return path1 + ["pickup"] + path2 + ["deliver"]
+
+
+    # for every robot initially there is an empty path to be followed
+    def initialize_shortest_paths(self):
+        for robot_id in self.envData.instance_ids:
+            self.shortest_paths[robot_id] = []
+
+    def assign_task_to_robot(self, robot_instanceID, task):
+        # update envData
+        self.envData.assign_task(robot_instanceID, task)
+        # compute path for robot
+        self.shortest_paths[robot_instanceID] = \
+            self.compute_path(self.envData.current_nodes_dictionary[robot_instanceID],task)
+        # send info to unity
+        taskDict = {"Task": {
+                        "PickUp": {"Row": task.PickUp.Row, "Column": task.PickUp.Column},
+                        "Delivery": {"Row": task.Delivery.Row, "Column": task.Delivery.Column},
+                        "ReleaseTime": task.ReleaseTime},
+                    "InstanceID": robot_instanceID}
+        self.taskChannel.send_string(json.dumps(taskDict))
+
diff --git a/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Graph.py b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Graph.py
new file mode 100644
index 0000000000000000000000000000000000000000..69e03b997172dae6855dca7f06890606239e7063
--- /dev/null
+++ b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Graph.py
@@ -0,0 +1,126 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+from networkx import DiGraph, shortest_path
+from Node import Node
+
+"""
+Class Graph creates a graph based on matrix, deviation (unit of rotation) and whether robots can move backwards).
+Its nodes contain position in the grid and orientation wrt north (see class <c>Node</c>).
+Networkx package as underlying data structure.
+"""
+
+class Graph:
+    def __init__(self, matrix, deviation, cangobackwards):
+        self.matrix = matrix
+        self.number_of_rows = len(matrix)
+        self.number_of_columns = len(matrix[0])
+        self.deviation = deviation
+        self.cangobackwards = cangobackwards
+        self.graph = DiGraph()
+
+        for i in range(self.number_of_rows):
+            for j in range(self.number_of_columns):
+                # we have to add nodes to the graph when we encounter a number different than 1
+                if matrix[i][j] != 1:
+                    self.addEdgesByRotation(i, j)
+                    self.addEdgesByMovingForward(i,j)
+
+    def addEdgesByRotation(self, row, column):
+        degree = 0
+        while degree < 360:
+            newnode = Node(row, column, degree)
+
+            # add all edges from newnode staying at the same position (row, number), i.e. rotation
+
+            # rotate left
+            rotateLeftNode = Node(row, column, get_degree_in_range_0_360(degree - self.deviation))
+            self.graph.add_edge(newnode, rotateLeftNode)
+
+            # rotate right
+            rotateRightNode = Node(row, column, get_degree_in_range_0_360(degree + self.deviation))
+            self.graph.add_edge(newnode, rotateRightNode)
+
+            degree += self.deviation
+
+    def addEdgesByMovingForward(self, row, column):
+        # check left
+        if column > 0 and self.matrix[row][column-1] != 1:
+            # we can move forward if we have degree 270
+            currentnode = Node(row, column, 270)
+            neighbourleft = Node(row, column-1, 270)
+            self.graph.add_edge(currentnode, neighbourleft)
+            # we can move backward if we have degree 90
+            if self.cangobackwards:
+                currentnode = Node(row, column, 90)
+                neighbourleft = Node(row, column-1, 90)
+                self.graph.add_edge(currentnode, neighbourleft)
+
+        # check right
+        if column < self.number_of_columns -1 and self.matrix[row][column+1] != 1:
+            # we can move forward if we have degree 90
+            currentnode = Node(row, column, 90)
+            neighbourright = Node(row, column+1, 90)
+            self.graph.add_edge(currentnode, neighbourright)
+            # we can move backward if we have degree 270
+            if self.cangobackwards:
+                currentnode = Node(row, column, 270)
+                neighbourright = Node(row, column+1, 270)
+                self.graph.add_edge(currentnode, neighbourright)
+
+        # check up
+        if row > 0 and self.matrix[row-1][column] != 1:
+            # we can move forward if we have degree 0
+            currentnode = Node(row, column, 0)
+            neighbourup = Node(row-1, column, 0)
+            self.graph.add_edge(currentnode, neighbourup)
+            # we can move backward if we have degree 180
+            if self.cangobackwards:
+                currentnode = Node(row, column, 180)
+                neighbourup = Node(row-1, column, 180)
+                self.graph.add_edge(currentnode, neighbourup)
+
+        # check down
+        if row < self.number_of_rows-1 and self.matrix[row+1][column] != 1:
+            # we can move forward if we have degree 180
+            currentnode = Node(row, column, 180)
+            neighbourdown = Node(row+1, column, 180)
+            self.graph.add_edge(currentnode, neighbourdown)
+            # we can move backward if we have degree 0
+            if self.cangobackwards:
+                currentnode = Node(row, column, 0)
+                neighbourdown = Node(row+1, column, 0)
+                self.graph.add_edge(currentnode, neighbourdown)
+
+    def computeShortestPath(self, start_node, end_node):
+        #compute shortest path from start_node to end_node: return a list
+        return shortest_path(self.graph, start_node, end_node)
+
+def get_degree_in_range_0_360(degree):
+    rest = degree % 360
+    if rest < 0:
+        return rest + 360
+    return rest
+
+
+
+
+
+
+
+
+
+
diff --git a/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Node.py b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Node.py
new file mode 100644
index 0000000000000000000000000000000000000000..126684f885f63b51edcd2b6684d26d7a847c51af
--- /dev/null
+++ b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Node.py
@@ -0,0 +1,57 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+Class Node represent nodes in the graph. Every node contains a
+position (x,y) in the grid
+and a rotation in degree where
+0 = North
+90 = East
+280 = South
+270 = West
+all degrees must be between 0 and 360
+
+attributes are set to private such that they cannot be overwritten and there is no problem with the hash
+"""
+
+class Node:
+    def __init__(self,x,y,g):
+        self._x = x
+        self._y = y
+        self._g = g
+
+    @property
+    def x(self):
+        return self._x
+
+    @property
+    def y(self):
+        return self._y
+
+    @property
+    def g(self):
+        return self._g
+
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.x == other.x and self.y == other.y and self.g == other.g
+
+
+    def __hash__(self):
+        return (((self.x * 397) ** self.y) * 397) **self.g
+
+    def __str__(self):
+        return "[(" + str(self.x) + ", " + str(self.y) + ")" + "," + str(self.g) + "]"
diff --git a/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Pipfile b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Pipfile
new file mode 100644
index 0000000000000000000000000000000000000000..2cf8108a7836978e89ef3320e61b72d3c4eb3be6
--- /dev/null
+++ b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Pipfile
@@ -0,0 +1,14 @@
+[[source]]
+url = "https://pypi.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+networkx = "==2.5"
+mlagents = "==0.23.0"
+mlagents-envs = "==0.23.0"
+
+[dev-packages]
+
+[requires]
+python_version = "3.6"
diff --git a/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Task.py b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Task.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ed7c37501e17a97a2a21349c34d6220720ad380
--- /dev/null
+++ b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/Task.py
@@ -0,0 +1,53 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+Class Task represents tasks which consist of 2 positions: a pickup and a delivery position and a release time.
+"""
+
+class Task:
+    def __init__(self, pos1, pos2, release):
+        self.PickUp = pos1
+        self.Delivery = pos2
+        self.ReleaseTime = release
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.PickUp == other.PickUp and\
+               self.Delivery == other.Delivery and self.ReleaseTime == other.ReleaseTime
+
+    def __hash__(self):
+        hash_code = hash(self.PickUp)
+        hash_code = (hash_code * 397) ** hash(self.Delivery)
+        hash_code = (hash_code * 397) ** hash(self.ReleaseTime)
+        return hash_code
+
+    def __str__(self):
+        return "[" + str(self.PickUp) + ", " + str(self.Delivery) + "]" + str(self.ReleaseTime)
+
+
+class Position:
+    def __init__(self, x, y):
+        self.Row = x
+        self.Column = y
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.Row == other.Row and self.Column == other.Column
+
+    def __hash__(self):
+        return ((self.Row * 397) ** self.Column) * 397
+
+    def __str__(self):
+        return "(" + str(self.Row) + ", " + str(self.Column) + ")"
diff --git a/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/TaskSideChannel.py b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/TaskSideChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f75664d7780ae5804ed869bebeac4a7815903e5
--- /dev/null
+++ b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/TaskSideChannel.py
@@ -0,0 +1,48 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+
+"""
+Class that processes info from the TaskSideChannel.
+- sends assignment of tasks to robots
+"""
+
+
+class TaskSideChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("c11ab982-82b8-4194-b387-3bd0fe9ebdc7")) #must coincide with ChannelId set in c#
+        self.environment_data = None #info on the environment
+
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        print(msg.read_string())
+
+    # channel sends information when a task has been assigned (to which robot)
+    def send_string(self, data: str) -> None:
+
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/main.py b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..8ac383f4edcaad078ae265e9a4a795e8d9f0810b
--- /dev/null
+++ b/Algorithms/Offline_Decentralized/Algorithm_test_toyexample_offline_decentralized/main.py
@@ -0,0 +1,44 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+Main file that controls decision making for the Offline Decentralized Pick Up and Delivery problem.
+This is a toy example!
+Uses EnvironmentManager who assigns tasks in order to available agents
+and then computes shortest paths, no check on collisions.
+"""
+
+from mlagents_envs.environment import UnityEnvironment
+import EnvChannel, TaskSideChannel
+import EnvironmentManager
+
+# as long as simulation_going is true, new actions will be generated
+
+simulation_going = True
+
+# setup side channels and unity environment
+envChannel = EnvChannel.EnvChannel()
+taskChannel = TaskSideChannel.TaskSideChannel()
+env = UnityEnvironment(file_name=None, side_channels=[envChannel, taskChannel])
+
+# set up environment manager
+envManager = EnvironmentManager.EnvironmentManager(envChannel.envData, env, envChannel, taskChannel)
+
+
+while simulation_going:
+    envManager.step()
+
+envManager.close()
diff --git a/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/EnvChannel.py b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/EnvChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..142cf2c27d8f9fa7d090c79496901190bb8bf2f3
--- /dev/null
+++ b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/EnvChannel.py
@@ -0,0 +1,46 @@
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from EnvironmentData import EnvironmentData
+
+"""
+class that processes information from SideChannel EnvChannel: stores all incoming information
+in an instance of class EnvironmentData
+"""
+
+class EnvChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("621f0a70-4f87-11ea-a6bf-784f4387d1f7")) #must coincide with ChannelId set in c#
+        self.envData = EnvironmentData() # object that stores info on environment
+
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        data = msg.read_string()
+        environment_info = json.loads(data)
+
+        self.envData.matrix = environment_info["matrixLayout"]
+        self.envData.rotation = environment_info["rotationRobot"]
+        self.envData.size_of_action = environment_info["sizeOfAction"]
+        self.envData.size_of_observation = environment_info["sizeOfObservation"]
+        self.envData.number_of_robots = environment_info["numberOfRobotsInEnv"]
+        self.envData.number_of_current_tasks = environment_info["numberOfCurrentTasks"]
+        self.envData.can_go_backwards = environment_info["backwards"]
+        self.envData.random_tasks = environment_info["tasksGeneratedRandomly"]
+        self.envData.instance_ids = environment_info["instanceIDSRobots"]
+
+        self.envData.set_initial_nodes_dictionary(environment_info["initialNodesOfRobots"])
+        self.envData.set_tasks_to_be_assigned(environment_info["currentTasks"])
+        self.envData.set_assigned_tasks()
+
+    def send_string(self, data: str) -> None:
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/EnvironmentData.py b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/EnvironmentData.py
new file mode 100644
index 0000000000000000000000000000000000000000..bac66852ffcfdfe8f738b1e24f91b339772fb042
--- /dev/null
+++ b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/EnvironmentData.py
@@ -0,0 +1,82 @@
+"""
+stores data on environment
+instance methods that initialize environment (used by EnvChannel)
+- set_initial_nodes_dictionary(initial_nodes): initializes current_nodes_dictionary
+containing current(next) nodes for each of the robots
+- set_tasks_to_be_assigned(tasks): initialize tasks_to_be_assigned: tasks that have to be assigned
+- set_assigned_tasks(): initialize assigned_tasks_dictionary containing
+ for every robot the current assigned task
+
+instance methods that update environment info
+- assign_task(robot_instanceID, task): assign task to a given robot
+- add_task_to_tasks_to_be_assigned(task): append a new task to tasks_to_be_assigned
+- task_done(instance_id): remove task from robot that was assigned this task
+"""
+
+
+from Node import Node
+from Task import Position, Task
+
+
+class EnvironmentData:
+
+    def __init__(self):
+        self.matrix = None
+        self.rotation = None
+        self.size_of_action = None
+        self.size_of_observation = None
+        self.number_of_robots = None
+        self.number_of_current_tasks = None
+        self.can_go_backwards = None
+        self.random_tasks = None  # if set to true random tasks will be send whenever a task has been completed,
+        # otherwise all tasks self.tasks_to_be_assigned
+
+        self.instance_ids = []
+        self.current_nodes_dictionary = {} # dictionary instance_id -> current node
+        self.tasks_to_be_assigned = [] # tasks that are still to be assigned
+        self.assigned_tasks_dictionary = {} # dictionary instance_id -> assigned task
+
+
+    #########################################
+    ## methods used by EnvChannel to initialize attributes:
+    #########################################
+
+    # given a correct string containing array of nodes
+    def set_initial_nodes_dictionary(self, initial_nodes):
+        for i in range(self.number_of_robots):
+            self.current_nodes_dictionary[self.instance_ids[i]] = Node(initial_nodes[i]["GridPosition"]["Row"],
+                                                      initial_nodes[i]["GridPosition"]["Column"],
+                                                      initial_nodes[i]["Degrees"])
+
+    # given a correct json_string containing array of tasks
+    def set_tasks_to_be_assigned(self, tasks):
+        for i in range(self.number_of_current_tasks):
+            pickup = Position(tasks[i]["PickUp"]["Row"], tasks[i]["PickUp"]["Column"])
+            delivery = Position(tasks[i]["Delivery"]["Row"], tasks[i]["Delivery"]["Column"])
+            self.tasks_to_be_assigned.append(Task(pickup, delivery))
+
+    # initialize dictionary robot instance_id -> task (None)
+    def set_assigned_tasks(self):
+        for i in range(self.number_of_robots):
+            self.assigned_tasks_dictionary[self.instance_ids[i]] = None
+
+    #########################################
+    ## methods used to update environment info
+    #########################################
+
+    # when a task is assigned to a robot, it has to be added to self.assigned_tasks
+    # and removed from self.tasks_to_be_assigned
+    def assign_task(self, robot_instanceID, task):
+        self.assigned_tasks_dictionary[robot_instanceID] = task
+        self.tasks_to_be_assigned.remove(task)
+
+    # when a new task is available it is added to tasks_to_be_assigned
+    # a check is made whether there are still tasks that can be added, but this should not be happening (diagnostical)
+    def add_task_to_tasks_to_be_assigned(self, task):
+        if len(self.tasks_to_be_assigned) == self.number_of_current_tasks:
+            raise Exception("cannot add more tasks")
+        self.tasks_to_be_assigned.append(task)
+
+    # when a robot has finished his task it has to be removed from assigned_tasks
+    def task_done(self, instance_id):
+        self.assigned_tasks_dictionary[instance_id] = None
diff --git a/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/EnvironmentManager.py b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/EnvironmentManager.py
new file mode 100644
index 0000000000000000000000000000000000000000..dab5fa9450b32f7f6029c56449f7c3641ab1ea56
--- /dev/null
+++ b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/EnvironmentManager.py
@@ -0,0 +1,186 @@
+"""'
+Class that contains and manages the information on the environment.
+- Initializes and holds information on the environment (EnvData).
+- Contains a reference to the sidechannel (EnvChannel).
+- Contains a reference to the sidechannel (TaskChannel).
+- Contains a reference to the unity environment (UnityEnv).
+Has instance methods
+- reset() which resets the environment.
+- step() which assigns tasks, computes a new action based on observation from the unity environment
+ and sends actions back to unity, updates info environment when a task has finished
+- close() which closes the environment/
+
+Has also some auxilary instance methods:
+- assign_new_task() which finds a new task and a robot that is free, then calls
+assign_task_to_robot(robot_instanceID, task)
+- compute_path(current_node, task) which computes paths starting in current_node completing a certain task
+- initialize_shortest_paths() which initializes a dictionary containing the paths robots are following
+- assign_task_to_robot(robot_instanceID, task) which assigns task to a robot with given instance ID,
+updates EnvData and sends information on assignment back to Unity
+
+Note that this a toy example. No checks are done on collisions.
+"""
+
+
+import json
+
+from mlagents_envs.base_env import ActionTuple
+
+from Graph import Graph
+from Node import Node
+
+import numpy as np
+
+
+class EnvironmentManager:
+
+    def __init__(self, envData, unityEnv, envChannel, taskChannel):
+        self.envData = envData
+        self.unityEnv = unityEnv
+        self.envChannel = envChannel
+        self.taskChannel = taskChannel
+
+        # IMPORTANT: sends info through envChannel, to be called before setting up connection envData an taskChannel
+        self.reset()
+
+        # taskChannel needs info on envData
+        self.taskChannel.environment_data = envData
+
+        # behavior name for agent
+        self.behavior_name = list(unityEnv.behavior_specs.keys())[0]
+
+        # graph that is used for computing paths
+        self.graph = Graph(envData.matrix, envData.rotation, envData.can_go_backwards)
+
+        # for every robot with instanceID id shortest_paths[id] gives the shortest path to
+        # its currently assigned task
+        self.shortest_paths = {}
+
+        self.initialize_shortest_paths()
+
+    # step in the environment
+    # 1) checks if new tasks can be assigned
+    # 2) collect observations
+    # 3) compute new actions
+    # 4) send actions back to Unity
+    def step(self):
+        self.assign_new_task()
+
+        # get information from the agent that requests an action
+        decision_steps, terminal_steps = self.unityEnv.get_steps(self.behavior_name)
+
+        # decision_steps.obs is a list of numpy arrays, first dimension corresponds to the number of agents that has requested
+        # a decision (here 1), the observation of the agent is the first element
+        observation = decision_steps.obs[0][0]
+
+        print("----------------------------------------")
+
+
+        actions = []  # long list of all actions
+        action_tuple = ActionTuple()  # actions to send to unity
+
+        # get observations per robot and store in dictionary observations[instance_id] -> observation
+        observations = {}
+        for i in range(self.envData.number_of_robots):
+            observation_i = observation[i * self.envData.size_of_observation:
+                                        i * self.envData.size_of_observation + self.envData.size_of_observation]
+            observations[observation_i[0]] = observation_i[1:]
+
+        # create an action for all robots and send at once to unity
+        for robot_id_unity in observations:
+
+            obs = observations[robot_id_unity]
+            print("robot " + str(robot_id_unity) + " at node [(" + str(obs[0]) + "," + str(obs[1]) + ")," + str(
+                obs[2]) + "]")
+
+            path = self.shortest_paths[robot_id_unity]
+            # if path is empty, then robot should stay at same node
+            if len(path) == 0:
+                actions.extend([robot_id_unity, obs[0], obs[1], obs[2], 0, 0])
+            # if path is not empty we get next action from shortest path
+            else:
+                next_action = path[0]  # is node or "pickup" or "deliver"
+                if next_action == "pickup":
+                    actions.extend([robot_id_unity, obs[0], obs[1], obs[2], 1, 0])
+                elif next_action == "deliver":
+                    actions.extend([robot_id_unity, obs[0], obs[1], obs[2], 0, 1])
+                    self.envData.assigned_tasks_dictionary[robot_id_unity] = None
+                else:
+                    actions.extend([robot_id_unity, next_action.x, next_action.y, next_action.g, 0, 0])
+                    # update current node
+                    self.envData.current_nodes_dictionary[robot_id_unity] = Node(next_action.x, next_action.y,
+                                                                                     next_action.g)
+                # update path
+                self.shortest_paths[robot_id_unity] = path[1:]
+
+        # add action to action_tuple and set the actions
+        actions = np.array(actions)
+        actions.resize(1, self.envData.size_of_action * self.envData.number_of_robots)
+        action_tuple.add_discrete(actions)
+
+        self.unityEnv.set_actions(self.behavior_name, action_tuple)
+        self.unityEnv.step() # send actions to unity and wait until a new decision is requested
+
+
+
+
+    # reset the environment
+    def reset(self):
+        self.unityEnv.reset()
+
+    # close the environment
+    def close(self):
+        self.close()
+
+    # assigns the next available task to an idle robot, if possible
+    def assign_new_task(self):
+        # check if there are tasks that have to be assigned
+        # if this is the case, get first task and assign to available robot
+        if len(self.envData.tasks_to_be_assigned) != 0:
+            task = self.envData.tasks_to_be_assigned[0]
+            # get available robot
+            for robot_id in self.envData.instance_ids:
+                if self.envData.assigned_tasks_dictionary[robot_id] is None:
+                     # robot is free: assign task to robot and break out of for loop
+                    self.assign_task_to_robot(robot_id, task)
+                    break
+
+
+    # compute path from current_node that finishes given task
+    # for test purposes pick up and delivery need to have rotation 0
+    # at pick up delivery robot stays at same node
+    # returns a sequence of nodes and pick up/delivery actions
+    def compute_path(self, current_node, task):
+        path1 = self.graph.computeShortestPath(current_node,
+                                          Node(task.PickUp.Row, task.PickUp.Column, 0))
+        path1 = path1[1:]
+        path2 = self.graph.computeShortestPath(Node(task.PickUp.Row, task.PickUp.Column, 0),
+                                          Node(task.Delivery.Row, task.Delivery.Column, 0))
+        path2 = path2[1:]
+
+        return path1 + ["pickup"] + path2 + ["deliver"]
+
+
+    # for every robot initially there is an empty path to be followed
+    def initialize_shortest_paths(self):
+        for robot_id in self.envData.instance_ids:
+            self.shortest_paths[robot_id] = []
+
+    def assign_task_to_robot(self, robot_instanceID, task):
+        # update envData
+        self.envData.assign_task(robot_instanceID, task)
+        # compute path for robot
+        self.shortest_paths[robot_instanceID] = \
+            self.compute_path(self.envData.current_nodes_dictionary[robot_instanceID],task)
+        # send info to unity
+        taskDict = {"Task": {
+                        "PickUp": {"Row": task.PickUp.Row, "Column": task.PickUp.Column},
+                        "Delivery": {"Row": task.Delivery.Row, "Column": task.Delivery.Column}},
+                    "InstanceID": robot_instanceID}
+        self.taskChannel.send_string(json.dumps(taskDict))
+
+
+
+
+
+
diff --git a/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Graph.py b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Graph.py
new file mode 100644
index 0000000000000000000000000000000000000000..c877def1fe99a2f5d82697167084c1a40dd0a30e
--- /dev/null
+++ b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Graph.py
@@ -0,0 +1,110 @@
+from networkx import DiGraph, shortest_path
+from Node import Node
+
+"""
+Class Graph creates a graph based on matrix, deviation (unit of rotation) and whether robots can move backwards).
+Its nodes contain position in the grid and orientation wrt north (see class <c>Node</c>).
+Networkx package as underlying data structure.
+"""
+
+class Graph:
+    def __init__(self, matrix, deviation, cangobackwards):
+        self.matrix = matrix
+        self.number_of_rows = len(matrix)
+        self.number_of_columns = len(matrix[0])
+        self.deviation = deviation
+        self.cangobackwards = cangobackwards
+        self.graph = DiGraph()
+
+        for i in range(self.number_of_rows):
+            for j in range(self.number_of_columns):
+                # we have to add nodes to the graph when we encounter a number different than 1
+                if matrix[i][j] != 1:
+                    self.addEdgesByRotation(i, j)
+                    self.addEdgesByMovingForward(i,j)
+
+    def addEdgesByRotation(self, row, column):
+        degree = 0
+        while degree < 360:
+            newnode = Node(row, column, degree)
+
+            # add all edges from newnode staying at the same position (row, number), i.e. rotation
+
+            # rotate left
+            rotateLeftNode = Node(row, column, get_degree_in_range_0_360(degree - self.deviation))
+            self.graph.add_edge(newnode, rotateLeftNode)
+
+            # rotate right
+            rotateRightNode = Node(row, column, get_degree_in_range_0_360(degree + self.deviation))
+            self.graph.add_edge(newnode, rotateRightNode)
+
+            degree += self.deviation
+
+    def addEdgesByMovingForward(self, row, column):
+        # check left
+        if column > 0 and self.matrix[row][column-1] != 1:
+            # we can move forward if we have degree 270
+            currentnode = Node(row, column, 270)
+            neighbourleft = Node(row, column-1, 270)
+            self.graph.add_edge(currentnode, neighbourleft)
+            # we can move backward if we have degree 90
+            if self.cangobackwards:
+                currentnode = Node(row, column, 90)
+                neighbourleft = Node(row, column-1, 90)
+                self.graph.add_edge(currentnode, neighbourleft)
+
+        # check right
+        if column < self.number_of_columns -1 and self.matrix[row][column+1] != 1:
+            # we can move forward if we have degree 90
+            currentnode = Node(row, column, 90)
+            neighbourright = Node(row, column+1, 90)
+            self.graph.add_edge(currentnode, neighbourright)
+            # we can move backward if we have degree 270
+            if self.cangobackwards:
+                currentnode = Node(row, column, 270)
+                neighbourright = Node(row, column+1, 270)
+                self.graph.add_edge(currentnode, neighbourright)
+
+        # check up
+        if row > 0 and self.matrix[row-1][column] != 1:
+            # we can move forward if we have degree 0
+            currentnode = Node(row, column, 0)
+            neighbourup = Node(row-1, column, 0)
+            self.graph.add_edge(currentnode, neighbourup)
+            # we can move backward if we have degree 180
+            if self.cangobackwards:
+                currentnode = Node(row, column, 180)
+                neighbourup = Node(row-1, column, 180)
+                self.graph.add_edge(currentnode, neighbourup)
+
+        # check down
+        if row < self.number_of_rows-1 and self.matrix[row+1][column] != 1:
+            # we can move forward if we have degree 180
+            currentnode = Node(row, column, 180)
+            neighbourdown = Node(row+1, column, 180)
+            self.graph.add_edge(currentnode, neighbourdown)
+            # we can move backward if we have degree 0
+            if self.cangobackwards:
+                currentnode = Node(row, column, 0)
+                neighbourdown = Node(row+1, column, 0)
+                self.graph.add_edge(currentnode, neighbourdown)
+
+    def computeShortestPath(self, start_node, end_node):
+        #compute shortest path from start_node to end_node: return a list
+        return shortest_path(self.graph, start_node, end_node)
+
+def get_degree_in_range_0_360(degree):
+    rest = degree % 360
+    if rest < 0:
+        return rest + 360
+    return rest
+
+
+
+
+
+
+
+
+
+
diff --git a/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Node.py b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Node.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7dc823be7e503837647d38290413521b04c1512
--- /dev/null
+++ b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Node.py
@@ -0,0 +1,41 @@
+"""
+Class Node represent nodes in the graph. Every node contains a
+position (x,y) in the grid
+and a rotation in degree where
+0 = North
+90 = East
+280 = South
+270 = West
+all degrees must be between 0 and 360
+
+attributes are set to private such that they cannot be overwritten and there is no problem with the hash
+"""
+
+class Node:
+    def __init__(self,x,y,g):
+        self._x = x
+        self._y = y
+        self._g = g
+
+    @property
+    def x(self):
+        return self._x
+
+    @property
+    def y(self):
+        return self._y
+
+    @property
+    def g(self):
+        return self._g
+
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.x == other.x and self.y == other.y and self.g == other.g
+
+
+    def __hash__(self):
+        return (((self.x * 397) ** self.y) * 397) **self.g
+
+    def __str__(self):
+        return "[(" + str(self.x) + ", " + str(self.y) + ")" + "," + str(self.g) + "]"
diff --git a/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Pipfile b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Pipfile
new file mode 100644
index 0000000000000000000000000000000000000000..2cf8108a7836978e89ef3320e61b72d3c4eb3be6
--- /dev/null
+++ b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Pipfile
@@ -0,0 +1,14 @@
+[[source]]
+url = "https://pypi.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+networkx = "==2.5"
+mlagents = "==0.23.0"
+mlagents-envs = "==0.23.0"
+
+[dev-packages]
+
+[requires]
+python_version = "3.6"
diff --git a/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Task.py b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Task.py
new file mode 100644
index 0000000000000000000000000000000000000000..286d0d8254452110b0f491296120de590b9a642c
--- /dev/null
+++ b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/Task.py
@@ -0,0 +1,31 @@
+"""
+Class Task represents tasks which consist of 2 positions: a pickup and a delivery position.
+"""
+class Task:
+    def __init__(self, pos1, pos2):
+        self.PickUp = pos1
+        self.Delivery = pos2
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.PickUp == other.PickUp and self.Delivery == other.Delivery
+
+    def __hash__(self):
+        return ((hash(self.PickUp) * 397) ** hash(self.Delivery)) * 397
+
+    def __str__(self):
+        return "[" + str(self.PickUp) + ", " + str(self.Delivery) + "]"
+
+
+class Position:
+    def __init__(self, x, y):
+        self.Row = x
+        self.Column = y
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.Row == other.Row and self.Column == other.Column
+
+    def __hash__(self):
+        return ((self.Row * 397) ** self.Column) * 397
+
+    def __str__(self):
+        return "(" + str(self.Row) + ", " + str(self.Column) + ")"
diff --git a/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/TaskSideChannel.py b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/TaskSideChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..a541d459d56aec589f8e20b09cd7f5485b92dcd4
--- /dev/null
+++ b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/TaskSideChannel.py
@@ -0,0 +1,41 @@
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from Task import Task, Position
+
+"""
+Class that processes info from the TaskSideChannel.
+- receives new tasks that have to assigned to robots
+- sends assignment of tasks to robots
+"""
+
+
+class TaskSideChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("c11ab982-82b8-4194-b387-3bd0fe9ebdc7")) #must coincide with ChannelId set in c#
+        self.environment_data = None #info on the environment
+
+    # channel receives new tasks that have to be assigned
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        data = msg.read_string()
+        new_task = json.loads(data)
+        new_task = new_task["task"]
+        task_to_add = Task(Position(new_task["PickUp"]["Row"], new_task["PickUp"]["Column"]),
+                           Position(new_task["Delivery"]["Row"], new_task["Delivery"]["Column"]))
+        # add task to tasks to be assigned
+        self.environment_data.add_task_to_tasks_to_be_assigned(task_to_add)
+
+    # channel sends information when a task has been assigned (to which robot)
+    def send_string(self, data: str) -> None:
+
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/main.py b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..3768c19ce07c27f85c2ab1aad60ff2c707e0dfce
--- /dev/null
+++ b/Algorithms/Online_Centralized/Algorithm_test_toyexample_online_centralized/main.py
@@ -0,0 +1,28 @@
+"""
+Main file that controls and decision making
+This is a toy example!
+Uses EnvironmentManager who assigns tasks in order to available agents
+and then computes shortest paths, no check on collisions.
+"""
+
+from mlagents_envs.environment import UnityEnvironment
+import EnvChannel, TaskSideChannel
+import EnvironmentManager
+
+# as long as simulation_going is true, new actions will be generated
+
+simulation_going = True
+
+# setup side channels and unity environment
+envChannel = EnvChannel.EnvChannel()
+taskChannel = TaskSideChannel.TaskSideChannel()
+env = UnityEnvironment(file_name=None, side_channels=[envChannel, taskChannel])
+
+# set up environment manager
+envManager = EnvironmentManager.EnvironmentManager(envChannel.envData, env, envChannel, taskChannel)
+
+
+while simulation_going:
+    envManager.step()
+
+envManager.close()
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/EnvChannel.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/EnvChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..89909eccb160d3bebb15087e72541ddbdd4ce2fd
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/EnvChannel.py
@@ -0,0 +1,45 @@
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from EnvironmentData import EnvironmentData
+
+"""
+class that processes information from SideChannel EnvChannel
+"""
+
+class EnvChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("621f0a70-4f87-11ea-a6bf-784f4387d1f7")) #must coincide with ChannelId set in c#
+        self.EnvData = EnvironmentData() # object that stores info on environment
+
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        data = msg.read_string()
+        environment_info = json.loads(data)
+
+        self.EnvData.matrix = environment_info["matrixLayout"]
+        self.EnvData.rotation = environment_info["rotationRobot"]
+        self.EnvData.action_size = environment_info["sizeOfAction"]
+        self.EnvData.observation_size = environment_info["sizeOfObservation"]
+        self.EnvData.number_of_robots = environment_info["numberOfRobotsInEnv"]
+        self.EnvData.number_of_current_tasks = environment_info["numberOfCurrentTasks"]
+        self.EnvData.can_go_backwards = environment_info["backwards"]
+        self.EnvData.random_tasks = environment_info["tasksGeneratedRandomly"]
+        self.EnvData.instance_ids = environment_info["instanceIDSRobots"]
+
+        self.EnvData.set_initial_nodes_dictionary(environment_info["initialNodesOfRobots"])
+        self.EnvData.set_tasks_to_be_assigned(environment_info["currentTasks"])
+        self.EnvData.set_assigned_tasks()
+
+    def send_string(self, data: str) -> None:
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/EnvironmentData.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/EnvironmentData.py
new file mode 100644
index 0000000000000000000000000000000000000000..82b6b1b7ee71726bd23a94aedbfea83657c7e988
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/EnvironmentData.py
@@ -0,0 +1,91 @@
+# stores data on environment
+# initialized when initial data is being sent through EnvChannel
+import json
+
+from Node import Node
+from ta_state import Location
+import tp_task
+
+
+class EnvironmentData:
+
+    def __init__(self):
+        self.matrix = None
+        self.rotation = None
+        self.action_size = None
+        self.observation_size = None
+        self.number_of_robots = None
+        self.number_of_current_tasks = None
+        self.can_go_backwards = None
+        self.random_tasks = None  # if set to true random tasks will be send whenever a task has been completed,
+        # otherwise all tasks self.tasks_to_be_assigned
+
+        self.instance_ids = []
+        self.current_nodes_dictionary = {} # dictionary instance_id -> current node
+        self.tasks_to_be_assigned = [] # tasks that are still to be assigned
+        self.assigned_tasks_dictionary = {} # dictionary instance_id -> assigned task
+
+        self.task_side_channel = None
+
+        self.tasksCreated = 0
+
+    #########################################
+    ## methods used by EnvChannel to initialize attributes:
+    #########################################
+
+    # set_initial_nodes_dictionary
+    # set_tasks_to_be_assigned
+    # set_assigned_tasks
+
+    # given a correct string containing array of nodes
+    def set_initial_nodes_dictionary(self, initial_nodes):
+        for i in range(self.number_of_robots):
+            self.current_nodes_dictionary[self.instance_ids[i]] = Node(initial_nodes[i]["GridPosition"]["Row"],
+                                                      initial_nodes[i]["GridPosition"]["Column"],
+                                                      initial_nodes[i]["Degrees"])
+
+    # given a correct json_string containing array of tasks
+    def set_tasks_to_be_assigned(self, tasks):
+
+        for i in range(self.number_of_current_tasks):
+            pickup = Location(tasks[i]["PickUp"]["Column"], tasks[i]["PickUp"]["Row"], 0)
+            delivery = Location(tasks[i]["Delivery"]["Column"], tasks[i]["Delivery"]["Row"], 0)
+            releaseTime = tasks[i]["ReleaseTime"]
+            task = tp_task.Task(tp_task.CURRENT_TASK_ID, pickup, delivery, releaseTime=releaseTime)
+            self.tasks_to_be_assigned.append(task)
+
+            tp_task.CURRENT_TASK_ID += 1
+
+    # initialize dictionary robot instance_id -> task (None)
+    def set_assigned_tasks(self):
+        for i in range(self.number_of_robots):
+            self.assigned_tasks_dictionary[self.instance_ids[i]] = None
+
+    #########################################
+    ## methods used to update environment info
+    #########################################
+
+    # when a task is assigned to a robot, it has to be added to self.assigned_tasks
+    # and removed from self.tasks_to_be_assigned
+    # info has to be sent to unity via the correct channel
+    def assign_task(self, robot_instanceID, task):
+        self.assigned_tasks_dictionary[robot_instanceID] = task
+        # self.tasks_to_be_assigned.remove(task)
+        taskDict = {"Task": {
+                        "PickUp": {"Column": str(task.pickup.col), "Row": str(task.pickup.row)},
+                        "Delivery": {"Column": str(task.delivery.col), "Row": str(task.delivery.row)},
+                        "ReleaseTime": str(task.releaseTime)},
+                    "InstanceID": str(robot_instanceID)}
+
+        self.task_side_channel.send_string(json.dumps(taskDict))
+
+    # when a new task is available it is added to tasks_to_be_assigned
+    # a check is made whether there are still tasks that can be added, but this should not be happening (diagnostical)
+    def add_task_to_tasks_to_be_assigned(self, task):
+        if len(self.tasks_to_be_assigned) == self.number_of_current_tasks:
+            raise Exception("cannot add more tasks")
+        self.tasks_to_be_assigned.append(task)
+
+    # when a robot has finished his task it has to be removed from assigned_tasks
+    def task_done(self, instance_id):
+        self.assigned_tasks_dictionary[instance_id] = None
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/Node.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/Node.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2bb07c8fdf941ab68a8e8c87e8478b6d2e79aba
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/Node.py
@@ -0,0 +1,39 @@
+# Class Node represent nodes in the graph. Every node contains a
+# position (x,y) in the grid
+# and a rotation in degree where
+# 0 = North
+# 90 = East
+# 280 = South
+# 270 = West
+# all degrees must be between 0 and 360
+
+# attributes are set to private such that they cannot be overwritten and there is no problem with the hash
+
+class Node:
+    def __init__(self,x,y,g):
+        self._x = x
+        self._y = y
+        self._g = g
+
+    @property
+    def x(self):
+        return self._x
+
+    @property
+    def y(self):
+        return self._y
+
+    @property
+    def g(self):
+        return self._g
+
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.x == other.x and self.y == other.y and self.g == other.g
+
+
+    def __hash__(self):
+        return (((self.x * 397) ** self.y) * 397) **self.g
+
+    def __str__(self):
+        return "[(" + str(self.x) + ", " + str(self.y) + ")" + "," + str(self.g) + "]"
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/Pipfile b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/Pipfile
new file mode 100644
index 0000000000000000000000000000000000000000..2cf8108a7836978e89ef3320e61b72d3c4eb3be6
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/Pipfile
@@ -0,0 +1,14 @@
+[[source]]
+url = "https://pypi.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+networkx = "==2.5"
+mlagents = "==0.23.0"
+mlagents-envs = "==0.23.0"
+
+[dev-packages]
+
+[requires]
+python_version = "3.6"
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/Readme.md b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/Readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..3c6b638256050c47eaa46819580e4985de7064d6
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/Readme.md
@@ -0,0 +1,52 @@
+# Token Passing (TP)
+
+The Token-Passing (TP) algorithm is a decentralized algorithm for the online variant of the MAPD problem.
+
+In the online variant of the MAPD problem the following is supported:
+- Using randomly generated tasks (randomtasks = True)
+- Using tasks from a taskslist (bv. ../config/tasks.txt)
+    -> When using a taskslist with releaseTimes: releaseTimes are ignored (only used in offline variant)
+- Tested from 1 agent up untill 50 agents (significant lag for larger amount of agents)
+
+## Running the algorithm
+
+1. Install the virtual environment
+    - pipenv install
+2. Run the "decentralized_decisionmaker_shortest_path.py" file
+    - pipenv run python decentralized_decisionmaker_shortest_path.py
+3. Start the game inside the Unity editor
+
+## Working of the algorithm
+
+This implementation is based on the "Lifelong Multi-Agent Path Finding for Online Pickup and Delivery Tasks" paper (https://arxiv.org/pdf/1705.10868.pdf).
+An explanation of the algorithm is available at:
+    - Section 4.1 of the "Lifelong Multi-Agent Path Finding for Online Pickup and Delivery Tasks" paper
+    - Section 2.2.1 of the paper provided in the "paper" directory
+
+General overview of working:
+    - Token contains:
+        * Paths of all agents
+        * Taskset
+        * Assignments of tasks of all agents
+    - In each timestep each agent moves one step following its path in the token
+    - When an agent reaches the end of its path (= free agent) it looks for a task:
+        - Task found: 
+            * Plan path to execute task and update token
+            * Remove the selected task from the task set
+        - No task found: 
+            * Plan path to safe location and update token
+
+## Overview of the provided files
+
+Main file:
+- decentralized_decisionmaker_shortest_path.py: Main file that runs the algorithm
+
+Token Passing:
+- tp_agent.py: Agent that are executing tasks
+- tp_system: System manages the agents and tasks
+- tp_task: Pickup and delivery tasks
+- tp_token: Token that is used for communicating global information between the agents
+
+A-star:
+- ta_astar.py: A-Star algorithm
+- ta_state.py: Contains Location and state classes used for the path planning
\ No newline at end of file
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/TaskSideChannel.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/TaskSideChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f03f1fbc3e78a07d30314469a72777623e13e7f
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/TaskSideChannel.py
@@ -0,0 +1,39 @@
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+import tp_task
+from ta_state import Location
+
+
+class TaskSideChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("c11ab982-82b8-4194-b387-3bd0fe9ebdc7")) #must coincide with ChannelId set in c#
+        self.environment_data = None #info on the environment
+
+    # channel receives new tasks that have to be assigned
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        data = msg.read_string()
+        new_task = json.loads(data)
+        new_task = new_task["task"]
+        task_to_add = tp_task.Task(tp_task.CURRENT_TASK_ID,
+                           Location(new_task["PickUp"]["Column"], new_task["PickUp"]["Row"], 0),
+                           Location(new_task["Delivery"]["Column"], new_task["Delivery"]["Row"], 0),
+                                   new_task["ReleaseTime"])
+        tp_task.CURRENT_TASK_ID += 1
+        # add task to task to be assigned
+        self.environment_data.add_task_to_tasks_to_be_assigned(task_to_add)
+
+    # channel sends information when a task has been assigned (to which robot)
+    def send_string(self, data: str) -> None:
+
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/decentralized_decisionmaker_shortest_path.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/decentralized_decisionmaker_shortest_path.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc5f1b5513a0f597bd3a231eb5629d0944afe9df
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/decentralized_decisionmaker_shortest_path.py
@@ -0,0 +1,163 @@
+##------------------##
+## Python libraries ##
+##------------------##
+
+import sys
+import numpy as np
+
+##-----------##
+## ML-agents ##
+##-----------##
+
+from mlagents_envs.environment import ActionTuple, UnityEnvironment
+import EnvChannel
+import TaskSideChannel
+from Node import Node
+
+##----##
+## TP ##
+##----##
+
+from tp_system import System as TP_System
+from ta_state import Location
+from tp_task import Task
+
+
+
+simulation_going = True
+
+# Load the side channels and Unity environment.
+envChannel = EnvChannel.EnvChannel()
+taskChannel = TaskSideChannel.TaskSideChannel()
+env = UnityEnvironment(file_name=None, side_channels=[envChannel, taskChannel])  # Open unity and press play to execute
+env.reset() # reset the environment and get info about environment through envChannel
+
+# Specify the used behaviour name for steering the agent
+behavior_names = list(env.behavior_specs.keys())
+behavior_name = behavior_names[0]
+
+# info obtained from environment
+environment_info = envChannel.EnvData
+# set up links between task side channel and environment info
+environment_info.task_side_channel = taskChannel
+taskChannel.environment_data = environment_info
+
+# Retrieve information from environment
+matrix = environment_info.matrix
+number_of_robots = environment_info.number_of_robots
+rotation = environment_info.rotation
+observation_size = environment_info.observation_size
+action_size = environment_info.action_size
+robot_can_go_backwards = environment_info.can_go_backwards
+
+# Initialize system
+system = TP_System(matrix, rotation)
+
+# Callback called when an agent assigns itself a task
+def on_task_assigned(agent_id, task_id):
+    environment_info.assign_task(agent_id, system.get_task(task_id))
+
+##----------------##
+## Robot Creation ##
+##----------------##
+
+# Number of agents in the configuration file
+n_agents = len(environment_info.instance_ids)
+
+# Create all the agents 
+for robot_id, start_node in environment_info.current_nodes_dictionary.items():
+    # Convert the Node that represents the agent's location to a Location
+    robot_position = Location(start_node.y, start_node.x, start_node.g)
+    # Create agent    
+    system.add_agent(robot_id, robot_position, on_task_assigned)
+
+# Each agent requests 1 action in each timestep
+# next timestep starts when all agents have requested an action in this timestep
+actions_requested_in_timestep = 0
+# Keep track of current timestep
+timestep = 0
+
+while simulation_going:
+    # If there are new tasks that need to be assigned add them to the task set
+    if len(environment_info.tasks_to_be_assigned) != 0:
+        for task in environment_info.tasks_to_be_assigned:
+            # Add task to task set
+            system.add_task(task)
+            # Task is already in task set, remove it from this list to avoid duplicates in task set
+            environment_info.tasks_to_be_assigned.remove(task)
+
+    # Get information on the agents that request an action
+    decision_steps, terminal_steps = env.get_steps(behavior_name)
+    agents = decision_steps.agent_id
+    observations = decision_steps.obs
+
+    # Actions that will be sent back to Unity
+    actions = []
+    action_tuple = ActionTuple()  # actions to send to unity
+
+    # Create an action for all agents that request an action
+    for i in range(len(agents)):
+        
+        ##--------------##
+        ## OBSERVATIONS ##
+        ##--------------## 
+
+        # Keep track of how many agents have requested an action in this timestep
+        actions_requested_in_timestep += 1
+        
+        # Collect agent's observations        
+        observation = observations[0][i]
+        # Extract observations
+        robot_id_unity = observation[0] # robot id in unity used to get correct precomputed path
+        robot_pos_x = observation[2]
+        robot_pos_y = observation[1]
+        robot_rot = observation[3]
+        # Convert coordinates to the agent's current position
+        robot_position = Location(robot_pos_x, robot_pos_y, robot_rot)
+
+        # Get Python Agent that represents robot
+        robot = system.get_agent(int(robot_id_unity))
+
+        ##-------------##
+        ## FOLLOW PATH ##
+        ##-------------##
+
+        # Follow previously computed path or plan new path when at the end of path
+        next_position = robot.move(system.token, timestep)
+        # Convert Location to Node
+        next_action = Node(next_position.row, next_position.col, next_position.rotation)
+        # Check if a task needs to be picked up / delivered
+        pickup_action = 0
+        delivery_action = 0
+        if next_position.to_pickup:
+            # Agent has to pick up his task
+            pickup_action = 1
+        elif next_position.to_deliver:
+            # Agent has to deliver his task
+            delivery_action = 1
+            # Agent has no task assigned anymore as the task is delivered
+            system.token.assignments[robot_id_unity] = None
+
+        # Send action to agent in Unity
+        actions.extend([next_action.x, next_action.y, next_action.g, pickup_action, delivery_action])              
+
+    # When all agents have moved in this timestep update the timestep
+    if (actions_requested_in_timestep == n_agents):
+        # Update the timestep
+        timestep += 1
+        # Reset the number of agents that have requested a timestep in this timestep
+        actions_requested_in_timestep = 0
+    
+    # Send actions to Unity
+    actions = np.array(actions)
+    actions.resize(len(agents), action_size)
+    action_tuple.add_discrete(actions)
+
+    env.set_actions(behavior_name, action_tuple)
+    env.step()
+
+
+
+
+
+
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/paper/Bachelorthesis.pdf b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/paper/Bachelorthesis.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..e9bf4fce9fccb3903a7f502782e4292f8c59e23d
Binary files /dev/null and b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/paper/Bachelorthesis.pdf differ
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/ta_astar.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/ta_astar.py
new file mode 100644
index 0000000000000000000000000000000000000000..975ff6a58ab1b48d69e3704354ce14919b0c315e
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/ta_astar.py
@@ -0,0 +1,164 @@
+"""
+Created on Wed Apr 22 07:43:03 2020
+
+@author: Pieter Cawood
+
+"""
+from heapq import *
+from ta_state import *
+
+def get_heuristic(start_location, goal_location, rotation):
+    # Admissible heuristic - manhattan distance
+    return abs(start_location.col - goal_location.col) + abs(start_location.row - goal_location.row)
+
+class AStar:
+    def __init__(self, world, rotation):
+        self.rotation = rotation
+        self.world = world
+        self.dim_x = len(world[0])
+        self.dim_y = len(world)
+        self.obstacles = {}
+        self.path_ends = dict()
+        self.other_agent_paths = []
+
+    def state_possible(self, current_state, new_state):
+        # Check if wall
+        not_obstacle = False
+        if new_state.location not in self.obstacles:
+            not_obstacle = True
+        # Check if location is in dimensions of grid and does not collide with another location/wall
+        return 0 <= new_state.location.col < self.dim_x and 0 <= new_state.location.row < self.dim_y \
+               and not_obstacle and not self.is_collision(current_state, new_state)
+
+    def is_collision(self, current_state, new_state):
+        for other_agent_path in self.other_agent_paths:
+            # Vertex collision
+            if new_state.time in other_agent_path:
+                if other_agent_path[new_state.time].row == new_state.location.row and other_agent_path[new_state.time].col == new_state.location.col:
+                    return True
+            # Edge collision
+            if new_state.time in other_agent_path and current_state.time in other_agent_path:
+                if other_agent_path[new_state.time].row == current_state.location.row and \
+                    other_agent_path[new_state.time].col == current_state.location.col and \
+                        other_agent_path[current_state.time].row == new_state.location.row and \
+                            other_agent_path[current_state.time].col == new_state.location.col:
+                    return True
+            # Last position of agent is his parking location
+            if new_state.location in self.path_ends:
+                busy_time = self.path_ends[new_state.location]
+                if new_state.time >= busy_time:
+                    return True
+        return False
+
+    def get_neighbours(self, current_state):
+        neighbours = []
+        neighbour_time_step = current_state.time + 1
+        # Wait in state
+        new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row, current_state.location.rotation))
+        if self.state_possible(current_state, new_state):
+            neighbours.append(new_state)
+        # Add rotation
+        new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row, (current_state.location.rotation+self.rotation) % 360))
+        if self.state_possible(current_state, new_state):
+            neighbours.append(new_state)
+        # Remove rotation
+        new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row, (current_state.location.rotation-self.rotation) % 360))
+        if self.state_possible(current_state, new_state):
+            neighbours.append(new_state)
+        if current_state.location.rotation == 0:
+            # Move down
+            new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row - 1, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)
+        elif current_state.location.rotation == 90:
+            # Move right
+            new_state = State(neighbour_time_step, Location(current_state.location.col + 1, current_state.location.row, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)
+        elif current_state.location.rotation == 180:
+            # Move up
+            new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row + 1, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)
+        elif current_state.location.rotation == 270:
+            # Move left
+            new_state = State(neighbour_time_step, Location(current_state.location.col - 1, current_state.location.row, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)       
+        return neighbours
+
+    def create_obstacles(self, other_agent_paths):
+        n_rotations = int(360/self.rotation)
+        # Keep track of all walls in the environment
+        for y in range(self.dim_y):
+            for x in range(self.dim_x):
+                # 1 represent a wall in the environment
+                if self.world[y][x] == 1:
+                    # A wall is always a collision, no matter the rotation
+                    for i in range(n_rotations):
+                        rot = i * self.rotation
+                        self.obstacles[Location(x, y, rot)] = True
+        # Keep track of where the paths of the other agents end
+        self.path_ends = dict()
+        for path in other_agent_paths:
+            # Get the last timestep in the path of the agent
+            last_time = list(path)[-1]
+            # Get the last location in the path of the agent
+            last_pos = path[last_time]
+            # Two agents always collide when they share the same location, no matter the rotation
+            for i in range(n_rotations):
+                rot = i * self.rotation
+                self.path_ends[Location(last_pos.col, last_pos.row, rot)] = last_time
+        # Keep track of the other paths of agents to detect collisions
+        self.other_agent_paths = other_agent_paths
+
+    # Returns the latest timestep at which a specific location will be used
+    def find_lastest_use(self, location):
+        # Keep track of all the uses of that location
+        uses = []
+        # Check in the path of each agent if that agent uses that location, if yes, add it to the list
+        for agent_path in self.other_agent_paths:
+            for t, loc in agent_path.items():
+                if loc.col == location.col and loc.row == location.row:
+                    uses.append(t)
+        # If the location is used at least once, return the maximum
+        if uses:
+            return max(uses)
+        # If the location is never used, return 0
+        else:
+            return 0
+        
+
+    def search(self, time_step, start_location, goal_location, other_agent_paths,
+               release_time=0, find_step = 0):
+        self.create_obstacles(other_agent_paths)
+        initial_state = State(time_step, start_location)
+        # Find the lastest use of the goal location to avoid parking on a location that is still going to be used
+        lastest_use = self.find_lastest_use(goal_location)
+        came_from = {}
+        open_list = [initial_state]
+        closed_set = set()
+        initial_state.g_score = 0
+        initial_state.f_score = get_heuristic(start_location, goal_location, self.rotation)
+        while open_list:
+            current = heappop(open_list)
+            if current.location == goal_location:
+                if current in came_from and came_from[current].location == goal_location:
+                    if current.time > lastest_use:
+                        new_path = [current]
+                        while current in came_from:
+                            current = came_from[current]
+                            new_path.append(current)
+                        # Reverse path
+                        return new_path[::-1]
+            closed_set |= {current}
+            neighbours = self.get_neighbours(current)
+            neighbour: State
+            for neighbour in neighbours:
+                # Only explore new states
+                if (neighbour not in closed_set) and (neighbour not in open_list):
+                    came_from[neighbour] = current
+                    neighbour.g = current.g + 1
+                    neighbour.f = neighbour.g + get_heuristic(neighbour.location, goal_location, self.rotation)
+                    heappush(open_list, neighbour)
+        return False
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/ta_state.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/ta_state.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6269547d945284d4fcff1503617d8a2e44b8ff4
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/ta_state.py
@@ -0,0 +1,60 @@
+"""
+Created on Sat Apr 18 10:45:11 2020
+
+@author: Pieter Cawood
+
+"""
+
+def h(pos1, pos2):
+    return abs(pos1.col - pos2.col) + abs(pos1.row - pos2.row)
+
+class Location(object):
+    def __init__(self, col, row, rotation):
+        self.col = col
+        self.row = row
+        self.rotation = rotation
+
+        # Relevant information for pickup and delivery actions
+        self.task_id = None
+        self.to_pickup = False
+        self.to_deliver = False
+
+    def __eq__(self, other):
+        return self.col == other.col and self.row == other.row and self.rotation == other.rotation
+
+    def __hash__(self):
+        return hash(str(self.col) + "_" + str(self.row) + "_" + str(self.rotation))
+
+    def __str__(self):
+        return str((self.col, self.row, self.rotation, self.to_pickup, self.to_deliver))
+
+    # Better information for debugging
+    def __repr__(self):
+        return f"Location({self.col}, {self.row}, {self.rotation}, {self.to_pickup}, {self.to_deliver})"
+
+
+class State(object):
+    def __init__(self, time, location):
+        self.time = time
+        self.location = location
+        self.g = 0
+        self.f = 0
+
+    def __eq__(self, other):
+        return self.time == other.time and self.location == other.location
+
+    def __hash__(self):
+        return hash(str(self.time) + str(self.location.col) + str(self.location.row))
+
+    def __str__(self):
+        return str((self.time, self.location.col, self.location.row))
+
+    def __lt__(self, other):
+        if self.f < other.f:
+            return True
+        else:
+            return False
+
+    # Better information for debugging
+    def __repr__(self):
+        return f"State(Time: {self.time}, Location(x: {self.location.col}, y: {self.location.row}, r: {self.location.rotation}))"
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_agent.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..092eb890db6d8d7decf3c9f8bf046c5cc60dcc09
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_agent.py
@@ -0,0 +1,161 @@
+# Python modules
+import sys
+import numpy as np
+# Pathfinding modules
+from ta_astar import AStar
+from ta_state import Location, h
+
+
+class Agent:
+    def __init__(self, id, initialLocation, system, environment, rotation, on_task_assigned):
+        self.id = id
+        # Position
+        self.pos = initialLocation
+        # Plan paths
+        self.a_star = AStar(environment, rotation)
+        # Used to request token when looking for a task
+        self.system = system
+
+        self.on_task_assigned = on_task_assigned
+
+    def look_for_task(self, token, timestep):
+        availableTasks = [] # List of all the tasks that are available to the agent
+
+        ##-- Check if pickup/delivery is not end of path of any other agent --##
+        # Get last locations of all paths in token
+        pathEnds = token.get_pathends(self.id)
+        # If pickup/delivery is not in pathEnds it's an available task
+        for t in token.taskSet:
+            if t.pickup not in pathEnds and t.delivery not in pathEnds:
+                availableTasks.append(t)
+        # If there is no available task plan a path to a location where the agent can wait
+        if len(availableTasks) == 0:
+            self.path2(token, timestep)
+        # There is at least one task the agent can execute
+        else:
+            # Find the "best" task (best = minimum h-value)
+            h_scores = np.array(map(lambda t: h(self.pos, t.pickup), availableTasks))
+            min_task = availableTasks[np.argmin(h_scores)]
+            # Plan path for that task
+            self.path1(token, min_task, timestep)
+        
+
+    def path1(self, token, task, timestep):
+        """[summary]
+        Args:
+            token (Token): The global token provided by the system
+            task (Task): The task for which a path needs to be planned
+            timestep (int): Current timestep
+        """
+
+        # All needed locations for the pathplanning
+        current_location = Location(self.pos.col, self.pos.row, self.pos.rotation) 
+        pickup_location = Location(task.pickup.col, task.pickup.row, task.pickup.rotation)
+        delivery_location = Location(task.delivery.col, task.delivery.row, task.delivery.rotation)
+        
+        ##----------------##
+        ## Path to pickup ##
+        ##----------------##
+
+        # Get the paths of all the other agents
+        other_agent_paths = token.get_other_agents_paths(timestep, self.id)
+        # Plan a path from the current location of the agent to the pickup location of the task
+        pickup_path = self.a_star.search(timestep, current_location, pickup_location, other_agent_paths)
+        # There should always be a path if the problem is well formed
+        if not pickup_path:
+            raise ValueError("[TP] No path to pickup location - Problem not well formed")
+        # Add newly planned path to the agent's path in the token
+        for state in pickup_path:
+            token.paths[self.id][state.time] = state.location
+        old_timestep = timestep
+
+        # Update the timestep to the timestep at the end of the planned path 
+        timestep = timestep + len(pickup_path) - 1
+
+        timestep_at_pickup = timestep
+
+        ##------------------##
+        ## Path to delivery ##
+        ##------------------##
+
+        # Get the paths of all the other agents
+        other_agent_paths = token.get_other_agents_paths(timestep, self.id)
+        # Plan a path from the pickup location of the task to the delivery location of the task
+        delivery_path = self.a_star.search(timestep, pickup_location, delivery_location, other_agent_paths)
+        # There should always be a path if the problem is well formed
+        if not delivery_path:
+            raise ValueError("[TP] No path to delivery location - Problem not well formed")
+        # Add newly planned path to the agent's path in the token
+        for state in delivery_path:
+            token.paths[self.id][state.time] = state.location
+
+        timestep = timestep + len(delivery_path) - 1
+
+        ##---------------------------##
+        ## Pickup / Delivery actions ##
+        ##---------------------------##
+
+        # Register in the last location of the path to the pickup location that the agent needs to pickup a task and register the task ID
+        token.paths[self.id][timestep_at_pickup].to_pickup = True
+        token.paths[self.id][timestep_at_pickup].task_id = task.id
+
+        # Register in the last location of the path to the delivery location that the agent needs to pickup a task and register the task ID
+        token.paths[self.id][timestep].to_deliver = True
+        token.paths[self.id][timestep].task_id = task.id
+
+        # Assign task to agent
+        token.assignments[self.id] = task.id
+        # Remove the task from the taskset
+        token.taskSet.remove(task)
+
+    def path2(self, token, timestep):
+        ##-- Check if current location is not delivery location of any task in taskSet --##
+        # Indicates whether agent needs to move
+        needToMove = False
+        for t in token.taskSet:
+            # If the agent is parked on the delivery location of a task he needs to move 
+            if t.delivery == self.pos:
+                needToMove = True
+        if not needToMove:
+            # Agent doesn't need to move, update the path with a trivial path to current position
+            token.paths[self.id][timestep] = Location(self.pos.col, self.pos.row, self.pos.rotation)
+        else:
+            ##-- Find a free endpoint to move to --##
+            endpoints = self.system.get_free_endpoints()
+            # Select the best endpoint (best = smallest h-score)
+            h_scores = list(map(lambda e: h(self.pos, e), endpoints))
+            chosen_endpoint = endpoints[np.argmin(h_scores)]
+
+            ##-- Plan path to free endpoint --##
+            # Make sure planned path doesn't collide with already planned paths
+            current_location = Location(self.pos.col, self.pos.row, self.pos.rotation) 
+            endpoint_location = Location(chosen_endpoint.col, chosen_endpoint.row, chosen_endpoint.rotation)
+            # Get the paths of all the other agents
+            other_agent_paths = token.get_other_agents_paths(timestep, self.id)
+            # Plan a path from the agent's current location to the chosen endpoint
+            path_to_endpoint = self.a_star.search(timestep, current_location, endpoint_location, other_agent_paths)
+            # There should always be a path if the problem is well formed
+            if not path_to_endpoint:
+                raise ValueError("[TP] No path to chosen endpoint - Problem not well formed")
+            # Add newly planned path to the agent's path in the token
+            for state in path_to_endpoint:
+                token.paths[self.id][state.time] = state.location
+
+    def move(self, token, timestep):
+        # Get the current path of the agent
+        path = token.paths[self.id]
+        # Check if the agent has already planned a move for this timestep
+        if timestep not in path:
+            # If agent has not yet planned a move for this timestep it requests the token and looks for a task
+            # Start looking for a new task
+            self.look_for_task(token, timestep)
+            # Check if the agent has assigned a task to itself and notify Unity if that is the case (using callback)
+            if token.assignments[self.id] is not None:
+                self.on_task_assigned(self.id, token.assignments[self.id])
+
+        # Select the move of the agent in this timestep
+        next_move = token.paths[self.id][timestep]
+        # Update the agent's position
+        self.pos = next_move
+        # Return the agent's next position            
+        return next_move
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_system.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_system.py
new file mode 100644
index 0000000000000000000000000000000000000000..121ce15369f3709c23c5101f0b56231b78fd3334
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_system.py
@@ -0,0 +1,104 @@
+# Python modules
+import sys
+import numpy as np
+# Pathfinding modules
+from ta_state import Location
+# Own modules
+from tp_agent import Agent
+from tp_token import Token
+
+# System manages the token
+class System:
+    def __init__(self, env, rotation):
+        # Keep track of the warehouse setup
+        self.environment = env
+        # Keep track of rotation
+        self.rotation = rotation
+
+        # Keep track of all agents in the system
+        self.agents = dict()
+        # Keep track of all tasks
+        self.tasks = dict()
+        # Token setup
+        self.token = Token()
+        # Keep track of all the non-task/task endpoints
+        self.task_endpoints = []
+        self.non_task_endpoints = []
+        # Get all the endpoints from the environment
+        self.init_endpoints()
+
+    # Find all the task and non-task endpoints in the environment
+    def init_endpoints(self):
+        # Get the dimensions of the environment
+        dim_y = len(self.environment)
+        dim_x = len(self.environment[0])
+        for y in range(dim_y):
+            for x in range(dim_x):
+                # Non-task endpoints (parking locations) are represented by 2
+                if self.environment[y][x] == 2:
+                    self.non_task_endpoints.append(Location(x, y, 0))
+                # Task endpoints (pickup/delivery locations) are represented by 3
+                elif self.environment[y][x] == 3:
+                    self.task_endpoints.append(Location(x, y, 0))
+
+    ##---------##
+    ## Getters ##
+    ##---------##
+        
+    def get_agent(self, a_id):
+        return self.agents[a_id]
+    
+    def get_task(self, task_id):
+        return self.tasks[task_id]
+
+    def get_endpoints(self):
+        return np.concatenate((self.non_task_endpoints, self.task_endpoints))
+
+    def get_non_task_endpoints(self):
+        return self.non_task_endpoints
+
+    def get_free_endpoints(self):
+        # List of all the endpoints
+        all_endpoints = self.get_endpoints()
+        free_endpoints = []
+        # Get a list of the last positions of each agent's path
+        endPaths = self.token.get_pathends()
+        # Generate a list of all the delivery locations of the tasks in the taskSet
+        deliveryLocations = []
+        for t in self.token.taskSet:
+            deliveryLocations.append(t.delivery)
+        for e in all_endpoints:
+            # If endpoint is not the end of the path of any agent
+            # or is not the delivery location of any task it's free
+            if e not in endPaths and e not in deliveryLocations:
+                free_endpoints.append(e)
+        return free_endpoints
+
+    ##---------------------##
+    ## Adding new elements ##
+    ##---------------------##
+
+    def add_task(self, task):
+        self.token.add_task(task)
+        self.tasks[task.id] = task
+        return True
+        
+    def add_agent(self, agent_id, agent_pos, on_task_assigned):
+        agent = Agent(agent_id, agent_pos, self, self.environment, self.rotation, on_task_assigned)
+        self.agents[agent_id] = agent
+        self.token.add_agent(agent)
+
+    ##-------------------##
+    ## Utilitary methods ##
+    ##-------------------##
+
+    def request_token(self):
+        return self.token
+
+    def is_endpoint(self, pos):
+        if pos in self.non_task_endpoints or pos in self.task_endpoints:
+            return True
+        else:
+            return False
+        
+
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_task.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_task.py
new file mode 100644
index 0000000000000000000000000000000000000000..105c02eabdb1cc0c4828f5b811455118e4e3bd22
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_task.py
@@ -0,0 +1,43 @@
+CURRENT_TASK_ID = 0
+
+class Task:
+    """ Represents a task in the pickup & delivery problem 
+
+        Attributes:
+        id: int 
+            Identifier of the task
+        pickupLocation: Position 
+            The location where the task needs to be picked up
+        deliveryLocation: Position 
+            The location where the task needs to be delivered
+    """
+    def __init__(self, id, pickupLocation, deliveryLocation, releaseTime=0):
+        self.id = id
+
+        self.pickup = pickupLocation
+        self.delivery = deliveryLocation
+
+        self.releaseTime = releaseTime
+        
+        # Keep track timestep when task enters the taskset and when it's executed => calculating service time
+        self.entered = None
+        self.delivered = None
+
+    def service_time(self):
+        if self.entered is not None and self.delivered is not None:
+            return self.delivered - self.entered
+        else:
+            return None
+
+    def __eq__(self, other):
+        return self.pickup == other.pickup and self.delivery == other.delivery
+
+    def __hash__(self):
+        return ((hash(self.pickup) * 397) ** hash(self.delivery)) * 397
+        
+    # Better information for debugging
+    def __repr__(self):
+        return f"Task({self.id},Pickup({self.pickup}), Delivery({self.delivery}))"
+
+    def __str__(self):
+        return f"Task({self.id},Pickup({self.pickup}), Delivery({self.delivery}))"
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_token.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_token.py
new file mode 100644
index 0000000000000000000000000000000000000000..f804b8d9dbe0dfc553d22065e9d17d8681b9c32a
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing/tp_token.py
@@ -0,0 +1,63 @@
+class Token:
+    def __init__(self):
+        # Keep track of the paths of all the agents
+        self.paths = dict()
+        # Keep track of which agent is executing which task
+        self.assignments = dict()
+        # Keep track of the remaining tasks
+        self.taskSet = []
+
+    ##---------##
+    ## Getters ##
+    ##---------##
+
+    # Returns the last location on the path of each agent
+    def get_pathends(self, given_id=None):
+        pathEnds = []
+        for a_id, k in self.paths.items():
+            if given_id is None or a_id != given_id:
+                pathEnds.append(k[list(k)[-1]])
+        return pathEnds
+
+    # Get the paths of all agents except the path of agent with ID = own_id
+    def get_other_agents_paths(self, timestep, own_id):
+        other_agent_paths = []
+        for a_id, path in self.paths.items():
+            if a_id != own_id:
+                other_agent_paths.append(path)
+        return other_agent_paths
+
+    ##------------------##
+    ## Add new elements ##
+    ##------------------##
+
+    # Adds a new agent to the system
+    def add_agent(self, agent):
+        a_id = agent.id
+        self.paths[a_id] = dict()
+        self.paths[a_id][0] = agent.pos
+        self.assignments[a_id] = None
+        
+    # Adds a new task to the system
+    def add_task(self, task):
+        self.taskSet.append(task)
+        
+    ##-------------------##
+    ## Utilitary methods ##
+    ##-------------------##
+        
+    # Restores the token with an old state of the token        
+    def restore(self, old_token):
+        self.paths = old_token.paths
+        self.assignments = old_token.assignments
+        self.taskSet = old_token.taskSet
+        
+    # Generates a copy of this token
+    def copy(self):
+        new_token = Token()
+        new_token.paths = self.paths
+        new_token.assignments = self.assignments
+        new_token.taskSet = self.taskSet
+        return new_token
+
+    
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/EnvChannel.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/EnvChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..89909eccb160d3bebb15087e72541ddbdd4ce2fd
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/EnvChannel.py
@@ -0,0 +1,45 @@
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from EnvironmentData import EnvironmentData
+
+"""
+class that processes information from SideChannel EnvChannel
+"""
+
+class EnvChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("621f0a70-4f87-11ea-a6bf-784f4387d1f7")) #must coincide with ChannelId set in c#
+        self.EnvData = EnvironmentData() # object that stores info on environment
+
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        data = msg.read_string()
+        environment_info = json.loads(data)
+
+        self.EnvData.matrix = environment_info["matrixLayout"]
+        self.EnvData.rotation = environment_info["rotationRobot"]
+        self.EnvData.action_size = environment_info["sizeOfAction"]
+        self.EnvData.observation_size = environment_info["sizeOfObservation"]
+        self.EnvData.number_of_robots = environment_info["numberOfRobotsInEnv"]
+        self.EnvData.number_of_current_tasks = environment_info["numberOfCurrentTasks"]
+        self.EnvData.can_go_backwards = environment_info["backwards"]
+        self.EnvData.random_tasks = environment_info["tasksGeneratedRandomly"]
+        self.EnvData.instance_ids = environment_info["instanceIDSRobots"]
+
+        self.EnvData.set_initial_nodes_dictionary(environment_info["initialNodesOfRobots"])
+        self.EnvData.set_tasks_to_be_assigned(environment_info["currentTasks"])
+        self.EnvData.set_assigned_tasks()
+
+    def send_string(self, data: str) -> None:
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/EnvironmentData.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/EnvironmentData.py
new file mode 100644
index 0000000000000000000000000000000000000000..ea3e19ffeee3dfbe56ad9e5cddeab3af61bcbfaf
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/EnvironmentData.py
@@ -0,0 +1,86 @@
+# stores data on environment
+# initialized when initial data is being sent through EnvChannel
+import json
+
+from Node import Node
+from ta_state import Location
+import tpts_task
+
+
+class EnvironmentData:
+
+    def __init__(self):
+        self.matrix = None
+        self.rotation = None
+        self.action_size = None
+        self.observation_size = None
+        self.number_of_robots = None
+        self.number_of_current_tasks = None
+        self.can_go_backwards = None
+        self.random_tasks = None  # if set to true random tasks will be send whenever a task has been completed,
+        # otherwise all tasks self.tasks_to_be_assigned
+
+        self.instance_ids = []
+        self.current_nodes_dictionary = {} # dictionary instance_id -> current node
+        self.tasks_to_be_assigned = [] # tasks that are still to be assigned
+        self.assigned_tasks_dictionary = {} # dictionary instance_id -> assigned task
+
+        self.task_side_channel = None
+
+        self.tasksCreated = 0
+
+    #########################################
+    ## methods used by EnvChannel to initialize attributes:
+    #########################################
+
+    # set_initial_nodes_dictionary
+    # set_tasks_to_be_assigned
+    # set_assigned_tasks
+
+    # given a correct string containing array of nodes
+    def set_initial_nodes_dictionary(self, initial_nodes):
+        for i in range(self.number_of_robots):
+            self.current_nodes_dictionary[self.instance_ids[i]] = Node(initial_nodes[i]["GridPosition"]["Row"],
+                                                      initial_nodes[i]["GridPosition"]["Column"],
+                                                      initial_nodes[i]["Degrees"])
+
+    # given a correct json_string containing array of tasks
+    def set_tasks_to_be_assigned(self, tasks):
+        for i in range(self.number_of_current_tasks):
+            pickup = Location(tasks[i]["PickUp"]["Column"], tasks[i]["PickUp"]["Row"], 0)
+            delivery = Location(tasks[i]["Delivery"]["Column"], tasks[i]["Delivery"]["Row"], 0)
+            self.tasks_to_be_assigned.append(tpts_task.Task(tpts_task.CURRENT_TASK_ID, pickup, delivery))
+            tpts_task.CURRENT_TASK_ID += 1
+
+    # initialize dictionary robot instance_id -> task (None)
+    def set_assigned_tasks(self):
+        for i in range(self.number_of_robots):
+            self.assigned_tasks_dictionary[self.instance_ids[i]] = None
+
+    #########################################
+    ## methods used to update environment info
+    #########################################
+
+    # when a task is assigned to a robot, it has to be added to self.assigned_tasks
+    # and removed from self.tasks_to_be_assigned
+    # info has to be sent to unity via the correct channel
+    def assign_task(self, robot_instanceID, task):
+        self.assigned_tasks_dictionary[robot_instanceID] = task
+        # self.tasks_to_be_assigned.remove(task)
+        taskDict = {"Task": {
+                        "PickUp": {"Column": str(task.pickup.col), "Row": str(task.pickup.row)},
+                        "Delivery": {"Column": str(task.delivery.col), "Row": str(task.delivery.row)}},
+                    "InstanceID": str(robot_instanceID)}
+
+        self.task_side_channel.send_string(json.dumps(taskDict))
+
+    # when a new task is available it is added to tasks_to_be_assigned
+    # a check is made whether there are still tasks that can be added, but this should not be happening (diagnostical)
+    def add_task_to_tasks_to_be_assigned(self, task):
+        if len(self.tasks_to_be_assigned) == self.number_of_current_tasks:
+            raise Exception("cannot add more tasks")
+        self.tasks_to_be_assigned.append(task)
+
+    # when a robot has finished his task it has to be removed from assigned_tasks
+    def task_done(self, instance_id):
+        self.assigned_tasks_dictionary[instance_id] = None
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/Node.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/Node.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2bb07c8fdf941ab68a8e8c87e8478b6d2e79aba
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/Node.py
@@ -0,0 +1,39 @@
+# Class Node represent nodes in the graph. Every node contains a
+# position (x,y) in the grid
+# and a rotation in degree where
+# 0 = North
+# 90 = East
+# 280 = South
+# 270 = West
+# all degrees must be between 0 and 360
+
+# attributes are set to private such that they cannot be overwritten and there is no problem with the hash
+
+class Node:
+    def __init__(self,x,y,g):
+        self._x = x
+        self._y = y
+        self._g = g
+
+    @property
+    def x(self):
+        return self._x
+
+    @property
+    def y(self):
+        return self._y
+
+    @property
+    def g(self):
+        return self._g
+
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.x == other.x and self.y == other.y and self.g == other.g
+
+
+    def __hash__(self):
+        return (((self.x * 397) ** self.y) * 397) **self.g
+
+    def __str__(self):
+        return "[(" + str(self.x) + ", " + str(self.y) + ")" + "," + str(self.g) + "]"
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/Pipfile b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/Pipfile
new file mode 100644
index 0000000000000000000000000000000000000000..2cf8108a7836978e89ef3320e61b72d3c4eb3be6
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/Pipfile
@@ -0,0 +1,14 @@
+[[source]]
+url = "https://pypi.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+networkx = "==2.5"
+mlagents = "==0.23.0"
+mlagents-envs = "==0.23.0"
+
+[dev-packages]
+
+[requires]
+python_version = "3.6"
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/Readme.md b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/Readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..d354f1ceb2311e731e56be3a148b0fb0cc535666
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/Readme.md
@@ -0,0 +1,59 @@
+# Token Passing with Task Swaps (TPTS)
+
+The Token-Passing with Task Swaps (TPTS) algorithm is a decentralized algorithm for the online variant of the MAPD problem.
+
+In the online variant of the MAPD problem the following is supported:
+- Using randomly generated tasks (randomtasks = True)
+- Using tasks from a taskslist (bv. ../config/tasks.txt)
+    -> When using a taskslist with releaseTimes: releaseTimes are ignored (only used in offline variant)
+- Tested from 1 agent up untill 50 agents (significant lag for larger amount of agents)
+
+## Running the algorithm
+
+1. Install the virtual environment
+    - pipenv install
+2. Run the "decentralized_decisionmaker_shortest_path.py" file
+    - pipenv run python decentralized_decisionmaker_shortest_path.py
+3. Start the game inside the Unity editor
+
+## Working of the algorithm
+
+This implementation is based on the "Lifelong Multi-Agent Path Finding for Online Pickup and Delivery Tasks" paper (https://arxiv.org/pdf/1705.10868.pdf).
+An explanation of the algorithm is available at:
+    - Section 4.2 of the "Lifelong Multi-Agent Path Finding for Online Pickup and Delivery Tasks" paper
+    - Section 2.2.2 of the paper provided in the "paper" directory
+
+General overview of working:
+    - Token contains:
+        * Paths of all agents
+        * Taskset
+        * Assignments of tasks of all agents
+    - In each timestep each agent moves one step following its path in the token
+        - When an agent reaches the pickup location of its task:
+            * Remove the task from the task set
+    - When an agent reaches the end of its path (= free agent) it looks for a task:
+        - Task found: 
+            * Plan path to execute task and update token
+        - No task found: 
+            * Plan path to safe location and update token
+
+Differece with Token Passing (TP):
+    - Availability tasks in token
+        * In the TP algorithm tasks are removed from the taskset as soon as an agent assigns that task to itself
+        * In the TPTS algorithm tasks are only removed when an agent reaches the pickup location of the task
+        => This allows agents to select tasks that are already assigned to other agents if they can execute the task more efficiently (= task swapping)
+
+## Overview of the provided files
+
+Main file:
+- decentralized_decisionmaker_shortest_path.py: Main file that runs the algorithm
+
+Token Passing with Task Swaps:
+- tpts_agent.py: Agent that are executing tasks
+- tpts_system: System manages the agents and tasks
+- tpts_task: Pickup and delivery tasks
+- tpts_token: Token that is used for communicating global information between the agents
+
+A-star:
+- ta_astar.py: A-Star algorithm
+- ta_state.py: Contains Location and state classes used for the path planning
\ No newline at end of file
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/TaskSideChannel.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/TaskSideChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..5905a60a0e4d906da492398691ce59c60764791a
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/TaskSideChannel.py
@@ -0,0 +1,38 @@
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+import tpts_task
+from ta_state import Location
+
+
+class TaskSideChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("c11ab982-82b8-4194-b387-3bd0fe9ebdc7")) #must coincide with ChannelId set in c#
+        self.environment_data = None #info on the environment
+
+    # channel receives new tasks that have to be assigned
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        data = msg.read_string()
+        new_task = json.loads(data)
+        new_task = new_task["task"]
+        task_to_add = tpts_task.Task(tpts_task.CURRENT_TASK_ID,
+                           Location(new_task["PickUp"]["Column"], new_task["PickUp"]["Row"], 0),
+                           Location(new_task["Delivery"]["Column"], new_task["Delivery"]["Row"], 0))
+        tpts_task.CURRENT_TASK_ID += 1
+        # add task to task to be assigned
+        self.environment_data.add_task_to_tasks_to_be_assigned(task_to_add)
+
+    # channel sends information when a task has been assigned (to which robot)
+    def send_string(self, data: str) -> None:
+
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/decentralized_decisionmaker_shortest_path.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/decentralized_decisionmaker_shortest_path.py
new file mode 100644
index 0000000000000000000000000000000000000000..9dba440c4b19d672bd25c54c07d8c4579d97a82a
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/decentralized_decisionmaker_shortest_path.py
@@ -0,0 +1,165 @@
+##------------------##
+## Python libraries ##
+##------------------##
+
+import sys
+import numpy as np
+
+##-----------##
+## ML-agents ##
+##-----------##
+
+from mlagents_envs.environment import ActionTuple, UnityEnvironment
+import EnvChannel
+import TaskSideChannel
+from Node import Node
+
+##------##
+## TPTS ##
+##------##
+
+from tpts_system import System as TPTS_System
+from ta_state import Location
+import tpts_task
+
+simulation_going = True
+
+# Load the side channels and Unity environment.
+envChannel = EnvChannel.EnvChannel()
+taskChannel = TaskSideChannel.TaskSideChannel()
+env = UnityEnvironment(file_name=None, side_channels=[envChannel, taskChannel])  # Open unity and press play to execute
+env.reset() # reset the environment and get info about environment through envChannel
+
+# Specify the used behaviour name for steering the agent
+behavior_names = list(env.behavior_specs.keys())
+behavior_name = behavior_names[0]
+
+# info obtained from environment
+environment_info = envChannel.EnvData
+# set up links between task side channel and environment info
+environment_info.task_side_channel = taskChannel
+taskChannel.environment_data = environment_info
+
+# Retrieve information from environment
+matrix = environment_info.matrix
+number_of_robots = environment_info.number_of_robots
+rotation = environment_info.rotation
+observation_size = environment_info.observation_size
+action_size = environment_info.action_size
+robot_can_go_backwards = environment_info.can_go_backwards
+
+# Initialize system
+system = TPTS_System(matrix, rotation)
+
+# Callback called when an agent assigns itself a task
+def on_task_assigned(agent_id, task_id):
+    environment_info.assign_task(agent_id, system.get_task(task_id))
+
+##----------------##
+## Robot Creation ##
+##----------------##
+
+# Number of agents in the configuration file
+n_agents = len(environment_info.instance_ids)
+
+# Create all the agents
+for robot_id, start_node in environment_info.current_nodes_dictionary.items():
+    # Convert the Node that represents the agent's location to a Location
+    robot_position = Location(start_node.y, start_node.x, start_node.g)
+    # Create agent    
+    system.add_agent(robot_id, robot_position, on_task_assigned)
+
+# Each agent requests 1 action in each timestep
+# next timestep starts when all agents have requested an action in this timestep
+actions_requested_in_timestep = 0
+# Keep track of current timestep
+timestep = 0
+
+while simulation_going:
+    # If there are new tasks that need to be assigned add them to the task set
+    if len(environment_info.tasks_to_be_assigned) != 0:
+        for task in environment_info.tasks_to_be_assigned:
+            # Add task to task set
+            system.add_task(task)
+            # Task is already in task set, remove it from this list to avoid duplicates in task set
+            environment_info.tasks_to_be_assigned.remove(task)
+
+    # Get information on the agents that request an action
+    decision_steps, terminal_steps = env.get_steps(behavior_name)
+    agents = decision_steps.agent_id
+    observations = decision_steps.obs
+
+    # Actions that will be sent back to Unity
+    actions = []
+    action_tuple = ActionTuple()  # actions to send to unity
+ 
+    # Create an action for all agents that request an action
+    for i in range(len(agents)):
+        
+        ##--------------##
+        ## OBSERVATIONS ##
+        ##--------------## 
+
+        # Keep track of how many agents have requested an action in this timestep
+        actions_requested_in_timestep += 1
+        
+        # Collect agent's observations        
+        observation = observations[0][i]
+        # Extract observations
+        robot_id_unity = observation[0] # robot id in unity used to get correct precomputed path
+        robot_pos_x = observation[2]
+        robot_pos_y = observation[1]
+        robot_rot = observation[3]
+        # Convert coordinates to position
+        robot_position = Location(robot_pos_x, robot_pos_y, robot_rot)
+
+        # Get Python Agent that represents robot
+        robot = system.get_agent(int(robot_id_unity))
+
+        ##-------------##
+        ## FOLLOW PATH ##
+        ##-------------##
+        
+        # Follow previously computed path or plan new path when at the end of path
+        next_position = robot.move(system.token, timestep)
+        # Convert Position to Node
+        next_action = Node(next_position.row, next_position.col, next_position.rotation)
+        # Check if a task needs to be picked up / delivered
+        pickup_action = 0
+        delivery_action = 0
+        if next_position.to_pickup:
+            # Agent has to pick up his task
+            pickup_action = 1
+            # Agent has picked up the task, no agent can swap from now on, remove it from the taskSet
+            to_remove = system.get_task(next_position.task_id)
+            system.token.taskSet.remove(to_remove)
+        elif next_position.to_deliver:
+            # Agent has to deliver his task
+            delivery_action = 1
+            # Agent has no task assigned anymore as the task is delivered
+            system.token.assignments[robot_id_unity] = None
+
+        # Send action to agent in Unity
+        actions.extend([next_action.x, next_action.y, next_action.g, pickup_action, delivery_action])              
+        
+
+    # When all agents have moved in this timestep update the timestep
+    if (actions_requested_in_timestep == n_agents):
+        # Update the timestep
+        timestep += 1
+        # Reset the number of agents that have requested a timestep in this timestep
+        actions_requested_in_timestep = 0
+    
+    # Send actions to Unity
+    actions = np.array(actions)
+    actions.resize(len(agents), action_size)
+    action_tuple.add_discrete(actions)
+
+    env.set_actions(behavior_name, action_tuple)
+    env.step()
+
+
+
+
+
+
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/paper/Bachelorthesis.pdf b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/paper/Bachelorthesis.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..e9bf4fce9fccb3903a7f502782e4292f8c59e23d
Binary files /dev/null and b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/paper/Bachelorthesis.pdf differ
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/ta_astar.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/ta_astar.py
new file mode 100644
index 0000000000000000000000000000000000000000..c936ffdaffbb6872143e2fd42caaa7ab35656dc1
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/ta_astar.py
@@ -0,0 +1,163 @@
+"""
+Created on Wed Apr 22 07:43:03 2020
+
+@author: Pieter Cawood
+
+"""
+from heapq import *
+from ta_state import * 
+
+def get_heuristic(start_location, goal_location, rotation):
+    # Admissible heuristic - manhattan distance
+    return abs(start_location.col - goal_location.col) + abs(start_location.row - goal_location.row)
+
+class AStar:
+    def __init__(self, world, rotation):
+        self.rotation = rotation
+        self.world = world
+        self.dim_x = len(world[0])
+        self.dim_y = len(world)
+        self.obstacles = {}
+        self.path_ends = dict()
+        self.other_agent_paths = []
+
+    def state_possible(self, current_state, new_state):
+        # Check if wall
+        not_obstacle = False
+        if new_state.location not in self.obstacles:
+            not_obstacle = True
+        return 0 <= new_state.location.col < self.dim_x and 0 <= new_state.location.row < self.dim_y \
+               and not_obstacle and not self.is_collision(current_state, new_state)
+
+    def is_collision(self, current_state, new_state):
+        for other_agent_path in self.other_agent_paths:
+            # Vertex collision
+            if new_state.time in other_agent_path:
+                if other_agent_path[new_state.time].row == new_state.location.row and other_agent_path[new_state.time].col == new_state.location.col:
+                    return True
+            # Edge collision
+            if new_state.time in other_agent_path and current_state.time in other_agent_path:
+                if other_agent_path[new_state.time].row == current_state.location.row and \
+                    other_agent_path[new_state.time].col == current_state.location.col and \
+                        other_agent_path[current_state.time].row == new_state.location.row and \
+                            other_agent_path[current_state.time].col == new_state.location.col:
+                    return True
+            # Last position of agent is his parking location
+            if new_state.location in self.path_ends:
+                busy_time = self.path_ends[new_state.location]
+                if new_state.time >= busy_time:
+                    return True
+        return False
+
+    def get_neighbours(self, current_state):
+        neighbours = []
+        neighbour_time_step = current_state.time + 1
+        # Wait in state
+        new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row, current_state.location.rotation))
+        if self.state_possible(current_state, new_state):
+            neighbours.append(new_state)
+        # Add rotation
+        new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row, (current_state.location.rotation+self.rotation) % 360))
+        if self.state_possible(current_state, new_state):
+            neighbours.append(new_state)
+        # Remove rotation
+        new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row, (current_state.location.rotation-self.rotation) % 360))
+        if self.state_possible(current_state, new_state):
+            neighbours.append(new_state)
+        if current_state.location.rotation == 0:
+            # Move down
+            new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row - 1, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)
+        elif current_state.location.rotation == 90:
+            # Move right
+            new_state = State(neighbour_time_step, Location(current_state.location.col + 1, current_state.location.row, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)
+        elif current_state.location.rotation == 180:
+            # Move up
+            new_state = State(neighbour_time_step, Location(current_state.location.col, current_state.location.row + 1, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)
+        elif current_state.location.rotation == 270:
+            # Move left
+            new_state = State(neighbour_time_step, Location(current_state.location.col - 1, current_state.location.row, current_state.location.rotation))
+            if self.state_possible(current_state, new_state):
+                neighbours.append(new_state)       
+        return neighbours
+
+    def create_obstacles(self, other_agent_paths):
+        n_rotations = int(360/self.rotation)
+        # Keep track of all walls in the environment
+        for y in range(self.dim_y):
+            for x in range(self.dim_x):
+                # 1 represent a wall in the environment
+                if self.world[y][x] == 1:
+                    # A wall is always a collision, no matter the rotation
+                    for i in range(n_rotations):
+                        rot = i * self.rotation
+                        self.obstacles[Location(x, y, rot)] = True
+        # Keep track of where the paths of the other agents end
+        self.path_ends = dict()
+        for path in other_agent_paths:
+            # Get the last timestep in the path of the agent
+            last_time = list(path)[-1]
+            # Get the last location in the path of the agent
+            last_pos = path[last_time]
+            # Two agents always collide when they share the same location, no matter the rotation
+            for i in range(n_rotations):
+                rot = i * self.rotation
+                self.path_ends[Location(last_pos.col, last_pos.row, rot)] = last_time
+        # Keep track of the other paths of agents to detect collisions
+        self.other_agent_paths = other_agent_paths
+
+    # Returns the latest timestep at which a specific location will be used
+    def find_lastest_use(self, location):
+        # Keep track of all the uses of that location
+        uses = []
+        # Check in the path of each agent if that agent uses that location, if yes, add it to the list
+        for agent_path in self.other_agent_paths:
+            for t, loc in agent_path.items():
+                if loc.col == location.col and loc.row == location.row:
+                    uses.append(t)
+        # If the location is used at least once, return the maximum
+        if uses:
+            return max(uses)
+        # If the location is never used, return 0
+        else:
+            return 0
+        
+
+    def search(self, time_step, start_location, goal_location, other_agent_paths,
+               release_time=0, find_step = 0):
+        self.create_obstacles(other_agent_paths)
+        initial_state = State(time_step, start_location)
+        # Find the lastest use of the goal location to avoid parking on a location that is still going to be used
+        lastest_use = self.find_lastest_use(goal_location)
+        came_from = {}
+        open_list = [initial_state]
+        closed_set = set()
+        initial_state.g_score = 0
+        initial_state.f_score = get_heuristic(start_location, goal_location, self.rotation)
+        while open_list:
+            current = heappop(open_list)
+            if current.location == goal_location:
+                if current in came_from and came_from[current].location == goal_location:
+                    if current.time > lastest_use:
+                        new_path = [current]
+                        while current in came_from:
+                            current = came_from[current]
+                            new_path.append(current)
+                        # Reverse path
+                        return new_path[::-1]
+            closed_set |= {current}
+            neighbours = self.get_neighbours(current)
+            neighbour: State
+            for neighbour in neighbours:
+                # Only explore new states
+                if (neighbour not in closed_set) and (neighbour not in open_list):
+                    came_from[neighbour] = current
+                    neighbour.g = current.g + 1
+                    neighbour.f = neighbour.g + get_heuristic(neighbour.location, goal_location, self.rotation)
+                    heappush(open_list, neighbour)
+        return False
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/ta_state.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/ta_state.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6269547d945284d4fcff1503617d8a2e44b8ff4
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/ta_state.py
@@ -0,0 +1,60 @@
+"""
+Created on Sat Apr 18 10:45:11 2020
+
+@author: Pieter Cawood
+
+"""
+
+def h(pos1, pos2):
+    return abs(pos1.col - pos2.col) + abs(pos1.row - pos2.row)
+
+class Location(object):
+    def __init__(self, col, row, rotation):
+        self.col = col
+        self.row = row
+        self.rotation = rotation
+
+        # Relevant information for pickup and delivery actions
+        self.task_id = None
+        self.to_pickup = False
+        self.to_deliver = False
+
+    def __eq__(self, other):
+        return self.col == other.col and self.row == other.row and self.rotation == other.rotation
+
+    def __hash__(self):
+        return hash(str(self.col) + "_" + str(self.row) + "_" + str(self.rotation))
+
+    def __str__(self):
+        return str((self.col, self.row, self.rotation, self.to_pickup, self.to_deliver))
+
+    # Better information for debugging
+    def __repr__(self):
+        return f"Location({self.col}, {self.row}, {self.rotation}, {self.to_pickup}, {self.to_deliver})"
+
+
+class State(object):
+    def __init__(self, time, location):
+        self.time = time
+        self.location = location
+        self.g = 0
+        self.f = 0
+
+    def __eq__(self, other):
+        return self.time == other.time and self.location == other.location
+
+    def __hash__(self):
+        return hash(str(self.time) + str(self.location.col) + str(self.location.row))
+
+    def __str__(self):
+        return str((self.time, self.location.col, self.location.row))
+
+    def __lt__(self, other):
+        if self.f < other.f:
+            return True
+        else:
+            return False
+
+    # Better information for debugging
+    def __repr__(self):
+        return f"State(Time: {self.time}, Location(x: {self.location.col}, y: {self.location.row}, r: {self.location.rotation}))"
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_agent.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..c274323e921b25304f7b3c82e81deef100d88206
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_agent.py
@@ -0,0 +1,248 @@
+# Python modules
+import sys
+import numpy as np
+# Pathfinding modules
+from ta_astar import AStar
+from ta_state import Location, h
+# Own modules
+
+class Agent:
+    def __init__(self, id, initial_position, system, environment, rotation, on_task_assigned):
+        # Identifier used to identify this agent
+        self.id = id
+        # Position of the agent        
+        self.pos = initial_position
+        # Keep track of the parking location of the agent
+        self.parkingLocation = initial_position
+        # AStar planner used to compute path
+        self.a_star = AStar(environment, rotation)
+        # System is used to request token to look for tasks
+        self.system = system
+        # Indicates whether agent is currently carying a package
+        self.carrying = False
+        # Callback called when agent assigns a task to itself
+        self.on_task_assigned = on_task_assigned
+
+    # Delete path of an agent from the token
+    def delete_path(self, token, agent, start_timestep):
+        del token.paths[agent.id]
+        
+    # Method that the agent calls to look for a new task and plan a path
+    def look_for_task(self, token, timestep):
+        # When look_for_task is called by another agent that tries to swap tasks agent might not be on an endpoint
+        if not self.system.is_endpoint(self.pos):
+            # Agent is not on an endpoint so planning a path to an endpoint might fail
+            found = self.path2(token, timestep)
+            if found:
+                # Agent can safely move to an endpoint -> Allow swapping
+                return True
+            else:
+                # Agent can not safely move to an endpoint -> Do not allow swapping
+                return False
+
+        availableTasks = [] # List of all the tasks that are available to the agent
+                
+        ##-- Check if pickup/delivery is not end of path of any other agent --##
+        # Get last locations of all paths in token
+        pathEndsWithID = token.get_pathends(self.id)
+        # Only keep the locations, ID's are not needed here
+        pathEnds = list(map(lambda x: x[0], pathEndsWithID))
+        # If pickup/delivery is not in pathEnds it's an available task
+        for t in token.taskSet:
+            # Task is available if it's delivery location is not the end of the path of any agent
+            if t.pickup not in pathEnds:
+                availableTasks.append(t)
+
+        # While there is still at least one task                
+        while len(availableTasks) > 0:
+            # Find the "best" task (best = minimum h-value)
+            h_scores = np.array(map(lambda t: h(self.pos, t.pickup), availableTasks))
+            min_task = availableTasks[np.argmin(h_scores)]
+            # Remove task from available tasks
+            availableTasks.remove(min_task)
+            
+            # Check if task has already been assigned
+            other_id = None
+            for a_id, t_id in token.assignments.items():
+                # If another agent has already assigned this task to itself, keep track of the agent
+                if t_id == min_task.id:
+                    other_id = a_id
+            if other_id is None:
+                # No other agent has already reserved this task
+
+                # Check if the path of any agent ends in the delivery location of the task: means that it can rest there forever, look for another task
+                if min_task.delivery in pathEnds:
+                    continue
+                # No agent is assigned to task
+                # Assign the task to this agent
+                token.assignments[self.id] = min_task.id
+                # Plan a path to execute the task
+                self.path1(min_task, token, timestep)
+                # Call the callback to notify Unity that the agent has a new task assignment
+                self.on_task_assigned(self.id, min_task.id)
+                # Agent was able to find a task and plan a path, return True
+                return True
+            else:
+                # Task is already assigned to another agent: check if this agent can reach the pickup location more efficiently
+                other_agent = self.system.get_agent(other_id)
+                # Check if the path of any other agent is the delivery location of the task: means that it can rest there forever, look for another task
+                if min_task.delivery in pathEnds and (min_task.delivery, other_id) not in pathEndsWithID:
+                    continue
+                # Check if other agent is already at the pickup location of the task: if yes, look for another task
+                if other_agent.pos == min_task.pickup:
+                    continue
+                # Make a copy of the token to restore it in case swapping is not allowed
+                token_copy = token.copy()
+                # Unassign the task from the other agent                
+                token.assignments[other_id] = None
+                # Assign this task to this agent
+                token.assignments[self.id] = min_task.id
+                # Delete the path of the other agent from the token
+                self.delete_path(token, other_agent, timestep)
+                # Plan a path to execute this task
+                self.path1(min_task, token, timestep)
+                # Calculate how many steps this agent needs to reach the pickup location
+                selfReached = timestep
+                while(token.paths[self.id][selfReached] != min_task.pickup):
+                    selfReached += 1
+                # Calculate how many steps the other agent needs to reach the pickup location
+                otherReached = timestep
+                while(token_copy.paths[other_id][otherReached] != min_task.pickup):
+                    otherReached += 1
+                # Check which agent reaches the pickup location of the task more efficiently
+                if (selfReached < otherReached):
+                    # This agent can reach the pickup location more efficiently, check if other agent can find another task or find a path to a safe location
+                    success = other_agent.look_for_task(token, timestep)
+                    if success:
+                        # Other agent was able to plan a path to another task or to a safe location -> Notify Unity that this agent has a new task assigned
+                        self.on_task_assigned(self.id, min_task.id)
+                        # Agent was able to find a task and plan a path, return True
+                        return True
+                # Task Swapping is not allowed or this agent can not reach the pickup location more efficiently, restore the token
+                token.restore(token_copy)
+        # Agent was not able to find a task, plan a path to a safe location
+
+        # Keep track of all the delivery locations of the tasks in the taskSet
+        delivery_locations = []
+        for task in token.taskSet:
+            delivery_locations.append(task.delivery)
+        # If the current position of the agent is not a delivery location the agent can rest at it's current position
+        if Location(self.pos.col, self.pos.row, 0) not in delivery_locations:
+            # Check if agent already has a path in the token (might have been deleted by other agent): create a path if there is none
+            if self.id not in token.paths:
+                token.paths[self.id] = dict()
+            # Register the trivial path to the agent's current location in its path: will try to look for a path in the next timestep
+            token.paths[self.id][timestep] = Location(self.pos.col, self.pos.row, self.pos.rotation)
+        else:
+            # Agent has to move as it's current location is a delivery location, plan a collision-free path to a safe location
+            self.path2(token, timestep)
+        # Agent was not able to find a task, but was able to plan a collision-free path to a safe location
+        return True
+          
+                
+    def path1(self, task, token, timestep):
+         # Plans a path from the current location of the agent to the pickup location and a path from pickup location to delivery location
+
+        # All needed locations for the pathplanning
+        current_location = Location(self.pos.col, self.pos.row, self.pos.rotation) 
+        pickup_location = Location(task.pickup.col, task.pickup.row, task.pickup.rotation)
+        delivery_location = Location(task.delivery.col, task.delivery.row, task.delivery.rotation)
+        
+        ##----------------##
+        ## Path to pickup ##
+        ##----------------##
+
+        # Get the paths of all the other agents
+        other_agent_paths = token.get_other_agents_paths(timestep, self.id)
+        # Plan a path from the current location of the agent to the pickup location of the task
+        pickup_path = self.a_star.search(timestep, current_location, pickup_location, other_agent_paths)
+        # There should always be a path if the problem is well formed
+        if not pickup_path:
+            raise ValueError("[TPTS] No path to pickup location - Problem not well formed")
+            
+        # Add newly planned path to the agent's path in the token
+        for state in pickup_path:
+            # Check if agent already has a path in the token (might have been deleted by other agent): create a path if there is none
+            if self.id not in token.paths:
+                token.paths[self.id] = dict()
+            token.paths[self.id][state.time] = state.location
+        # Update the timestep to the timestep at the end of the planned path 
+        timestep = timestep + len(pickup_path) - 1
+
+        # Keep track of the timestep when the agent reaches the pickup location
+        timestep_at_pickup = timestep
+
+        ##------------------##
+        ## Path to delivery ##
+        ##------------------##
+
+        # Get the paths of all the other agents
+        other_agent_paths = token.get_other_agents_paths(timestep, self.id)
+        # Plan a path from the pickup location of the task to the delivery location of the task
+        delivery_path = self.a_star.search(timestep, pickup_location, delivery_location, other_agent_paths)
+        # There should always be a path if the problem is well formed
+        if not delivery_path:
+            raise ValueError("[TP] No path to delivery location - Problem not well formed")
+        # Add newly planned path to the agent's path in the token
+        for state in delivery_path:
+            token.paths[self.id][state.time] = state.location
+
+        # Keep track of the timestep at which the agent reaches the delivery location
+        timestep = timestep + len(delivery_path) - 1
+
+        ##---------------------------##
+        ## Pickup / Delivery actions ##
+        ##---------------------------##
+
+        # Register in the last location of the path to the pickup location that the agent needs to pickup a task and register the task ID
+        token.paths[self.id][timestep_at_pickup].to_pickup = True
+        token.paths[self.id][timestep_at_pickup].task_id = task.id
+
+        # Register in the last location of the path to the delivery location that the agent needs to pickup a task and register the task ID
+        token.paths[self.id][timestep].to_deliver = True
+        token.paths[self.id][timestep].task_id = task.id
+
+    """ Path2 plans a path from the agent's current location
+        to the closest free endpoint    
+    """
+    def path2(self, token, timestep):
+        # Agent is not at an endpoint, path planning might fail
+        ##-- Find free endpoints to move to --##
+        endpoints = self.system.get_free_endpoints()
+        # Select the best endpoint (best = smallest h-score)
+        h_scores = list(map(lambda e: h(self.pos, e), endpoints))
+        chosen_endpoint = endpoints[np.argmin(h_scores)]
+
+        ##-- Plan path to free endpoint --##
+        # Make sure planned path doesn't collide with already planned paths
+        current_location = Location(self.pos.col, self.pos.row, self.pos.rotation) 
+        endpoint_location = Location(chosen_endpoint.col, chosen_endpoint.row, chosen_endpoint.rotation)
+        # Get the paths of all the other agents
+        other_agent_paths = token.get_other_agents_paths(timestep, self.id)
+        # Plan a path from the agent's current location to the chosen endpoint
+        path_to_endpoint = self.a_star.search(timestep, current_location, endpoint_location, other_agent_paths)
+        # If agent is not currently at an endpoint, there might be no possible path, return False
+        if not path_to_endpoint:
+            return False
+        # Add newly planned path to the agent's path in the token
+        for state in path_to_endpoint:
+            # Check if agent already has a path in the token (might have been deleted by other agent): create a path if there is none
+            if self.id not in token.paths:
+                token.paths[self.id] = dict()
+            token.paths[self.id][state.time] = state.location
+        return True    
+    
+    def move(self, token, timestep):
+        # Get the current path of the agent
+        path = token.paths[self.id]
+        # Check if the agent has already planned a move for this timestep
+        if timestep not in path:
+            # If agent has not yet planned a move for this timestep it requests the token and looks for a task
+            token = self.system.request_token()
+            self.look_for_task(token, timestep)
+        # Select the move of the agent in this timestep
+        next_move = token.paths[self.id][timestep]
+        # Update the agent's position
+        self.pos = next_move
+        # Return the agent's next position
+        return next_move
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_system.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_system.py
new file mode 100644
index 0000000000000000000000000000000000000000..d5c22f40302601435063882364577e7bd16da96c
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_system.py
@@ -0,0 +1,104 @@
+# Python modules
+import sys
+import numpy as np
+# Pathfinding modules
+from ta_state import Location
+# Own modules
+from tpts_token import Token
+from tpts_agent import Agent
+
+class System:
+    def __init__(self, environment, rotation):
+        # Keep track of the warehouse setup
+        self.environment = environment
+        # Keep track of rotation
+        self.rotation = rotation
+
+        # Keep track of all agents in the system
+        self.agents = dict()
+        # Keep track of all tasks
+        self.tasks = dict()
+        # Token setup
+        self.token = Token()
+        
+        # Keep track of all the non-task/task endpoints
+        self.task_endpoints = []
+        self.non_task_endpoints = []
+        # Get all the endpoints from the environment
+        self.init_endpoints()
+
+    # Find all the task and non-task endpoints in the environment
+    def init_endpoints(self):
+        # Get the dimensions of the environment
+        dim_y = len(self.environment)
+        dim_x = len(self.environment[0])
+        for y in range(dim_y):
+            for x in range(dim_x):
+                # Non-task endpoints (parking locations) are represented by 2
+                if self.environment[y][x] == 2:
+                    self.non_task_endpoints.append(Location(x, y, 0))
+                # Task endpoints (pickup/delivery locations) are represented by 3
+                elif self.environment[y][x] == 3:
+                    self.task_endpoints.append(Location(x, y, 0))
+
+    ##---------##
+    ## Getters ##
+    ##---------##
+
+    def get_agent(self, agent_id):
+        return self.agents[agent_id]
+
+    def get_task(self, task_id):
+        return self.tasks[task_id]
+
+    def get_endpoints(self):
+        return np.concatenate((self.non_task_endpoints, self.task_endpoints))
+
+    def get_free_endpoints(self):
+        # List of all the endpoints
+        all_endpoints = self.get_endpoints()
+        free_endpoints = []
+        # Get a list of the last positions of each agent's path
+        endPathsWithID = self.token.get_pathends()
+        endPaths = list(map(lambda x: x[0], endPathsWithID))
+        # Generate a list of all the delivery locations of the tasks in the taskSet
+        deliveryLocations = []
+        for t in self.token.taskSet:
+            deliveryLocations.append(t.delivery)
+        for e in all_endpoints:
+            # If endpoint is not the end of the path of any agent
+            # or is not the delivery location of any task it's free
+            if e not in endPaths and e not in deliveryLocations:
+                free_endpoints.append(e)
+        return free_endpoints
+
+    def get_non_task_endpoints(self):
+        return self.non_task_endpoints
+
+    ##---------------------##
+    ## Adding new elements ##
+    ##---------------------##
+
+    def add_agent(self, agent_id, agent_pos, on_task_assigned):
+        agent = Agent(agent_id, agent_pos, self, self.environment,
+                      self.rotation, on_task_assigned)
+        self.agents[agent.id] = agent
+        self.token.add_agent(agent)
+
+    def add_task(self, task):
+        self.token.add_task(task)
+        self.tasks[task.id] = task
+
+    ##-------------------##
+    ## Utilitary methods ##
+    ##-------------------##
+        
+    def request_token(self):
+        return self.token
+
+    def is_endpoint(self, endpoint):
+        endpoint_loc = Location(endpoint.col, endpoint.row, 0)
+        if endpoint_loc in self.non_task_endpoints or endpoint_loc in self.task_endpoints:
+            return True
+        else:
+            return False
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_task.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_task.py
new file mode 100644
index 0000000000000000000000000000000000000000..03e2b01468fb260764e4733a86d8571643c48b16
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_task.py
@@ -0,0 +1,35 @@
+CURRENT_TASK_ID = 0
+
+class Task:
+    """ Represents a task in the pickup & delivery problem 
+
+        Attributes:
+        id: int 
+            Identifier of the task
+        pickupLocation: Position 
+            The location where the task needs to be picked up
+        deliveryLocation: Position 
+            The location where the task needs to be delivered
+    """
+    def __init__(self, id, pickupLocation, deliveryLocation):
+        self.id = id
+
+        self.pickup = pickupLocation
+        self.delivery = deliveryLocation
+        
+        # Keep track timestep when task enters the taskset and when it's executed => calculating service time
+        self.entered = None
+        self.delivered = None
+
+    def service_time(self):
+        if self.entered is not None and self.delivered is not None:
+            return self.delivered - self.entered
+        else:
+            return None
+        
+    # Better information for debugging
+    def __repr__(self):
+        return f"Task({self.id},Pickup({self.pickup}), Delivery({self.delivery}))"
+
+    def __str__(self):
+        return f"Task({self.id},Pickup({self.pickup}), Delivery({self.delivery}))"
diff --git a/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_token.py b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_token.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e42d8ffd46c51fdebcea3639f91cab0c9e5e311
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_Token_Passing_with_Task_Swapping/tpts_token.py
@@ -0,0 +1,75 @@
+from ta_state import Location
+
+class Token:
+    def __init__(self):
+        # Keep track of the paths of all the agents
+        self.paths = dict()
+        # Keep track of which agent is executing which task
+        self.assignments = dict()
+        # Keep track of the remaining tasks
+        self.taskSet = []
+
+    ##---------##
+    ## Getters ##
+    ##---------##
+
+    # Returns the last location on the path of each agent
+    def get_pathends(self, given_id=None):
+        pathEnds = []
+        for a_id, k in self.paths.items():
+            if given_id is None or a_id != given_id:
+                loc = k[list(k)[-1]]
+                pathEnds.append((Location(loc.col, loc.row, 0), a_id))
+        return pathEnds
+
+    # Get the paths of all agents except the path of agent with ID = own_id
+    def get_other_agents_paths(self, timestep, own_id):
+        other_agent_paths = []
+        for a_id, path in self.paths.items():
+            if a_id != own_id:
+                other_agent_paths.append(path)
+        return other_agent_paths
+
+    ##------------------##
+    ## Add new elements ##
+    ##------------------##
+
+    # Adds a new agent to the system
+    def add_agent(self, agent):
+        a_id = agent.id
+        self.paths[a_id] = dict()
+        self.paths[a_id][0] = agent.pos
+        self.assignments[a_id] = None
+        
+    # Adds a new task to the system
+    def add_task(self, task):
+        self.taskSet.append(task)
+
+    ##-------------------##
+    ## Utilitary methods ##
+    ##-------------------##
+        
+    # Restores the token with an old state of the token
+    def restore(self, old_token):
+        self.paths = old_token.paths
+        self.assignments = old_token.assignments
+        self.taskSet = old_token.taskSet
+        
+    # Generates a copy of this token
+    def copy(self):
+        new_token = Token()
+        # Copy paths
+        new_token.paths = dict()
+        for a_id, path in self.paths.items():
+            new_token.paths[a_id] = dict()
+            for t, loc in path.items():
+                new_token.paths[a_id][t] = loc
+        # Copy assignments
+        new_token.assignments = dict()
+        for a_id, t_id in self.assignments.items():
+            new_token.assignments[a_id] = t_id
+        # Copy tasks
+        new_token.taskSet = []
+        for task in self.taskSet:
+            new_token.taskSet.append(task)
+        return new_token
diff --git a/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/EnvChannel.py b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/EnvChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6d62add37419b9cfe1ddb9b07a70b150a07a6d7
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/EnvChannel.py
@@ -0,0 +1,63 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from EnvironmentData import EnvironmentData
+
+"""
+class that processes information from SideChannel EnvChannel: stores all incoming information
+in an instance of class EnvironmentData
+"""
+
+
+class EnvChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("621f0a70-4f87-11ea-a6bf-784f4387d1f7")) #must coincide with ChannelId set in c#
+        self.envData = EnvironmentData() # object that stores info on environment
+
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        # We simply read a string from the message and print it.
+        data = msg.read_string()
+        environment_info = json.loads(data)
+
+        self.envData.matrix = environment_info["matrixLayout"]
+        self.envData.rotation = environment_info["rotationRobot"]
+        self.envData.size_of_action = environment_info["sizeOfAction"]
+        self.envData.size_of_observation = environment_info["sizeOfObservation"]
+        self.envData.number_of_robots = environment_info["numberOfRobotsInEnv"]
+        self.envData.number_of_current_tasks = environment_info["numberOfCurrentTasks"]
+        self.envData.can_go_backwards = environment_info["backwards"]
+        self.envData.random_tasks = environment_info["tasksGeneratedRandomly"]
+        self.envData.instance_ids = environment_info["instanceIDSRobots"]
+
+        self.envData.set_initial_nodes_dictionary(environment_info["initialNodesOfRobots"])
+        self.envData.set_tasks_to_be_assigned(environment_info["currentTasks"])
+        self.envData.set_assigned_tasks()
+
+    def send_string(self, data: str) -> None:
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/EnvironmentData.py b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/EnvironmentData.py
new file mode 100644
index 0000000000000000000000000000000000000000..ddc7bc4ddf6d4e8de2c6a5143287a3809f728196
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/EnvironmentData.py
@@ -0,0 +1,101 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+stores data on environment
+instance methods that initialize environment (used by EnvChannel)
+- set_initial_nodes_dictionary(initial_nodes): initializes current_nodes_dictionary
+containing current(next) nodes for each of the robots
+- set_tasks_to_be_assigned(tasks): initialize tasks_to_be_assigned: tasks that have to be assigned
+- set_assigned_tasks(): initialize assigned_tasks_dictionary containing
+ for every robot the current assigned task
+
+instance methods that update environment info
+- assign_task(robot_instanceID, task): assign task to a given robot
+- add_task_to_tasks_to_be_assigned(task): append a new task to tasks_to_be_assigned
+- task_done(instance_id): remove task from robot that was assigned this task
+"""
+
+
+import json
+
+from Node import Node
+from Task import Position, Task
+
+
+class EnvironmentData:
+
+    def __init__(self):
+        self.matrix = None
+        self.rotation = None
+        self.size_of_action = None
+        self.size_of_observation = None
+        self.number_of_robots = None
+        self.number_of_current_tasks = None
+        self.can_go_backwards = None
+        self.random_tasks = None  # if set to true random tasks will be send whenever a task has been completed,
+        # otherwise all tasks self.tasks_to_be_assigned
+
+        self.instance_ids = []
+        self.current_nodes_dictionary = {} # dictionary instance_id -> current node
+        self.tasks_to_be_assigned = [] # tasks that are still to be assigned
+        self.assigned_tasks_dictionary = {} # dictionary instance_id -> assigned task
+
+
+    #########################################
+    ## methods used by EnvChannel to initialize attributes:
+    #########################################
+
+    # given a correct string containing array of nodes
+    def set_initial_nodes_dictionary(self, initial_nodes):
+        for i in range(self.number_of_robots):
+            self.current_nodes_dictionary[self.instance_ids[i]] = Node(initial_nodes[i]["GridPosition"]["Row"],
+                                                      initial_nodes[i]["GridPosition"]["Column"],
+                                                      initial_nodes[i]["Degrees"])
+
+    # given a correct json_string containing array of tasks
+    def set_tasks_to_be_assigned(self, tasks):
+        for i in range(self.number_of_current_tasks):
+            pickup = Position(tasks[i]["PickUp"]["Row"], tasks[i]["PickUp"]["Column"])
+            delivery = Position(tasks[i]["Delivery"]["Row"], tasks[i]["Delivery"]["Column"])
+            self.tasks_to_be_assigned.append(Task(pickup, delivery))
+
+    # initialize dictionary robot instance_id -> task (None)
+    def set_assigned_tasks(self):
+        for i in range(self.number_of_robots):
+            self.assigned_tasks_dictionary[self.instance_ids[i]] = None
+
+    #########################################
+    ## methods used to update environment info
+    #########################################
+
+    # when a task is assigned to a robot, it has to be added to self.assigned_tasks
+    # and removed from self.tasks_to_be_assigned
+    # info has to be sent to unity via the correct channel
+    def assign_task(self, robot_instanceID, task):
+        self.assigned_tasks_dictionary[robot_instanceID] = task
+        self.tasks_to_be_assigned.remove(task)
+
+    # when a new task is available it is added to tasks_to_be_assigned
+    # a check is made whether there are still tasks that can be added, but this should not be happening (diagnostical)
+    def add_task_to_tasks_to_be_assigned(self, task):
+        if len(self.tasks_to_be_assigned) == self.number_of_current_tasks:
+            raise Exception("cannot add more tasks")
+        self.tasks_to_be_assigned.append(task)
+
+    # when a robot has finished his task it has to be removed from assigned_tasks
+    def task_done(self, instance_id):
+        self.assigned_tasks_dictionary[instance_id] = None
diff --git a/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/EnvironmentManager.py b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/EnvironmentManager.py
new file mode 100644
index 0000000000000000000000000000000000000000..d839fb86c4c64858daad064023e5293d8de187fb
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/EnvironmentManager.py
@@ -0,0 +1,195 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""'
+Class that contains and manages the information on the environment.
+- Initializes and holds information on the environment (EnvData).
+- Contains a reference to the sidechannel (EnvChannel).
+- Contains a reference to the sidechannel (TaskChannel).
+- Contains a reference to the unity environment (UnityEnv).
+Has instance methods
+- reset() which resets the environment.
+- step() which assigns tasks, computes a new action based on observation from the unity environment
+ and sends actions back to unity, updates info environment when a task has finished
+- close() which closes the environment/
+
+Has also some auxiliary instance methods:
+- assign_new_task() which finds a new task and a robot that is free, then calls
+assign_task_to_robot(robot_instanceID, task)
+- compute_path(current_node, task) which computes paths starting in current_node completing a certain task
+- initialize_shortest_paths() which initializes a dictionary containing the paths robots are following
+- assign_task_to_robot(robot_instanceID, task) which assigns task to a robot with given instance ID,
+updates EnvData and sends information on assignment back to Unity
+
+Note that this a toy example. No checks are done on collisions.
+"""
+
+import json
+
+from mlagents_envs.base_env import ActionTuple
+
+from Graph import Graph
+from Node import Node
+
+import numpy as np
+
+
+class EnvironmentManager:
+
+    def __init__(self, envData, unityEnv, envChannel, taskChannel):
+        self.envData = envData
+        self.unityEnv = unityEnv
+        self.envChannel = envChannel
+        self.taskChannel = taskChannel
+
+        # IMPORTANT: sends info through envChannel, to be called before setting up connection envData an taskChannel
+        self.reset()
+
+        # taskChannel needs info on envData
+        self.taskChannel.environment_data = envData
+
+        # behavior name for agent
+        self.behavior_name = list(unityEnv.behavior_specs.keys())[0]
+
+        # graph that is used for computing paths
+        self.graph = Graph(envData.matrix, envData.rotation, envData.can_go_backwards)
+
+        # for every robot with instanceID id shortest_paths[id] gives the shortest path to
+        # its currently assigned task
+        self.shortest_paths = {}
+
+        self.initialize_shortest_paths()
+
+    # step in the environment
+    # 1) checks if new tasks can be assigned
+    # 2) collect observations
+    # 3) compute new actions
+    # 4) send actions back to Unity
+    def step(self):
+        self.assign_new_task()
+
+        # get information from the agent that requests an action
+        decision_steps, terminal_steps = self.unityEnv.get_steps(self.behavior_name)
+
+        print("request is being made by")
+        agents = decision_steps.agent_id
+        print(str(len(agents)) + " agents")
+
+        # decision_steps.obs is a list of numpy arrays, first dimension corresponds to the number of agents that has requested
+        # a decision (here len(agents))
+        observations = decision_steps.obs
+
+        print("----------------------------------------")
+
+
+        actions = []  # long list of all actions
+        action_tuple = ActionTuple()  # actions to send to unity
+
+        # create an action for all agents that request an action
+        for i in range(len(agents)):
+            observation = observations[0][i]  # observation of current agent
+            robot_id_unity = observation[0]
+            row = observation[1]
+            column = observation[2]
+            degrees = observation[3]
+
+            print("robot " + str(robot_id_unity) + " at node [(" + str(row) + "," + str(column) + ")," + str(
+                degrees) + "]")
+
+            path = self.shortest_paths[robot_id_unity]
+
+            # if path is empty, then robot should stay at same node
+            if len(path) == 0:
+                actions.extend([row, column, degrees, 0, 0])
+            # if path is not empty we get next action from shortest path
+            else:
+                next_action = path[0]  # is a node or "pickup" or "deliver"
+                if next_action == "pickup":
+                    actions.extend([row, column, degrees, 1, 0])
+                elif next_action == "deliver":
+                    actions.extend([row, column, degrees, 0, 1])
+                    self.envData.assigned_tasks_dictionary[robot_id_unity] = None
+                else:
+                    actions.extend([next_action.x, next_action.y, next_action.g, 0, 0])
+                    # update current node
+                    self.envData.current_nodes_dictionary[robot_id_unity] = Node(next_action.x, next_action.y,
+                                                                                     next_action.g)
+                # update path
+                self.shortest_paths[robot_id_unity] = path[1:]
+
+        # add action to action_tuple and set the actions
+        actions = np.array(actions)
+        actions.resize(len(agents), self.envData.size_of_action)
+        action_tuple.add_discrete(actions)
+
+        self.unityEnv.set_actions(self.behavior_name, action_tuple)
+        self.unityEnv.step() # send actions to unity and wait until a new decision is requested
+
+    # reset the environment
+    def reset(self):
+        self.unityEnv.reset()
+
+    # close the environment
+    def close(self):
+        self.close()
+
+    # assigns the next available task to an idle robot, if possible
+    def assign_new_task(self):
+        # check if there are tasks that have to be assigned
+        # if this is the case, get first task and assign to available robot
+        if len(self.envData.tasks_to_be_assigned) != 0:
+            task = self.envData.tasks_to_be_assigned[0]
+            # get available robot
+            for robot_id in self.envData.instance_ids:
+                if self.envData.assigned_tasks_dictionary[robot_id] is None:
+                     # robot is free: assign task to robot and break out of for loop
+                    self.assign_task_to_robot(robot_id, task)
+                    break
+
+
+    # compute path from current_node that finishes given task
+    # for test purposes pick up and delivery need to have rotation 0
+    # at pick up delivery robot stays at same node
+    # returns a sequence of nodes and pick up/delivery actions
+    def compute_path(self, current_node, task):
+        path1 = self.graph.computeShortestPath(current_node,
+                                          Node(task.PickUp.Row, task.PickUp.Column, 0))
+        path1 = path1[1:]
+        path2 = self.graph.computeShortestPath(Node(task.PickUp.Row, task.PickUp.Column, 0),
+                                          Node(task.Delivery.Row, task.Delivery.Column, 0))
+        path2 = path2[1:]
+
+        return path1 + ["pickup"] + path2 + ["deliver"]
+
+
+    # for every robot initially there is an empty path to be followed
+    def initialize_shortest_paths(self):
+        for robot_id in self.envData.instance_ids:
+            self.shortest_paths[robot_id] = []
+
+    def assign_task_to_robot(self, robot_instanceID, task):
+        # update envData
+        self.envData.assign_task(robot_instanceID, task)
+        # compute path for robot
+        self.shortest_paths[robot_instanceID] = \
+            self.compute_path(self.envData.current_nodes_dictionary[robot_instanceID],task)
+        # send info to unity
+        taskDict = {"Task": {
+                        "PickUp": {"Row": task.PickUp.Row, "Column": task.PickUp.Column},
+                        "Delivery": {"Row": task.Delivery.Row, "Column": task.Delivery.Column}},
+                    "InstanceID": robot_instanceID}
+        self.taskChannel.send_string(json.dumps(taskDict))
+
diff --git a/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Graph.py b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Graph.py
new file mode 100644
index 0000000000000000000000000000000000000000..69e03b997172dae6855dca7f06890606239e7063
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Graph.py
@@ -0,0 +1,126 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+from networkx import DiGraph, shortest_path
+from Node import Node
+
+"""
+Class Graph creates a graph based on matrix, deviation (unit of rotation) and whether robots can move backwards).
+Its nodes contain position in the grid and orientation wrt north (see class <c>Node</c>).
+Networkx package as underlying data structure.
+"""
+
+class Graph:
+    def __init__(self, matrix, deviation, cangobackwards):
+        self.matrix = matrix
+        self.number_of_rows = len(matrix)
+        self.number_of_columns = len(matrix[0])
+        self.deviation = deviation
+        self.cangobackwards = cangobackwards
+        self.graph = DiGraph()
+
+        for i in range(self.number_of_rows):
+            for j in range(self.number_of_columns):
+                # we have to add nodes to the graph when we encounter a number different than 1
+                if matrix[i][j] != 1:
+                    self.addEdgesByRotation(i, j)
+                    self.addEdgesByMovingForward(i,j)
+
+    def addEdgesByRotation(self, row, column):
+        degree = 0
+        while degree < 360:
+            newnode = Node(row, column, degree)
+
+            # add all edges from newnode staying at the same position (row, number), i.e. rotation
+
+            # rotate left
+            rotateLeftNode = Node(row, column, get_degree_in_range_0_360(degree - self.deviation))
+            self.graph.add_edge(newnode, rotateLeftNode)
+
+            # rotate right
+            rotateRightNode = Node(row, column, get_degree_in_range_0_360(degree + self.deviation))
+            self.graph.add_edge(newnode, rotateRightNode)
+
+            degree += self.deviation
+
+    def addEdgesByMovingForward(self, row, column):
+        # check left
+        if column > 0 and self.matrix[row][column-1] != 1:
+            # we can move forward if we have degree 270
+            currentnode = Node(row, column, 270)
+            neighbourleft = Node(row, column-1, 270)
+            self.graph.add_edge(currentnode, neighbourleft)
+            # we can move backward if we have degree 90
+            if self.cangobackwards:
+                currentnode = Node(row, column, 90)
+                neighbourleft = Node(row, column-1, 90)
+                self.graph.add_edge(currentnode, neighbourleft)
+
+        # check right
+        if column < self.number_of_columns -1 and self.matrix[row][column+1] != 1:
+            # we can move forward if we have degree 90
+            currentnode = Node(row, column, 90)
+            neighbourright = Node(row, column+1, 90)
+            self.graph.add_edge(currentnode, neighbourright)
+            # we can move backward if we have degree 270
+            if self.cangobackwards:
+                currentnode = Node(row, column, 270)
+                neighbourright = Node(row, column+1, 270)
+                self.graph.add_edge(currentnode, neighbourright)
+
+        # check up
+        if row > 0 and self.matrix[row-1][column] != 1:
+            # we can move forward if we have degree 0
+            currentnode = Node(row, column, 0)
+            neighbourup = Node(row-1, column, 0)
+            self.graph.add_edge(currentnode, neighbourup)
+            # we can move backward if we have degree 180
+            if self.cangobackwards:
+                currentnode = Node(row, column, 180)
+                neighbourup = Node(row-1, column, 180)
+                self.graph.add_edge(currentnode, neighbourup)
+
+        # check down
+        if row < self.number_of_rows-1 and self.matrix[row+1][column] != 1:
+            # we can move forward if we have degree 180
+            currentnode = Node(row, column, 180)
+            neighbourdown = Node(row+1, column, 180)
+            self.graph.add_edge(currentnode, neighbourdown)
+            # we can move backward if we have degree 0
+            if self.cangobackwards:
+                currentnode = Node(row, column, 0)
+                neighbourdown = Node(row+1, column, 0)
+                self.graph.add_edge(currentnode, neighbourdown)
+
+    def computeShortestPath(self, start_node, end_node):
+        #compute shortest path from start_node to end_node: return a list
+        return shortest_path(self.graph, start_node, end_node)
+
+def get_degree_in_range_0_360(degree):
+    rest = degree % 360
+    if rest < 0:
+        return rest + 360
+    return rest
+
+
+
+
+
+
+
+
+
+
diff --git a/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Node.py b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Node.py
new file mode 100644
index 0000000000000000000000000000000000000000..126684f885f63b51edcd2b6684d26d7a847c51af
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Node.py
@@ -0,0 +1,57 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+Class Node represent nodes in the graph. Every node contains a
+position (x,y) in the grid
+and a rotation in degree where
+0 = North
+90 = East
+280 = South
+270 = West
+all degrees must be between 0 and 360
+
+attributes are set to private such that they cannot be overwritten and there is no problem with the hash
+"""
+
+class Node:
+    def __init__(self,x,y,g):
+        self._x = x
+        self._y = y
+        self._g = g
+
+    @property
+    def x(self):
+        return self._x
+
+    @property
+    def y(self):
+        return self._y
+
+    @property
+    def g(self):
+        return self._g
+
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.x == other.x and self.y == other.y and self.g == other.g
+
+
+    def __hash__(self):
+        return (((self.x * 397) ** self.y) * 397) **self.g
+
+    def __str__(self):
+        return "[(" + str(self.x) + ", " + str(self.y) + ")" + "," + str(self.g) + "]"
diff --git a/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Pipfile b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Pipfile
new file mode 100644
index 0000000000000000000000000000000000000000..2cf8108a7836978e89ef3320e61b72d3c4eb3be6
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Pipfile
@@ -0,0 +1,14 @@
+[[source]]
+url = "https://pypi.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+networkx = "==2.5"
+mlagents = "==0.23.0"
+mlagents-envs = "==0.23.0"
+
+[dev-packages]
+
+[requires]
+python_version = "3.6"
diff --git a/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Task.py b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Task.py
new file mode 100644
index 0000000000000000000000000000000000000000..16dd163021e1d3fb53b5ea42052621255e9a7e79
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/Task.py
@@ -0,0 +1,50 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+Class Task represents tasks which consist of 2 positions: a pickup and a delivery position.
+"""
+
+class Task:
+    def __init__(self, pos1, pos2):
+        self.PickUp = pos1
+        self.Delivery = pos2
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.PickUp == other.PickUp and self.Delivery == other.Delivery
+
+    def __hash__(self):
+        hash_code = hash(self.PickUp)
+        hash_code = (hash_code * 397) ** hash(self.Delivery)
+        return hash_code
+
+    def __str__(self):
+        return "[" + str(self.PickUp) + ", " + str(self.Delivery) + "]"
+
+
+class Position:
+    def __init__(self, x, y):
+        self.Row = x
+        self.Column = y
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.Row == other.Row and self.Column == other.Column
+
+    def __hash__(self):
+        return ((self.Row * 397) ** self.Column) * 397
+
+    def __str__(self):
+        return "(" + str(self.Row) + ", " + str(self.Column) + ")"
diff --git a/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/TaskSideChannel.py b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/TaskSideChannel.py
new file mode 100644
index 0000000000000000000000000000000000000000..dd99877185ec3103f5ccda97c5352856e9745634
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/TaskSideChannel.py
@@ -0,0 +1,58 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+import json
+from mlagents_envs.side_channel.side_channel import (
+    SideChannel,
+    IncomingMessage,
+    OutgoingMessage,
+)
+import uuid
+
+from Task import Task, Position
+
+
+"""
+Class that processes info from the TaskSideChannel.
+- receives new tasks that have to assigned to robots
+- sends assignment of tasks to robots
+"""
+
+
+class TaskSideChannel(SideChannel):
+
+    def __init__(self) -> None:
+        super().__init__(uuid.UUID("c11ab982-82b8-4194-b387-3bd0fe9ebdc7")) #must coincide with ChannelId set in c#
+        self.environment_data = None #info on the environment
+
+    # channel receives new tasks that have to be assigned
+    def on_message_received(self, msg: IncomingMessage) -> None:
+        data = msg.read_string()
+        new_task = json.loads(data)
+        new_task = new_task["task"]
+        task_to_add = Task(Position(new_task["PickUp"]["Row"], new_task["PickUp"]["Column"]),
+                           Position(new_task["Delivery"]["Row"], new_task["Delivery"]["Column"]))
+        # add task to task to be assigned
+        self.environment_data.add_task_to_tasks_to_be_assigned(task_to_add)
+
+    # channel sends information when a task has been assigned (to which robot)
+    def send_string(self, data: str) -> None:
+
+        # Add the string to an OutgoingMessage
+        msg = OutgoingMessage()
+        msg.write_string(data)
+        # We call this method to queue the data we want to send
+        super().queue_message_to_send(msg)
\ No newline at end of file
diff --git a/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/main.py b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..130dda386a5fd019fb5c84e3c36d457a2493b824
--- /dev/null
+++ b/Algorithms/Online_Decentralized/Algorithm_test_toyexample_online_decentralized/main.py
@@ -0,0 +1,44 @@
+"""
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+"""
+Main file that controls decision making for the Online Centralized Pick Up and Delivery Problem
+This is a toy example!
+Uses EnvironmentManager who assigns tasks in order to available agents
+and then computes shortest paths, no check on collisions.
+"""
+
+from mlagents_envs.environment import UnityEnvironment
+import EnvChannel, TaskSideChannel
+import EnvironmentManager
+
+# as long as simulation_going is true, new actions will be generated
+
+simulation_going = True
+
+# setup side channels and unity environment
+envChannel = EnvChannel.EnvChannel()
+taskChannel = TaskSideChannel.TaskSideChannel()
+env = UnityEnvironment(file_name=None, side_channels=[envChannel, taskChannel])
+
+# set up environment manager
+envManager = EnvironmentManager.EnvironmentManager(envChannel.envData, env, envChannel, taskChannel)
+
+
+while simulation_going:
+    envManager.step()
+
+envManager.close()
diff --git a/PickUpandDelivery/.gitignore b/PickUpandDelivery/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..8c31b4fb7a402827dadeb8e1f7881f6b62b25528
--- /dev/null
+++ b/PickUpandDelivery/.gitignore
@@ -0,0 +1,98 @@
+# This .gitignore file should be placed at the root of your Unity project directory
+#
+# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
+#
+/[Ll]ibrary/
+/[Tt]emp/
+/[Oo]bj/
+/[Bb]uild/
+/[Bb]uilds/
+/[Ll]ogs/
+/[Uu]ser[Ss]ettings/
+
+# MemoryCaptures can get excessive in size.
+# They also could contain extremely sensitive data
+/[Mm]emoryCaptures/
+
+# Asset meta data should only be ignored when the corresponding asset is also ignored
+!/[Aa]ssets/**/*.meta
+
+# Uncomment this line if you wish to ignore the asset store tools plugin
+# /[Aa]ssets/AssetStoreTools*
+
+# Autogenerated Jetbrains Rider plugin
+/[Aa]ssets/Plugins/Editor/JetBrains*
+
+# Visual Studio cache directory
+.vs/
+
+# Gradle cache directory
+.gradle/
+
+# Autogenerated VS/MD/Consulo solution and project files
+ExportedObj/
+.consulo/
+*.csproj
+*.unityproj
+*.sln
+*.suo
+*.tmp
+*.user
+*.userprefs
+*.pidb
+*.booproj
+*.svd
+*.pdb
+*.mdb
+*.opendb
+*.VC.db
+
+# Unity3D generated meta files
+*.pidb.meta
+*.pdb.meta
+*.mdb.meta
+
+# Unity3D generated file on crash reports
+sysinfo.txt
+
+# Builds
+*.apk
+*.aab
+*.unitypackage
+
+# Crashlytics generated file
+crashlytics-build.properties
+
+# Packed Addressables
+/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
+
+# Temporary auto-generated Android Assets
+/[Aa]ssets/[Ss]treamingAssets/aa.meta
+/[Aa]ssets/[Ss]treamingAssets/aa/*
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+.idea/
+
+# Generated files
+.idea/**/contentModel.xml
+
+.DS_Store
+__pycache__/
+
+
+# Extra
+./build
+./obj
+./Logs
+./Library
+./Temp
+./ProjectSettings
+
+#ML agents
+/Assets/ML-Agents/Timers*
+
diff --git a/PickUpandDelivery/Assembly-CSharp.csproj.DotSettings b/PickUpandDelivery/Assembly-CSharp.csproj.DotSettings
new file mode 100644
index 0000000000000000000000000000000000000000..b5b235a96cba87306e02eb00fa185c185f99c22f
--- /dev/null
+++ b/PickUpandDelivery/Assembly-CSharp.csproj.DotSettings
@@ -0,0 +1,2 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">Default</s:String></wpf:ResourceDictionary>
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Fonts.meta b/PickUpandDelivery/Assets/Fonts.meta
new file mode 100644
index 0000000000000000000000000000000000000000..b21a2be7e93069be1414f4e55f2281efe2bbf640
--- /dev/null
+++ b/PickUpandDelivery/Assets/Fonts.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7c67c373f3538ef46bc6cad48b8fc69f
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Fonts/ArialCE.ttf b/PickUpandDelivery/Assets/Fonts/ArialCE.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..a53879583c273432b10231e109677f10a30ee290
Binary files /dev/null and b/PickUpandDelivery/Assets/Fonts/ArialCE.ttf differ
diff --git a/PickUpandDelivery/Assets/Fonts/ArialCE.ttf.meta b/PickUpandDelivery/Assets/Fonts/ArialCE.ttf.meta
new file mode 100644
index 0000000000000000000000000000000000000000..b5465334c10b78ec9c2f289eb7b4e28ebb8dc6fb
--- /dev/null
+++ b/PickUpandDelivery/Assets/Fonts/ArialCE.ttf.meta
@@ -0,0 +1,22 @@
+fileFormatVersion: 2
+guid: 424c8962f52026a4c96be91a0f9cc09d
+TrueTypeFontImporter:
+  externalObjects: {}
+  serializedVersion: 4
+  fontSize: 16
+  forceTextureCase: -2
+  characterSpacing: 0
+  characterPadding: 1
+  includeFontData: 1
+  fontName: Arial CE
+  fontNames:
+  - Arial CE
+  fallbackFontReferences: []
+  customCharacters: 
+  fontRenderingMode: 0
+  ascentCalculationMode: 1
+  useLegacyBoundsCalculation: 0
+  shouldRoundAdvanceValue: 1
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/ML-Agents.meta b/PickUpandDelivery/Assets/ML-Agents.meta
new file mode 100644
index 0000000000000000000000000000000000000000..cc6931f55431e3405539c60d283f04e4f66e768c
--- /dev/null
+++ b/PickUpandDelivery/Assets/ML-Agents.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1c329b599f3585243a8ef689890c9264
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Materials.meta b/PickUpandDelivery/Assets/Materials.meta
new file mode 100644
index 0000000000000000000000000000000000000000..56af04ecde68ef744e07dadbee36551a03e67c20
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 81ccf87ab9c53bf4193803e5daa4485b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Materials/AgentBlue.mat b/PickUpandDelivery/Assets/Materials/AgentBlue.mat
new file mode 100644
index 0000000000000000000000000000000000000000..98afe276c85991a80022bc840443e213ce8898c9
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/AgentBlue.mat
@@ -0,0 +1,80 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_Name: AgentBlue
+  m_Shader: {fileID: 47, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _SpecGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 0
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 0
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 0.12941177, g: 0.5882353, b: 0.9529412, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/PickUpandDelivery/Assets/Materials/AgentBlue.mat.meta b/PickUpandDelivery/Assets/Materials/AgentBlue.mat.meta
new file mode 100644
index 0000000000000000000000000000000000000000..8869d32d9f6cba37e1949e2cedc800dcf82623cc
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/AgentBlue.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 65c786e6f7696492e9956e3b8eac5564
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Materials/Eye.mat b/PickUpandDelivery/Assets/Materials/Eye.mat
new file mode 100644
index 0000000000000000000000000000000000000000..703bddeb2b720271b3f10738fb6345fe61da8e16
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/Eye.mat
@@ -0,0 +1,77 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_Name: Eye
+  m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: _ALPHATEST_ON _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: 2450
+  stringTagMap:
+    RenderType: TransparentCutout
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 10912, guid: 0000000000000000f000000000000000, type: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 0
+    - _Metallic: 0
+    - _Mode: 1
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 0
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 0.058823526, g: 0.058823526, b: 0.058823526, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/PickUpandDelivery/Assets/Materials/Eye.mat.meta b/PickUpandDelivery/Assets/Materials/Eye.mat.meta
new file mode 100644
index 0000000000000000000000000000000000000000..5188e4a58bd34b2e232fc93e254a36e254880ec4
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/Eye.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4ed73faac93ee4f8dbaaf5edf7376682
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Materials/Headband.mat b/PickUpandDelivery/Assets/Materials/Headband.mat
new file mode 100644
index 0000000000000000000000000000000000000000..13b5854401121e714a66c0cfcac42cd501591113
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/Headband.mat
@@ -0,0 +1,76 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_Name: Headband
+  m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 1
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 0.98039216, g: 0.6509804, b: 0.16078432, a: 1}
+    - _EmissionColor: {r: 0.98039216, g: 0.6509804, b: 0.16078432, a: 1}
diff --git a/PickUpandDelivery/Assets/Materials/Headband.mat.meta b/PickUpandDelivery/Assets/Materials/Headband.mat.meta
new file mode 100644
index 0000000000000000000000000000000000000000..59b630f9eb3a46e059d66e63e03fbd7cde324c34
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/Headband.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 651c8f7b5f94e4712bb6738769a27fed
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Materials/TextMaterial.mat b/PickUpandDelivery/Assets/Materials/TextMaterial.mat
new file mode 100644
index 0000000000000000000000000000000000000000..141085a5d0bd7efa26d10945931f26118f17b6e3
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/TextMaterial.mat
@@ -0,0 +1,77 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: TextMaterial
+  m_Shader: {fileID: 4800000, guid: 3b25d06e715175541a7601ed730df7c6, type: 3}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 2800000, guid: 424c8962f52026a4c96be91a0f9cc09d, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/PickUpandDelivery/Assets/Materials/TextMaterial.mat.meta b/PickUpandDelivery/Assets/Materials/TextMaterial.mat.meta
new file mode 100644
index 0000000000000000000000000000000000000000..3d91073f2c3dc0a376f6e2c51e2c8d66b64cc80b
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/TextMaterial.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9a31293b7f33d9e41811a9f5e33f80fa
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Materials/Tile.mat b/PickUpandDelivery/Assets/Materials/Tile.mat
new file mode 100644
index 0000000000000000000000000000000000000000..7576715697f26ba96eb94fba81ec11eb5fc9dcd8
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/Tile.mat
@@ -0,0 +1,77 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: Tile
+  m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 0.6698113, g: 0.6698113, b: 0.6698113, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/PickUpandDelivery/Assets/Materials/Tile.mat.meta b/PickUpandDelivery/Assets/Materials/Tile.mat.meta
new file mode 100644
index 0000000000000000000000000000000000000000..5e00a1df9721debafcf7bd5d5c8f266f497b3d6c
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/Tile.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 015f80b5c4ae946a88dafd7feae278d9
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Materials/X.mat b/PickUpandDelivery/Assets/Materials/X.mat
new file mode 100644
index 0000000000000000000000000000000000000000..10e6ba7d3ebbcd4e2520fa52d84650e92128ab12
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/X.mat
@@ -0,0 +1,77 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: X
+  m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 1
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/PickUpandDelivery/Assets/Materials/X.mat.meta b/PickUpandDelivery/Assets/Materials/X.mat.meta
new file mode 100644
index 0000000000000000000000000000000000000000..f56645adfdbdb4cfd6879e6f833a779b420e17a4
--- /dev/null
+++ b/PickUpandDelivery/Assets/Materials/X.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c491227f9c123ab4f82f045383d91485
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Plugins.meta b/PickUpandDelivery/Assets/Plugins.meta
new file mode 100644
index 0000000000000000000000000000000000000000..80031e8149bfecaf25cfecef19acec476490068f
--- /dev/null
+++ b/PickUpandDelivery/Assets/Plugins.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f401d27e12cbd6548b27de328ce5b37b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Plugins/Newtonsoft.Json.dll b/PickUpandDelivery/Assets/Plugins/Newtonsoft.Json.dll
new file mode 100644
index 0000000000000000000000000000000000000000..3772590130fa624f93bc2ca75cbc56be2b2b00c8
Binary files /dev/null and b/PickUpandDelivery/Assets/Plugins/Newtonsoft.Json.dll differ
diff --git a/PickUpandDelivery/Assets/Plugins/Newtonsoft.Json.dll.meta b/PickUpandDelivery/Assets/Plugins/Newtonsoft.Json.dll.meta
new file mode 100644
index 0000000000000000000000000000000000000000..c372e408ffafd1cda11683f8d08271146e433d1d
--- /dev/null
+++ b/PickUpandDelivery/Assets/Plugins/Newtonsoft.Json.dll.meta
@@ -0,0 +1,33 @@
+fileFormatVersion: 2
+guid: b0827a2f804d24c789672af19d1683f2
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      Any: 
+    second:
+      enabled: 1
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        DefaultValueInitialized: true
+  - first:
+      Windows Store Apps: WindowsStoreApps
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Prefabs.meta b/PickUpandDelivery/Assets/Prefabs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..cf19c1e3537c6f81f393e2d943b0ebfab4a0bfbd
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 702e69246a5bf1f4abf39e9514807a2b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Prefabs/EndPoint.prefab b/PickUpandDelivery/Assets/Prefabs/EndPoint.prefab
new file mode 100644
index 0000000000000000000000000000000000000000..d8810959d79d88f1ff11372d5ebff5916a62d8d5
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/EndPoint.prefab
@@ -0,0 +1,392 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &784985611624235947
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 357068018734814567}
+  - component: {fileID: 990189179575991127}
+  - component: {fileID: 2675203881973562991}
+  - component: {fileID: 6721500656427338880}
+  m_Layer: 0
+  m_Name: x1
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &357068018734814567
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 784985611624235947}
+  m_LocalRotation: {x: 0, y: 0.38268343, z: 0, w: 0.92387956}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.08, y: 0.08, z: 0.02}
+  m_Children: []
+  m_Father: {fileID: 7903164002163363415}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0}
+--- !u!33 &990189179575991127
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 784985611624235947}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &2675203881973562991
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 784985611624235947}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: c491227f9c123ab4f82f045383d91485, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!64 &6721500656427338880
+MeshCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 784985611624235947}
+  m_Material: {fileID: 0}
+  m_IsTrigger: 0
+  m_Enabled: 1
+  serializedVersion: 4
+  m_Convex: 0
+  m_CookingOptions: 30
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!1 &3537248152627339076
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2017623479251953269}
+  - component: {fileID: 6124382143263498424}
+  - component: {fileID: 8765626904929566005}
+  - component: {fileID: 7556388547506331738}
+  m_Layer: 0
+  m_Name: x2
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &2017623479251953269
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3537248152627339076}
+  m_LocalRotation: {x: 0, y: -0.38268343, z: 0, w: 0.92387956}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.08, y: 0.08, z: 0.02}
+  m_Children: []
+  m_Father: {fileID: 7903164002163363415}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: -45, z: 0}
+--- !u!33 &6124382143263498424
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3537248152627339076}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &8765626904929566005
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3537248152627339076}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: c491227f9c123ab4f82f045383d91485, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!64 &7556388547506331738
+MeshCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3537248152627339076}
+  m_Material: {fileID: 0}
+  m_IsTrigger: 0
+  m_Enabled: 1
+  serializedVersion: 4
+  m_Convex: 0
+  m_CookingOptions: 30
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!1 &6314994090778056550
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 7903164002163363415}
+  - component: {fileID: 5447487630165351505}
+  - component: {fileID: 4185037264137122964}
+  - component: {fileID: 7916022369362927641}
+  - component: {fileID: 6937335721257966020}
+  m_Layer: 0
+  m_Name: EndPoint
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &7903164002163363415
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6314994090778056550}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 357068018734814567}
+  - {fileID: 2017623479251953269}
+  - {fileID: 7126322845514153872}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &5447487630165351505
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6314994090778056550}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &4185037264137122964
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6314994090778056550}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 015f80b5c4ae946a88dafd7feae278d9, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!65 &7916022369362927641
+BoxCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6314994090778056550}
+  m_Material: {fileID: 0}
+  m_IsTrigger: 0
+  m_Enabled: 1
+  serializedVersion: 2
+  m_Size: {x: 1, y: 1, z: 1}
+  m_Center: {x: 0, y: 0, z: 0}
+--- !u!114 &6937335721257966020
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6314994090778056550}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: f3dcff173f5992d4db93b38be21d0d1d, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+--- !u!1 &6412298205908224070
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 7126322845514153872}
+  - component: {fileID: 8849749889804757716}
+  - component: {fileID: 4644426937966420123}
+  m_Layer: 0
+  m_Name: text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &7126322845514153872
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6412298205908224070}
+  m_LocalRotation: {x: 0.5, y: -0.5, z: 0.5, w: 0.5}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.1, y: 0.1, z: 0.02}
+  m_Children: []
+  m_Father: {fileID: 7903164002163363415}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 90, y: -90, z: 0}
+--- !u!23 &8849749889804757716
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6412298205908224070}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 9a31293b7f33d9e41811a9f5e33f80fa, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!102 &4644426937966420123
+TextMesh:
+  serializedVersion: 3
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6412298205908224070}
+  m_Text: 1000
+  m_OffsetZ: 0
+  m_CharacterSize: 4
+  m_LineSpacing: 1
+  m_Anchor: 4
+  m_Alignment: 1
+  m_TabSize: 4
+  m_FontSize: 15
+  m_FontStyle: 1
+  m_RichText: 1
+  m_Font: {fileID: 12800000, guid: 424c8962f52026a4c96be91a0f9cc09d, type: 3}
+  m_Color:
+    serializedVersion: 2
+    rgba: 4283710242
diff --git a/PickUpandDelivery/Assets/Prefabs/EndPoint.prefab.meta b/PickUpandDelivery/Assets/Prefabs/EndPoint.prefab.meta
new file mode 100644
index 0000000000000000000000000000000000000000..a3492ec921a75ca5f4db1a6c81bfd3f873a0b19d
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/EndPoint.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8ddb9b3dc215c2b4e97741bad9ced662
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Prefabs/RobotOfflineCentralizedPrefab.prefab b/PickUpandDelivery/Assets/Prefabs/RobotOfflineCentralizedPrefab.prefab
new file mode 100644
index 0000000000000000000000000000000000000000..f3b7aa72e014706001e371713d860b2286fc94f6
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/RobotOfflineCentralizedPrefab.prefab
@@ -0,0 +1,637 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &1218265376493012
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4082575947564308}
+  - component: {fileID: 33986757750372936}
+  - component: {fileID: 23248495933290848}
+  m_Layer: 0
+  m_Name: eye
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4082575947564308
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: 0.29999995, y: 0.07399994, z: 0.50040054}
+  m_LocalScale: {x: 0.29457998, y: 0.29457998, z: 0.29457998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33986757750372936
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23248495933290848
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1321468028730240
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4679453577574622}
+  - component: {fileID: 5294701982035410442}
+  m_Layer: 0
+  m_Name: RobotOfflineCentralizedPrefab
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4679453577574622
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 5}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4780098186595842}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &5294701982035410442
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 54b9a4088e4329849b24b0da23b5d39d, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  idleColor: {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+--- !u!1 &1424713891854676
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4780098186595842}
+  m_Layer: 0
+  m_Name: Agent
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4780098186595842
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1424713891854676}
+  m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4294419716796784}
+  m_Father: {fileID: 4679453577574622}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
+--- !u!1 &1619100162539582
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4425897039098228}
+  - component: {fileID: 33259119028337980}
+  - component: {fileID: 23108868206887546}
+  m_Layer: 0
+  m_Name: mouth
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4425897039098228
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: 0, y: -0.18299997, z: 0.50040054}
+  m_LocalScale: {x: 0.27602, y: 0.042489994, z: 0.13891}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33259119028337980
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23108868206887546
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1854695166504686
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4300192163442926}
+  - component: {fileID: 33165976320323760}
+  - component: {fileID: 23468552506669568}
+  m_Layer: 0
+  m_Name: Headband
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4300192163442926
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_LocalRotation: {x: -0, y: -0, z: 0.016506119, w: 0.9998638}
+  m_LocalPosition: {x: 0, y: 0.341, z: 0}
+  m_LocalScale: {x: 1.0441425, y: 0.19278127, z: 1.0441422}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: -179.99998, z: 1.8920001}
+--- !u!33 &33165976320323760
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23468552506669568
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 651c8f7b5f94e4712bb6738769a27fed, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1859240399150782
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4294419716796784}
+  - component: {fileID: 33973749152356522}
+  - component: {fileID: 23340305563606254}
+  m_Layer: 0
+  m_Name: AgentCube_Blue
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4294419716796784
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_LocalRotation: {x: 0, y: 1, z: 0, w: 0}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4082575947564308}
+  - {fileID: 4144856465265480}
+  - {fileID: 4425897039098228}
+  - {fileID: 4300192163442926}
+  - {fileID: 8910510863212595550}
+  - {fileID: 5852217119192457300}
+  m_Father: {fileID: 4780098186595842}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33973749152356522
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23340305563606254
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1999020414315134
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4144856465265480}
+  - component: {fileID: 33069174244444078}
+  - component: {fileID: 23048386147321498}
+  m_Layer: 0
+  m_Name: eye
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4144856465265480
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: -0.29999995, y: 0.07399994, z: 0.50040054}
+  m_LocalScale: {x: 0.29457998, y: 0.29457998, z: 0.29457998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33069174244444078
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23048386147321498
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &5885360301775037259
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5852217119192457300}
+  - component: {fileID: 1187121205107757005}
+  - component: {fileID: 3213252032395258356}
+  m_Layer: 0
+  m_Name: x2
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &5852217119192457300
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_LocalRotation: {x: -0, y: -0.38268346, z: -0, w: -0.9238795}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.07999999, y: 0.08, z: 0.019999998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 5
+  m_LocalEulerAnglesHint: {x: 0, y: -45, z: 0}
+--- !u!33 &1187121205107757005
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &3213252032395258356
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &6501887724070931806
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8910510863212595550}
+  - component: {fileID: 1257352226056678973}
+  - component: {fileID: 3406077584688725003}
+  m_Layer: 0
+  m_Name: x1
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &8910510863212595550
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_LocalRotation: {x: -0, y: -0.9238795, z: -0, w: -0.38268346}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.08, y: 0.08, z: 0.02}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0}
+--- !u!33 &1257352226056678973
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &3406077584688725003
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
diff --git a/PickUpandDelivery/Assets/Prefabs/RobotOfflineCentralizedPrefab.prefab.meta b/PickUpandDelivery/Assets/Prefabs/RobotOfflineCentralizedPrefab.prefab.meta
new file mode 100644
index 0000000000000000000000000000000000000000..6ee54b59b9beede9bbe751dc8012125e8b2838f6
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/RobotOfflineCentralizedPrefab.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: eaded20e79e164040a7073677ba44c47
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Prefabs/RobotOfflineDecentralizedPrefab.prefab b/PickUpandDelivery/Assets/Prefabs/RobotOfflineDecentralizedPrefab.prefab
new file mode 100644
index 0000000000000000000000000000000000000000..b8f041d4a5ac648ed652f62045ab68bf6bc2a7ac
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/RobotOfflineDecentralizedPrefab.prefab
@@ -0,0 +1,672 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &1218265376493012
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4082575947564308}
+  - component: {fileID: 33986757750372936}
+  - component: {fileID: 23248495933290848}
+  m_Layer: 0
+  m_Name: eye
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4082575947564308
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: 0.29999995, y: 0.07399994, z: 0.50040054}
+  m_LocalScale: {x: 0.29457998, y: 0.29457998, z: 0.29457998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33986757750372936
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23248495933290848
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1321468028730240
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4679453577574622}
+  - component: {fileID: 163425050273668575}
+  - component: {fileID: -4965312288568279513}
+  m_Layer: 0
+  m_Name: RobotOfflineDecentralizedPrefab
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4679453577574622
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 5}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4780098186595842}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &163425050273668575
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: e224beeb8f8781f479c65279d3e07a01, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  agentParameters:
+    maxStep: 0
+  hasUpgradedFromAgentParameters: 1
+  MaxStep: 0
+  idleColor: {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+--- !u!114 &-4965312288568279513
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5d1c4e0b1822b495aa52bc52839ecb30, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_BrainParameters:
+    VectorObservationSize: 4
+    NumStackedVectorObservations: 1
+    m_ActionSpec:
+      m_NumContinuousActions: 0
+      BranchSizes: 0000000000000000000000000000000000000000
+    VectorActionSize: 0000000000000000000000000000000000000000
+    VectorActionDescriptions: []
+    VectorActionSpaceType: 0
+    hasUpgradedBrainParametersWithActionSpec: 1
+  m_Model: {fileID: 0}
+  m_InferenceDevice: 0
+  m_BehaviorType: 0
+  m_BehaviorName: RobotBehavior
+  TeamId: 0
+  m_UseChildSensors: 1
+  m_UseChildActuators: 1
+  m_ObservableAttributeHandling: 0
+--- !u!1 &1424713891854676
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4780098186595842}
+  m_Layer: 0
+  m_Name: Agent
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4780098186595842
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1424713891854676}
+  m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4294419716796784}
+  m_Father: {fileID: 4679453577574622}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
+--- !u!1 &1619100162539582
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4425897039098228}
+  - component: {fileID: 33259119028337980}
+  - component: {fileID: 23108868206887546}
+  m_Layer: 0
+  m_Name: mouth
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4425897039098228
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: 0, y: -0.18299997, z: 0.50040054}
+  m_LocalScale: {x: 0.27602, y: 0.042489994, z: 0.13891}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33259119028337980
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23108868206887546
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1854695166504686
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4300192163442926}
+  - component: {fileID: 33165976320323760}
+  - component: {fileID: 23468552506669568}
+  m_Layer: 0
+  m_Name: Headband
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4300192163442926
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_LocalRotation: {x: -0, y: -0, z: 0.016506119, w: 0.9998638}
+  m_LocalPosition: {x: 0, y: 0.341, z: 0}
+  m_LocalScale: {x: 1.0441425, y: 0.19278127, z: 1.0441422}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: -179.99998, z: 1.8920001}
+--- !u!33 &33165976320323760
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23468552506669568
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 651c8f7b5f94e4712bb6738769a27fed, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1859240399150782
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4294419716796784}
+  - component: {fileID: 33973749152356522}
+  - component: {fileID: 23340305563606254}
+  m_Layer: 0
+  m_Name: AgentCube_Blue
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4294419716796784
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_LocalRotation: {x: 0, y: 1, z: 0, w: 0}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4082575947564308}
+  - {fileID: 4144856465265480}
+  - {fileID: 4425897039098228}
+  - {fileID: 4300192163442926}
+  - {fileID: 8910510863212595550}
+  - {fileID: 5852217119192457300}
+  m_Father: {fileID: 4780098186595842}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33973749152356522
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23340305563606254
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1999020414315134
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4144856465265480}
+  - component: {fileID: 33069174244444078}
+  - component: {fileID: 23048386147321498}
+  m_Layer: 0
+  m_Name: eye
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4144856465265480
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: -0.29999995, y: 0.07399994, z: 0.50040054}
+  m_LocalScale: {x: 0.29457998, y: 0.29457998, z: 0.29457998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33069174244444078
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23048386147321498
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &5885360301775037259
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5852217119192457300}
+  - component: {fileID: 1187121205107757005}
+  - component: {fileID: 3213252032395258356}
+  m_Layer: 0
+  m_Name: x2
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &5852217119192457300
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_LocalRotation: {x: -0, y: -0.38268346, z: -0, w: -0.9238795}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.07999999, y: 0.08, z: 0.019999998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 5
+  m_LocalEulerAnglesHint: {x: 0, y: -45, z: 0}
+--- !u!33 &1187121205107757005
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &3213252032395258356
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &6501887724070931806
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8910510863212595550}
+  - component: {fileID: 1257352226056678973}
+  - component: {fileID: 3406077584688725003}
+  m_Layer: 0
+  m_Name: x1
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &8910510863212595550
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_LocalRotation: {x: -0, y: -0.9238795, z: -0, w: -0.38268346}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.08, y: 0.08, z: 0.02}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0}
+--- !u!33 &1257352226056678973
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &3406077584688725003
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
diff --git a/PickUpandDelivery/Assets/Prefabs/RobotOfflineDecentralizedPrefab.prefab.meta b/PickUpandDelivery/Assets/Prefabs/RobotOfflineDecentralizedPrefab.prefab.meta
new file mode 100644
index 0000000000000000000000000000000000000000..c50e4611c0e30c7c613e0ea95ba3435560b38619
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/RobotOfflineDecentralizedPrefab.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 832f1310dfa5fd24dac021345a803d31
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Prefabs/RobotOnlineCentralizedPrefab.prefab b/PickUpandDelivery/Assets/Prefabs/RobotOnlineCentralizedPrefab.prefab
new file mode 100644
index 0000000000000000000000000000000000000000..4f0a711db9f2324f9eb9c2503987ea4ef129d856
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/RobotOnlineCentralizedPrefab.prefab
@@ -0,0 +1,637 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &1218265376493012
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4082575947564308}
+  - component: {fileID: 33986757750372936}
+  - component: {fileID: 23248495933290848}
+  m_Layer: 0
+  m_Name: eye
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4082575947564308
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: 0.29999995, y: 0.07399994, z: 0.50040054}
+  m_LocalScale: {x: 0.29457998, y: 0.29457998, z: 0.29457998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33986757750372936
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23248495933290848
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1321468028730240
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4679453577574622}
+  - component: {fileID: -6752361495951348029}
+  m_Layer: 0
+  m_Name: RobotOnlineCentralizedPrefab
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4679453577574622
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 5}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4780098186595842}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &-6752361495951348029
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0ee9f4e10c142784c91290b59532cb09, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  idleColor: {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+--- !u!1 &1424713891854676
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4780098186595842}
+  m_Layer: 0
+  m_Name: Agent
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4780098186595842
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1424713891854676}
+  m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4294419716796784}
+  m_Father: {fileID: 4679453577574622}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
+--- !u!1 &1619100162539582
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4425897039098228}
+  - component: {fileID: 33259119028337980}
+  - component: {fileID: 23108868206887546}
+  m_Layer: 0
+  m_Name: mouth
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4425897039098228
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: 0, y: -0.18299997, z: 0.50040054}
+  m_LocalScale: {x: 0.27602, y: 0.042489994, z: 0.13891}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33259119028337980
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23108868206887546
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1854695166504686
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4300192163442926}
+  - component: {fileID: 33165976320323760}
+  - component: {fileID: 23468552506669568}
+  m_Layer: 0
+  m_Name: Headband
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4300192163442926
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_LocalRotation: {x: -0, y: -0, z: 0.016506119, w: 0.9998638}
+  m_LocalPosition: {x: 0, y: 0.341, z: 0}
+  m_LocalScale: {x: 1.0441425, y: 0.19278127, z: 1.0441422}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: -179.99998, z: 1.8920001}
+--- !u!33 &33165976320323760
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23468552506669568
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 651c8f7b5f94e4712bb6738769a27fed, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1859240399150782
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4294419716796784}
+  - component: {fileID: 33973749152356522}
+  - component: {fileID: 23340305563606254}
+  m_Layer: 0
+  m_Name: AgentCube_Blue
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4294419716796784
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_LocalRotation: {x: 0, y: 1, z: 0, w: 0}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4082575947564308}
+  - {fileID: 4144856465265480}
+  - {fileID: 4425897039098228}
+  - {fileID: 4300192163442926}
+  - {fileID: 8910510863212595550}
+  - {fileID: 5852217119192457300}
+  m_Father: {fileID: 4780098186595842}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33973749152356522
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23340305563606254
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1999020414315134
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4144856465265480}
+  - component: {fileID: 33069174244444078}
+  - component: {fileID: 23048386147321498}
+  m_Layer: 0
+  m_Name: eye
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4144856465265480
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: -0.29999995, y: 0.07399994, z: 0.50040054}
+  m_LocalScale: {x: 0.29457998, y: 0.29457998, z: 0.29457998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33069174244444078
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23048386147321498
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &5885360301775037259
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5852217119192457300}
+  - component: {fileID: 1187121205107757005}
+  - component: {fileID: 3213252032395258356}
+  m_Layer: 0
+  m_Name: x2
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &5852217119192457300
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_LocalRotation: {x: -0, y: -0.38268346, z: -0, w: -0.9238795}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.07999999, y: 0.08, z: 0.019999998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 5
+  m_LocalEulerAnglesHint: {x: 0, y: -45, z: 0}
+--- !u!33 &1187121205107757005
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &3213252032395258356
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &6501887724070931806
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8910510863212595550}
+  - component: {fileID: 1257352226056678973}
+  - component: {fileID: 3406077584688725003}
+  m_Layer: 0
+  m_Name: x1
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &8910510863212595550
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_LocalRotation: {x: -0, y: -0.9238795, z: -0, w: -0.38268346}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.08, y: 0.08, z: 0.02}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0}
+--- !u!33 &1257352226056678973
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &3406077584688725003
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
diff --git a/PickUpandDelivery/Assets/Prefabs/RobotOnlineCentralizedPrefab.prefab.meta b/PickUpandDelivery/Assets/Prefabs/RobotOnlineCentralizedPrefab.prefab.meta
new file mode 100644
index 0000000000000000000000000000000000000000..c2b861d943c47cc4fef5534d555c69ebf93ca3df
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/RobotOnlineCentralizedPrefab.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 189960379d04e524eb29a18f9c0de39d
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Prefabs/RobotOnlineDecentralizedPrefab.prefab b/PickUpandDelivery/Assets/Prefabs/RobotOnlineDecentralizedPrefab.prefab
new file mode 100644
index 0000000000000000000000000000000000000000..f625865c56f7df353343eb26f3cf8c4bf0ceecb7
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/RobotOnlineDecentralizedPrefab.prefab
@@ -0,0 +1,673 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &1218265376493012
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4082575947564308}
+  - component: {fileID: 33986757750372936}
+  - component: {fileID: 23248495933290848}
+  m_Layer: 0
+  m_Name: eye
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4082575947564308
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: 0.29999995, y: 0.07399994, z: 0.50040054}
+  m_LocalScale: {x: 0.29457998, y: 0.29457998, z: 0.29457998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33986757750372936
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23248495933290848
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1218265376493012}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1321468028730240
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4679453577574622}
+  - component: {fileID: 6178260321861954731}
+  - component: {fileID: -4965312288568279513}
+  m_Layer: 0
+  m_Name: 3DBall
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4679453577574622
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 5}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4780098186595842}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &6178260321861954731
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 388587dedc7732c449a7c4461107ddc3, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  agentParameters:
+    maxStep: 0
+  hasUpgradedFromAgentParameters: 1
+  MaxStep: 0
+  simulationManager: {fileID: 0}
+  idleColor: {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+--- !u!114 &-4965312288568279513
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1321468028730240}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5d1c4e0b1822b495aa52bc52839ecb30, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_BrainParameters:
+    VectorObservationSize: 4
+    NumStackedVectorObservations: 1
+    m_ActionSpec:
+      m_NumContinuousActions: 0
+      BranchSizes: 0000000000000000000000000000000000000000
+    VectorActionSize: 0000000000000000000000000000000000000000
+    VectorActionDescriptions: []
+    VectorActionSpaceType: 0
+    hasUpgradedBrainParametersWithActionSpec: 1
+  m_Model: {fileID: 0}
+  m_InferenceDevice: 0
+  m_BehaviorType: 0
+  m_BehaviorName: RobotBehavior
+  TeamId: 0
+  m_UseChildSensors: 1
+  m_UseChildActuators: 1
+  m_ObservableAttributeHandling: 0
+--- !u!1 &1424713891854676
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4780098186595842}
+  m_Layer: 0
+  m_Name: Agent
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4780098186595842
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1424713891854676}
+  m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4294419716796784}
+  m_Father: {fileID: 4679453577574622}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
+--- !u!1 &1619100162539582
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4425897039098228}
+  - component: {fileID: 33259119028337980}
+  - component: {fileID: 23108868206887546}
+  m_Layer: 0
+  m_Name: mouth
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4425897039098228
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: 0, y: -0.18299997, z: 0.50040054}
+  m_LocalScale: {x: 0.27602, y: 0.042489994, z: 0.13891}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33259119028337980
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23108868206887546
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1619100162539582}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1854695166504686
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4300192163442926}
+  - component: {fileID: 33165976320323760}
+  - component: {fileID: 23468552506669568}
+  m_Layer: 0
+  m_Name: Headband
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4300192163442926
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_LocalRotation: {x: -0, y: -0, z: 0.016506119, w: 0.9998638}
+  m_LocalPosition: {x: 0, y: 0.341, z: 0}
+  m_LocalScale: {x: 1.0441425, y: 0.19278127, z: 1.0441422}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: -179.99998, z: 1.8920001}
+--- !u!33 &33165976320323760
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23468552506669568
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1854695166504686}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 651c8f7b5f94e4712bb6738769a27fed, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1859240399150782
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4294419716796784}
+  - component: {fileID: 33973749152356522}
+  - component: {fileID: 23340305563606254}
+  m_Layer: 0
+  m_Name: AgentCube_Blue
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4294419716796784
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_LocalRotation: {x: 0, y: 1, z: 0, w: 0}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4082575947564308}
+  - {fileID: 4144856465265480}
+  - {fileID: 4425897039098228}
+  - {fileID: 4300192163442926}
+  - {fileID: 8910510863212595550}
+  - {fileID: 5852217119192457300}
+  m_Father: {fileID: 4780098186595842}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33973749152356522
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23340305563606254
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1859240399150782}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &1999020414315134
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4144856465265480}
+  - component: {fileID: 33069174244444078}
+  - component: {fileID: 23048386147321498}
+  m_Layer: 0
+  m_Name: eye
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4144856465265480
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
+  m_LocalPosition: {x: -0.29999995, y: 0.07399994, z: 0.50040054}
+  m_LocalScale: {x: 0.29457998, y: 0.29457998, z: 0.29457998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
+--- !u!33 &33069174244444078
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &23048386147321498
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1999020414315134}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 4ed73faac93ee4f8dbaaf5edf7376682, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 1
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &5885360301775037259
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5852217119192457300}
+  - component: {fileID: 1187121205107757005}
+  - component: {fileID: 3213252032395258356}
+  m_Layer: 0
+  m_Name: x2
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &5852217119192457300
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_LocalRotation: {x: -0, y: -0.38268346, z: -0, w: -0.9238795}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.07999999, y: 0.08, z: 0.019999998}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 5
+  m_LocalEulerAnglesHint: {x: 0, y: -45, z: 0}
+--- !u!33 &1187121205107757005
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &3213252032395258356
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5885360301775037259}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!1 &6501887724070931806
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8910510863212595550}
+  - component: {fileID: 1257352226056678973}
+  - component: {fileID: 3406077584688725003}
+  m_Layer: 0
+  m_Name: x1
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &8910510863212595550
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_LocalRotation: {x: -0, y: -0.9238795, z: -0, w: -0.38268346}
+  m_LocalPosition: {x: 0, y: 0.51, z: 0}
+  m_LocalScale: {x: 0.08, y: 0.08, z: 0.02}
+  m_Children: []
+  m_Father: {fileID: 4294419716796784}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0}
+--- !u!33 &1257352226056678973
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &3406077584688725003
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6501887724070931806}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 65c786e6f7696492e9956e3b8eac5564, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
diff --git a/PickUpandDelivery/Assets/Prefabs/RobotOnlineDecentralizedPrefab.prefab.meta b/PickUpandDelivery/Assets/Prefabs/RobotOnlineDecentralizedPrefab.prefab.meta
new file mode 100644
index 0000000000000000000000000000000000000000..08858463e7adb58ab8c97e8463e9a81004cb8539
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/RobotOnlineDecentralizedPrefab.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5b62ae8d6539a4637bba603a6015fe86
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Prefabs/TileWall.prefab b/PickUpandDelivery/Assets/Prefabs/TileWall.prefab
new file mode 100644
index 0000000000000000000000000000000000000000..8d74658f79515f356361820ff32ef19466def618
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/TileWall.prefab
@@ -0,0 +1,95 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &7692220640868168301
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5136915043093844274}
+  - component: {fileID: 639462588314027066}
+  - component: {fileID: 1131881454912184682}
+  - component: {fileID: 6436653372698916071}
+  m_Layer: 0
+  m_Name: TileWall
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &5136915043093844274
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7692220640868168301}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 4.369123, y: -0.5599309, z: 6.53695}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &639462588314027066
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7692220640868168301}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &1131881454912184682
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7692220640868168301}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 015f80b5c4ae946a88dafd7feae278d9, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+--- !u!65 &6436653372698916071
+BoxCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7692220640868168301}
+  m_Material: {fileID: 0}
+  m_IsTrigger: 0
+  m_Enabled: 1
+  serializedVersion: 2
+  m_Size: {x: 1, y: 1, z: 1}
+  m_Center: {x: 0, y: 0, z: 0}
diff --git a/PickUpandDelivery/Assets/Prefabs/TileWall.prefab.meta b/PickUpandDelivery/Assets/Prefabs/TileWall.prefab.meta
new file mode 100644
index 0000000000000000000000000000000000000000..c7c7cddf35081d2524be13daaef24e85b0d3e1f3
--- /dev/null
+++ b/PickUpandDelivery/Assets/Prefabs/TileWall.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: de70788c970f16940b9f517cf39194b0
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scenes.meta b/PickUpandDelivery/Assets/Scenes.meta
new file mode 100644
index 0000000000000000000000000000000000000000..4a2d7e549e1b886de946a48bcefcb5ee594909de
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scenes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 45802cab3f0230a4aac55237b4131b37
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scenes/Offline_Centralized.unity b/PickUpandDelivery/Assets/Scenes/Offline_Centralized.unity
new file mode 100644
index 0000000000000000000000000000000000000000..88af974c39cab3b2fccd16b2f6187492ebd3c23b
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scenes/Offline_Centralized.unity
@@ -0,0 +1,442 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 705507994}
+  m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 11
+  m_GIWorkflowMode: 1
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 0
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 500
+    m_PVRBounces: 2
+    m_PVREnvironmentSampleCount: 500
+    m_PVREnvironmentReferencePointCount: 2048
+    m_PVRFilteringMode: 2
+    m_PVRDenoiserTypeDirect: 0
+    m_PVRDenoiserTypeIndirect: 0
+    m_PVRDenoiserTypeAO: 0
+    m_PVRFilterTypeDirect: 0
+    m_PVRFilterTypeIndirect: 0
+    m_PVRFilterTypeAO: 0
+    m_PVREnvironmentMIS: 0
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_UseShadowmask: 1
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &93153075
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 93153076}
+  - component: {fileID: 93153077}
+  - component: {fileID: 93153078}
+  m_Layer: 0
+  m_Name: SimulationController
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &93153076
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &93153077
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: ec6a5fb578df5504186ba78f15f70a56, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  agentParameters:
+    maxStep: 0
+  hasUpgradedFromAgentParameters: 1
+  MaxStep: 0
+  robotPrefab: {fileID: 1321468028730240, guid: eaded20e79e164040a7073677ba44c47,
+    type: 3}
+--- !u!114 &93153078
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5d1c4e0b1822b495aa52bc52839ecb30, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_BrainParameters:
+    VectorObservationSize: 1
+    NumStackedVectorObservations: 1
+    m_ActionSpec:
+      m_NumContinuousActions: 0
+      BranchSizes: 01000000
+    VectorActionSize: 01000000
+    VectorActionDescriptions: []
+    VectorActionSpaceType: 0
+    hasUpgradedBrainParametersWithActionSpec: 1
+  m_Model: {fileID: 0}
+  m_InferenceDevice: 0
+  m_BehaviorType: 0
+  m_BehaviorName: My Behavior
+  TeamId: 0
+  m_UseChildSensors: 1
+  m_UseChildActuators: 1
+  m_ObservableAttributeHandling: 0
+--- !u!1 &225044881
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 225044882}
+  - component: {fileID: 225044883}
+  m_Layer: 0
+  m_Name: Floor
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &225044882
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 225044881}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &225044883
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 225044881}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: a74be3508dbe36342858e20cec768f98, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  tileWallPrefab: {fileID: 7692220640868168301, guid: de70788c970f16940b9f517cf39194b0,
+    type: 3}
+  endPointPrefab: {fileID: 6314994090778056550, guid: 8ddb9b3dc215c2b4e97741bad9ced662,
+    type: 3}
+  mainCamera: {fileID: 963194227}
+  SimulationController: {fileID: 93153077}
+--- !u!1 &705507993
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 705507995}
+  - component: {fileID: 705507994}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &705507994
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 705507993}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+  m_Intensity: 1
+  m_Range: 10
+  m_SpotAngle: 30
+  m_InnerSpotAngle: 21.80208
+  m_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+    m_CullingMatrixOverride:
+      e00: 1
+      e01: 0
+      e02: 0
+      e03: 0
+      e10: 0
+      e11: 1
+      e12: 0
+      e13: 0
+      e20: 0
+      e21: 0
+      e22: 1
+      e23: 0
+      e30: 0
+      e31: 0
+      e32: 0
+      e33: 1
+    m_UseCullingMatrixOverride: 0
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 1
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+  m_UseBoundingSphereOverride: 0
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &705507995
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 705507993}
+  m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+  m_LocalPosition: {x: 0, y: 3, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!1 &963194225
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 963194228}
+  - component: {fileID: 963194227}
+  - component: {fileID: 963194226}
+  - component: {fileID: 963194229}
+  m_Layer: 0
+  m_Name: Main Camera
+  m_TagString: MainCamera
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!81 &963194226
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+--- !u!20 &963194227
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+  serializedVersion: 2
+  m_ClearFlags: 1
+  m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+  m_projectionMatrixMode: 1
+  m_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  m_FocalLength: 50
+  m_NormalizedViewPortRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  near clip plane: 0.3
+  far clip plane: 1000
+  field of view: 60
+  orthographic: 0
+  orthographic size: 5
+  m_Depth: -1
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingPath: -1
+  m_TargetTexture: {fileID: 0}
+  m_TargetDisplay: 0
+  m_TargetEye: 3
+  m_HDR: 1
+  m_AllowMSAA: 1
+  m_AllowDynamicResolution: 0
+  m_ForceIntoRT: 0
+  m_OcclusionCulling: 1
+  m_StereoConvergence: 10
+  m_StereoSeparation: 0.022
+--- !u!4 &963194228
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 1, z: -10}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &963194229
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 208230689b9953844af11c709edefaea, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  speed: 0.5
+  sensitivity: 1
diff --git a/PickUpandDelivery/Assets/Scenes/Offline_Centralized.unity.meta b/PickUpandDelivery/Assets/Scenes/Offline_Centralized.unity.meta
new file mode 100644
index 0000000000000000000000000000000000000000..851ee36aca9bd0405c1a655119551adcaf2c0e2d
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scenes/Offline_Centralized.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 767a15f082bfafb48aa82817daae4814
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scenes/Offline_Decentralized.unity b/PickUpandDelivery/Assets/Scenes/Offline_Decentralized.unity
new file mode 100644
index 0000000000000000000000000000000000000000..915201ed05470990b51451e7e5e6d692b321ca06
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scenes/Offline_Decentralized.unity
@@ -0,0 +1,407 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 705507994}
+  m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 11
+  m_GIWorkflowMode: 1
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 0
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 500
+    m_PVRBounces: 2
+    m_PVREnvironmentSampleCount: 500
+    m_PVREnvironmentReferencePointCount: 2048
+    m_PVRFilteringMode: 2
+    m_PVRDenoiserTypeDirect: 0
+    m_PVRDenoiserTypeIndirect: 0
+    m_PVRDenoiserTypeAO: 0
+    m_PVRFilterTypeDirect: 0
+    m_PVRFilterTypeIndirect: 0
+    m_PVRFilterTypeAO: 0
+    m_PVREnvironmentMIS: 0
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_UseShadowmask: 1
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &93153075
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 93153076}
+  - component: {fileID: 93153077}
+  m_Layer: 0
+  m_Name: SimulationController
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &93153076
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &93153077
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 00bf636c107a31d489dc615292930654, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  robotPrefab: {fileID: 1321468028730240, guid: 832f1310dfa5fd24dac021345a803d31,
+    type: 3}
+--- !u!1 &225044881
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 225044882}
+  - component: {fileID: 225044883}
+  m_Layer: 0
+  m_Name: Floor
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &225044882
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 225044881}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &225044883
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 225044881}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: a74be3508dbe36342858e20cec768f98, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  tileWallPrefab: {fileID: 7692220640868168301, guid: de70788c970f16940b9f517cf39194b0,
+    type: 3}
+  endPointPrefab: {fileID: 6314994090778056550, guid: 8ddb9b3dc215c2b4e97741bad9ced662,
+    type: 3}
+  mainCamera: {fileID: 963194227}
+  SimulationController: {fileID: 93153077}
+--- !u!1 &705507993
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 705507995}
+  - component: {fileID: 705507994}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &705507994
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 705507993}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+  m_Intensity: 1
+  m_Range: 10
+  m_SpotAngle: 30
+  m_InnerSpotAngle: 21.80208
+  m_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+    m_CullingMatrixOverride:
+      e00: 1
+      e01: 0
+      e02: 0
+      e03: 0
+      e10: 0
+      e11: 1
+      e12: 0
+      e13: 0
+      e20: 0
+      e21: 0
+      e22: 1
+      e23: 0
+      e30: 0
+      e31: 0
+      e32: 0
+      e33: 1
+    m_UseCullingMatrixOverride: 0
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 1
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+  m_UseBoundingSphereOverride: 0
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &705507995
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 705507993}
+  m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+  m_LocalPosition: {x: 0, y: 3, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!1 &963194225
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 963194228}
+  - component: {fileID: 963194227}
+  - component: {fileID: 963194226}
+  - component: {fileID: 963194229}
+  m_Layer: 0
+  m_Name: Main Camera
+  m_TagString: MainCamera
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!81 &963194226
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+--- !u!20 &963194227
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+  serializedVersion: 2
+  m_ClearFlags: 1
+  m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+  m_projectionMatrixMode: 1
+  m_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  m_FocalLength: 50
+  m_NormalizedViewPortRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  near clip plane: 0.3
+  far clip plane: 1000
+  field of view: 60
+  orthographic: 0
+  orthographic size: 5
+  m_Depth: -1
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingPath: -1
+  m_TargetTexture: {fileID: 0}
+  m_TargetDisplay: 0
+  m_TargetEye: 3
+  m_HDR: 1
+  m_AllowMSAA: 1
+  m_AllowDynamicResolution: 0
+  m_ForceIntoRT: 0
+  m_OcclusionCulling: 1
+  m_StereoConvergence: 10
+  m_StereoSeparation: 0.022
+--- !u!4 &963194228
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 1, z: -10}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &963194229
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 208230689b9953844af11c709edefaea, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  speed: 0.5
+  sensitivity: 1
diff --git a/PickUpandDelivery/Assets/Scenes/Offline_Decentralized.unity.meta b/PickUpandDelivery/Assets/Scenes/Offline_Decentralized.unity.meta
new file mode 100644
index 0000000000000000000000000000000000000000..b06ed74695c8997d984daefe1b020d57f50b511d
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scenes/Offline_Decentralized.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4d6a107688c48a745813862826c4aed6
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scenes/Online_Centralized.unity b/PickUpandDelivery/Assets/Scenes/Online_Centralized.unity
new file mode 100644
index 0000000000000000000000000000000000000000..9f265bb5b0a1beaa578f17a12abb7a06d2710d03
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scenes/Online_Centralized.unity
@@ -0,0 +1,442 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 705507994}
+  m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 11
+  m_GIWorkflowMode: 1
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 0
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 500
+    m_PVRBounces: 2
+    m_PVREnvironmentSampleCount: 500
+    m_PVREnvironmentReferencePointCount: 2048
+    m_PVRFilteringMode: 2
+    m_PVRDenoiserTypeDirect: 0
+    m_PVRDenoiserTypeIndirect: 0
+    m_PVRDenoiserTypeAO: 0
+    m_PVRFilterTypeDirect: 0
+    m_PVRFilterTypeIndirect: 0
+    m_PVRFilterTypeAO: 0
+    m_PVREnvironmentMIS: 0
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_UseShadowmask: 1
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &93153075
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 93153076}
+  - component: {fileID: 93153077}
+  - component: {fileID: 93153078}
+  m_Layer: 0
+  m_Name: SimulationController
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &93153076
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &93153077
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: e6bf74ca92d023a4dadefd09723b6558, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  agentParameters:
+    maxStep: 0
+  hasUpgradedFromAgentParameters: 1
+  MaxStep: 0
+  robotPrefab: {fileID: 1321468028730240, guid: 189960379d04e524eb29a18f9c0de39d,
+    type: 3}
+--- !u!114 &93153078
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5d1c4e0b1822b495aa52bc52839ecb30, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_BrainParameters:
+    VectorObservationSize: 1
+    NumStackedVectorObservations: 1
+    m_ActionSpec:
+      m_NumContinuousActions: 0
+      BranchSizes: 01000000
+    VectorActionSize: 01000000
+    VectorActionDescriptions: []
+    VectorActionSpaceType: 0
+    hasUpgradedBrainParametersWithActionSpec: 1
+  m_Model: {fileID: 0}
+  m_InferenceDevice: 0
+  m_BehaviorType: 0
+  m_BehaviorName: My Behavior
+  TeamId: 0
+  m_UseChildSensors: 1
+  m_UseChildActuators: 1
+  m_ObservableAttributeHandling: 0
+--- !u!1 &225044881
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 225044882}
+  - component: {fileID: 225044883}
+  m_Layer: 0
+  m_Name: Floor
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &225044882
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 225044881}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &225044883
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 225044881}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: a74be3508dbe36342858e20cec768f98, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  tileWallPrefab: {fileID: 7692220640868168301, guid: de70788c970f16940b9f517cf39194b0,
+    type: 3}
+  endPointPrefab: {fileID: 6314994090778056550, guid: 8ddb9b3dc215c2b4e97741bad9ced662,
+    type: 3}
+  mainCamera: {fileID: 963194227}
+  SimulationController: {fileID: 93153077}
+--- !u!1 &705507993
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 705507995}
+  - component: {fileID: 705507994}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &705507994
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 705507993}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+  m_Intensity: 1
+  m_Range: 10
+  m_SpotAngle: 30
+  m_InnerSpotAngle: 21.80208
+  m_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+    m_CullingMatrixOverride:
+      e00: 1
+      e01: 0
+      e02: 0
+      e03: 0
+      e10: 0
+      e11: 1
+      e12: 0
+      e13: 0
+      e20: 0
+      e21: 0
+      e22: 1
+      e23: 0
+      e30: 0
+      e31: 0
+      e32: 0
+      e33: 1
+    m_UseCullingMatrixOverride: 0
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 1
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+  m_UseBoundingSphereOverride: 0
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &705507995
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 705507993}
+  m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+  m_LocalPosition: {x: 0, y: 3, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!1 &963194225
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 963194228}
+  - component: {fileID: 963194227}
+  - component: {fileID: 963194226}
+  - component: {fileID: 963194229}
+  m_Layer: 0
+  m_Name: Main Camera
+  m_TagString: MainCamera
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!81 &963194226
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+--- !u!20 &963194227
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+  serializedVersion: 2
+  m_ClearFlags: 1
+  m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+  m_projectionMatrixMode: 1
+  m_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  m_FocalLength: 50
+  m_NormalizedViewPortRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  near clip plane: 0.3
+  far clip plane: 1000
+  field of view: 60
+  orthographic: 0
+  orthographic size: 5
+  m_Depth: -1
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingPath: -1
+  m_TargetTexture: {fileID: 0}
+  m_TargetDisplay: 0
+  m_TargetEye: 3
+  m_HDR: 1
+  m_AllowMSAA: 1
+  m_AllowDynamicResolution: 0
+  m_ForceIntoRT: 0
+  m_OcclusionCulling: 1
+  m_StereoConvergence: 10
+  m_StereoSeparation: 0.022
+--- !u!4 &963194228
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 1, z: -10}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &963194229
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 208230689b9953844af11c709edefaea, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  speed: 0.5
+  sensitivity: 1
diff --git a/PickUpandDelivery/Assets/Scenes/Online_Centralized.unity.meta b/PickUpandDelivery/Assets/Scenes/Online_Centralized.unity.meta
new file mode 100644
index 0000000000000000000000000000000000000000..149175f1f35c979cdb54888a570415ea75cf6b23
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scenes/Online_Centralized.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: c22ac62bd8f63044a827178aa567b823
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scenes/Online_Decentralized.unity b/PickUpandDelivery/Assets/Scenes/Online_Decentralized.unity
new file mode 100644
index 0000000000000000000000000000000000000000..64deb18a4961b32fcff61046487b206d12de7d29
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scenes/Online_Decentralized.unity
@@ -0,0 +1,407 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 705507994}
+  m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 11
+  m_GIWorkflowMode: 1
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 0
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 500
+    m_PVRBounces: 2
+    m_PVREnvironmentSampleCount: 500
+    m_PVREnvironmentReferencePointCount: 2048
+    m_PVRFilteringMode: 2
+    m_PVRDenoiserTypeDirect: 0
+    m_PVRDenoiserTypeIndirect: 0
+    m_PVRDenoiserTypeAO: 0
+    m_PVRFilterTypeDirect: 0
+    m_PVRFilterTypeIndirect: 0
+    m_PVRFilterTypeAO: 0
+    m_PVREnvironmentMIS: 0
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_UseShadowmask: 1
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &93153075
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 93153076}
+  - component: {fileID: 93153077}
+  m_Layer: 0
+  m_Name: SimulationController
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &93153076
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &93153077
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 93153075}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: a6033bfb5a3a1f747b8a528a445711a6, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  robotPrefab: {fileID: 1321468028730240, guid: 5b62ae8d6539a4637bba603a6015fe86,
+    type: 3}
+--- !u!1 &225044881
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 225044882}
+  - component: {fileID: 225044883}
+  m_Layer: 0
+  m_Name: Floor
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &225044882
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 225044881}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &225044883
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 225044881}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: a74be3508dbe36342858e20cec768f98, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  tileWallPrefab: {fileID: 7692220640868168301, guid: de70788c970f16940b9f517cf39194b0,
+    type: 3}
+  endPointPrefab: {fileID: 6314994090778056550, guid: 8ddb9b3dc215c2b4e97741bad9ced662,
+    type: 3}
+  mainCamera: {fileID: 963194227}
+  SimulationController: {fileID: 93153077}
+--- !u!1 &705507993
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 705507995}
+  - component: {fileID: 705507994}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &705507994
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 705507993}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+  m_Intensity: 1
+  m_Range: 10
+  m_SpotAngle: 30
+  m_InnerSpotAngle: 21.80208
+  m_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+    m_CullingMatrixOverride:
+      e00: 1
+      e01: 0
+      e02: 0
+      e03: 0
+      e10: 0
+      e11: 1
+      e12: 0
+      e13: 0
+      e20: 0
+      e21: 0
+      e22: 1
+      e23: 0
+      e30: 0
+      e31: 0
+      e32: 0
+      e33: 1
+    m_UseCullingMatrixOverride: 0
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 1
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+  m_UseBoundingSphereOverride: 0
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &705507995
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 705507993}
+  m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+  m_LocalPosition: {x: 0, y: 3, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!1 &963194225
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 963194228}
+  - component: {fileID: 963194227}
+  - component: {fileID: 963194226}
+  - component: {fileID: 963194229}
+  m_Layer: 0
+  m_Name: Main Camera
+  m_TagString: MainCamera
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!81 &963194226
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+--- !u!20 &963194227
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+  serializedVersion: 2
+  m_ClearFlags: 1
+  m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+  m_projectionMatrixMode: 1
+  m_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  m_FocalLength: 50
+  m_NormalizedViewPortRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  near clip plane: 0.3
+  far clip plane: 1000
+  field of view: 60
+  orthographic: 0
+  orthographic size: 5
+  m_Depth: -1
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingPath: -1
+  m_TargetTexture: {fileID: 0}
+  m_TargetDisplay: 0
+  m_TargetEye: 3
+  m_HDR: 1
+  m_AllowMSAA: 1
+  m_AllowDynamicResolution: 0
+  m_ForceIntoRT: 0
+  m_OcclusionCulling: 1
+  m_StereoConvergence: 10
+  m_StereoSeparation: 0.022
+--- !u!4 &963194228
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 1, z: -10}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &963194229
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 208230689b9953844af11c709edefaea, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  speed: 0.5
+  sensitivity: 1
diff --git a/PickUpandDelivery/Assets/Scenes/Online_Decentralized.unity.meta b/PickUpandDelivery/Assets/Scenes/Online_Decentralized.unity.meta
new file mode 100644
index 0000000000000000000000000000000000000000..952bd1e9e110583d94b471a30ff4ddd69f4aee7d
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scenes/Online_Decentralized.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9fc0d4010bbf28b4594072e72b8655ab
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts.meta b/PickUpandDelivery/Assets/Scripts.meta
new file mode 100644
index 0000000000000000000000000000000000000000..976748fdba857f0df5545bc22656f99324c1c1c1
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: eeec7c13660dbba42b8a8df0a27ca542
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common.meta b/PickUpandDelivery/Assets/Scripts/Common.meta
new file mode 100644
index 0000000000000000000000000000000000000000..420236084e42050a641b19f7fb22c5fbc4f369f8
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: bb96f31e5d7da9e4d9750f484538c33b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Robot.meta b/PickUpandDelivery/Assets/Scripts/Common/Robot.meta
new file mode 100644
index 0000000000000000000000000000000000000000..c31fb5ac36f8ae0c17fb802fe7e098b3c460fc47
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Robot.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 961c621f85b64a8cbdfc0f1130b7735d
+timeCreated: 1628838762
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Robot/IRobot.cs b/PickUpandDelivery/Assets/Scripts/Common/Robot/IRobot.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eaa09010e417ae65c6e35fe66df8e5bc87ff03be
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Robot/IRobot.cs
@@ -0,0 +1,18 @@
+using Common.SimulationManager;
+using Common.Warehouse;
+using UnityEngine;
+
+namespace Common.Robot
+{
+    public interface IRobot
+    {
+        ISimulationManager  simulationManager { get; set; }
+        Task assignedTask { get; set; }
+        
+        //METHODS
+        MonoBehaviour GetMonoBehaviour();
+        void AssignTask(Task task);
+        void PickUp();
+        Task Deliver();
+    }
+}
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Robot/IRobot.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Robot/IRobot.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..7c04a5f287b558ba7d72f9cb9873793b2adfe09f
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Robot/IRobot.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5ab51108ccb54e19a3721df3d82ce8f3
+timeCreated: 1628601434
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Robot/RobotMethods.cs b/PickUpandDelivery/Assets/Scripts/Common/Robot/RobotMethods.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1f4c95db81bad6863742785680ed82b081ae6308
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Robot/RobotMethods.cs
@@ -0,0 +1,255 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System;
+using System.Linq;
+using Common.Warehouse;
+using Unity.MLAgents.Actuators;
+using Unity.MLAgents.Sensors;
+using UnityEngine;
+
+namespace Common.Robot
+{
+    /// <summary>
+    /// Static class <c> RobotMethods </c> contains methods used by classes implementing the <c> IRobot </c> interface.
+    /// - InitializeRobotAtStart(IRobot robot) draws robot using initial nodes and sets parameters for collision detection
+    /// - UpdatePosition(IRobot robot): updates position and rotation for robot
+    /// - CollisionEvent(IRobot robot): determines what happens when a robot collides
+    /// - AssignTask(IRobot robot, Task task): assign task to robot, color robot in task color
+    /// - PickUp(IRobot robot): pick up: add cross on top of robot
+    /// - Deliver(IRobot robot): deliver task: remove cross, reset color of robot
+    /// - CollectObservations(IRobot robot, VectorSensor sensor): collect observations when robot is agent
+    /// - OnActionReceived(IRobot robot, ActionBuffers actionBuffers,  Color defaultColor): do action when robot is agent
+    ///
+    /// Private methods:
+    /// - RemoveTask(IRobot robot, Color defaultColor): removes tasks for robot, resets color and removes cross
+    /// - ActivateCross(IRobot robot, Task assignedTask): activate cross on robot using complementary color of task
+    /// - DeactivateCross(IRobot robot): deactivate cross
+    /// </summary>
+    public static class RobotMethods
+    {
+        /// <summary>
+        /// Draw robot at start.
+        /// </summary>
+        /// <param name="robot"></param>
+        public static void InitializeRobotAtStart(IRobot robot)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            // draw robot 
+            robotMB.transform.localScale = robot.simulationManager.SIZE * robot.simulationManager.SCALEROBOT * Vector3.one;
+            robotMB.transform.localPosition = new Vector3(
+                robot.simulationManager.GetCurrentNode(robotMB.gameObject.GetInstanceID()).GridPosition.Row * robot.simulationManager.SIZE,
+                robotMB.transform.localScale.y / 2 + robot.simulationManager.YROBOTFLOATING, // put on tile + floating 
+                robot.simulationManager.GetCurrentNode(robotMB.gameObject.GetInstanceID()).GridPosition.Column * robot.simulationManager.SIZE);
+            robotMB.transform.eulerAngles =
+                new Vector3(0, robot.simulationManager.GetCurrentNode(robotMB.gameObject.GetInstanceID()).Degrees, 0);
+
+            // add rigidbody and collider for collision detection
+            // change size of boxcollider otherwise there is a collision when 
+            robotMB.gameObject.AddComponent<Rigidbody>();
+            robotMB.gameObject.GetComponent<Rigidbody>().useGravity = false;
+            robotMB.gameObject.GetComponent<Rigidbody>().isKinematic = false;
+            robotMB.gameObject.AddComponent<BoxCollider>().isTrigger = true;
+
+            // deactivate cross on top of robot
+            DeactivateCross(robot);
+        }
+
+        /// <summary>
+        /// Update robot position and rotation.
+        /// </summary>
+        /// <param name="robot"></param>
+        public static void UpdatePosition(IRobot robot)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            // only update positions robot if there haven't been detected any collisions
+            if (!robot.simulationManager.collisions)
+            {
+                var maxDistance = robot.simulationManager.SIZE * Time.fixedDeltaTime;
+                var maxDegs = robot.simulationManager.parameters.Rotation * Time.fixedDeltaTime;
+
+                robotMB.transform.localPosition = Vector3.MoveTowards(
+                    robotMB.transform.localPosition,
+                    new Vector3(
+                        robot.simulationManager.GetCurrentNode(robotMB.gameObject.GetInstanceID()).GridPosition.Row *
+                        robot.simulationManager.SIZE,
+                        robotMB.transform.localPosition.y,
+                        robot.simulationManager.GetCurrentNode(robotMB.gameObject.GetInstanceID()).GridPosition.Column *
+                        robot.simulationManager.SIZE),
+                    maxDistance
+                );
+
+                robotMB.transform.rotation = Quaternion.RotateTowards(
+                    robotMB.transform.rotation,
+                    Quaternion.Euler(0, robot.simulationManager.GetCurrentNode(robotMB.gameObject.GetInstanceID()).Degrees, 0),
+                    maxDegs
+                );
+            }
+        }
+        
+        /// <summary>
+        /// Method used when robot is decision maker.
+        /// Collect observations and add to sensor.
+        /// An observation for one robot consists of a row, a column and a number of degrees.
+        /// </summary>
+        /// <param name="robot"></param>
+        /// <param name="sensor"></param>
+        public static void CollectObservations(IRobot robot, VectorSensor sensor)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            sensor.AddObservation(robotMB.gameObject.GetInstanceID());
+            var node = robot.simulationManager.GetCurrentNode(robotMB.gameObject.GetInstanceID());
+            sensor.AddObservation(node.GridPosition.Row);
+            sensor.AddObservation(node.GridPosition.Column);
+            sensor.AddObservation(node.Degrees);
+        }
+        
+        /// <summary>
+        /// Method used when Robot is decision maker.
+        /// When an action is received the position and location of the robot is updated and if applicable
+        /// pickup or delivery action is invoked.
+        /// </summary>
+        /// <param name="robot"></param>
+        /// <param name="actionBuffers"></param>
+        public static void OnActionReceived(IRobot robot, ActionBuffers actionBuffers,  Color defaultColor)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            var individualActions = actionBuffers.DiscreteActions.ToArray();
+            var row = individualActions[0];
+            var column = individualActions[1];
+            var degrees = individualActions[2];
+            var pickup = individualActions[3];
+            var deliver = individualActions[4];
+            Debug.Log(String.Format("Robot {0} received action [{1}, {2}, {3}, {4}, {5}]",
+                robotMB.gameObject.GetInstanceID(), row, column, degrees, pickup, deliver));
+            robot.simulationManager.currentNodes[robotMB.gameObject.GetInstanceID()] = new Node(new Position(row, column), degrees);
+
+            if (pickup == 1)
+            {
+                PickUp(robot);
+            }
+
+            if (deliver == 1)
+            {
+                // remove task in simulation manager
+                robot.simulationManager.RemoveTask(robot.assignedTask);
+                
+                // remove task for robot
+                Deliver(robot, defaultColor);
+                
+                // create new task
+                robot.simulationManager.AddNewTask();
+            }
+        }
+
+        /// <summary>
+        /// After an collision event, simulationManager has to be notified.
+        /// </summary>
+        /// <param name="robot"></param>
+        public static void CollisionEvent(IRobot robot)
+        {
+            robot.simulationManager.collisions = true;
+        }
+        
+        /// <summary>
+        /// Assign task to robot. Color robot using task color. 
+        /// </summary>
+        /// <param name="task"> a Task object</param>
+        public static void AssignTask(IRobot robot, Task task)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            robot.assignedTask = task;
+            robotMB.transform.Find("Agent").Find("AgentCube_Blue").GetComponent<Renderer>().material.color = 
+                robot.simulationManager.currentTasks[task];
+        }
+        
+        /// <summary>
+        /// Remove assigned task for robot. Reset color to default and deactivate cross.
+        /// </summary>
+        private static void RemoveTask(IRobot robot, Color defaultColor)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            robot.assignedTask = null;
+            robotMB.transform.Find("Agent").Find("AgentCube_Blue").GetComponent<Renderer>().material.color = defaultColor;
+                
+            // deactivate cross on top of robot
+            DeactivateCross(robot);
+        }
+        
+        /// <summary>
+        /// After pick up, a cross is added on top of the agent. We use the complementary color of the task color.
+        /// </summary>
+        /// <exception cref="Exception"> if robot is not at the pick up position</exception>
+        public static void PickUp(IRobot robot)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            if (! robot.assignedTask.PickUp.Equals(robot.simulationManager.currentNodes[robotMB.gameObject.GetInstanceID()].GridPosition))
+            {
+                throw new Exception("robot " + robotMB.gameObject.GetInstanceID() + "pickup incorrect position: " 
+                                    + robot.simulationManager.currentNodes[robotMB.gameObject.GetInstanceID()].GridPosition);
+            }
+        
+            // activate cross on top of robot
+            ActivateCross(robot, robot.assignedTask);
+        }
+        
+        /// <summary>
+        /// After delivering a task, the assigned task must be removed and the robot's color has to be resetted to defaultcolor
+        /// and the cross has to be removed.
+        /// </summary>
+        /// <param name="robot"></param>
+        /// <param name="defaultColor"></param>
+        /// <returns></returns>
+        /// <exception cref="Exception">if robot is not at the delivery position</exception>
+        public static Task Deliver(IRobot robot, Color defaultColor)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            if (! robot.assignedTask.Delivery.Equals(robot.simulationManager.currentNodes[robotMB.gameObject.GetInstanceID()].GridPosition))
+            {
+                throw new Exception("robot " + robotMB.gameObject.GetInstanceID() + "delivery incorrect position: " 
+                                    + robot.simulationManager.currentNodes[robotMB.gameObject.GetInstanceID()].GridPosition);
+            }
+        
+            var taskToReturn = robot.assignedTask;
+            RemoveTask(robot, defaultColor);
+            return taskToReturn;
+        }
+
+        /// <summary>
+        /// Deactivate cross on top of robot.
+        /// </summary>
+        /// <param name="robot"></param>
+        private static void DeactivateCross(IRobot robot)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            robotMB.transform.Find("Agent").Find("AgentCube_Blue").Find("x1").gameObject.SetActive(false);
+            robotMB.transform.Find("Agent").Find("AgentCube_Blue").Find("x2").gameObject.SetActive(false);
+        }
+        
+        /// <summary>
+        /// Activate cross on top of robot and color robot in complementary color of assigned task color.
+        /// </summary>
+        private static void ActivateCross(IRobot robot, Task assignedTask)
+        {
+            MonoBehaviour robotMB = robot.GetMonoBehaviour();
+            robotMB.transform.Find("Agent").Find("AgentCube_Blue").Find("x1").gameObject.SetActive(true);
+            robotMB.transform.Find("Agent").Find("AgentCube_Blue").Find("x2").gameObject.SetActive(true);
+            Color negativeColor = UtilityMethods.GetNegativeColor(robot.simulationManager.currentTasks[assignedTask]);
+            robotMB.transform.Find("Agent").Find("AgentCube_Blue").Find("x1").GetComponent<Renderer>().material.color = negativeColor;
+            robotMB.transform.Find("Agent").Find("AgentCube_Blue").Find("x2").GetComponent<Renderer>().material.color = negativeColor;
+        }
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Robot/RobotMethods.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Robot/RobotMethods.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..e93eb39c778b1a53d5e604321ad00f3a33e9e6ad
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Robot/RobotMethods.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 94d94501e73f4450bbb36cfedaeb7ec8
+timeCreated: 1628838963
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Scripts.meta b/PickUpandDelivery/Assets/Scripts/Common/Scripts.meta
new file mode 100644
index 0000000000000000000000000000000000000000..e5ce89abb67f1d5865e70e9a3c5562bd3f722eff
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Scripts.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 7f30b9cb10964db1bf69c766b3bd9a94
+timeCreated: 1628838540
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Scripts/CameraMoveScript.cs b/PickUpandDelivery/Assets/Scripts/Common/Scripts/CameraMoveScript.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dceecb4d57b02b61de703c0e1c938d7e7348a5d7
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Scripts/CameraMoveScript.cs
@@ -0,0 +1,66 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using UnityEngine;
+
+namespace Common.Scripts
+{
+    public class CameraMoveScript: MonoBehaviour
+    {
+        [SerializeField] float speed = 0.5f;
+        [SerializeField] float sensitivity = 1.0f;
+
+        Camera cam;
+        Vector3 anchorPoint;
+        Quaternion anchorRot;
+
+        private void Awake()
+        {
+            cam = GetComponent<Camera>();
+        }
+
+        void FixedUpdate()
+        {
+            Vector3 move = Vector3.zero;
+            if (Input.GetKey(KeyCode.W))
+                move += Vector3.forward * speed;
+            if (Input.GetKey(KeyCode.S))
+                move -= Vector3.forward * speed;
+            if (Input.GetKey(KeyCode.D))
+                move += Vector3.right * speed;
+            if (Input.GetKey(KeyCode.A))
+                move -= Vector3.right * speed;
+            if (Input.GetKey(KeyCode.E))
+                move += Vector3.up * speed;
+            if (Input.GetKey(KeyCode.Q))
+                move -= Vector3.up * speed;
+            transform.Translate(move);
+
+            if (Input.GetMouseButtonDown(1))
+            {
+                anchorPoint = new Vector3(Input.mousePosition.y, -Input.mousePosition.x);
+                anchorRot = transform.rotation;
+            }
+            if (Input.GetMouseButton(1))
+            {
+                Quaternion rot = anchorRot;
+                Vector3 dif = anchorPoint - new Vector3(Input.mousePosition.y, -Input.mousePosition.x);
+                rot.eulerAngles += dif * sensitivity;
+                transform.rotation = rot;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Scripts/CameraMoveScript.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Scripts/CameraMoveScript.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..532e4d444ac4a2869182d28986df5e30ec4fe2ca
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Scripts/CameraMoveScript.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 208230689b9953844af11c709edefaea
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Scripts/EndPoint.cs b/PickUpandDelivery/Assets/Scripts/Common/Scripts/EndPoint.cs
new file mode 100644
index 0000000000000000000000000000000000000000..01952c7d4970b942935ac255d76afe0640ec20d2
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Scripts/EndPoint.cs
@@ -0,0 +1,72 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using Common.SimulationManager;
+using Common.Warehouse;
+using UnityEngine;
+
+namespace Common.Scripts
+{
+    /// <summary>
+    /// Script <c> EndPoint </c> takes care of coloring the endpoints and contains methods
+    /// - ResetColors(): changes color back to default, removes cross on top
+    /// - SetAsPickUp(Color taskColor): changes color to taskColor, removes cross on top
+    /// - SetAsDelivery(Color taskColor): changes color to taskColor, adds cross on top in complementary color of taskColor
+    /// </summary>
+
+    public class EndPoint : MonoBehaviour
+    {
+        public ISimulationManager simulationManager;
+    
+        // endpoint as default (not pickup, not delivery)
+        public void ResetColors()
+        {
+            gameObject.GetComponent<Renderer>().material.color = simulationManager.colorEndPoint;
+            transform.Find("x1").gameObject.SetActive(false);
+            transform.Find("x2").gameObject.SetActive(false);
+            transform.Find("text").gameObject.SetActive(false);
+        }
+
+        //set as pick up point for a certain task (color and release time)
+        public void SetAsPickUp(Task task)
+        {
+            Color taskColor = simulationManager.currentTasks[task];
+            gameObject.GetComponent<Renderer>().material.color = taskColor;
+            transform.Find("x1").gameObject.SetActive(false);
+            transform.Find("x2").gameObject.SetActive(false);
+            if (task.ReleaseTime != 0)
+            {
+                transform.Find("text").gameObject.SetActive(true);
+                transform.Find("text").gameObject.GetComponent<TextMesh>().text = task.ReleaseTime.ToString();
+                transform.Find("text").gameObject.GetComponent<MeshRenderer>().material.color =
+                    UtilityMethods.GetNegativeColor(taskColor);
+            }
+        }
+    
+        // set as delivery point for a certain task (color): there will be an x drawn on top
+        public void SetAsDelivery(Task task)
+        {
+            Color taskColor = simulationManager.currentTasks[task];
+            gameObject.GetComponent<Renderer>().material.color = taskColor;
+            transform.Find("x1").gameObject.SetActive(true);
+            transform.Find("x2").gameObject.SetActive(true);
+            transform.Find("text").gameObject.SetActive(false);
+            transform.Find("x1").GetComponent<Renderer>().material.color = UtilityMethods.GetNegativeColor(taskColor);
+            transform.Find("x2").GetComponent<Renderer>().material.color = UtilityMethods.GetNegativeColor(taskColor);
+        }
+
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Scripts/EndPoint.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Scripts/EndPoint.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..1f523e30802ecd593c4dbc9e8c5bccd0f6bcb03e
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Scripts/EndPoint.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f3dcff173f5992d4db93b38be21d0d1d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Scripts/Floor.cs b/PickUpandDelivery/Assets/Scripts/Common/Scripts/Floor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f42f783961dc28d5c8678fa41534c878444e0cb5
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Scripts/Floor.cs
@@ -0,0 +1,154 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System;
+using Common.SimulationManager;
+using Common.Warehouse;
+using UnityEngine;
+
+namespace Common.Scripts
+{
+    /// <summary>
+    /// Script <c> Floor </c> sets up the floor
+    /// - draws tiles, walls, endpoints, parking
+    /// - draws initial tasks (pick up and delivery)
+    /// and sets up the camera
+    /// </summary>
+
+    public class Floor : MonoBehaviour
+    {
+        [SerializeField] 
+        private GameObject tileWallPrefab = default; // prefab for tiles and walls
+        [SerializeField] 
+        private GameObject endPointPrefab = default; // prefab for endPoints
+        [SerializeField] 
+        private Camera mainCamera = default; 
+        [SerializeField]
+        private MonoBehaviour SimulationController = default;// add gameobject SimulationController in editor
+
+        private ISimulationManager simulationManager;
+    
+        // Start is called before the first frame update
+        void Start()
+        {
+            simulationManager = SimulationController as ISimulationManager;
+
+            // draw tiles and walls (initial status, no tasks)
+            for (var row = 0; row < simulationManager.parameters.Matrix.Length; row++)
+            {
+                for (var column = 0; column < simulationManager.parameters.Matrix[0].Length; column++)
+                {
+                    GameObject cube; 
+
+                    if (simulationManager.parameters.Matrix[row][column] == simulationManager.parameters.CodeWall) //wall
+                    {
+                        cube = Instantiate(tileWallPrefab);
+                        cube.GetComponent<Renderer>().material.color = simulationManager.colorWall;
+                    }
+                
+                    else if (simulationManager.parameters.Matrix[row][column] == simulationManager.parameters.CodeTile) // normal tile
+                    {
+                        cube = Instantiate(tileWallPrefab);
+                        cube.GetComponent<Renderer>().material.color = simulationManager.colorTile;
+                    }
+
+                    else if (simulationManager.parameters.Matrix[row][column] == simulationManager.parameters.CodeEndPoint) //  end point
+                    {
+                        cube = Instantiate(endPointPrefab);
+                        cube.GetComponent<EndPoint>().simulationManager = simulationManager;
+                        cube.GetComponent<EndPoint>().ResetColors();
+                        simulationManager.endPoints[new Position(row, column)] = cube;
+                    }
+                    else //parking
+                    {
+                        cube = Instantiate(tileWallPrefab);
+                        cube.GetComponent<Renderer>().material.color = simulationManager.colorParking;
+                    }
+                
+                    // we want to detect collisions between robots and walls
+                    cube.GetComponent<BoxCollider>().enabled =
+                        simulationManager.parameters.Matrix[row][column] == simulationManager.parameters.CodeWall;
+                    cube.GetComponent<BoxCollider>().isTrigger =
+                        simulationManager.parameters.Matrix[row][column] == simulationManager.parameters.CodeWall;
+                
+                    // add size tile/wall
+                    cube.transform.localScale = new Vector3(simulationManager.SIZE,
+                        simulationManager.parameters.Matrix[row][column] == simulationManager.parameters.CodeWall ? simulationManager.SIZE : 0.2f,
+                        simulationManager.SIZE);
+                
+                    cube.transform.position = new Vector3(row*simulationManager.SIZE,
+                        0, column*simulationManager.SIZE);
+
+                    cube.transform.parent = gameObject.transform;
+                }
+            }
+            // add colors to current tasks
+            //TODO: what with tasks from list? -> they might overlap
+            foreach (var task in simulationManager.currentTasks)
+            {
+                var pickUp = task.Key.PickUp;
+                var delivery = task.Key.Delivery;
+            
+                simulationManager.endPoints[pickUp].GetComponent<EndPoint>().SetAsPickUp(task.Key);
+                simulationManager.endPoints[delivery].GetComponent<EndPoint>().SetAsDelivery(task.Key);
+            }
+        
+            SetCamera();
+        }
+
+        private void SetCamera()
+        {
+            var maxbound = Math.Max(simulationManager.parameters.Matrix.Length, simulationManager.parameters.Matrix[0].Length);
+            mainCamera.gameObject.transform.position =
+                new Vector3(simulationManager.SIZE * maxbound + simulationManager.SIZE, 
+                    simulationManager.SIZE * maxbound, - simulationManager.SIZE);
+            mainCamera.gameObject.transform.LookAt(gameObject.GetBoundsWithChildren().center);
+        }
+    }
+
+    public static class UnityExtensions
+    {
+        public static Bounds GetBoundsWithChildren(this GameObject gameObject)
+        {
+            // GetComponentsInChildren() also returns components on gameobject which you call it on
+            // you don't need to get component specially on gameObject
+            Renderer[] renderers = gameObject.GetComponentsInChildren<Renderer>();
+
+            // If renderers.Length = 0, you'll get OutOfRangeException
+            Bounds bounds = renderers.Length > 0 ? renderers[0].bounds : new Bounds();
+
+            // Start from 1 because we've already encapsulated renderers[0]
+            for (int i = 1; i < renderers.Length; i++)
+            {
+                if (renderers[i].enabled)
+                {
+                    bounds.Encapsulate(renderers[i].bounds);
+                }
+            }
+
+            return bounds;
+        }
+
+        public static void FocusOn(this Camera camera, GameObject focusedObject, float marginPercentage)
+        {
+            Bounds bounds = focusedObject.GetBoundsWithChildren();
+            float maxExtent = bounds.extents.magnitude;
+            float minDistance = (maxExtent * marginPercentage) / Mathf.Sin(Mathf.Deg2Rad * camera.fieldOfView / 2f);
+            camera.transform.position = focusedObject.transform.position - Vector3.forward * minDistance;
+            camera.nearClipPlane = minDistance - maxExtent;
+        }
+    }
+}
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Scripts/Floor.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Scripts/Floor.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..b0c33767854c37e49af831d753810e7981dd87c3
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Scripts/Floor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a74be3508dbe36342858e20cec768f98
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SideChannels.meta b/PickUpandDelivery/Assets/Scripts/Common/SideChannels.meta
new file mode 100644
index 0000000000000000000000000000000000000000..fe09df17e6f2a481f6867d37b24c0acaefde0dae
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SideChannels.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f0be1d97d4954270a69446174d8b05e2
+timeCreated: 1628838678
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SideChannels/EnvSideChannel.cs b/PickUpandDelivery/Assets/Scripts/Common/SideChannels/EnvSideChannel.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dfbd17e817abffaef70f4ba6783981a6801d30a2
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SideChannels/EnvSideChannel.cs
@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System;
+using Unity.MLAgents.SideChannels;
+
+namespace Common.SideChannels
+{
+    /// <summary>
+    /// SideChannel used for sending initial information on environment to Python client.
+    /// </summary>
+
+    public class EnvSideChannel : SideChannel
+    {
+        public EnvSideChannel()
+        {
+            ChannelId = new Guid("621f0a70-4f87-11ea-a6bf-784f4387d1f7");
+        }
+
+        protected override void OnMessageReceived(IncomingMessage msg)
+        {
+            //var receivedString = msg.ReadString();
+            //Debug.LogError("From Python : " + receivedString);
+        }
+
+        public void SendEnv(string message)
+        {
+            var stringToSend = message;
+            using (var msgOut = new OutgoingMessage())
+            {
+                msgOut.WriteString(stringToSend);
+                QueueMessageToSend(msgOut);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SideChannels/EnvSideChannel.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/SideChannels/EnvSideChannel.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..7524541d0ada964c61a8bb7166de5742f326606b
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SideChannels/EnvSideChannel.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 30ce75aad8425a644b59307793a9af24
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SideChannels/TaskSideChannel.cs b/PickUpandDelivery/Assets/Scripts/Common/SideChannels/TaskSideChannel.cs
new file mode 100644
index 0000000000000000000000000000000000000000..067346e475ab7a23e0c537e7f5b60f003d06c7cc
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SideChannels/TaskSideChannel.cs
@@ -0,0 +1,68 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System;
+using Common.SimulationManager;
+using Common.Warehouse;
+using Newtonsoft.Json;
+using Unity.MLAgents.SideChannels;
+using UnityEngine;
+
+namespace Common.SideChannels
+{
+    /// <summary>
+    /// SideChannel used for sending and receiving information on tasks.
+    /// - sends initial information on tasks (initial tasks)
+    /// - receives information on assigned tasks
+    /// </summary>
+
+    public class TaskSideChannel : SideChannel
+    {
+        private class TaskAssignment
+        {
+            public Task Task = null;
+            public int InstanceId = 0;
+        }
+
+        public ISimulationManager SimulationManager;
+    
+        public TaskSideChannel()
+        {
+            ChannelId = new Guid("c11ab982-82b8-4194-b387-3bd0fe9ebdc7");
+        }
+
+        protected override void OnMessageReceived(IncomingMessage msg)
+        {
+            var receivedString = msg.ReadString();
+            Debug.Log("message received");
+            var newTask = JsonConvert.DeserializeObject<TaskAssignment>(receivedString);
+            if (newTask != null)
+            {
+                SimulationManager.AssignTask(newTask.Task, newTask.InstanceId);
+            }
+        }
+
+        public void SendEnv(string message)
+        {
+            var stringToSend = message;
+            using (var msgOut = new OutgoingMessage())
+            {
+                msgOut.WriteString(stringToSend);
+                QueueMessageToSend(msgOut);
+            }
+        }
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SideChannels/TaskSideChannel.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/SideChannels/TaskSideChannel.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..607eb97952f2026887a605686f0e9d79ff05ee69
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SideChannels/TaskSideChannel.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 15225950aa7307b4086f7d0a544ca3c1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SimulationManager.meta b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager.meta
new file mode 100644
index 0000000000000000000000000000000000000000..21f8c0cbd4b13a7977cf237a1d1b69f3f1198b50
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e59645e254214d8995295041954a75cf
+timeCreated: 1628838787
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/ISimulationManager.cs b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/ISimulationManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b2b6b7c410feedcc0003d2a2124240357226e9c7
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/ISimulationManager.cs
@@ -0,0 +1,89 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System.Collections.Generic;
+using Common.SideChannels;
+using Common.Warehouse;
+using UnityEngine;
+
+namespace Common.SimulationManager
+{
+    public interface ISimulationManager
+    {
+        // PARAMETERS 
+        // parameters of warehouse
+        WarehouseParameters parameters { get; set; }
+        // offline or online
+        bool online { get; }
+        // input warehouse and tasks
+        string warehouseConfigFile { get; }
+        string tasksListFile { get; }
+        
+        // COLORS
+        // colors for tiles and walls
+        Color colorWall { get; }
+        Color colorTile { get; }
+        Color colorEndPoint { get; }
+        Color colorParking { get; }
+
+        // colors used for tasks and the robots that have been assigned these tasks: initially colors will be created
+        // and stored in notAssignedColors, when assigned to a task, color will be moved to assignedColors
+        HashSet<Color> assignedColors { get; set; }
+        HashSet<Color> notAssignedColors { get; set; }
+
+        // ENDPOINTS
+        // dictionary containing all endpoints
+        // every endpointposition points to a gameobject, gameobject will be setup by the Floor script
+        Dictionary<Position, GameObject> endPoints { get; set; }
+
+        // TASKS
+        // at every timestep there will be max numberOfTasks tasks that have to be assigned (by the python code)
+        // current available tasks and their assigned colors: these are the tasks to remain to be assigned to robots
+        Dictionary<Task, Color> currentTasks { get; set; }
+        // when using a predefined set of tasks, the tasks that are not yet in currentTasks are sstored in remainingTasks
+        Task[] remainingTasks { get; set; }
+
+        // ROBOTS
+        // For every robot the current node where he is going, i.e. the next action 
+        Dictionary<int, Node> currentNodes { get; }
+        // unity instance ID and corresponding game object
+        Dictionary<int, GameObject> robotGameObjects { get; set; }
+
+        // ENVIRONMENT VARIABLES
+        // check for collisions
+        bool collisions { get; set; }
+        // observation- and actionsize
+        int observationSize { get; }
+        int actionSize { get; }
+        // environment variables for drawing
+        float SIZE { get; } // Size of square/tile, this is kept constant to avoid having to change camera perspective
+        float SCALEROBOT { get; } // Ratio robot to tile, for drawing robot
+        float YROBOTFLOATING { get; } // Floating y value robot, for drawing robot
+        
+        //SIDE CHANNELS
+        EnvSideChannel envChannel { get; set; }
+        TaskSideChannel taskChannel { get; set; }
+
+
+        //METHODS
+        Node GetCurrentNode(int instanceID);
+        void RemoveTask(Task task);
+        void AddNewTask();
+        void AssignTask(Task task, int instanceID);
+        MonoBehaviour GetMonoBehaviour(); 
+    }
+}
+
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/ISimulationManager.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/ISimulationManager.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..c921a4853f3f02bbaf6ade3d8564793494197b64
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/ISimulationManager.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b03b437f56df4d82a29a944ac1b111ae
+timeCreated: 1628603152
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/SimulationManagerMethods.cs b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/SimulationManagerMethods.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a178dbd9b5fab9a5b93c45ad0c28508ef10c64cb
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/SimulationManagerMethods.cs
@@ -0,0 +1,484 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Common.Robot;
+using Common.Scripts;
+using Common.SideChannels;
+using Common.Warehouse;
+using Newtonsoft.Json;
+using Unity.MLAgents.Actuators;
+using Unity.MLAgents.Policies;
+using Unity.MLAgents.Sensors;
+using Unity.MLAgents.SideChannels;
+using Random = System.Random;
+using UnityEngine;
+
+namespace Common.SimulationManager
+{
+    /// <summary>
+    /// Static class <c> SimulationManagerMethods </c> contains methods used by
+    /// classes implementing the <c> ISimulationManager </c> interface.
+    /// - SetUpWarehouse<T>(ISimulationManager simulationManager, GameObject robotPrefab, bool isDecisionMaker): setup warehouse, tasks,
+    /// side channels, behavior component
+    /// - GetCurrentNode(ISimulationManager simulationManager, int instanceID): get next node for robot with given id
+    /// - AssignTask<T>(ISimulationManager simulationManager, Task task, int instanceID): assign a task to a robot with given instanceID
+    /// - AddNewTask(ISimulationManager simulationManager): add a new task to <c> simulationManager.currentTasks </c> if there are
+    /// still tasks available
+    /// - RemoveTask(ISimulationManager simulationManager, Task task): remove a task from <c> simulationManager.currentTasks </c>
+    /// - CollectObservations(ISimulationManager simulationManager, VectorSensor sensor): collect observations for all robots and
+    /// add to sensor
+    /// - ShowCollisionMessage(ISimulationManager simulationManager): show message collision
+    ///
+    /// private methods:
+    /// - ReadInput(ISimulationManager simulationManager): set parameters and tasks from input
+    /// - SetUpRobots<T>(ISimulationManager simulationManager, GameObject robotPrefab): initialize and set up robots
+    /// - SetUpSideChannels(ISimulationManager simulationManager): set up side channels
+    /// - SetUpBehaviorParameters(ISimulationManager simulationManager): set up behavior parameters
+    /// - CreateColors(ISimulationManager simulationManager): create as many colors as there are tasks available at every point in time
+    /// and store in set <c> simulationManager.notAssignedColors </c>
+    /// - SetUpEndPoints(ISimulationManager simulationManager): store positions for all endpoints in dictionary <c> simulationManager.endPoints </c>
+    /// - InitializeCurrentTasks(ISimulationManager simulationManager): store first tasks in <c>
+    /// - GetNewTask(ISimulationManager simulationManager): get next task to be added to <c> simulationManager.currentTasks </c>
+    /// </summary>
+    public static class SimulationManagerMethods
+    {
+        
+        /// <summary>
+        /// Sets up warehouse: reads input, creates colors for tasks, sets up tasks, sets up endpoints, sets up robots
+        /// using the prefab, sets up side channels. If applicable sets up a behavior component.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        /// <param name="robotPrefab"></param>
+        /// <param name="isDecisionMaker"></param>
+        /// <typeparam name="T"></typeparam>
+        public static void SetUpWarehouse<T>(ISimulationManager simulationManager, GameObject robotPrefab, bool isDecisionMaker) where T:IRobot
+        {
+            // read input and set up parameters
+            ReadInput(simulationManager);
+
+            // setup colors
+            CreateColors(simulationManager);
+
+            // setup endpoints
+            SetUpEndPoints(simulationManager);
+
+            // setup tasks:
+            InitializeCurrentTasks(simulationManager);
+        
+            // setup robots
+            SetUpRobots<T>(simulationManager, robotPrefab);
+
+            // set up side channels
+            SetUpSideChannels(simulationManager);
+            
+            // set up behavior parameters
+            if (isDecisionMaker)
+            {
+                SetUpBehaviorParameters(simulationManager);
+            }
+        }
+        
+        /// <summary>
+        /// Returns current node, i.e. the next node to go to, for a robot with a given instance ID.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        /// <param name="instanceID"></param>
+        /// <returns>current node</returns>
+        public static Node GetCurrentNode(ISimulationManager simulationManager, int instanceID)
+        {
+            return simulationManager.currentNodes[instanceID];
+        }
+
+        /// <summary>
+        /// Assign a task to a robot with a given instanceID.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        /// <param name="task"></param>
+        /// <param name="instanceID"></param>
+        /// <typeparam name="T"> the corresponding robot type </typeparam>
+        public static void AssignTask<T>(ISimulationManager simulationManager, Task task, int instanceID) where T:IRobot
+        {
+            simulationManager.robotGameObjects[instanceID].GetComponent<T>().AssignTask(task);
+        }
+        
+        /// <summary>
+        /// Add a task to <c> simulationManager.currentTasks </c> if there are still tasks available.
+        /// Assign a color and send information to python code.
+        /// </summary>
+        /// <exception cref="Exception">thrown when currentTasks has already reached capacity</exception>
+        public static void AddNewTask(ISimulationManager simulationManager)
+        {
+            if (simulationManager.currentTasks.Count == simulationManager.parameters.NumberOfTasks)
+            {
+                throw new Exception("currentTasks is full");
+            }
+
+            if (simulationManager.notAssignedColors.Count == 0)
+            {
+                throw new Exception("no colors left");
+            }
+
+            var newTask = GetNewTask(simulationManager);
+
+            // newTask can be null if there are no tasks left 
+            if (newTask != null)
+            {
+                // get color from notAssignedColors (will not be empty, we can always take element at index 0) and move to assignedColors
+                var color = simulationManager.notAssignedColors.ElementAt(0);
+                simulationManager.notAssignedColors.Remove(color);
+                simulationManager.assignedColors.Add(color);
+
+                // add task to currentTasks
+                simulationManager.currentTasks.Add(newTask, color);
+
+                // color pickup/deliver
+                simulationManager.endPoints[newTask.PickUp].GetComponent<EndPoint>().SetAsPickUp(newTask);
+                simulationManager.endPoints[newTask.Delivery].GetComponent<EndPoint>().SetAsDelivery(newTask);
+
+                // use task sidechannel
+                var jsonTask = JsonConvert.SerializeObject(
+                    new
+                    {
+                        task = newTask
+                    });
+                simulationManager.taskChannel.SendEnv(jsonTask);
+            }
+        }
+        
+        /// <summary>
+        /// Remove a task from <c> simulationManager.currentTasks </c> that was assigned to a robot.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        /// <param name="task"></param>
+        /// <exception cref="Exception"></exception>
+        public static void RemoveTask(ISimulationManager simulationManager, Task task)
+        {
+            if (!simulationManager.currentTasks.ContainsKey(task))
+            {
+                throw new Exception("task was not assigned and cannot be removed: " + task);
+            }
+
+            var colorOfTask = simulationManager.currentTasks[task];
+
+            // reset color of pickup/deliver endpoints
+            simulationManager.endPoints[task.PickUp].GetComponent<EndPoint>().ResetColors();
+            simulationManager.endPoints[task.Delivery].GetComponent<EndPoint>().ResetColors();
+
+            // move color to notAssignedColors
+            simulationManager.assignedColors.Remove(colorOfTask);
+            simulationManager.notAssignedColors.Add(colorOfTask);
+
+            // remove from currentTasks
+           simulationManager.currentTasks.Remove(task);
+        }
+
+        /// <summary>
+        /// Method used when simulationManager is decision maker.
+        /// Collect observations for each robot and add to sensor.
+        /// An observation for one robot consists of an instance id, a row, a column and a number of degrees.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        /// <param name="sensor"></param>
+        public static void CollectObservations(ISimulationManager simulationManager, VectorSensor sensor)
+        {
+            foreach (var node in simulationManager.currentNodes)
+            {
+                sensor.AddObservation(node.Key);
+                sensor.AddObservation(node.Value.GridPosition.Row);
+                sensor.AddObservation(node.Value.GridPosition.Column);
+                sensor.AddObservation(node.Value.Degrees);
+            }
+        }
+        
+        /// <summary>
+        /// When actions are received, do actions. Update position robots, and if applicable pickup or deliver.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        /// <param name="actionBuffers"></param>
+        /// <typeparam name="T"></typeparam>
+        public static void OnActionReceived<T>(ISimulationManager simulationManager, ActionBuffers actionBuffers)  where T:IRobot
+        {
+            for (var i = 0; i < simulationManager.parameters.NumberOfRobots; i++)
+            {
+                var individualActions 
+                    = actionBuffers.DiscreteActions.Skip(i * simulationManager.actionSize).Take(simulationManager.actionSize).ToArray();
+                var instanceID = individualActions[0];
+                var row =  individualActions[1];
+                var column = individualActions[2];
+                var degrees =  individualActions[3];
+                var pickup = individualActions[4];
+                var deliver = individualActions[5];
+                Debug.Log(String.Format("Robot {0} received action [{1}, {2}, {3}, {4}, {5}]",
+                    instanceID, row, column, degrees, pickup, deliver));
+                simulationManager.currentNodes[instanceID] = new Node(new Position(row, column), degrees);
+            
+                if (pickup == 1)    
+                {
+                    simulationManager.robotGameObjects[instanceID].gameObject.GetComponent<T>().PickUp();
+                }
+        
+                if (deliver == 1)
+                {
+                    // remove task for robot
+                    var deliveredTask 
+                        = simulationManager.robotGameObjects[instanceID].gameObject.GetComponent<T>().Deliver();
+                    
+                    // remove task in simulationmanager
+                    RemoveTask(simulationManager,deliveredTask);
+                
+                    // add new task 
+                    AddNewTask(simulationManager);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Read input and set parameters and if applicable preset tasks.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        private static void ReadInput(ISimulationManager simulationManager)
+        {
+            simulationManager.parameters = new ReadConfig(simulationManager.warehouseConfigFile).Parameters;
+
+            //offline: check whether randomTasks is set to false
+            if (!simulationManager.online && simulationManager.parameters.RandomTasks)
+            {
+                throw new ArgumentException("In offline setting random tasks should be set to false");
+            }
+            
+            // if tasks are not generated randomly they are taken from a preset list of tasks
+            if (! simulationManager.parameters.RandomTasks)
+            {
+                // release time allowed (online -> false, offline -> true)
+                simulationManager.remainingTasks = 
+                    new ReadTasks(simulationManager.tasksListFile, simulationManager.parameters.Matrix, 
+                        simulationManager.parameters.CodeEndPoint, ! simulationManager.online).ListOfTasks;
+                // in any case there should be at least simulationManager.parameters.NumberOfTasks in preset list of tasks
+                if (simulationManager.remainingTasks.Length < simulationManager.parameters.NumberOfTasks)
+                {
+                    throw new ArgumentException("given predefined set of tasks should contain at least " +
+                                                "the given number of tasks");
+                }
+                // in offline setting simulationManager.parameters.NumberOfTasks in preset list of tasks must be exactly
+                // equal to the length of the list of tasks
+                if (!simulationManager.online && simulationManager.remainingTasks.Length !=
+                    simulationManager.parameters.NumberOfTasks)
+                {
+                    throw new ArgumentException("given predefined set of tasks should contain " +
+                                                "the given number of tasks");
+                }
+            }
+        }
+
+        public static void ShowCollisionMessage(ISimulationManager simulationManager)
+        {
+            GUI.Box(new Rect(50, 50, 100, 25), "Collision!");
+        }
+
+        /// <summary>
+        /// Set up robots using a prefab. Save the gameobject together with its instance id in <c> simulationManager.robotGameObjects </c>
+        /// and add th current node together with its istance id to <c> simulationManager.currentNodes </c>.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        /// <param name="robotPrefab"></param>
+        /// <typeparam name="T"></typeparam>
+        private static void SetUpRobots<T>(ISimulationManager simulationManager, GameObject robotPrefab) where T:IRobot
+        {
+            for (var i = 0; i < simulationManager.parameters.NumberOfRobots; i++)
+            {
+                var robot = MonoBehaviour.Instantiate(robotPrefab);
+                robot.GetComponent<T>().simulationManager = simulationManager;
+                simulationManager.robotGameObjects.Add(robot.GetInstanceID(), robot);
+                simulationManager.currentNodes.Add(robot.GetInstanceID(), simulationManager.parameters.InitialNodes[i]);
+            }
+        }
+
+        /// <summary>
+        /// Set up side channels and send initial information on warehouse to Python code.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        private static void SetUpSideChannels(ISimulationManager simulationManager)
+        {
+            // create side channel for communication on the environment
+            simulationManager.envChannel = new EnvSideChannel();
+            // The channel must be registered with the SideChannelManager class
+            SideChannelManager.RegisterSideChannel(simulationManager.envChannel);
+            // communicate info on environment to Python code through the SideChannel
+            var json = JsonConvert.SerializeObject(
+                new
+                {
+                    matrixLayout = simulationManager.parameters.Matrix,
+                    rotationRobot = simulationManager.parameters.Rotation,
+                    sizeOfAction = simulationManager.actionSize,
+                    sizeOfObservation = simulationManager.observationSize,
+                    numberOfRobotsInEnv = simulationManager.parameters.NumberOfRobots,
+                    initialNodesOfRobots = simulationManager.parameters.InitialNodes,
+                    currentTasks = simulationManager.currentTasks.Keys,
+                    numberOfCurrentTasks = simulationManager.parameters.NumberOfTasks,
+                    backwards = simulationManager.parameters.CanGoBackWards,
+                    instanceIDSRobots = simulationManager.robotGameObjects.Keys,
+                    tasksGeneratedRandomly = simulationManager.parameters.RandomTasks
+                });
+            simulationManager.envChannel.SendEnv(json);
+
+            // create side channel for communication on tasks
+            simulationManager.taskChannel = new TaskSideChannel();
+            SideChannelManager.RegisterSideChannel(simulationManager.taskChannel);
+            simulationManager.taskChannel.SimulationManager = simulationManager;
+        }
+
+        /// <summary>
+        /// Set up behaviorparameters.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        private static void SetUpBehaviorParameters(ISimulationManager simulationManager)
+        {
+            MonoBehaviour simulationManagerMB = simulationManager.GetMonoBehaviour();
+            var component = simulationManagerMB.GetComponent<BehaviorParameters>();
+            // Set up the parameters of the behavioral component.
+            component.BrainParameters.VectorObservationSize 
+                = simulationManager.parameters.NumberOfRobots*simulationManager.observationSize;
+            component.BrainParameters.ActionSpec 
+                = ActionSpec.MakeDiscrete(new int [simulationManager.parameters.NumberOfRobots*simulationManager.actionSize]);
+        }
+        
+        /// <summary>
+        /// Create random colors as many as there are available tasks (at any point in time). They should be all different
+        /// and also not equal to the default tile/wall/endpoint/parking colors.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        private static void CreateColors(ISimulationManager simulationManager)
+        {
+            simulationManager.notAssignedColors = new HashSet<Color>();
+            
+            var rand = new Random();
+            while (simulationManager.notAssignedColors.Count < simulationManager.parameters.NumberOfTasks)
+            {
+                var randomColor = new Color(
+                    (float) rand.NextDouble(),
+                    (float) rand.NextDouble(),
+                    (float) rand.NextDouble(),
+                    1
+                );
+
+                if (!randomColor.Equals(simulationManager.colorWall) && !randomColor.Equals(simulationManager.colorTile)
+                                                   && !randomColor.Equals(simulationManager.colorEndPoint) &&
+                                                   !randomColor.Equals(simulationManager.colorParking))
+                {
+                    simulationManager.notAssignedColors
+                        .Add(randomColor); // if randomColor is already in notAssignedColors it will not be added
+                }
+            }
+        }
+        
+        /// <summary>
+        /// Setup Endpoints dictionary. Gameobjects will be created and added by the <c>Floor</c> script.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        private static void SetUpEndPoints(ISimulationManager simulationManager)
+        {
+            simulationManager.endPoints = new Dictionary<Position, GameObject>();
+            
+            for (var row = 0; row < simulationManager.parameters.Matrix.Length; row++)
+            {
+                for (var column = 0; column < simulationManager.parameters.Matrix[0].Length; column++)
+                {
+                    if (simulationManager.parameters.Matrix[row][column] == simulationManager.parameters.CodeEndPoint)
+                    {
+                        simulationManager.endPoints.Add(new Position(row, column), null);
+                    }
+                }
+            }
+        }
+        
+        /// <summary>
+        /// Setup CurrentTasks: add tasks to <c> simulationManager.currentTasks </c> until we have
+        /// <c> simulationManager.parameters.NumberOfTaskss </c> tasks. Assign a color to each task. Initialize
+        /// <c> simulationManager.assignedColor </c> to keep track of assigned colors.
+        /// Initial coloring is done by the <c>Floor</c> script.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        private static void InitializeCurrentTasks(ISimulationManager simulationManager)
+        {
+            simulationManager.currentTasks = new Dictionary<Task, Color>();
+            simulationManager.assignedColors = new HashSet<Color>();
+            
+            while (simulationManager.currentTasks.Count < simulationManager.parameters.NumberOfTasks)
+            {
+                // get new task (this will not be null by the restriction that remainingTasks should have at least numberOfTasks elements)
+                var newTask = GetNewTask(simulationManager); 
+
+                // get color from notAssignedColors (will not be empty, we can always take element at index 0) and move to assignedColors
+                var color = simulationManager.notAssignedColors.ElementAt(0);
+                simulationManager.notAssignedColors.Remove(color);
+                simulationManager.assignedColors.Add(color);
+
+                // add to currentTasks
+                simulationManager.currentTasks.Add(newTask, color);
+            }
+        }
+        
+        /// <summary>
+        /// Get a new task.
+        /// - If randomTasks == true, we create a new task that is not in currentTasks.
+        /// - If randomTasks == false, we get the next task from remainingTasks, if there are no tasks left return null.
+        /// </summary>
+        /// <param name="simulationManager"></param>
+        /// <returns>A new task</returns>
+        private static Task GetNewTask(ISimulationManager simulationManager)
+        {
+            //random task generation
+            if (simulationManager.parameters.RandomTasks)
+            {
+                var random = new Random();
+                // get random endpoint as candidate for next pick up
+                var randomPickUp = simulationManager.endPoints.Keys.ElementAt(random.Next(0, simulationManager.endPoints.Count));
+                // update randomPickUp until is not an endpoint in currentTasks
+                while (simulationManager.currentTasks.Any(task => task.Key.HasEndPoint(randomPickUp)))
+                {
+                    randomPickUp = simulationManager.endPoints.Keys.ElementAt(random.Next(0, simulationManager.endPoints.Count));
+                }
+                // get random endpoint as candidate for next delivery
+                var randomDelivery = simulationManager.endPoints.Keys.ElementAt(random.Next(0, simulationManager.endPoints.Count));
+                //update randomDelivery until is not an endpoint in currentTasks and different from randomPickUp
+                while (simulationManager.currentTasks.Any(task => task.Key.HasEndPoint(randomDelivery))
+                       || randomDelivery.Equals(randomPickUp))
+                {
+                    randomDelivery = simulationManager.endPoints.Keys.ElementAt(random.Next(0, simulationManager.endPoints.Count));
+                }
+
+                return new Task(randomPickUp, randomDelivery,0);
+            }
+        
+            // non random task generation: we get next task from remainingTasks and update remainingTasks
+        
+            // there are no remaining tasks left
+            if (simulationManager.remainingTasks.Length == 0)
+            {
+                return null;
+            }
+        
+            // there are remaining tasks left
+            var newTask = simulationManager.remainingTasks[0];
+            simulationManager.remainingTasks = simulationManager.remainingTasks.Skip(1).ToArray();
+            return newTask;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/SimulationManagerMethods.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/SimulationManagerMethods.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..b85ef31b92a6040395056edf8759a1ceace1266d
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/SimulationManager/SimulationManagerMethods.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: cd8f59650b1a42caa417c3842ef8806c
+timeCreated: 1628858423
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/UtilityMethods.meta b/PickUpandDelivery/Assets/Scripts/Common/UtilityMethods.meta
new file mode 100644
index 0000000000000000000000000000000000000000..60296f45b4f36ed92b0fda5e4a1922d1984feafb
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/UtilityMethods.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ddc2bac031dc4237900a0faec627a6fd
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse.meta b/PickUpandDelivery/Assets/Scripts/Common/Warehouse.meta
new file mode 100644
index 0000000000000000000000000000000000000000..05f2a350aae902853017b79884c3d1db2ec82ac6
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 911a6d88db034382a0c812352f12439e
+timeCreated: 1628838833
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Node.cs b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Node.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e2dabd56b9ee0682341efaf71745569b58a0005c
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Node.cs
@@ -0,0 +1,67 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+
+namespace Common.Warehouse
+{
+    /// <summary>
+    /// Class <c> Node </c> represents the nodes in the graph. Every node contains
+    /// - a position (x,y) in the grid
+    /// - the difference in degrees with the direction north:
+    ///     - 0 = North
+    ///     - 90 = East
+    ///     - 180 = South
+    ///     - 270 = West
+    /// </summary>
+
+    public class Node
+    {
+        public Position GridPosition { get; set; }
+        public int Degrees { get; }
+
+        public Node(Position pos, int degrees)
+        {
+            GridPosition = pos;
+            Degrees = degrees;
+        }
+
+        protected bool Equals(Node other)
+        {
+            return Equals(GridPosition, other.GridPosition) && Degrees == other.Degrees;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != this.GetType()) return false;
+            return Equals((Node) obj);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                return ((GridPosition != null ? GridPosition.GetHashCode() : 0) * 397) ^ Degrees;
+            }
+        }
+
+        public override string ToString()
+        {
+            return "(" + GridPosition.Row + "," + GridPosition.Column + ")" + " " + Degrees;
+        }
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Node.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Node.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..c1332fd67db4a07ac8df46efb8df6ae36a0c26a2
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Node.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 192efae1e20ced443998b710269bfeee
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Position.cs b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Position.cs
new file mode 100644
index 0000000000000000000000000000000000000000..69973cb6e99f53800fd3d68d121a1a5edec1e8cf
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Position.cs
@@ -0,0 +1,63 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+namespace Common.Warehouse
+{
+    /// <summary>
+    /// A position in the grid is described by two integers Row and Column,e.g.
+    /// for a grid with dimensions 2 rows and 3 columns we have following positions
+    /// (0,0) (0,1) (0,2)
+    /// (1,0) (1,1) (1,2)
+    /// </summary>
+    
+    public class Position
+    {
+        public int Row { get; set; }
+        public int Column { get; set; }
+
+        public Position(int row, int column)
+        {
+            Row = row;
+            Column = column;
+        }
+
+        protected bool Equals(Position other)
+        {
+            return Row == other.Row && Column == other.Column;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != this.GetType()) return false;
+            return Equals((Position) obj);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                return (Row * 397) ^ Column;
+            }
+        }
+    
+        public override string ToString()
+        {
+            return "(" + Row + "," + Column + ")";
+        }
+    }
+}
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Position.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Position.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..fd9da1efbff63704ba48101e50d5423fcd20af34
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Position.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 31b30aafb0088be4aab3311716cb5315
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadConfig.cs b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadConfig.cs
new file mode 100644
index 0000000000000000000000000000000000000000..826b1aa592e2d79293c6df58418d71a3e5bfbc36
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadConfig.cs
@@ -0,0 +1,171 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System;
+using System.IO;
+using Newtonsoft.Json;
+
+namespace Common.Warehouse
+{
+    /// <summary>
+    /// Class reads a json string and converting it to an object of the class WarehouseParameters.
+    /// does multiple checks on the resulting object
+    /// - CheckMatrix(): checks dimensions of the matrix and the values of the entries 
+    /// - CheckRotation(): checks whether the unit of rotation is a divisor of 90
+    /// - CheckNumberOfRobots(): checks whether for each robot exactly 1 initial node is given
+    /// - CheckValidityNodes(): checks whether the given initial nodes are valid nodes (the position should
+    /// correspond to a parking location in the matrix and the rotation should be a divisor of the unit of rotation)
+    /// - CheckNumberOfTasks(): checks whether there no more current tasks than the available endpoints can accomodate 
+    /// </summary>
+
+    public class ReadConfig
+    {
+        public WarehouseParameters Parameters { get; }
+        private int numberOfEndpoints;
+
+        public ReadConfig(string pathToFile)
+        {
+            var jsonString = File.ReadAllText(pathToFile);
+            Parameters = JsonConvert.DeserializeObject<WarehouseParameters>(jsonString);
+            CheckMatrix();
+            CheckRotation();
+            CheckNumberOfRobots();
+            CheckValidityNodes();
+            CheckNumberOfTasks();
+        }
+    
+        /// <summary>
+        /// Checks validity of rotation.
+        /// </summary>
+        /// <exception cref="ArgumentException"> thrown when the rotation is not a divisor of 90.</exception>
+        private void CheckRotation()
+        {
+            if (90 % Parameters.Rotation != 0)
+            {
+                throw new ArgumentException("Invalid rotation in config file");
+            }
+        }
+    
+        /// <summary>
+        /// Checks number of initial nodes.
+        /// </summary>
+        /// <exception cref="ArgumentException"> thrown when number of initial nodes does not coincide
+        /// with given number of robots.</exception>
+        private void CheckNumberOfRobots()
+        {
+            if (Parameters.NumberOfRobots != Parameters.InitialNodes.Length)
+            {
+                throw new ArgumentException("Invalid number of robots in config file");
+            }
+        }
+
+        /// <summary>
+        /// Checks validity of initial nodes.
+        /// </summary>
+        /// <exception cref="ArgumentException"> thrown when an initial node is not a parking node
+        /// or an allowed rotation. </exception>
+        private void CheckValidityNodes()
+        {
+            for (var i = 0; i < Parameters.NumberOfRobots; i++)
+            {
+                var initialNode = Parameters.InitialNodes[i];
+                if (Parameters.Matrix[initialNode.GridPosition.Row][initialNode.GridPosition.Column] != Parameters.CodeParking
+                    || IsInvalidNodeRotation(initialNode.Degrees))
+                {
+                    throw new ArgumentException("Invalid initial node in config file: " + initialNode);
+                }
+            }
+        }
+    
+        /// <summary>
+        /// Checks shape of matrix and entries. Counts number of endpoints.
+        /// </summary>
+        /// <exception cref="ArgumentException"> thrown when matrix does not have correct shape or when entries are not valid</exception>
+        private void CheckMatrix()
+        {
+            var numberOfRows = Parameters.Matrix.Length;
+            if (numberOfRows == 0)
+            {
+                throw new ArgumentException("Matrix has length 0");
+            }
+
+            var numberOfColumns = Parameters.Matrix[0].Length;
+        
+            for (var row = 0; row < numberOfRows; row++)
+            {
+                // check shape
+                if (Parameters.Matrix[row].Length != numberOfColumns)
+                {
+                    throw new ArgumentException("Matrix has incorrect shape");
+                }
+            
+                for (var column = 0; column < numberOfColumns; column++)
+                {
+                    if (IsInvalidCode(Parameters.Matrix[row][column]))
+                    {
+                        throw new ArgumentException("Matrix contains unaccepted value at position " +
+                                                    "(" + row + "," + column + ")");
+                    }
+
+                    if (Parameters.Matrix[row][column] == Parameters.CodeEndPoint)
+                    {
+                        numberOfEndpoints++;
+                    }
+                }
+            }
+        }
+    
+        /// <summary>
+        /// Checks whether the rotation is valid for nodes. 
+        /// </summary>
+        /// <param name="rotation"> an int </param>
+        /// <returns> true when the unit of rotation is not a divisor of rotation</returns>
+        private bool IsInvalidNodeRotation(int rotation)
+        {
+            return rotation % Parameters.Rotation != 0;
+        }
+
+        /// <summary>
+        /// Checks whether it is a valid code.
+        /// </summary>
+        /// <param name="code"></param>
+        /// <returns> true when the given code is not valid.</returns>
+        private bool IsInvalidCode(int code)
+        {
+            return code != Parameters.CodeWall
+                   && code != Parameters.CodeTile
+                   && code != Parameters.CodeParking
+                   && code != Parameters.CodeEndPoint;
+        }
+
+        /// <summary>
+        /// Checks whether the number of tasks is not more than the endpoints can accomodate, i.e. endpoints/2.
+        /// Do not call this method before CheckMatrix().
+        /// </summary>
+        /// <exception cref="ArgumentException"> thrown when there are no endpoints or when there are too many tasks</exception>
+        private void CheckNumberOfTasks()
+        {
+            if (numberOfEndpoints == 0)
+            {
+                throw new ArgumentException("There are no endpoints. Did you run Checkmatrix()?");
+            }
+            if (Parameters.NumberOfTasks > numberOfEndpoints / 2)
+            {
+                throw new ArgumentException("Invalid number of tasks, not enough endpoints");
+            }
+        }
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadConfig.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadConfig.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..d90c1b489f0716c655e49760feb09a2af960a648
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadConfig.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 12faaaf5e8d363f4b8d5a75aafc56fe2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadTasks.cs b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadTasks.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4c0c2b22d1b04fd90d71694fe70c7caa9ef617a2
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadTasks.cs
@@ -0,0 +1,70 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+
+using System;
+using System.IO;
+using Newtonsoft.Json;
+
+namespace Common.Warehouse
+{
+    /// <summary>
+    /// Class <c> ReadTasks </c> is used to read a preset list of tasks (json format). It converts the list to
+    /// an instance of Task[] and will only be called in the offline problem setting.
+    /// Does multiple checks on the resulting object:
+    /// - every tasks has to be a valid endpoint and has to correspond to the correct code in the config matrix
+    /// - whether release time is allowed or not 
+    /// </summary>
+    public class ReadTasks
+    {
+        public Task[] ListOfTasks;
+        private int[][] Matrix;
+        private int EndPointCode;
+        private bool ReleaseTimeAllowed;
+
+        public ReadTasks(string pathToFile, int[][] matrix, int endPointCode, bool releaseTimeAllowed)
+        {
+            Matrix = matrix;
+            var jsonString = File.ReadAllText(pathToFile);
+            ListOfTasks = JsonConvert.DeserializeObject<Task[]>(jsonString);
+            EndPointCode = endPointCode;
+            ReleaseTimeAllowed = releaseTimeAllowed;
+            CheckInput();
+        }
+
+        // check whether pickup and delivery correspond to the correct number in the matrix
+        private void CheckInput()
+        {
+            foreach(var task in ListOfTasks)
+            {
+                if (Matrix[task.PickUp.Row][task.PickUp.Column] != EndPointCode)
+                {
+                    throw new ArgumentException("Invalid task pickup " + task.PickUp);
+                }
+                if (Matrix[task.Delivery.Row][task.Delivery.Column] != EndPointCode)
+                {
+                    throw new ArgumentException("Invalid task deliver " + task.Delivery);
+                }
+
+                if (!ReleaseTimeAllowed && task.ReleaseTime != 0)
+                {
+                    throw new ArgumentException("Releasetime task cannot be equal to zero " + task.PickUp + " " +
+                                                task.Delivery);
+                }
+            }
+        }
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadTasks.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadTasks.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..2f1bf911cc1f3bf5b117c7ad9eee104a42e5dd8a
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/ReadTasks.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 50ade04715a988d4d8eac455082416b2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Task.cs b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Task.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d90ffb3b2b881c05189a8a5fcad82a1c92696ffa
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Task.cs
@@ -0,0 +1,76 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System.ComponentModel;
+using Newtonsoft.Json;
+
+namespace Common.Warehouse
+{
+    /// <summary>
+    /// Class <c> Task </c> represents a task. A task consists of 2 positions: a pick up and a delivery position and a release time.
+    /// Default release time equals 0.
+    ///
+    ///  contains instance method
+    /// - HasEndPoint(Position pos): checks whether pos is an endpoint (pick up or delivery) of the task
+    /// </summary>
+    public class Task
+    {
+        public Position PickUp { get; set; }
+        public Position Delivery { get; set; }
+
+        [DefaultValue(0)]
+        [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
+        public int ReleaseTime { get; set; }
+
+        public Task(Position pickUp, Position delivery, int releaseTime)
+        {
+            PickUp = pickUp;
+            Delivery = delivery;
+            ReleaseTime = releaseTime;
+        }
+    
+        // check whether a position is an endpoint of a task
+        public bool HasEndPoint(Position pos)
+        {
+            return pos.Equals(PickUp) || pos.Equals(Delivery);
+        }
+
+        protected bool Equals(Task other)
+        {
+            return Equals(PickUp, other.PickUp) && Equals(Delivery, other.Delivery) && ReleaseTime == other.ReleaseTime;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != this.GetType()) return false;
+            return Equals((Task) obj);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                var hashCode = (PickUp != null ? PickUp.GetHashCode() : 0);
+                hashCode = (hashCode * 397) ^ (Delivery != null ? Delivery.GetHashCode() : 0);
+                hashCode = (hashCode * 397) ^ ReleaseTime;
+                return hashCode;
+            }
+        }
+    
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Task.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Task.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..ad3b93b8ac7e92d8013bba97bad2b1cabf056426
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/Task.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8bbe96fcd2953ed4b9c3fdee2b6ccc1d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/UtilityMethods.cs b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/UtilityMethods.cs
new file mode 100644
index 0000000000000000000000000000000000000000..06adb2fe93e9a97a63b90189f80e7113dc5579e4
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/UtilityMethods.cs
@@ -0,0 +1,40 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using UnityEngine;
+
+namespace Common.Warehouse
+{
+    /// <summary>
+    /// Static class <c> UtilityMethods </c> contains static helper methods.
+    /// </summary>
+
+    public static class UtilityMethods 
+    {
+        /// <summary>
+        /// Returns complementary color.
+        /// </summary>
+        /// <param name="color"></param>
+        /// <returns>the complementary color</returns>
+        public static Color GetNegativeColor(Color color)
+        {
+            Color.RGBToHSV(color, out float H, out float S, out float V);
+            float negativeH = (H + 0.5f) % 1f;
+            return Color.HSVToRGB(negativeH, S, V);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/UtilityMethods.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/UtilityMethods.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..4daac6d5cd73cf85b3440f6134fd85e22d2bb0e2
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/UtilityMethods.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: fc3d6a786841450292dc559c0be8cb2f
+timeCreated: 1628848095
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/WarehouseParameters.cs b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/WarehouseParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..135953c6d534a5af7872869b4ba5ccc97c4495b9
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/WarehouseParameters.cs
@@ -0,0 +1,46 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+
+namespace Common.Warehouse
+{
+    /// <summary>
+    /// Class <c> WarehouseParameters </c> contains all parameters needed to set up the warehouse.
+    /// </summary>
+
+    public class WarehouseParameters
+    {
+        public int[][] Matrix { get; set; } // 1 is wall, 0 is tile, 2 is endpoint (pick up or delivery), 3 is parking
+
+        public int Rotation { get; set; } // unit of rotation
+        public int TimeRobotPerTile { get; set; } // time needed to traverse one tile
+    
+        public int NumberOfRobots { get; set; }
+        public Node[] InitialNodes { get; set; }
+
+        public int NumberOfTasks { get; set; } // at all times there will be this number of tasks to be done
+    
+        public bool CanGoBackWards { get; set; } // robot can go backwards
+    
+        public bool RandomTasks { get; set; } // whether tasks are created random or taken from list
+
+        // codes for matrix entries
+        public readonly int CodeWall = 1;
+        public readonly int CodeTile = 0;
+        public readonly int CodeEndPoint = 3;
+        public readonly int CodeParking = 2;
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Common/Warehouse/WarehouseParameters.cs.meta b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/WarehouseParameters.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..4596e3b46bb250696629a500ee8d5dda622240d5
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Common/Warehouse/WarehouseParameters.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 810902285cb122d4cb8ceec8fa99aa9f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Centralized.meta b/PickUpandDelivery/Assets/Scripts/Offline_Centralized.meta
new file mode 100644
index 0000000000000000000000000000000000000000..7bbad8183aa6465f04c21a4f444efddab7c31ff6
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Centralized.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 125388dc41b974b4f9620a18d4842943
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Centralized/RobotOfflineCentralized.cs b/PickUpandDelivery/Assets/Scripts/Offline_Centralized/RobotOfflineCentralized.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7dddb615cbf73f83d3235ff66e61eb14cc5afc52
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Centralized/RobotOfflineCentralized.cs
@@ -0,0 +1,90 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+
+using Common.Robot;
+using Common.SimulationManager;
+using Common.Warehouse;
+using UnityEngine;
+
+/// <summary>
+/// Script <c> RobotOnlineDecentralized </c>
+/// has public instance methods:
+/// - GetMonoBehaviour(): return instance as Monobehaviour
+/// - AssignTask(Task task): assign a task to robot and update color of robot accordingly
+/// - PickUp(): after picking up, a cross is drawn on top of the robot using the complementary color of the task
+/// - Deliver(): calls RemoveTask() and returns delivered task
+/// has private instance methods:
+/// - OnTriggerEnter(Collider other) for collision detection
+/// </summary>
+public class RobotOfflineCentralized : MonoBehaviour, IRobot
+{
+    public ISimulationManager  simulationManager { get; set; }
+
+    public Task assignedTask { get; set; } = null; // the task a robot is assigned, mainly used for coloring
+    [SerializeField] private Material idleColor = default; // color when no task assigned
+
+    void Start()
+    {
+        RobotMethods.InitializeRobotAtStart(this);
+    }
+
+    void FixedUpdate()
+    {
+        RobotMethods.UpdatePosition(this);
+    }
+    
+    /// <summary>
+    /// Return this as MonoBehaviour.
+    /// </summary>
+    /// <returns></returns>
+    public MonoBehaviour GetMonoBehaviour()
+    {
+        return this;
+    }
+    
+    // collision handling
+    private void OnTriggerEnter(Collider other)
+    {
+        RobotMethods.CollisionEvent(this);
+    }
+
+    /// <summary>
+    /// Assign task to robot. 
+    /// </summary>
+    /// <param name="task"> a Task object</param>
+    public void AssignTask(Task task)
+    {
+        RobotMethods.AssignTask(this, task);
+    }
+
+    /// <summary>
+    /// Pick up.
+    /// </summary>
+    public void PickUp()
+    {
+        RobotMethods.PickUp(this);
+    }
+
+    /// <summary>
+    /// Delivery. 
+    /// </summary>
+    /// <returns>the delivered task</returns>
+    public Task Deliver()
+    {
+        return RobotMethods.Deliver(this, idleColor.color);
+    }
+}
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Centralized/RobotOfflineCentralized.cs.meta b/PickUpandDelivery/Assets/Scripts/Offline_Centralized/RobotOfflineCentralized.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..504752fbabf7d90204f43f2609538c60f5de30aa
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Centralized/RobotOfflineCentralized.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 54b9a4088e4329849b24b0da23b5d39d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Centralized/SimulationManagerOfflineCentralized.cs b/PickUpandDelivery/Assets/Scripts/Offline_Centralized/SimulationManagerOfflineCentralized.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8e35665fabe9fb3b281bb4e53f5f5f33d2496b35
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Centralized/SimulationManagerOfflineCentralized.cs
@@ -0,0 +1,219 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System.Collections.Generic;
+using System;
+using System.IO;
+using UnityEngine;
+using Unity.MLAgents.SideChannels;
+using Newtonsoft.Json;
+using System.Linq;
+using Common.Scripts;
+using Common.SideChannels;
+using Common.SimulationManager;
+using Common.Warehouse;
+using Unity.MLAgents;
+using Unity.MLAgents.Actuators;
+using Unity.MLAgents.Policies;
+using Unity.MLAgents.Sensors;
+using Random = System.Random;
+
+/// <summary>
+/// Class <c> SimulationManagerOfflineCentralized </c> controls the simulation for the Offline Centralized Pick Up and
+/// Delivery problem.
+///
+/// The only fields that should be altered here is warehouseConfigFile, the path to the txt file containing
+/// the configurable parameters of the simulation and the path to the preset tasks.
+///
+/// Has instance methods: 
+/// - GetMonoBehaviour(): return object as monobehaviour
+/// - GetCurrentNode(int instanceID): get current node for a robot with given instance ID
+/// - RemoveTask(Task task): remove a tasks from current tasks
+/// - AddNewTask(): add a new task to current tasks
+/// - AssignTask(Task task, int instanceID): assign a task to a robot with given instance ID
+/// </summary>.
+
+
+public class SimulationManagerOfflineCentralized : Agent, ISimulationManager
+{
+    public string warehouseConfigFile { get; } = "ConfigurationFiles/Offline_Centralized/warehousejson.txt";
+    public string tasksListFile { get; }= "ConfigurationFiles/Offline_Centralized/tasks_releasetime.txt";
+    
+    // online or offline
+    public bool online { get; } = false;
+    
+    private int counter; // Count time in ms (used in advance method), to make sure every timeRobotPerTile a new action or node is given
+
+    // colors
+    // colors for walls, tiles and prefabs
+    public Color colorWall { get; } = Color.black;
+    public Color colorTile { get; } = Color.white;
+    public Color colorEndPoint { get; }= new Color(0.5f, 0.5f, 1f); // blue-ish
+    public Color colorParking { get; } = Color.gray;
+
+    // colors for tasks and the robots that have been assigned these tasks
+    public HashSet<Color> assignedColors { get; set; } = new HashSet<Color>();
+    public HashSet<Color> notAssignedColors { get; set; } = new HashSet<Color>();
+
+    // endpoints
+    // dictionary containing all endpoints
+    // every endpoint will point to a gameobject, this will be setup by the Floor script
+    public Dictionary<Position, GameObject> endPoints { get; set; }= new Dictionary<Position, GameObject>();
+
+    // parameters of warehouse
+    public WarehouseParameters parameters { get; set; }
+
+    // tasks
+    // at every timestep there will be max numberOfTasks tasks that have to be assigned (by the python code), in 
+    // the offline setting this has to be same as the number of preset tasks
+    // current available tasks and their assigned colors: these are the tasks to remain to be assigned to robots
+    public Dictionary<Task, Color> currentTasks { get; set; } = new Dictionary<Task, Color>();
+    // all remaining tasks, used to store tasks read from file
+    public Task[] remainingTasks { get; set; }
+
+    // robots
+    [SerializeField] private GameObject robotPrefab = default; // GameObject prefab used for the robot
+
+    // For every robot the current node where he is going, i.e. the next action 
+    public Dictionary<int, Node> currentNodes { get; } = new Dictionary<int, Node>();
+
+    // For every robot the corresponding gameobject
+    public Dictionary<int, GameObject> robotGameObjects { get; set; } = new Dictionary<int, GameObject>();
+
+    // environment variables
+    // check for collisions
+    public bool collisions { get; set; }
+
+    // observations and actions
+    public int observationSize { get; }= 4; // id,x,y,rotation
+    public int actionSize { get; } = 6; // id,x,y,rotation,pick up, delivery
+
+    // environment variables for drawing
+    public float
+        SIZE { get; } = 1; // Size of square/tile, this is kept constant to avoid having to change camera perspective
+
+    public float SCALEROBOT { get; } = 0.49f; // Ratio robot to tile, for drawing robot
+    public float YROBOTFLOATING { get; }= 0.2f; // Floating y value robot, for drawing robot
+
+    // sidechannels
+    public EnvSideChannel envChannel { get; set; } // SideChannel for communication initial environment parameters
+    public TaskSideChannel taskChannel { get; set; } // SideChannel for communication on tasks
+
+    void Awake()
+    {
+        SimulationManagerMethods.SetUpWarehouse<RobotOfflineCentralized>(this, robotPrefab, true);
+    }
+    
+    /// <summary>
+    /// Return this as MonoBehaviour.
+    /// </summary>
+    /// <returns></returns>
+    public MonoBehaviour GetMonoBehaviour()
+    {
+        return this;
+    }
+
+   /// <summary>
+    /// Every timeRobotPerTile a new decision is requested: observations are collected (<c>CollectObservations</c>) and actions are received
+    /// (<c>OnActionReceived</c>)
+    /// </summary>
+    public void FixedUpdate()
+    {
+        counter += 20; // FixedUpdate is called every 20ms, add 20ms to counter
+        // if counter has passed timeRobotPerTile and there is a python client listening new actions are requested
+        // if a collisions has been detected no new requests are made
+        if (counter >= parameters.TimeRobotPerTile && Academy.Instance.IsCommunicatorOn)
+        {
+            if (!collisions)
+            {
+                RequestDecision(); // manually request a decision
+            }
+
+            counter = 0; // reset counter
+        }
+    }
+    
+    /// <summary>
+    /// Collect observations, will be executed when requested.
+    /// Note that the number of observations per robot should be equal to <c>ObservationSize</c>.
+    /// </summary>
+    /// <param name="sensor"></param>
+    public override void CollectObservations(VectorSensor sensor)
+    {
+        SimulationManagerMethods.CollectObservations(this, sensor);
+    }
+    
+    /// <summary>
+    /// Receive actions, will be executed when requested.
+    /// Note that the number of actions per robot should be equal to <c>ActionSize</c>.
+    /// </summary>
+    public override void OnActionReceived(ActionBuffers actionBuffers)
+    {
+        SimulationManagerMethods.OnActionReceived<RobotOfflineCentralized>(this,actionBuffers);
+    }
+    
+    /// <summary>
+    /// Show message when a collision has occured.
+    /// </summary>
+    private void OnGUI()
+    {
+        if (collisions)
+        {
+            SimulationManagerMethods.ShowCollisionMessage(this);
+        }
+    }
+    
+    /// <summary>
+    /// Returns current node, i.e. the next node to go to, for a robot with a given instance ID.
+    /// </summary>
+    /// <param name="instanceID"> an int</param>
+    /// <returns> A node corresponding to the current node.</returns>
+    public Node GetCurrentNode(int instanceID)
+    {
+        return SimulationManagerMethods.GetCurrentNode(this,instanceID);
+    }
+
+    /// <summary>
+    /// Remove a task from CurrentTasks. Reset color of pick up and delivery endpoints.
+    /// Make color available. 
+    /// </summary>
+    /// <param name="task"></param>
+    /// <exception cref="Exception">thrown if it was not assigned to a robot</exception>
+    public void RemoveTask(Task task)
+    {
+        SimulationManagerMethods.RemoveTask(this, task);
+    }
+    
+    /// <summary>
+    /// Add a task to currentTasks if there are still tasks available. Assign a color and send information to python code.
+    /// </summary>
+    /// <exception cref="Exception">thrown when currentTasks has already reached capacity</exception>
+    public void AddNewTask()
+    {
+        SimulationManagerMethods.AddNewTask(this);
+    }
+    
+    /// <summary>
+    /// Assign a task to a robot with a given instanceID.
+    /// </summary>
+    /// <param name="task"></param>
+    /// <param name="instanceID"></param>
+    public void AssignTask(Task task, int instanceID)
+    {
+        SimulationManagerMethods.AssignTask<RobotOfflineCentralized>(this, task, instanceID);
+    }
+}
+
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Centralized/SimulationManagerOfflineCentralized.cs.meta b/PickUpandDelivery/Assets/Scripts/Offline_Centralized/SimulationManagerOfflineCentralized.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..6d05e96b6804a89d5eb6bd7683ef73f7189e1009
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Centralized/SimulationManagerOfflineCentralized.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ec6a5fb578df5504186ba78f15f70a56
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Decentralized.meta b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized.meta
new file mode 100644
index 0000000000000000000000000000000000000000..9eb4f284b983de8ee07f3f68b610a085b5768b39
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c819bbdde6c1a9143a5866dbd9669aa0
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/RobotOfflineDecentralized.cs b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/RobotOfflineDecentralized.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fe2a58e17db8ddab215ed704284098f418058054
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/RobotOfflineDecentralized.cs
@@ -0,0 +1,135 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+
+using System;
+using System.Linq;
+using Common.Robot;
+using Common.SimulationManager;
+using Common.Warehouse;
+using Unity.MLAgents;
+using Unity.MLAgents.Actuators;
+using Unity.MLAgents.Sensors;
+using UnityEngine;
+
+/// <summary>
+/// Script <c> RobotOfflineDecentralized </c>
+/// has public instance methods:
+/// - GetMonoBehaviour(): return instance as Monobehaviour
+/// - AssignTask(Task task): assign a task to robot and update color of robot accordingly
+/// - CollectObservations(VectorSensor sensor): collect an observation
+/// - OnActionReceived(ActionBuffers actionBuffers): do action
+/// - Pickup() and Delivery(): unused methods from interface IRobot
+/// has private instance methods:
+/// - OnTriggerEnter(Collider other) for collision detection
+/// </summary>
+public class RobotOfflineDecentralized : Agent, IRobot
+{
+    public ISimulationManager  simulationManager { get; set; }
+
+    private int
+        counter; // Count time in ms (used in advance method), to make sure every timeRobotPerTile a new action or node is given
+
+    public Task assignedTask { get; set; } = null; // the task a robot is assigned, mainly used for coloring
+    [SerializeField] private Material idleColor = default; // color when no task assigned
+
+    void Start()
+    {
+        RobotMethods.InitializeRobotAtStart(this);
+    }
+
+
+    /// <summary>
+    /// Every timeRobotPerTile a new decision is requested: observations are collected (<c>CollectObservations</c>) and actions are received
+    /// (<c>OnActionReceived</c>).
+    /// </summary>
+    void FixedUpdate()
+    {
+        counter += 20; // FixedUpdate is called every 20ms, add 20ms to counter
+        // if counter has passed timeRobotPerTile and there is a python client listening new actions are requested
+        // if a collisions has been detected no new requests are made
+        if (counter >= simulationManager.parameters.TimeRobotPerTile && Academy.Instance.IsCommunicatorOn)
+        {
+            if (!simulationManager.collisions)
+            {
+                Debug.Log("request by " + gameObject.GetInstanceID());
+                RequestDecision(); // manually request a decision
+            }
+
+            counter = 0; // reset counter
+        }
+        RobotMethods.UpdatePosition(this);
+    }
+    
+    /// <summary>
+    /// Return this as MonoBehaviour.
+    /// </summary>
+    /// <returns></returns>
+    public MonoBehaviour GetMonoBehaviour()
+    {
+        return this;
+    }
+
+    /// <summary>
+    /// Collect observation, will be executed when requested.
+    /// </summary>
+    /// <param name="sensor"></param>
+    public override void CollectObservations(VectorSensor sensor)
+    {
+        RobotMethods.CollectObservations(this,sensor);
+    }
+
+    /// <summary>
+    /// Do action when received, will be executed when requested.
+    /// </summary>
+    /// <param name="actionBuffers"></param>
+    public override void OnActionReceived(ActionBuffers actionBuffers)
+    {
+        RobotMethods.OnActionReceived(this, actionBuffers, idleColor.color);
+    }
+
+    // collision handling
+    private void OnTriggerEnter(Collider other)
+    {
+        RobotMethods.CollisionEvent(this);
+    }
+
+    /// <summary>
+    /// Assign task to robot. 
+    /// </summary>
+    /// <param name="task"> a Task object</param>
+    public void AssignTask(Task task)
+    {
+        RobotMethods.AssignTask(this, task);
+    }
+    
+    /// <summary>
+    /// Pick up.
+    /// </summary>
+    public void PickUp()
+    {
+        RobotMethods.PickUp(this);
+    }
+    
+    /// <summary>
+    /// Delivery. 
+    /// </summary>
+    /// <returns>the delivered task</returns>
+    public Task Deliver()
+    {
+        return RobotMethods.Deliver(this, idleColor.color);
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/RobotOfflineDecentralized.cs.meta b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/RobotOfflineDecentralized.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..fe499e5080631e0c05cd4d65b0fc146b4fec55ae
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/RobotOfflineDecentralized.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e224beeb8f8781f479c65279d3e07a01
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/SimulationManagerOfflineDecentralized.cs b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/SimulationManagerOfflineDecentralized.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c6f0d22e7530e21a350006dfa2548fddb2bb281e
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/SimulationManagerOfflineDecentralized.cs
@@ -0,0 +1,173 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System.Collections.Generic;
+using System;
+using System.IO;
+using UnityEngine;
+using Unity.MLAgents.SideChannels;
+using Newtonsoft.Json;
+using System.Linq;
+using Common.Scripts;
+using Common.SideChannels;
+using Common.SimulationManager;
+using Common.Warehouse;
+using Random = System.Random;
+
+/// <summary>
+/// Class <c> SimulationManagerOfflineDecentralized </c> controls the simulation for the Offline Decentralized Pick Up and
+/// Delivery problem.
+///
+/// The only fields that should be altered here is warehouseConfigFile, the path to the txt file containing
+/// the configurable parameters of the simulation and the path to the preset tasks.
+///
+/// Has instance methods:
+/// - GetMonoBehaviour(): return object as monobehavior
+/// - GetCurrentNode(int instanceID): get current node for a robot with given instance ID
+/// - RemoveTask(Task task): remove a tasks from current tasks
+/// - AddNewTask(): add a new task to current tasks
+/// - AssignTask(Task task, int instanceID): assign a task to a robot with given instance ID
+/// </summary>
+
+
+public class SimulationManagerOfflineDecentralized : MonoBehaviour, ISimulationManager
+{
+    public string warehouseConfigFile { get; }= "ConfigurationFiles/Offline_Decentralized/warehousejson.txt";
+    public string tasksListFile { get; }= "ConfigurationFiles/Offline_Decentralized/tasks_releasetime.txt";
+
+    // online or offline
+    public bool online { get; } = false;
+    
+    // colors
+    // colors for walls, tiles and prefabs
+    public Color colorWall { get; } = Color.black;
+    public Color colorTile { get; } = Color.white;
+    public Color colorEndPoint { get; }= new Color(0.5f, 0.5f, 1f); // blue-ish
+    public Color colorParking { get; } = Color.gray;
+
+    // colors for tasks and the robots that have been assigned these tasks
+    public HashSet<Color> assignedColors { get; set; } = new HashSet<Color>();
+    public HashSet<Color> notAssignedColors { get; set; } = new HashSet<Color>();
+
+    // endpoints
+    // dictionary containing all endpoints
+    // every endpoint will point to a gameobject, this will be setup by the Floor script
+    public Dictionary<Position, GameObject> endPoints { get; set; }= new Dictionary<Position, GameObject>();
+
+    // parameters of warehouse
+    public WarehouseParameters parameters { get; set; }
+
+    // tasks
+    // at every timestep there will be max numberOfTasks tasks that have to be assigned (by the python code), in 
+    // the offline setting this has to be same as the number of preset tasks
+    // current available tasks and their assigned colors: these are the tasks to remain to be assigned to robots
+    public Dictionary<Task, Color> currentTasks { get; set; } = new Dictionary<Task, Color>();
+    // all remaining tasks, used to store tasks read from file
+    public Task[] remainingTasks { get; set; }
+
+    // robots
+    [SerializeField] private GameObject robotPrefab = default; // GameObject prefab used for the robot
+
+    // For every robot the current node where he is going, i.e. the next action 
+    public Dictionary<int, Node> currentNodes { get; } = new Dictionary<int, Node>();
+
+    // For every robot the corresponding gameobject
+    public Dictionary<int, GameObject> robotGameObjects { get; set; } = new Dictionary<int, GameObject>();
+
+    // environment variables
+    // check for collisions
+    public bool collisions { get; set; }
+
+    // observations and actions
+    public int observationSize { get; }= 4; //id,x,y,rotation
+    public int actionSize { get; } = 5; //x,y,rotation,pick up, delivery
+
+    // environment variables for drawing
+    public float
+        SIZE { get; } = 1; // Size of square/tile, this is kept constant to avoid having to change camera perspective
+
+    public float SCALEROBOT { get; } = 0.49f; // Ratio robot to tile, for drawing robot
+    public float YROBOTFLOATING { get; }= 0.2f; // Floating y value robot, for drawing robot
+
+    // sidechannels
+    public EnvSideChannel envChannel { get; set; } // SideChannel for communication initial environment parameters
+    public TaskSideChannel taskChannel { get; set; } // SideChannel for communication on tasks
+
+    void Awake()
+    {
+        SimulationManagerMethods.SetUpWarehouse<RobotOfflineDecentralized>(this, robotPrefab, false);
+    }
+    
+    /// <summary>
+    /// Return this as MonoBehaviour.
+    /// </summary>
+    /// <returns></returns>
+    public MonoBehaviour GetMonoBehaviour()
+    {
+        return this;
+    }
+
+    /// <summary>
+    /// Show message when a collision has occured.
+    /// </summary>
+    public void OnGUI()
+    {
+        if (collisions)
+        {
+            SimulationManagerMethods.ShowCollisionMessage(this);
+        }
+    }
+
+    /// <summary>
+    /// Returns current node, i.e. the next node to go to, for a robot with a given instance ID.
+    /// </summary>
+    /// <param name="instanceID"> an int</param>
+    /// <returns> A node corresponding to the current node.</returns>
+    public Node GetCurrentNode(int instanceID)
+    {
+        return SimulationManagerMethods.GetCurrentNode(this,instanceID);
+    }
+
+    /// <summary>
+    /// Remove a task from CurrentTasks that was assigned to a robot.
+    /// </summary>
+    /// <param name="task"></param>
+    /// <exception cref="Exception">thrown if it was not assigned to a robot</exception>
+    public void RemoveTask(Task task)
+    {
+        SimulationManagerMethods.RemoveTask(this, task);
+    }
+
+    /// <summary>
+    /// Add a task to currentTasks if there are still tasks available. Assign a color and send information to python code.
+    /// </summary>
+    /// <exception cref="Exception">thrown when currentTasks has already reached capacity</exception>
+    public void AddNewTask()
+    {
+        SimulationManagerMethods.AddNewTask(this);
+    }
+
+    /// <summary>
+    /// Assign a task to a robot with a given instanceID.
+    /// </summary>
+    /// <param name="task"></param>
+    /// <param name="instanceID"></param>
+    public void AssignTask(Task task, int instanceID)
+    {
+        SimulationManagerMethods.AssignTask<RobotOfflineDecentralized>(this, task, instanceID);
+    }
+}
+
diff --git a/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/SimulationManagerOfflineDecentralized.cs.meta b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/SimulationManagerOfflineDecentralized.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..9b690ed9a0c7b40954dc07699918f57f0881d7f9
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Offline_Decentralized/SimulationManagerOfflineDecentralized.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 00bf636c107a31d489dc615292930654
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Centralized.meta b/PickUpandDelivery/Assets/Scripts/Online_Centralized.meta
new file mode 100644
index 0000000000000000000000000000000000000000..d22a27c7180498ecd4b764b76c6c574b1fff08a2
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Centralized.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 16849455029256649b94eab199627f93
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Centralized/RobotOnlineCentralized.cs b/PickUpandDelivery/Assets/Scripts/Online_Centralized/RobotOnlineCentralized.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2803a4333c420edb2c16900c9b1d8c730d1c1c13
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Centralized/RobotOnlineCentralized.cs
@@ -0,0 +1,90 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using Common.Robot;
+using Common.SimulationManager;
+using Common.Warehouse;
+using UnityEngine;
+
+/// <summary>
+/// Script <c> RobotOnlineCentralized </c>
+/// has public instance methods:
+/// - GetMonoBehaviour(): return instance as Monobehaviour
+/// - AssignTask(Task task): assign a task to robot and update color of robot accordingly
+/// - PickUp(): after picking up, a cross is drawn on top of the robot using the complementary color of the task
+/// - Deliver(): calls RemoveTask() and returns delivered task
+/// has private instance methods:
+/// - OnTriggerEnter(Collider other) for collision detection
+/// </summary>
+
+public class RobotOnlineCentralized : MonoBehaviour, IRobot
+{
+    public ISimulationManager  simulationManager { get; set; }
+
+    public Task assignedTask { get; set; } = null; // the task a robot is assigned, mainly used for coloring
+    [SerializeField] private Material idleColor = default; // color when no task assigned
+
+    void Start()
+    {
+        RobotMethods.InitializeRobotAtStart(this);
+    }
+    
+    void FixedUpdate()
+    {
+        RobotMethods.UpdatePosition(this);
+    }
+
+    /// <summary>
+    /// Return this as MonoBehaviour.
+    /// </summary>
+    /// <returns></returns>
+    public MonoBehaviour GetMonoBehaviour()
+    {
+        return this;
+    }
+    
+    // collision handling
+    private void OnTriggerEnter(Collider other)
+    {
+        RobotMethods.CollisionEvent(this);
+    }
+
+    /// <summary>
+    /// Assign task to robot. 
+    /// </summary>
+    /// <param name="task"> a Task object</param>
+    public void AssignTask(Task task)
+    {
+        RobotMethods.AssignTask(this, task);
+    }
+
+    /// <summary>
+    /// Pick up.
+    /// </summary>
+    public void PickUp()
+    {
+        RobotMethods.PickUp(this);
+    }
+
+    /// <summary>
+    /// Delivery. 
+    /// </summary>
+    /// <returns>the delivered task</returns>
+    public Task Deliver()
+    {
+        return RobotMethods.Deliver(this, idleColor.color);
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Centralized/RobotOnlineCentralized.cs.meta b/PickUpandDelivery/Assets/Scripts/Online_Centralized/RobotOnlineCentralized.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..1814ac0aed389c9765ca48f8cfc78d1f1ea498e7
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Centralized/RobotOnlineCentralized.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0ee9f4e10c142784c91290b59532cb09
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Centralized/SimulationManagerOnlineCentralized.cs b/PickUpandDelivery/Assets/Scripts/Online_Centralized/SimulationManagerOnlineCentralized.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9cb299d077f184010af2d1195a4a79c9624d5ec9
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Centralized/SimulationManagerOnlineCentralized.cs
@@ -0,0 +1,211 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System.Collections.Generic;
+using System;
+using UnityEngine;
+using Common.SideChannels;
+using Common.SimulationManager;
+using Common.Warehouse;
+using Unity.MLAgents;
+using Unity.MLAgents.Actuators;
+using Unity.MLAgents.Sensors;
+
+/// <summary>
+/// Class <c> SimulationManagerOnlineCentralized </c> controls the simulation for the Online Centralized Pick Up and
+/// Delivery problem.
+///
+/// The only field that should be altered here is warehouseConfigFile, the path to the txt file containing
+/// the configurable parameters of the simulation. Optionally a preset set of tasks.
+///
+/// Has instance methods: 
+/// - GetMonoBehaviour(): return object as monobehaviour
+/// - GetCurrentNode(int instanceID): get current node for a robot with given instance ID
+/// - RemoveTask(Task task): remove a tasks from current tasks
+/// - AddNewTask(): add a new task to current tasks
+/// - AssignTask(Task task, int instanceID): assign a task to a robot with given instance ID
+/// </summary>
+
+
+public class SimulationManagerOnlineCentralized : Agent, ISimulationManager
+{
+    //public string warehouseConfigFile {get;} = "ConfigurationFiles/Online_Centralized/warehousejson_random.txt";
+    public string warehouseConfigFile { get; } = "ConfigurationFiles/Online_Centralized/warehousejson_not_random.txt";
+    public string tasksListFile { get; }= "ConfigurationFiles/Online_Centralized/tasks.txt";
+    
+    // online or offline
+    public bool online { get; } = true;
+    
+    private int counter; // Count time in ms (used in advance method), to make sure every timeRobotPerTile a new action or node is given
+    
+    // colors
+    // colors for walls, tiles and prefabs
+    public Color colorWall { get; } = Color.black;
+    public Color colorTile { get; } = Color.white;
+    public Color colorEndPoint { get; }= new Color(0.5f, 0.5f, 1f); // blue-ish
+    public Color colorParking { get; } = Color.gray;
+
+    // colors for tasks and the robots that have been assigned these tasks
+    public HashSet<Color> assignedColors { get; set; } = new HashSet<Color>();
+    public HashSet<Color> notAssignedColors { get; set; } = new HashSet<Color>();
+
+    // endpoints
+    // dictionary containing all endpoints
+    // every endpoint will point to a gameobject, this will be setup by the Floor script
+    public Dictionary<Position, GameObject> endPoints { get; set; }= new Dictionary<Position, GameObject>();
+
+    // parameters of warehouse
+    public WarehouseParameters parameters { get; set; }
+
+    // tasks
+    // at every timestep there will be max numberOfTasks tasks that have to be assigned (by the python code)
+    // current available tasks and their assigned colors: these are the tasks to remain to be assigned to robots
+    public Dictionary<Task, Color> currentTasks { get; set; } = new Dictionary<Task, Color>();
+    // all remaining tasks, not yet in currentTasks, if not generated randomly and taken from predefined list
+    public Task[] remainingTasks { get; set; }
+
+    // robots
+    [SerializeField] private GameObject robotPrefab = default; // GameObject prefab used for the robot
+
+    // For every robot the current node where he is going, i.e. the next action 
+    public Dictionary<int, Node> currentNodes { get; } = new Dictionary<int, Node>();
+
+    // For every robot the corresponding gameobject
+    public Dictionary<int, GameObject> robotGameObjects { get; set; }= new Dictionary<int, GameObject>();
+
+    // environment variables
+    // check for collisions
+    public bool collisions { get; set; }
+
+    // observations and actions
+    public int observationSize { get; }= 4; // id,x,y,rotation
+    public int actionSize { get; }= 6; // id,x,y,rotation,pick up, delivery
+
+    // environment variables for drawing
+    public float
+        SIZE { get; } = 1; // Size of square/tile, this is kept constant to avoid having to change camera perspective
+
+    public float SCALEROBOT { get; } = 0.49f; // Ratio robot to tile, for drawing robot
+    public float YROBOTFLOATING { get; }= 0.2f; // Floating y value robot, for drawing robot
+
+    // sidechannels
+    public EnvSideChannel envChannel { get; set; } // SideChannel for communication initial environment parameters
+    public TaskSideChannel taskChannel { get; set; } // SideChannel for communication on tasks
+
+    void Awake()
+    {
+        SimulationManagerMethods.SetUpWarehouse<RobotOnlineCentralized>(this, robotPrefab, true);
+    }
+
+    /// <summary>
+    /// Every timeRobotPerTile a new decision is requested: observations are collected (<c>CollectObservations</c>) and actions are received
+    /// (<c>OnActionReceived</c>)
+    /// </summary>
+    public void FixedUpdate()
+    {
+        counter += 20; // FixedUpdate is called every 20ms, add 20ms to counter
+        // if counter has passed timeRobotPerTile and there is a python client listening new actions are requested
+        // if a collisions has been detected no new requests are made
+        if (counter >= parameters.TimeRobotPerTile && Academy.Instance.IsCommunicatorOn)
+        {
+            if (!collisions)
+            {
+                RequestDecision(); // manually request a decision
+            }
+
+            counter = 0; // reset counter
+        }
+    }
+   
+   /// <summary>
+   /// Return this as MonoBehaviour.
+   /// </summary>
+   /// <returns></returns>
+   public MonoBehaviour GetMonoBehaviour()
+   {
+       return this;
+   }
+    
+    /// <summary>
+    /// Collect observations, will be executed when requested.
+    /// </summary>
+    /// <param name="sensor"></param>
+    public override void CollectObservations(VectorSensor sensor)
+    {
+        SimulationManagerMethods.CollectObservations(this, sensor);
+    }
+    
+    /// <summary>
+    /// Receive actions, will be executed when requested.
+    /// Note that the number of actions per robot should be equal to <c>ActionSize</c>.
+    /// </summary>
+    public override void OnActionReceived(ActionBuffers actionBuffers)
+    {
+        SimulationManagerMethods.OnActionReceived<RobotOnlineCentralized>(this,actionBuffers);
+    }
+    
+    /// <summary>
+    /// Show message when a collision has occured.
+    /// </summary>
+    private void OnGUI()
+    {
+        if (collisions)
+        {
+            SimulationManagerMethods.ShowCollisionMessage(this);
+        }
+    }
+    
+    /// <summary>
+    /// Returns current node, i.e. the next node to go to, for a robot with a given instance ID.
+    /// </summary>
+    /// <param name="instanceID"> an int</param>
+    /// <returns> A node corresponding to the current node.</returns>
+    public Node GetCurrentNode(int instanceID)
+    {
+        return SimulationManagerMethods.GetCurrentNode(this,instanceID);
+    }
+
+    /// <summary>
+    /// Remove a task from CurrentTasks. Reset color of pick up and delivery endpoints.
+    /// Make color available. 
+    /// </summary>
+    /// <param name="task"></param>
+    /// <exception cref="Exception">thrown if it was not assigned to a robot</exception>
+    public void RemoveTask(Task task)
+    {
+        SimulationManagerMethods.RemoveTask(this, task);
+    }
+    
+    /// <summary>
+    /// Add a task to currentTasks if there are still tasks available. Assign a color and send information to python code.
+    /// </summary>
+    /// <exception cref="Exception">thrown when currentTasks has already reached capacity</exception>
+    public void AddNewTask()
+    {
+        SimulationManagerMethods.AddNewTask(this);
+    }
+
+    /// <summary>
+    /// Assign a task to a robot with a given instanceID.
+    /// </summary>
+    /// <param name="task"></param>
+    /// <param name="instanceID"></param>
+    public void AssignTask(Task task, int instanceID)
+    {
+        SimulationManagerMethods.AssignTask<RobotOnlineCentralized>(this, task, instanceID);
+    }
+}
+
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Centralized/SimulationManagerOnlineCentralized.cs.meta b/PickUpandDelivery/Assets/Scripts/Online_Centralized/SimulationManagerOnlineCentralized.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..876b08d111b677caa17052cc901d7c751de0d1c9
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Centralized/SimulationManagerOnlineCentralized.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e6bf74ca92d023a4dadefd09723b6558
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Decentralized.meta b/PickUpandDelivery/Assets/Scripts/Online_Decentralized.meta
new file mode 100644
index 0000000000000000000000000000000000000000..ac4f46d805fc3096aadf4406370e4e259f8ba1fd
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Decentralized.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d36c6186b86728445b8ce6bc5a7c8180
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Decentralized/RobotOnlineDecentralized.cs b/PickUpandDelivery/Assets/Scripts/Online_Decentralized/RobotOnlineDecentralized.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9b866a5270c0553dbd9129fad783340836197b78
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Decentralized/RobotOnlineDecentralized.cs
@@ -0,0 +1,129 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+
+using Common.Robot;
+using Common.SimulationManager;
+using Common.Warehouse;
+using Unity.MLAgents;
+using Unity.MLAgents.Actuators;
+using Unity.MLAgents.Sensors;
+using UnityEngine;
+
+/// <summary>
+/// Script <c> RobotOnlineDecentralized </c>
+/// has public instance methods:
+/// - GetMonoBehaviour(): return instance as Monobehaviour
+/// - AssignTask(Task task): assign a task to robot and update color of robot accordingly
+/// - CollectObservations(VectorSensor sensor): collect an observation
+/// - OnActionReceived(ActionBuffers actionBuffers): do action
+/// - Pickup() and Delivery(): unused methods from interface IRobot
+/// has private instance methods:
+/// - OnTriggerEnter(Collider other) for collision detection
+/// </summary>
+public class RobotOnlineDecentralized : Agent, IRobot
+{
+    public ISimulationManager  simulationManager { get; set; }
+
+    private int
+        counter; // Count time in ms (used in advance method), to make sure every timeRobotPerTile a new action or node is given
+
+    public Task assignedTask { get; set; }= null; // the task a robot is assigned, mainly used for coloring
+    [SerializeField] private Material idleColor = default; // color when no task assigned
+
+    void Start()
+    {
+        RobotMethods.InitializeRobotAtStart(this);
+    }
+    
+    void FixedUpdate()
+    {
+        counter += 20; // FixedUpdate is called every 20ms, add 20ms to counter
+        // if counter has passed timeRobotPerTile and there is a python client listening new actions are requested
+        // if a collisions has been detected no new requests are made
+        if (counter >= simulationManager.parameters.TimeRobotPerTile && Academy.Instance.IsCommunicatorOn)
+        {
+            if (!simulationManager.collisions)
+            {
+                Debug.Log("request by " + gameObject.GetInstanceID());
+                RequestDecision(); // manually request a decision
+            }
+
+            counter = 0; // reset counter
+        }
+
+        RobotMethods.UpdatePosition(this);
+    }
+    
+    /// <summary>
+    /// Return this as MonoBehaviour.
+    /// </summary>
+    /// <returns></returns>
+    public MonoBehaviour GetMonoBehaviour()
+    {
+        return this;
+    }
+
+    /// <summary>
+    /// Collect observation, will be executed when requested.
+    /// </summary>
+    /// <param name="sensor"></param>
+    public override void CollectObservations(VectorSensor sensor)
+    {
+        RobotMethods.CollectObservations(this,sensor);
+    }
+    
+    /// <summary>
+    /// Do action when received, will be executed when requested.
+    /// </summary>
+    /// <param name="actionBuffers"></param>
+    public override void OnActionReceived(ActionBuffers actionBuffers)
+    {
+        RobotMethods.OnActionReceived(this, actionBuffers, idleColor.color);
+    }
+
+    // collision handling
+    private void OnTriggerEnter(Collider other)
+    {
+        RobotMethods.CollisionEvent(this);
+    }
+
+    /// <summary>
+    /// Assign task to robot. 
+    /// </summary>
+    /// <param name="task"> a Task object</param>
+    public void AssignTask(Task task)
+    {
+        RobotMethods.AssignTask(this, task);
+    }
+    
+    /// <summary>
+    /// Pick up.
+    /// </summary>
+    public void PickUp()
+    {
+        RobotMethods.PickUp(this);
+    }
+    
+    /// <summary>
+    /// Delivery. 
+    /// </summary>
+    /// <returns>the delivered task</returns>
+    public Task Deliver()
+    {
+        return RobotMethods.Deliver(this, idleColor.color);
+    }
+}
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Decentralized/RobotOnlineDecentralized.cs.meta b/PickUpandDelivery/Assets/Scripts/Online_Decentralized/RobotOnlineDecentralized.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..f93b82ae59289b27f28d39db8d38f1405187ea88
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Decentralized/RobotOnlineDecentralized.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 388587dedc7732c449a7c4461107ddc3
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Decentralized/SimulationManagerOnlineDecentralized.cs b/PickUpandDelivery/Assets/Scripts/Online_Decentralized/SimulationManagerOnlineDecentralized.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eb396aba5055ea2c556f8dd00f6c1ec8d40aed04
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Decentralized/SimulationManagerOnlineDecentralized.cs
@@ -0,0 +1,167 @@
+/*
+ Copyright (c) 2021. AI Lab, Vrije Universiteit Brussel.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using System.Collections.Generic;
+using System;
+using UnityEngine;
+using Common.SideChannels;
+using Common.SimulationManager;
+using Common.Warehouse;
+
+/// <summary>
+/// Class <c> SimulationManagerOnlineDecentralized </c> controls the simulation for the Online Decentralized Pick Up and
+/// Delivery problem.
+///
+/// The only field that should be altered here is warehouseConfigFile, the path to the txt file containing
+/// the configurable parameters of the simulation. Optionally a preset set of tasks.
+///
+/// Has instance methods:
+/// - GetMonoBehaviour(): return object as monobehavior
+/// - GetCurrentNode(int instanceID): get current node for a robot with given instance ID
+/// - RemoveTask(Task task): remove a tasks from current tasks
+/// - AddNewTask(): add a new task to current tasks
+/// - AssignTask(Task task, int instanceID): assign a task to a robot with given instance ID
+/// </summary>
+
+
+public class SimulationManagerOnlineDecentralized : MonoBehaviour, ISimulationManager
+{
+    //public string warehouseConfigFile { get; } = "ConfigurationFiles/Online_Decentralized/warehousejson_not_random.txt";
+    public string warehouseConfigFile {get;} = "ConfigurationFiles/Online_Centralized/warehousejson_random.txt";
+    public string tasksListFile { get; } = "ConfigurationFiles/Online_Decentralized/tasks.txt";
+
+    // online or offline
+    public bool online { get; } = true;
+    
+    // colors
+    // colors for walls, tiles and prefabs
+    public Color colorWall { get; } = Color.black;
+    public Color colorTile { get; } = Color.white;
+    public Color colorEndPoint { get; }= new Color(0.5f, 0.5f, 1f); // blue-ish
+    public Color colorParking { get; } = Color.gray;
+
+    // colors for tasks and the robots that have been assigned these tasks
+    public HashSet<Color> assignedColors { get; set; } 
+    public HashSet<Color> notAssignedColors { get; set; } 
+
+    // endpoints
+    // dictionary containing all endpoints
+    // every endpoint will point to a gameobject, this will be setup by the Floor script
+    public Dictionary<Position, GameObject> endPoints { get; set; }
+
+    // parameters of warehouse
+    public WarehouseParameters parameters { get; set; }
+
+    // tasks
+    // at every timestep there will be max numberOfTasks tasks that have to be assigned (by the python code)
+    // current available tasks and their assigned colors: these are the tasks to remain to be assigned to robots
+    public Dictionary<Task, Color> currentTasks { get; set; }
+    // all remaining tasks, not yet in currentTasks, if not generated randomly and taken from predefined list
+    public Task[] remainingTasks { get; set; }
+
+    // robots
+    [SerializeField] private GameObject robotPrefab = default; // GameObject prefab used for the robot
+
+    // For every robot the current node where he is going, i.e. the next action 
+    public Dictionary<int, Node> currentNodes { get; } = new Dictionary<int, Node>();
+
+    // For every robot the corresponding gameobject
+    public Dictionary<int, GameObject> robotGameObjects { get; set; }= new Dictionary<int, GameObject>();
+
+    // environment variables
+    // check for collisions
+    public bool collisions { get; set; }
+
+    // observations and actions
+    public int observationSize { get;  } = 4; //id,x,y,rotation
+    public int actionSize { get; } = 5; //x,y,rotation,pick up, delivery
+
+    // environment variables for drawing
+    public float
+        SIZE { get; } = 1; // Size of square/tile, this is kept constant to avoid having to change camera perspective
+
+    public float SCALEROBOT { get; } = 0.49f; // Ratio robot to tile, for drawing robot
+    public float YROBOTFLOATING { get; }= 0.2f; // Floating y value robot, for drawing robot
+
+    // sidechannels
+    public EnvSideChannel envChannel { get; set; } // SideChannel for communication initial environment parameters
+    public TaskSideChannel taskChannel { get; set; } // SideChannel for communication on tasks
+
+    void Awake()
+    {
+        SimulationManagerMethods.SetUpWarehouse<RobotOnlineDecentralized>(this, robotPrefab, false);
+    }
+    
+    /// <summary>
+    /// Return this as MonoBehaviour.
+    /// </summary>
+    /// <returns></returns>
+    public MonoBehaviour GetMonoBehaviour()
+    {
+        return this;
+    }
+
+    /// <summary>
+    /// Show message when a collision has occured.
+    /// </summary>
+    public void OnGUI()
+    {
+        if (collisions)
+        {
+            SimulationManagerMethods.ShowCollisionMessage(this);
+        }
+    }
+
+    /// <summary>
+    /// Returns current node, i.e. the next node to go to, for a robot with a given instance ID.
+    /// </summary>
+    /// <param name="instanceID"> an int</param>
+    /// <returns> A node corresponding to the current node.</returns>
+    public Node GetCurrentNode(int instanceID)
+    {
+        return SimulationManagerMethods.GetCurrentNode(this,instanceID);
+    }
+
+    /// <summary>
+    /// Remove a task from CurrentTasks that was assigned to a robot.
+    /// </summary>
+    /// <param name="task"></param>
+    /// <exception cref="Exception">thrown if it was not assigned to a robot</exception>
+    public void RemoveTask(Task task)
+    {
+        SimulationManagerMethods.RemoveTask(this, task);
+    }
+
+    /// <summary>
+    /// Add a task to currentTasks if there are still tasks available. Assign a color and send information to python code.
+    /// </summary>
+    /// <exception cref="Exception">thrown when currentTasks has already reached capacity</exception>
+    public void AddNewTask()
+    {
+        SimulationManagerMethods.AddNewTask(this);
+    }
+
+    /// <summary>
+    /// Assign a task to a robot with a given instanceID.
+    /// </summary>
+    /// <param name="task"></param>
+    /// <param name="instanceID"></param>
+    public void AssignTask(Task task, int instanceID)
+    {
+        SimulationManagerMethods.AssignTask<RobotOnlineDecentralized>(this, task, instanceID);
+    }
+}
+
diff --git a/PickUpandDelivery/Assets/Scripts/Online_Decentralized/SimulationManagerOnlineDecentralized.cs.meta b/PickUpandDelivery/Assets/Scripts/Online_Decentralized/SimulationManagerOnlineDecentralized.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..7e69fb08dd730ea41b154b9fe5213a4e28948a23
--- /dev/null
+++ b/PickUpandDelivery/Assets/Scripts/Online_Decentralized/SimulationManagerOnlineDecentralized.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a6033bfb5a3a1f747b8a528a445711a6
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Shaders.meta b/PickUpandDelivery/Assets/Shaders.meta
new file mode 100644
index 0000000000000000000000000000000000000000..58b6c1ad82bc6cf9bb3caeb3afcaf71c00f3d8de
--- /dev/null
+++ b/PickUpandDelivery/Assets/Shaders.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c5ae9f1e9e172db45b8fcd2ac5c729b3
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/Assets/Shaders/TextShader.shader b/PickUpandDelivery/Assets/Shaders/TextShader.shader
new file mode 100644
index 0000000000000000000000000000000000000000..4f433e4bda5c6c2d7ec7ae61ba06f6bff7e0b456
--- /dev/null
+++ b/PickUpandDelivery/Assets/Shaders/TextShader.shader
@@ -0,0 +1,18 @@
+Shader "GUI/3D Text Shader - Cull Back" {
+    Properties {
+        _MainTex ("Font Texture", 2D) = "white" {}
+        _Color ("Text Color", Color) = (1,1,1,1)
+    }
+ 
+    SubShader {
+        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
+        Lighting Off Cull Back ZWrite Off Fog { Mode Off }
+        Blend SrcAlpha OneMinusSrcAlpha
+        Pass {
+            Color [_Color]
+            SetTexture [_MainTex] {
+                combine primary, texture * primary
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/PickUpandDelivery/Assets/Shaders/TextShader.shader.meta b/PickUpandDelivery/Assets/Shaders/TextShader.shader.meta
new file mode 100644
index 0000000000000000000000000000000000000000..dcd31128c12e19e8cb61854841daf86ab4c86e42
--- /dev/null
+++ b/PickUpandDelivery/Assets/Shaders/TextShader.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 3b25d06e715175541a7601ed730df7c6
+ShaderImporter:
+  externalObjects: {}
+  defaultTextures: []
+  nonModifiableTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/tasks.txt b/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/tasks.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7f62b76ad2e3d4b861325ef0b7eb42389ca6e419
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/tasks.txt
@@ -0,0 +1,52 @@
+[
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 2
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 9
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 9
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 3,
+      "Column": 4
+    },
+    "Delivery": {
+      "Row": 5,
+      "Column": 7
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 6,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 7,
+      "Column": 3
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 7,
+      "Column": 5
+    },
+    "Delivery": {
+      "Row": 9,
+      "Column": 6
+    }
+  }
+]
diff --git a/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/tasks_releasetime.txt b/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/tasks_releasetime.txt
new file mode 100644
index 0000000000000000000000000000000000000000..81ed04c0bf18e033fe7179b97919ff63f696d922
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/tasks_releasetime.txt
@@ -0,0 +1,57 @@
+[
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 2
+    },
+    "ReleaseTime": 5
+  },
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 9
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 9
+    },
+    "ReleaseTime": 9
+  },
+  {
+    "PickUp": {
+      "Row": 3,
+      "Column": 4
+    },
+    "Delivery": {
+      "Row": 5,
+      "Column": 7
+    },
+    "ReleaseTime": 10
+  },
+  {
+    "PickUp": {
+      "Row": 6,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 7,
+      "Column": 3
+    },
+    "ReleaseTime": 2
+  },
+  {
+    "PickUp": {
+      "Row": 7,
+      "Column": 5
+    },
+    "Delivery": {
+      "Row": 9,
+      "Column": 6
+    },
+    "ReleaseTime": 2
+  }
+]
diff --git a/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/warehousejson.txt b/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/warehousejson.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6c208ca746adf0f3fed6cefc87bc3e5a9b104892
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Offline_Centralized/warehousejson.txt
@@ -0,0 +1,26 @@
+{
+  "Matrix": [
+  [2,2,2,2,2,2,2,2,2,2],
+  [2,2,2,2,2,2,2,2,2,2],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3]
+  ],
+  "Rotation": 45,
+  "TimeRobotPerTile": 1000,
+  "NumberOfRobots": 3,
+  "InitialNodes" : [
+  {"GridPosition":{"Row":0,"Column":0},"Degrees":0},
+  {"GridPosition":{"Row":1,"Column":4},"Degrees":270},
+  {"GridPosition":{"Row":0,"Column":9},"Degrees":270}
+  ],
+  "NumberOfTasks": 5,
+  "CanGoBackWards": false,
+  "RandomTasks": false
+}
diff --git a/PickUpandDelivery/ConfigurationFiles/Offline_Decentralized/tasks.txt b/PickUpandDelivery/ConfigurationFiles/Offline_Decentralized/tasks.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7f62b76ad2e3d4b861325ef0b7eb42389ca6e419
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Offline_Decentralized/tasks.txt
@@ -0,0 +1,52 @@
+[
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 2
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 9
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 9
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 3,
+      "Column": 4
+    },
+    "Delivery": {
+      "Row": 5,
+      "Column": 7
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 6,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 7,
+      "Column": 3
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 7,
+      "Column": 5
+    },
+    "Delivery": {
+      "Row": 9,
+      "Column": 6
+    }
+  }
+]
diff --git a/PickUpandDelivery/ConfigurationFiles/Offline_Decentralized/tasks_releasetime.txt b/PickUpandDelivery/ConfigurationFiles/Offline_Decentralized/tasks_releasetime.txt
new file mode 100644
index 0000000000000000000000000000000000000000..81ed04c0bf18e033fe7179b97919ff63f696d922
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Offline_Decentralized/tasks_releasetime.txt
@@ -0,0 +1,57 @@
+[
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 2
+    },
+    "ReleaseTime": 5
+  },
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 9
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 9
+    },
+    "ReleaseTime": 9
+  },
+  {
+    "PickUp": {
+      "Row": 3,
+      "Column": 4
+    },
+    "Delivery": {
+      "Row": 5,
+      "Column": 7
+    },
+    "ReleaseTime": 10
+  },
+  {
+    "PickUp": {
+      "Row": 6,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 7,
+      "Column": 3
+    },
+    "ReleaseTime": 2
+  },
+  {
+    "PickUp": {
+      "Row": 7,
+      "Column": 5
+    },
+    "Delivery": {
+      "Row": 9,
+      "Column": 6
+    },
+    "ReleaseTime": 2
+  }
+]
diff --git a/PickUpandDelivery/ConfigurationFiles/Offline_Decentralized/warehousejson.txt b/PickUpandDelivery/ConfigurationFiles/Offline_Decentralized/warehousejson.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6c208ca746adf0f3fed6cefc87bc3e5a9b104892
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Offline_Decentralized/warehousejson.txt
@@ -0,0 +1,26 @@
+{
+  "Matrix": [
+  [2,2,2,2,2,2,2,2,2,2],
+  [2,2,2,2,2,2,2,2,2,2],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3]
+  ],
+  "Rotation": 45,
+  "TimeRobotPerTile": 1000,
+  "NumberOfRobots": 3,
+  "InitialNodes" : [
+  {"GridPosition":{"Row":0,"Column":0},"Degrees":0},
+  {"GridPosition":{"Row":1,"Column":4},"Degrees":270},
+  {"GridPosition":{"Row":0,"Column":9},"Degrees":270}
+  ],
+  "NumberOfTasks": 5,
+  "CanGoBackWards": false,
+  "RandomTasks": false
+}
diff --git a/PickUpandDelivery/ConfigurationFiles/Online_Centralized/tasks.txt b/PickUpandDelivery/ConfigurationFiles/Online_Centralized/tasks.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7f62b76ad2e3d4b861325ef0b7eb42389ca6e419
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Online_Centralized/tasks.txt
@@ -0,0 +1,52 @@
+[
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 2
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 9
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 9
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 3,
+      "Column": 4
+    },
+    "Delivery": {
+      "Row": 5,
+      "Column": 7
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 6,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 7,
+      "Column": 3
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 7,
+      "Column": 5
+    },
+    "Delivery": {
+      "Row": 9,
+      "Column": 6
+    }
+  }
+]
diff --git a/PickUpandDelivery/ConfigurationFiles/Online_Centralized/warehousejson_not_random.txt b/PickUpandDelivery/ConfigurationFiles/Online_Centralized/warehousejson_not_random.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ac87e23386d1b4c8fcefd1f55f4c6596aa0e5abe
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Online_Centralized/warehousejson_not_random.txt
@@ -0,0 +1,26 @@
+{
+  "Matrix": [
+  [2,2,2,2,2,2,2,2,2,2],
+  [2,2,2,2,2,2,2,2,2,2],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3]
+  ],
+  "Rotation": 45,
+  "TimeRobotPerTile": 1000,
+  "NumberOfRobots": 3,
+  "InitialNodes" : [
+  {"GridPosition":{"Row":0,"Column":0},"Degrees":0},
+  {"GridPosition":{"Row":1,"Column":4},"Degrees":270},
+  {"GridPosition":{"Row":0,"Column":9},"Degrees":270}
+  ],
+  "NumberOfTasks": 3,
+  "CanGoBackWards": false,
+  "RandomTasks": false
+}
diff --git a/PickUpandDelivery/ConfigurationFiles/Online_Centralized/warehousejson_random.txt b/PickUpandDelivery/ConfigurationFiles/Online_Centralized/warehousejson_random.txt
new file mode 100644
index 0000000000000000000000000000000000000000..985e2f98b15dc780fe819ea29221f566ad395764
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Online_Centralized/warehousejson_random.txt
@@ -0,0 +1,26 @@
+{
+  "Matrix": [
+  [2,2,2,2,2,2,2,2,2,2],
+  [2,2,2,2,2,2,2,2,2,2],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3]
+  ],
+  "Rotation": 45,
+  "TimeRobotPerTile": 1000,
+  "NumberOfRobots": 3,
+  "InitialNodes" : [
+  {"GridPosition":{"Row":0,"Column":0},"Degrees":0},
+  {"GridPosition":{"Row":1,"Column":4},"Degrees":270},
+  {"GridPosition":{"Row":0,"Column":9},"Degrees":270}
+  ],
+  "NumberOfTasks": 3,
+  "CanGoBackWards": false,
+  "RandomTasks": true
+}
diff --git a/PickUpandDelivery/ConfigurationFiles/Online_Decentralized/tasks.txt b/PickUpandDelivery/ConfigurationFiles/Online_Decentralized/tasks.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7f62b76ad2e3d4b861325ef0b7eb42389ca6e419
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Online_Decentralized/tasks.txt
@@ -0,0 +1,52 @@
+[
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 2
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 2,
+      "Column": 9
+    },
+    "Delivery": {
+      "Row": 3,
+      "Column": 9
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 3,
+      "Column": 4
+    },
+    "Delivery": {
+      "Row": 5,
+      "Column": 7
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 6,
+      "Column": 0
+    },
+    "Delivery": {
+      "Row": 7,
+      "Column": 3
+    }
+  },
+  {
+    "PickUp": {
+      "Row": 7,
+      "Column": 5
+    },
+    "Delivery": {
+      "Row": 9,
+      "Column": 6
+    }
+  }
+]
diff --git a/PickUpandDelivery/ConfigurationFiles/Online_Decentralized/warehousejson_not_random.txt b/PickUpandDelivery/ConfigurationFiles/Online_Decentralized/warehousejson_not_random.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ac87e23386d1b4c8fcefd1f55f4c6596aa0e5abe
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Online_Decentralized/warehousejson_not_random.txt
@@ -0,0 +1,26 @@
+{
+  "Matrix": [
+  [2,2,2,2,2,2,2,2,2,2],
+  [2,2,2,2,2,2,2,2,2,2],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3]
+  ],
+  "Rotation": 45,
+  "TimeRobotPerTile": 1000,
+  "NumberOfRobots": 3,
+  "InitialNodes" : [
+  {"GridPosition":{"Row":0,"Column":0},"Degrees":0},
+  {"GridPosition":{"Row":1,"Column":4},"Degrees":270},
+  {"GridPosition":{"Row":0,"Column":9},"Degrees":270}
+  ],
+  "NumberOfTasks": 3,
+  "CanGoBackWards": false,
+  "RandomTasks": false
+}
diff --git a/PickUpandDelivery/ConfigurationFiles/Online_Decentralized/warehousejson_random.txt b/PickUpandDelivery/ConfigurationFiles/Online_Decentralized/warehousejson_random.txt
new file mode 100644
index 0000000000000000000000000000000000000000..985e2f98b15dc780fe819ea29221f566ad395764
--- /dev/null
+++ b/PickUpandDelivery/ConfigurationFiles/Online_Decentralized/warehousejson_random.txt
@@ -0,0 +1,26 @@
+{
+  "Matrix": [
+  [2,2,2,2,2,2,2,2,2,2],
+  [2,2,2,2,2,2,2,2,2,2],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,1,1,1,1,1,1,0,3],
+  [3,0,3,3,3,3,3,3,0,3],
+  [3,0,0,0,0,0,0,0,0,3]
+  ],
+  "Rotation": 45,
+  "TimeRobotPerTile": 1000,
+  "NumberOfRobots": 3,
+  "InitialNodes" : [
+  {"GridPosition":{"Row":0,"Column":0},"Degrees":0},
+  {"GridPosition":{"Row":1,"Column":4},"Degrees":270},
+  {"GridPosition":{"Row":0,"Column":9},"Degrees":270}
+  ],
+  "NumberOfTasks": 3,
+  "CanGoBackWards": false,
+  "RandomTasks": true
+}
diff --git a/PickUpandDelivery/Packages/manifest.json b/PickUpandDelivery/Packages/manifest.json
new file mode 100644
index 0000000000000000000000000000000000000000..e9d691a6c4a01ff2d6d7575d39ad268b1aec2145
--- /dev/null
+++ b/PickUpandDelivery/Packages/manifest.json
@@ -0,0 +1,43 @@
+{
+  "dependencies": {
+    "com.unity.collab-proxy": "1.2.16",
+    "com.unity.ide.rider": "1.1.4",
+    "com.unity.ide.vscode": "1.2.1",
+    "com.unity.ml-agents": "1.7.2-preview",
+    "com.unity.test-framework": "1.1.16",
+    "com.unity.textmeshpro": "2.1.1",
+    "com.unity.timeline": "1.2.17",
+    "com.unity.ugui": "1.0.0",
+    "com.unity.modules.ai": "1.0.0",
+    "com.unity.modules.androidjni": "1.0.0",
+    "com.unity.modules.animation": "1.0.0",
+    "com.unity.modules.assetbundle": "1.0.0",
+    "com.unity.modules.audio": "1.0.0",
+    "com.unity.modules.cloth": "1.0.0",
+    "com.unity.modules.director": "1.0.0",
+    "com.unity.modules.imageconversion": "1.0.0",
+    "com.unity.modules.imgui": "1.0.0",
+    "com.unity.modules.jsonserialize": "1.0.0",
+    "com.unity.modules.particlesystem": "1.0.0",
+    "com.unity.modules.physics": "1.0.0",
+    "com.unity.modules.physics2d": "1.0.0",
+    "com.unity.modules.screencapture": "1.0.0",
+    "com.unity.modules.terrain": "1.0.0",
+    "com.unity.modules.terrainphysics": "1.0.0",
+    "com.unity.modules.tilemap": "1.0.0",
+    "com.unity.modules.ui": "1.0.0",
+    "com.unity.modules.uielements": "1.0.0",
+    "com.unity.modules.umbra": "1.0.0",
+    "com.unity.modules.unityanalytics": "1.0.0",
+    "com.unity.modules.unitywebrequest": "1.0.0",
+    "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
+    "com.unity.modules.unitywebrequestaudio": "1.0.0",
+    "com.unity.modules.unitywebrequesttexture": "1.0.0",
+    "com.unity.modules.unitywebrequestwww": "1.0.0",
+    "com.unity.modules.vehicles": "1.0.0",
+    "com.unity.modules.video": "1.0.0",
+    "com.unity.modules.vr": "1.0.0",
+    "com.unity.modules.wind": "1.0.0",
+    "com.unity.modules.xr": "1.0.0"
+  }
+}
diff --git a/PickUpandDelivery/Packages/packages-lock.json b/PickUpandDelivery/Packages/packages-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..2eb734f3c1e7fd77fd7d0e096bd6fec7e0b1407b
--- /dev/null
+++ b/PickUpandDelivery/Packages/packages-lock.json
@@ -0,0 +1,353 @@
+{
+  "dependencies": {
+    "com.unity.barracuda": {
+      "version": "1.2.1-preview",
+      "depth": 1,
+      "source": "registry",
+      "dependencies": {
+        "com.unity.burst": "1.3.4",
+        "com.unity.modules.jsonserialize": "1.0.0",
+        "com.unity.modules.imageconversion": "1.0.0"
+      },
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.burst": {
+      "version": "1.3.4",
+      "depth": 2,
+      "source": "registry",
+      "dependencies": {
+        "com.unity.mathematics": "1.2.1"
+      },
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.collab-proxy": {
+      "version": "1.2.16",
+      "depth": 0,
+      "source": "registry",
+      "dependencies": {},
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.ext.nunit": {
+      "version": "1.0.0",
+      "depth": 1,
+      "source": "registry",
+      "dependencies": {},
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.ide.rider": {
+      "version": "1.1.4",
+      "depth": 0,
+      "source": "registry",
+      "dependencies": {
+        "com.unity.test-framework": "1.1.1"
+      },
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.ide.vscode": {
+      "version": "1.2.1",
+      "depth": 0,
+      "source": "registry",
+      "dependencies": {},
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.mathematics": {
+      "version": "1.2.1",
+      "depth": 3,
+      "source": "registry",
+      "dependencies": {},
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.ml-agents": {
+      "version": "1.7.2-preview",
+      "depth": 0,
+      "source": "registry",
+      "dependencies": {
+        "com.unity.barracuda": "1.2.1-preview",
+        "com.unity.modules.imageconversion": "1.0.0",
+        "com.unity.modules.jsonserialize": "1.0.0",
+        "com.unity.modules.physics": "1.0.0",
+        "com.unity.modules.physics2d": "1.0.0",
+        "com.unity.modules.unityanalytics": "1.0.0"
+      },
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.test-framework": {
+      "version": "1.1.16",
+      "depth": 0,
+      "source": "registry",
+      "dependencies": {
+        "com.unity.ext.nunit": "1.0.0",
+        "com.unity.modules.imgui": "1.0.0",
+        "com.unity.modules.jsonserialize": "1.0.0"
+      },
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.textmeshpro": {
+      "version": "2.1.1",
+      "depth": 0,
+      "source": "registry",
+      "dependencies": {
+        "com.unity.ugui": "1.0.0"
+      },
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.timeline": {
+      "version": "1.2.17",
+      "depth": 0,
+      "source": "registry",
+      "dependencies": {},
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.ugui": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.ui": "1.0.0",
+        "com.unity.modules.imgui": "1.0.0"
+      }
+    },
+    "com.unity.modules.ai": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.androidjni": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.animation": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.assetbundle": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.audio": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.cloth": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.physics": "1.0.0"
+      }
+    },
+    "com.unity.modules.director": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.audio": "1.0.0",
+        "com.unity.modules.animation": "1.0.0"
+      }
+    },
+    "com.unity.modules.imageconversion": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.imgui": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.jsonserialize": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.particlesystem": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.physics": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.physics2d": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.screencapture": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.imageconversion": "1.0.0"
+      }
+    },
+    "com.unity.modules.subsystems": {
+      "version": "1.0.0",
+      "depth": 1,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.jsonserialize": "1.0.0"
+      }
+    },
+    "com.unity.modules.terrain": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.terrainphysics": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.physics": "1.0.0",
+        "com.unity.modules.terrain": "1.0.0"
+      }
+    },
+    "com.unity.modules.tilemap": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.physics2d": "1.0.0"
+      }
+    },
+    "com.unity.modules.ui": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.uielements": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.imgui": "1.0.0",
+        "com.unity.modules.jsonserialize": "1.0.0"
+      }
+    },
+    "com.unity.modules.umbra": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.unityanalytics": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.unitywebrequest": "1.0.0",
+        "com.unity.modules.jsonserialize": "1.0.0"
+      }
+    },
+    "com.unity.modules.unitywebrequest": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.unitywebrequestassetbundle": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.assetbundle": "1.0.0",
+        "com.unity.modules.unitywebrequest": "1.0.0"
+      }
+    },
+    "com.unity.modules.unitywebrequestaudio": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.unitywebrequest": "1.0.0",
+        "com.unity.modules.audio": "1.0.0"
+      }
+    },
+    "com.unity.modules.unitywebrequesttexture": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.unitywebrequest": "1.0.0",
+        "com.unity.modules.imageconversion": "1.0.0"
+      }
+    },
+    "com.unity.modules.unitywebrequestwww": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.unitywebrequest": "1.0.0",
+        "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
+        "com.unity.modules.unitywebrequestaudio": "1.0.0",
+        "com.unity.modules.audio": "1.0.0",
+        "com.unity.modules.assetbundle": "1.0.0",
+        "com.unity.modules.imageconversion": "1.0.0"
+      }
+    },
+    "com.unity.modules.vehicles": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.physics": "1.0.0"
+      }
+    },
+    "com.unity.modules.video": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.audio": "1.0.0",
+        "com.unity.modules.ui": "1.0.0",
+        "com.unity.modules.unitywebrequest": "1.0.0"
+      }
+    },
+    "com.unity.modules.vr": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.jsonserialize": "1.0.0",
+        "com.unity.modules.physics": "1.0.0",
+        "com.unity.modules.xr": "1.0.0"
+      }
+    },
+    "com.unity.modules.wind": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {}
+    },
+    "com.unity.modules.xr": {
+      "version": "1.0.0",
+      "depth": 0,
+      "source": "builtin",
+      "dependencies": {
+        "com.unity.modules.physics": "1.0.0",
+        "com.unity.modules.jsonserialize": "1.0.0",
+        "com.unity.modules.subsystems": "1.0.0"
+      }
+    }
+  }
+}
diff --git a/PickUpandDelivery/ProjectSettings/AudioManager.asset b/PickUpandDelivery/ProjectSettings/AudioManager.asset
new file mode 100644
index 0000000000000000000000000000000000000000..07ebfb05df3b58b4a596eac64cd19529d36ce565
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/AudioManager.asset
@@ -0,0 +1,19 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!11 &1
+AudioManager:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Volume: 1
+  Rolloff Scale: 1
+  Doppler Factor: 1
+  Default Speaker Mode: 2
+  m_SampleRate: 0
+  m_DSPBufferSize: 1024
+  m_VirtualVoiceCount: 512
+  m_RealVoiceCount: 32
+  m_SpatializerPlugin: 
+  m_AmbisonicDecoderPlugin: 
+  m_DisableAudio: 0
+  m_VirtualizeEffects: 1
+  m_RequestedDSPBufferSize: 1024
diff --git a/PickUpandDelivery/ProjectSettings/ClusterInputManager.asset b/PickUpandDelivery/ProjectSettings/ClusterInputManager.asset
new file mode 100644
index 0000000000000000000000000000000000000000..e7886b266a005f4d9d80f2fef8d1649dcfd3ed2b
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/ClusterInputManager.asset
@@ -0,0 +1,6 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!236 &1
+ClusterInputManager:
+  m_ObjectHideFlags: 0
+  m_Inputs: []
diff --git a/PickUpandDelivery/ProjectSettings/DynamicsManager.asset b/PickUpandDelivery/ProjectSettings/DynamicsManager.asset
new file mode 100644
index 0000000000000000000000000000000000000000..cdc1f3eab509699e163f46fd14f0e81eb3a5dbaf
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/DynamicsManager.asset
@@ -0,0 +1,34 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!55 &1
+PhysicsManager:
+  m_ObjectHideFlags: 0
+  serializedVersion: 11
+  m_Gravity: {x: 0, y: -9.81, z: 0}
+  m_DefaultMaterial: {fileID: 0}
+  m_BounceThreshold: 2
+  m_SleepThreshold: 0.005
+  m_DefaultContactOffset: 0.01
+  m_DefaultSolverIterations: 6
+  m_DefaultSolverVelocityIterations: 1
+  m_QueriesHitBackfaces: 0
+  m_QueriesHitTriggers: 1
+  m_EnableAdaptiveForce: 0
+  m_ClothInterCollisionDistance: 0
+  m_ClothInterCollisionStiffness: 0
+  m_ContactsGeneration: 1
+  m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+  m_AutoSimulation: 1
+  m_AutoSyncTransforms: 0
+  m_ReuseCollisionCallbacks: 1
+  m_ClothInterCollisionSettingsToggle: 0
+  m_ContactPairsMode: 0
+  m_BroadphaseType: 0
+  m_WorldBounds:
+    m_Center: {x: 0, y: 0, z: 0}
+    m_Extent: {x: 250, y: 250, z: 250}
+  m_WorldSubdivisions: 8
+  m_FrictionType: 0
+  m_EnableEnhancedDeterminism: 0
+  m_EnableUnifiedHeightmaps: 1
+  m_DefaultMaxAngluarSpeed: 7
diff --git a/PickUpandDelivery/ProjectSettings/EditorBuildSettings.asset b/PickUpandDelivery/ProjectSettings/EditorBuildSettings.asset
new file mode 100644
index 0000000000000000000000000000000000000000..0147887ef4b113c3a3b8da44ef30e3208f1e9120
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/EditorBuildSettings.asset
@@ -0,0 +1,8 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1045 &1
+EditorBuildSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Scenes: []
+  m_configObjects: {}
diff --git a/PickUpandDelivery/ProjectSettings/EditorSettings.asset b/PickUpandDelivery/ProjectSettings/EditorSettings.asset
new file mode 100644
index 0000000000000000000000000000000000000000..f92054474a36ddeca10712dccb2aaf7a6a3bcfb9
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/EditorSettings.asset
@@ -0,0 +1,35 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!159 &1
+EditorSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_ExternalVersionControlSupport: Visible Meta Files
+  m_SerializationMode: 2
+  m_LineEndingsForNewScripts: 0
+  m_DefaultBehaviorMode: 0
+  m_PrefabRegularEnvironment: {fileID: 0}
+  m_PrefabUIEnvironment: {fileID: 0}
+  m_SpritePackerMode: 0
+  m_SpritePackerPaddingPower: 1
+  m_EtcTextureCompressorBehavior: 1
+  m_EtcTextureFastCompressor: 1
+  m_EtcTextureNormalCompressor: 2
+  m_EtcTextureBestCompressor: 4
+  m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref
+  m_ProjectGenerationRootNamespace: 
+  m_CollabEditorSettings:
+    inProgressEnabled: 1
+  m_EnableTextureStreamingInEditMode: 1
+  m_EnableTextureStreamingInPlayMode: 1
+  m_AsyncShaderCompilation: 1
+  m_EnterPlayModeOptionsEnabled: 0
+  m_EnterPlayModeOptions: 3
+  m_ShowLightmapResolutionOverlay: 1
+  m_UseLegacyProbeSampleCount: 0
+  m_AssetPipelineMode: 1
+  m_CacheServerMode: 0
+  m_CacheServerEndpoint: 
+  m_CacheServerNamespacePrefix: default
+  m_CacheServerEnableDownload: 1
+  m_CacheServerEnableUpload: 1
diff --git a/PickUpandDelivery/ProjectSettings/GraphicsSettings.asset b/PickUpandDelivery/ProjectSettings/GraphicsSettings.asset
new file mode 100644
index 0000000000000000000000000000000000000000..43369e3c51bec3405f9e8d1388aa0468ab413513
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/GraphicsSettings.asset
@@ -0,0 +1,63 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!30 &1
+GraphicsSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 13
+  m_Deferred:
+    m_Mode: 1
+    m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0}
+  m_DeferredReflections:
+    m_Mode: 1
+    m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0}
+  m_ScreenSpaceShadows:
+    m_Mode: 1
+    m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0}
+  m_LegacyDeferred:
+    m_Mode: 1
+    m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0}
+  m_DepthNormals:
+    m_Mode: 1
+    m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0}
+  m_MotionVectors:
+    m_Mode: 1
+    m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0}
+  m_LightHalo:
+    m_Mode: 1
+    m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0}
+  m_LensFlare:
+    m_Mode: 1
+    m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0}
+  m_AlwaysIncludedShaders:
+  - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0}
+  - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0}
+  - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0}
+  - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0}
+  - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
+  - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
+  m_PreloadedShaders: []
+  m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000,
+    type: 0}
+  m_CustomRenderPipeline: {fileID: 0}
+  m_TransparencySortMode: 0
+  m_TransparencySortAxis: {x: 0, y: 0, z: 1}
+  m_DefaultRenderingPath: 1
+  m_DefaultMobileRenderingPath: 1
+  m_TierSettings: []
+  m_LightmapStripping: 0
+  m_FogStripping: 0
+  m_InstancingStripping: 0
+  m_LightmapKeepPlain: 1
+  m_LightmapKeepDirCombined: 1
+  m_LightmapKeepDynamicPlain: 1
+  m_LightmapKeepDynamicDirCombined: 1
+  m_LightmapKeepShadowMask: 1
+  m_LightmapKeepSubtractive: 1
+  m_FogKeepLinear: 1
+  m_FogKeepExp: 1
+  m_FogKeepExp2: 1
+  m_AlbedoSwatchInfos: []
+  m_LightsUseLinearIntensity: 0
+  m_LightsUseColorTemperature: 0
+  m_LogWhenShaderIsCompiled: 0
+  m_AllowEnlightenSupportForUpgradedProject: 0
diff --git a/PickUpandDelivery/ProjectSettings/InputManager.asset b/PickUpandDelivery/ProjectSettings/InputManager.asset
new file mode 100644
index 0000000000000000000000000000000000000000..17c8f538e2152c0a0310b4870979eeecece2153c
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/InputManager.asset
@@ -0,0 +1,295 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!13 &1
+InputManager:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Axes:
+  - serializedVersion: 3
+    m_Name: Horizontal
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: left
+    positiveButton: right
+    altNegativeButton: a
+    altPositiveButton: d
+    gravity: 3
+    dead: 0.001
+    sensitivity: 3
+    snap: 1
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Vertical
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: down
+    positiveButton: up
+    altNegativeButton: s
+    altPositiveButton: w
+    gravity: 3
+    dead: 0.001
+    sensitivity: 3
+    snap: 1
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Fire1
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: left ctrl
+    altNegativeButton: 
+    altPositiveButton: mouse 0
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Fire2
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: left alt
+    altNegativeButton: 
+    altPositiveButton: mouse 1
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Fire3
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: left shift
+    altNegativeButton: 
+    altPositiveButton: mouse 2
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Jump
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: space
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Mouse X
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: 
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 0
+    dead: 0
+    sensitivity: 0.1
+    snap: 0
+    invert: 0
+    type: 1
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Mouse Y
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: 
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 0
+    dead: 0
+    sensitivity: 0.1
+    snap: 0
+    invert: 0
+    type: 1
+    axis: 1
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Mouse ScrollWheel
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: 
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 0
+    dead: 0
+    sensitivity: 0.1
+    snap: 0
+    invert: 0
+    type: 1
+    axis: 2
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Horizontal
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: 
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 0
+    dead: 0.19
+    sensitivity: 1
+    snap: 0
+    invert: 0
+    type: 2
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Vertical
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: 
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 0
+    dead: 0.19
+    sensitivity: 1
+    snap: 0
+    invert: 1
+    type: 2
+    axis: 1
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Fire1
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: joystick button 0
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Fire2
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: joystick button 1
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Fire3
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: joystick button 2
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Jump
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: joystick button 3
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Submit
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: return
+    altNegativeButton: 
+    altPositiveButton: joystick button 0
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Submit
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: enter
+    altNegativeButton: 
+    altPositiveButton: space
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: Cancel
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: escape
+    altNegativeButton: 
+    altPositiveButton: joystick button 1
+    gravity: 1000
+    dead: 0.001
+    sensitivity: 1000
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 0
diff --git a/PickUpandDelivery/ProjectSettings/NavMeshAreas.asset b/PickUpandDelivery/ProjectSettings/NavMeshAreas.asset
new file mode 100644
index 0000000000000000000000000000000000000000..3b0b7c3d183abdd300112f56965916ef11667f54
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/NavMeshAreas.asset
@@ -0,0 +1,91 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!126 &1
+NavMeshProjectSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  areas:
+  - name: Walkable
+    cost: 1
+  - name: Not Walkable
+    cost: 1
+  - name: Jump
+    cost: 2
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  - name: 
+    cost: 1
+  m_LastAgentTypeID: -887442657
+  m_Settings:
+  - serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.75
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    debug:
+      m_Flags: 0
+  m_SettingNames:
+  - Humanoid
diff --git a/PickUpandDelivery/ProjectSettings/PackageManagerSettings.asset b/PickUpandDelivery/ProjectSettings/PackageManagerSettings.asset
new file mode 100644
index 0000000000000000000000000000000000000000..9418901fcb67b88885674769811bfbd5d207207b
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/PackageManagerSettings.asset
@@ -0,0 +1,38 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &1
+MonoBehaviour:
+  m_ObjectHideFlags: 61
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 0}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 0}
+  m_Name: 
+  m_EditorClassIdentifier: UnityEditor:UnityEditor.PackageManager.UI:PackageManagerProjectSettings
+  m_ScopedRegistriesSettingsExpanded: 1
+  oneTimeWarningShown: 0
+  m_Registries:
+  - m_Id: main
+    m_Name: 
+    m_Url: https://packages.unity.com
+    m_Scopes: []
+    m_IsDefault: 1
+  m_UserSelectedRegistryName: 
+  m_UserAddingNewScopedRegistry: 0
+  m_RegistryInfoDraft:
+    m_ErrorMessage: 
+    m_Original:
+      m_Id: 
+      m_Name: 
+      m_Url: 
+      m_Scopes: []
+      m_IsDefault: 0
+    m_Modified: 0
+    m_Name: 
+    m_Url: 
+    m_Scopes:
+    - 
+    m_SelectedScopeIndex: 0
diff --git a/PickUpandDelivery/ProjectSettings/Physics2DSettings.asset b/PickUpandDelivery/ProjectSettings/Physics2DSettings.asset
new file mode 100644
index 0000000000000000000000000000000000000000..47880b1c8c8e3b6306101004bb9826527d80e05e
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/Physics2DSettings.asset
@@ -0,0 +1,56 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!19 &1
+Physics2DSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 4
+  m_Gravity: {x: 0, y: -9.81}
+  m_DefaultMaterial: {fileID: 0}
+  m_VelocityIterations: 8
+  m_PositionIterations: 3
+  m_VelocityThreshold: 1
+  m_MaxLinearCorrection: 0.2
+  m_MaxAngularCorrection: 8
+  m_MaxTranslationSpeed: 100
+  m_MaxRotationSpeed: 360
+  m_BaumgarteScale: 0.2
+  m_BaumgarteTimeOfImpactScale: 0.75
+  m_TimeToSleep: 0.5
+  m_LinearSleepTolerance: 0.01
+  m_AngularSleepTolerance: 2
+  m_DefaultContactOffset: 0.01
+  m_JobOptions:
+    serializedVersion: 2
+    useMultithreading: 0
+    useConsistencySorting: 0
+    m_InterpolationPosesPerJob: 100
+    m_NewContactsPerJob: 30
+    m_CollideContactsPerJob: 100
+    m_ClearFlagsPerJob: 200
+    m_ClearBodyForcesPerJob: 200
+    m_SyncDiscreteFixturesPerJob: 50
+    m_SyncContinuousFixturesPerJob: 50
+    m_FindNearestContactsPerJob: 100
+    m_UpdateTriggerContactsPerJob: 100
+    m_IslandSolverCostThreshold: 100
+    m_IslandSolverBodyCostScale: 1
+    m_IslandSolverContactCostScale: 10
+    m_IslandSolverJointCostScale: 10
+    m_IslandSolverBodiesPerJob: 50
+    m_IslandSolverContactsPerJob: 50
+  m_AutoSimulation: 1
+  m_QueriesHitTriggers: 1
+  m_QueriesStartInColliders: 1
+  m_CallbacksOnDisable: 1
+  m_ReuseCollisionCallbacks: 1
+  m_AutoSyncTransforms: 0
+  m_AlwaysShowColliders: 0
+  m_ShowColliderSleep: 1
+  m_ShowColliderContacts: 0
+  m_ShowColliderAABB: 0
+  m_ContactArrowScale: 0.2
+  m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412}
+  m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432}
+  m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745}
+  m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804}
+  m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
diff --git a/PickUpandDelivery/ProjectSettings/PresetManager.asset b/PickUpandDelivery/ProjectSettings/PresetManager.asset
new file mode 100644
index 0000000000000000000000000000000000000000..67a94daefe2e6bce3ec73546ad7cda94f702ad22
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/PresetManager.asset
@@ -0,0 +1,7 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1386491679 &1
+PresetManager:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_DefaultPresets: {}
diff --git a/PickUpandDelivery/ProjectSettings/ProjectSettings.asset b/PickUpandDelivery/ProjectSettings/ProjectSettings.asset
new file mode 100644
index 0000000000000000000000000000000000000000..fed8e2fdaf302936ce5cc6051236b163956d99d8
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/ProjectSettings.asset
@@ -0,0 +1,668 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!129 &1
+PlayerSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 20
+  productGUID: b51819efc0bece9459ecfe47e46deed1
+  AndroidProfiler: 0
+  AndroidFilterTouchesWhenObscured: 0
+  AndroidEnableSustainedPerformanceMode: 0
+  defaultScreenOrientation: 4
+  targetDevice: 2
+  useOnDemandResources: 0
+  accelerometerFrequency: 60
+  companyName: DefaultCompany
+  productName: Pick Up and Delivery
+  defaultCursor: {fileID: 0}
+  cursorHotspot: {x: 0, y: 0}
+  m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
+  m_ShowUnitySplashScreen: 1
+  m_ShowUnitySplashLogo: 1
+  m_SplashScreenOverlayOpacity: 1
+  m_SplashScreenAnimation: 1
+  m_SplashScreenLogoStyle: 1
+  m_SplashScreenDrawMode: 0
+  m_SplashScreenBackgroundAnimationZoom: 1
+  m_SplashScreenLogoAnimationZoom: 1
+  m_SplashScreenBackgroundLandscapeAspect: 1
+  m_SplashScreenBackgroundPortraitAspect: 1
+  m_SplashScreenBackgroundLandscapeUvs:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  m_SplashScreenBackgroundPortraitUvs:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  m_SplashScreenLogos: []
+  m_VirtualRealitySplashScreen: {fileID: 0}
+  m_HolographicTrackingLossScreen: {fileID: 0}
+  defaultScreenWidth: 1024
+  defaultScreenHeight: 768
+  defaultScreenWidthWeb: 960
+  defaultScreenHeightWeb: 600
+  m_StereoRenderingPath: 0
+  m_ActiveColorSpace: 0
+  m_MTRendering: 1
+  m_StackTraceTypes: 010000000100000001000000010000000100000001000000
+  iosShowActivityIndicatorOnLoading: -1
+  androidShowActivityIndicatorOnLoading: -1
+  iosUseCustomAppBackgroundBehavior: 0
+  iosAllowHTTPDownload: 1
+  allowedAutorotateToPortrait: 1
+  allowedAutorotateToPortraitUpsideDown: 1
+  allowedAutorotateToLandscapeRight: 1
+  allowedAutorotateToLandscapeLeft: 1
+  useOSAutorotation: 1
+  use32BitDisplayBuffer: 1
+  preserveFramebufferAlpha: 0
+  disableDepthAndStencilBuffers: 0
+  androidStartInFullscreen: 1
+  androidRenderOutsideSafeArea: 1
+  androidUseSwappy: 0
+  androidBlitType: 0
+  defaultIsNativeResolution: 1
+  macRetinaSupport: 1
+  runInBackground: 1
+  captureSingleScreen: 0
+  muteOtherAudioSources: 0
+  Prepare IOS For Recording: 0
+  Force IOS Speakers When Recording: 0
+  deferSystemGesturesMode: 0
+  hideHomeButton: 0
+  submitAnalytics: 1
+  usePlayerLog: 1
+  bakeCollisionMeshes: 0
+  forceSingleInstance: 0
+  useFlipModelSwapchain: 1
+  resizableWindow: 0
+  useMacAppStoreValidation: 0
+  macAppStoreCategory: public.app-category.games
+  gpuSkinning: 1
+  xboxPIXTextureCapture: 0
+  xboxEnableAvatar: 0
+  xboxEnableKinect: 0
+  xboxEnableKinectAutoTracking: 0
+  xboxEnableFitness: 0
+  visibleInBackground: 1
+  allowFullscreenSwitch: 1
+  fullscreenMode: 1
+  xboxSpeechDB: 0
+  xboxEnableHeadOrientation: 0
+  xboxEnableGuest: 0
+  xboxEnablePIXSampling: 0
+  metalFramebufferOnly: 0
+  xboxOneResolution: 0
+  xboxOneSResolution: 0
+  xboxOneXResolution: 3
+  xboxOneMonoLoggingLevel: 0
+  xboxOneLoggingLevel: 1
+  xboxOneDisableEsram: 0
+  xboxOneEnableTypeOptimization: 0
+  xboxOnePresentImmediateThreshold: 0
+  switchQueueCommandMemory: 0
+  switchQueueControlMemory: 16384
+  switchQueueComputeMemory: 262144
+  switchNVNShaderPoolsGranularity: 33554432
+  switchNVNDefaultPoolsGranularity: 16777216
+  switchNVNOtherPoolsGranularity: 16777216
+  switchNVNMaxPublicTextureIDCount: 0
+  switchNVNMaxPublicSamplerIDCount: 0
+  stadiaPresentMode: 0
+  stadiaTargetFramerate: 0
+  vulkanNumSwapchainBuffers: 3
+  vulkanEnableSetSRGBWrite: 0
+  vulkanEnableLateAcquireNextImage: 0
+  m_SupportedAspectRatios:
+    4:3: 1
+    5:4: 1
+    16:10: 1
+    16:9: 1
+    Others: 1
+  bundleVersion: 0.1
+  preloadedAssets: []
+  metroInputSource: 0
+  wsaTransparentSwapchain: 0
+  m_HolographicPauseOnTrackingLoss: 1
+  xboxOneDisableKinectGpuReservation: 1
+  xboxOneEnable7thCore: 1
+  vrSettings:
+    cardboard:
+      depthFormat: 0
+      enableTransitionView: 0
+    daydream:
+      depthFormat: 0
+      useSustainedPerformanceMode: 0
+      enableVideoLayer: 0
+      useProtectedVideoMemory: 0
+      minimumSupportedHeadTracking: 0
+      maximumSupportedHeadTracking: 1
+    hololens:
+      depthFormat: 1
+      depthBufferSharingEnabled: 1
+    lumin:
+      depthFormat: 0
+      frameTiming: 2
+      enableGLCache: 0
+      glCacheMaxBlobSize: 524288
+      glCacheMaxFileSize: 8388608
+    oculus:
+      sharedDepthBuffer: 1
+      dashSupport: 1
+      lowOverheadMode: 0
+      protectedContext: 0
+      v2Signing: 1
+    enable360StereoCapture: 0
+  isWsaHolographicRemotingEnabled: 0
+  enableFrameTimingStats: 0
+  useHDRDisplay: 0
+  D3DHDRBitDepth: 0
+  m_ColorGamuts: 00000000
+  targetPixelDensity: 30
+  resolutionScalingMode: 0
+  androidSupportedAspectRatio: 1
+  androidMaxAspectRatio: 2.1
+  applicationIdentifier: {}
+  buildNumber: {}
+  AndroidBundleVersionCode: 1
+  AndroidMinSdkVersion: 19
+  AndroidTargetSdkVersion: 0
+  AndroidPreferredInstallLocation: 1
+  aotOptions: 
+  stripEngineCode: 1
+  iPhoneStrippingLevel: 0
+  iPhoneScriptCallOptimization: 0
+  ForceInternetPermission: 0
+  ForceSDCardPermission: 0
+  CreateWallpaper: 0
+  APKExpansionFiles: 0
+  keepLoadedShadersAlive: 0
+  StripUnusedMeshComponents: 1
+  VertexChannelCompressionMask: 4054
+  iPhoneSdkVersion: 988
+  iOSTargetOSVersionString: 10.0
+  tvOSSdkVersion: 0
+  tvOSRequireExtendedGameController: 0
+  tvOSTargetOSVersionString: 10.0
+  uIPrerenderedIcon: 0
+  uIRequiresPersistentWiFi: 0
+  uIRequiresFullScreen: 1
+  uIStatusBarHidden: 1
+  uIExitOnSuspend: 0
+  uIStatusBarStyle: 0
+  appleTVSplashScreen: {fileID: 0}
+  appleTVSplashScreen2x: {fileID: 0}
+  tvOSSmallIconLayers: []
+  tvOSSmallIconLayers2x: []
+  tvOSLargeIconLayers: []
+  tvOSLargeIconLayers2x: []
+  tvOSTopShelfImageLayers: []
+  tvOSTopShelfImageLayers2x: []
+  tvOSTopShelfImageWideLayers: []
+  tvOSTopShelfImageWideLayers2x: []
+  iOSLaunchScreenType: 0
+  iOSLaunchScreenPortrait: {fileID: 0}
+  iOSLaunchScreenLandscape: {fileID: 0}
+  iOSLaunchScreenBackgroundColor:
+    serializedVersion: 2
+    rgba: 0
+  iOSLaunchScreenFillPct: 100
+  iOSLaunchScreenSize: 100
+  iOSLaunchScreenCustomXibPath: 
+  iOSLaunchScreeniPadType: 0
+  iOSLaunchScreeniPadImage: {fileID: 0}
+  iOSLaunchScreeniPadBackgroundColor:
+    serializedVersion: 2
+    rgba: 0
+  iOSLaunchScreeniPadFillPct: 100
+  iOSLaunchScreeniPadSize: 100
+  iOSLaunchScreeniPadCustomXibPath: 
+  iOSUseLaunchScreenStoryboard: 0
+  iOSLaunchScreenCustomStoryboardPath: 
+  iOSDeviceRequirements: []
+  iOSURLSchemes: []
+  iOSBackgroundModes: 0
+  iOSMetalForceHardShadows: 0
+  metalEditorSupport: 1
+  metalAPIValidation: 1
+  iOSRenderExtraFrameOnPause: 0
+  appleDeveloperTeamID: 
+  iOSManualSigningProvisioningProfileID: 
+  tvOSManualSigningProvisioningProfileID: 
+  iOSManualSigningProvisioningProfileType: 0
+  tvOSManualSigningProvisioningProfileType: 0
+  appleEnableAutomaticSigning: 0
+  iOSRequireARKit: 0
+  iOSAutomaticallyDetectAndAddCapabilities: 1
+  appleEnableProMotion: 0
+  clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea
+  templatePackageId: com.unity.template.3d@4.2.8
+  templateDefaultScene: Assets/Scenes/SampleScene.unity
+  AndroidTargetArchitectures: 1
+  AndroidSplashScreenScale: 0
+  androidSplashScreen: {fileID: 0}
+  AndroidKeystoreName: 
+  AndroidKeyaliasName: 
+  AndroidBuildApkPerCpuArchitecture: 0
+  AndroidTVCompatibility: 0
+  AndroidIsGame: 1
+  AndroidEnableTango: 0
+  androidEnableBanner: 1
+  androidUseLowAccuracyLocation: 0
+  androidUseCustomKeystore: 0
+  m_AndroidBanners:
+  - width: 320
+    height: 180
+    banner: {fileID: 0}
+  androidGamepadSupportLevel: 0
+  AndroidValidateAppBundleSize: 1
+  AndroidAppBundleSizeToValidate: 150
+  m_BuildTargetIcons: []
+  m_BuildTargetPlatformIcons: []
+  m_BuildTargetBatching:
+  - m_BuildTarget: Standalone
+    m_StaticBatching: 1
+    m_DynamicBatching: 0
+  - m_BuildTarget: tvOS
+    m_StaticBatching: 1
+    m_DynamicBatching: 0
+  - m_BuildTarget: Android
+    m_StaticBatching: 1
+    m_DynamicBatching: 0
+  - m_BuildTarget: iPhone
+    m_StaticBatching: 1
+    m_DynamicBatching: 0
+  - m_BuildTarget: WebGL
+    m_StaticBatching: 0
+    m_DynamicBatching: 0
+  m_BuildTargetGraphicsJobs:
+  - m_BuildTarget: MacStandaloneSupport
+    m_GraphicsJobs: 0
+  - m_BuildTarget: Switch
+    m_GraphicsJobs: 1
+  - m_BuildTarget: MetroSupport
+    m_GraphicsJobs: 1
+  - m_BuildTarget: AppleTVSupport
+    m_GraphicsJobs: 0
+  - m_BuildTarget: BJMSupport
+    m_GraphicsJobs: 1
+  - m_BuildTarget: LinuxStandaloneSupport
+    m_GraphicsJobs: 1
+  - m_BuildTarget: PS4Player
+    m_GraphicsJobs: 1
+  - m_BuildTarget: iOSSupport
+    m_GraphicsJobs: 0
+  - m_BuildTarget: WindowsStandaloneSupport
+    m_GraphicsJobs: 1
+  - m_BuildTarget: XboxOnePlayer
+    m_GraphicsJobs: 1
+  - m_BuildTarget: LuminSupport
+    m_GraphicsJobs: 0
+  - m_BuildTarget: AndroidPlayer
+    m_GraphicsJobs: 0
+  - m_BuildTarget: WebGLSupport
+    m_GraphicsJobs: 0
+  m_BuildTargetGraphicsJobMode:
+  - m_BuildTarget: PS4Player
+    m_GraphicsJobMode: 0
+  - m_BuildTarget: XboxOnePlayer
+    m_GraphicsJobMode: 0
+  m_BuildTargetGraphicsAPIs:
+  - m_BuildTarget: AndroidPlayer
+    m_APIs: 150000000b000000
+    m_Automatic: 0
+  - m_BuildTarget: iOSSupport
+    m_APIs: 10000000
+    m_Automatic: 1
+  - m_BuildTarget: AppleTVSupport
+    m_APIs: 10000000
+    m_Automatic: 0
+  - m_BuildTarget: WebGLSupport
+    m_APIs: 0b000000
+    m_Automatic: 1
+  m_BuildTargetVRSettings:
+  - m_BuildTarget: Standalone
+    m_Enabled: 0
+    m_Devices:
+    - Oculus
+    - OpenVR
+  openGLRequireES31: 0
+  openGLRequireES31AEP: 0
+  openGLRequireES32: 0
+  m_TemplateCustomTags: {}
+  mobileMTRendering:
+    Android: 1
+    iPhone: 1
+    tvOS: 1
+  m_BuildTargetGroupLightmapEncodingQuality: []
+  m_BuildTargetGroupLightmapSettings: []
+  playModeTestRunnerEnabled: 0
+  runPlayModeTestAsEditModeTest: 0
+  actionOnDotNetUnhandledException: 1
+  enableInternalProfiler: 0
+  logObjCUncaughtExceptions: 1
+  enableCrashReportAPI: 0
+  cameraUsageDescription: 
+  locationUsageDescription: 
+  microphoneUsageDescription: 
+  switchNetLibKey: 
+  switchSocketMemoryPoolSize: 6144
+  switchSocketAllocatorPoolSize: 128
+  switchSocketConcurrencyLimit: 14
+  switchScreenResolutionBehavior: 2
+  switchUseCPUProfiler: 0
+  switchApplicationID: 0x01004b9000490000
+  switchNSODependencies: 
+  switchTitleNames_0: 
+  switchTitleNames_1: 
+  switchTitleNames_2: 
+  switchTitleNames_3: 
+  switchTitleNames_4: 
+  switchTitleNames_5: 
+  switchTitleNames_6: 
+  switchTitleNames_7: 
+  switchTitleNames_8: 
+  switchTitleNames_9: 
+  switchTitleNames_10: 
+  switchTitleNames_11: 
+  switchTitleNames_12: 
+  switchTitleNames_13: 
+  switchTitleNames_14: 
+  switchPublisherNames_0: 
+  switchPublisherNames_1: 
+  switchPublisherNames_2: 
+  switchPublisherNames_3: 
+  switchPublisherNames_4: 
+  switchPublisherNames_5: 
+  switchPublisherNames_6: 
+  switchPublisherNames_7: 
+  switchPublisherNames_8: 
+  switchPublisherNames_9: 
+  switchPublisherNames_10: 
+  switchPublisherNames_11: 
+  switchPublisherNames_12: 
+  switchPublisherNames_13: 
+  switchPublisherNames_14: 
+  switchIcons_0: {fileID: 0}
+  switchIcons_1: {fileID: 0}
+  switchIcons_2: {fileID: 0}
+  switchIcons_3: {fileID: 0}
+  switchIcons_4: {fileID: 0}
+  switchIcons_5: {fileID: 0}
+  switchIcons_6: {fileID: 0}
+  switchIcons_7: {fileID: 0}
+  switchIcons_8: {fileID: 0}
+  switchIcons_9: {fileID: 0}
+  switchIcons_10: {fileID: 0}
+  switchIcons_11: {fileID: 0}
+  switchIcons_12: {fileID: 0}
+  switchIcons_13: {fileID: 0}
+  switchIcons_14: {fileID: 0}
+  switchSmallIcons_0: {fileID: 0}
+  switchSmallIcons_1: {fileID: 0}
+  switchSmallIcons_2: {fileID: 0}
+  switchSmallIcons_3: {fileID: 0}
+  switchSmallIcons_4: {fileID: 0}
+  switchSmallIcons_5: {fileID: 0}
+  switchSmallIcons_6: {fileID: 0}
+  switchSmallIcons_7: {fileID: 0}
+  switchSmallIcons_8: {fileID: 0}
+  switchSmallIcons_9: {fileID: 0}
+  switchSmallIcons_10: {fileID: 0}
+  switchSmallIcons_11: {fileID: 0}
+  switchSmallIcons_12: {fileID: 0}
+  switchSmallIcons_13: {fileID: 0}
+  switchSmallIcons_14: {fileID: 0}
+  switchManualHTML: 
+  switchAccessibleURLs: 
+  switchLegalInformation: 
+  switchMainThreadStackSize: 1048576
+  switchPresenceGroupId: 
+  switchLogoHandling: 0
+  switchReleaseVersion: 0
+  switchDisplayVersion: 1.0.0
+  switchStartupUserAccount: 0
+  switchTouchScreenUsage: 0
+  switchSupportedLanguagesMask: 0
+  switchLogoType: 0
+  switchApplicationErrorCodeCategory: 
+  switchUserAccountSaveDataSize: 0
+  switchUserAccountSaveDataJournalSize: 0
+  switchApplicationAttribute: 0
+  switchCardSpecSize: -1
+  switchCardSpecClock: -1
+  switchRatingsMask: 0
+  switchRatingsInt_0: 0
+  switchRatingsInt_1: 0
+  switchRatingsInt_2: 0
+  switchRatingsInt_3: 0
+  switchRatingsInt_4: 0
+  switchRatingsInt_5: 0
+  switchRatingsInt_6: 0
+  switchRatingsInt_7: 0
+  switchRatingsInt_8: 0
+  switchRatingsInt_9: 0
+  switchRatingsInt_10: 0
+  switchRatingsInt_11: 0
+  switchRatingsInt_12: 0
+  switchLocalCommunicationIds_0: 
+  switchLocalCommunicationIds_1: 
+  switchLocalCommunicationIds_2: 
+  switchLocalCommunicationIds_3: 
+  switchLocalCommunicationIds_4: 
+  switchLocalCommunicationIds_5: 
+  switchLocalCommunicationIds_6: 
+  switchLocalCommunicationIds_7: 
+  switchParentalControl: 0
+  switchAllowsScreenshot: 1
+  switchAllowsVideoCapturing: 1
+  switchAllowsRuntimeAddOnContentInstall: 0
+  switchDataLossConfirmation: 0
+  switchUserAccountLockEnabled: 0
+  switchSystemResourceMemory: 16777216
+  switchSupportedNpadStyles: 22
+  switchNativeFsCacheSize: 32
+  switchIsHoldTypeHorizontal: 0
+  switchSupportedNpadCount: 8
+  switchSocketConfigEnabled: 0
+  switchTcpInitialSendBufferSize: 32
+  switchTcpInitialReceiveBufferSize: 64
+  switchTcpAutoSendBufferSizeMax: 256
+  switchTcpAutoReceiveBufferSizeMax: 256
+  switchUdpSendBufferSize: 9
+  switchUdpReceiveBufferSize: 42
+  switchSocketBufferEfficiency: 4
+  switchSocketInitializeEnabled: 1
+  switchNetworkInterfaceManagerInitializeEnabled: 1
+  switchPlayerConnectionEnabled: 1
+  ps4NPAgeRating: 12
+  ps4NPTitleSecret: 
+  ps4NPTrophyPackPath: 
+  ps4ParentalLevel: 11
+  ps4ContentID: ED1633-NPXX51362_00-0000000000000000
+  ps4Category: 0
+  ps4MasterVersion: 01.00
+  ps4AppVersion: 01.00
+  ps4AppType: 0
+  ps4ParamSfxPath: 
+  ps4VideoOutPixelFormat: 0
+  ps4VideoOutInitialWidth: 1920
+  ps4VideoOutBaseModeInitialWidth: 1920
+  ps4VideoOutReprojectionRate: 60
+  ps4PronunciationXMLPath: 
+  ps4PronunciationSIGPath: 
+  ps4BackgroundImagePath: 
+  ps4StartupImagePath: 
+  ps4StartupImagesFolder: 
+  ps4IconImagesFolder: 
+  ps4SaveDataImagePath: 
+  ps4SdkOverride: 
+  ps4BGMPath: 
+  ps4ShareFilePath: 
+  ps4ShareOverlayImagePath: 
+  ps4PrivacyGuardImagePath: 
+  ps4ExtraSceSysFile: 
+  ps4NPtitleDatPath: 
+  ps4RemotePlayKeyAssignment: -1
+  ps4RemotePlayKeyMappingDir: 
+  ps4PlayTogetherPlayerCount: 0
+  ps4EnterButtonAssignment: 1
+  ps4ApplicationParam1: 0
+  ps4ApplicationParam2: 0
+  ps4ApplicationParam3: 0
+  ps4ApplicationParam4: 0
+  ps4DownloadDataSize: 0
+  ps4GarlicHeapSize: 2048
+  ps4ProGarlicHeapSize: 2560
+  playerPrefsMaxSize: 32768
+  ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ
+  ps4pnSessions: 1
+  ps4pnPresence: 1
+  ps4pnFriends: 1
+  ps4pnGameCustomData: 1
+  playerPrefsSupport: 0
+  enableApplicationExit: 0
+  resetTempFolder: 1
+  restrictedAudioUsageRights: 0
+  ps4UseResolutionFallback: 0
+  ps4ReprojectionSupport: 0
+  ps4UseAudio3dBackend: 0
+  ps4UseLowGarlicFragmentationMode: 1
+  ps4SocialScreenEnabled: 0
+  ps4ScriptOptimizationLevel: 0
+  ps4Audio3dVirtualSpeakerCount: 14
+  ps4attribCpuUsage: 0
+  ps4PatchPkgPath: 
+  ps4PatchLatestPkgPath: 
+  ps4PatchChangeinfoPath: 
+  ps4PatchDayOne: 0
+  ps4attribUserManagement: 0
+  ps4attribMoveSupport: 0
+  ps4attrib3DSupport: 0
+  ps4attribShareSupport: 0
+  ps4attribExclusiveVR: 0
+  ps4disableAutoHideSplash: 0
+  ps4videoRecordingFeaturesUsed: 0
+  ps4contentSearchFeaturesUsed: 0
+  ps4CompatibilityPS5: 0
+  ps4GPU800MHz: 1
+  ps4attribEyeToEyeDistanceSettingVR: 0
+  ps4IncludedModules: []
+  ps4attribVROutputEnabled: 0
+  monoEnv: 
+  splashScreenBackgroundSourceLandscape: {fileID: 0}
+  splashScreenBackgroundSourcePortrait: {fileID: 0}
+  blurSplashScreenBackground: 1
+  spritePackerPolicy: 
+  webGLMemorySize: 16
+  webGLExceptionSupport: 1
+  webGLNameFilesAsHashes: 0
+  webGLDataCaching: 1
+  webGLDebugSymbols: 0
+  webGLEmscriptenArgs: 
+  webGLModulesDirectory: 
+  webGLTemplate: APPLICATION:Default
+  webGLAnalyzeBuildSize: 0
+  webGLUseEmbeddedResources: 0
+  webGLCompressionFormat: 1
+  webGLLinkerTarget: 1
+  webGLThreadsSupport: 0
+  webGLWasmStreaming: 0
+  scriptingDefineSymbols: {}
+  platformArchitecture: {}
+  scriptingBackend: {}
+  il2cppCompilerConfiguration: {}
+  managedStrippingLevel: {}
+  incrementalIl2cppBuild: {}
+  allowUnsafeCode: 0
+  additionalIl2CppArgs: 
+  scriptingRuntimeVersion: 1
+  gcIncremental: 0
+  gcWBarrierValidation: 0
+  apiCompatibilityLevelPerPlatform: {}
+  m_RenderingPath: 1
+  m_MobileRenderingPath: 1
+  metroPackageName: Template_3D
+  metroPackageVersion: 
+  metroCertificatePath: 
+  metroCertificatePassword: 
+  metroCertificateSubject: 
+  metroCertificateIssuer: 
+  metroCertificateNotAfter: 0000000000000000
+  metroApplicationDescription: Template_3D
+  wsaImages: {}
+  metroTileShortName: 
+  metroTileShowName: 0
+  metroMediumTileShowName: 0
+  metroLargeTileShowName: 0
+  metroWideTileShowName: 0
+  metroSupportStreamingInstall: 0
+  metroLastRequiredScene: 0
+  metroDefaultTileSize: 1
+  metroTileForegroundText: 2
+  metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0}
+  metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628,
+    a: 1}
+  metroSplashScreenUseBackgroundColor: 0
+  platformCapabilities: {}
+  metroTargetDeviceFamilies: {}
+  metroFTAName: 
+  metroFTAFileTypes: []
+  metroProtocolName: 
+  XboxOneProductId: 
+  XboxOneUpdateKey: 
+  XboxOneSandboxId: 
+  XboxOneContentId: 
+  XboxOneTitleId: 
+  XboxOneSCId: 
+  XboxOneGameOsOverridePath: 
+  XboxOnePackagingOverridePath: 
+  XboxOneAppManifestOverridePath: 
+  XboxOneVersion: 1.0.0.0
+  XboxOnePackageEncryption: 0
+  XboxOnePackageUpdateGranularity: 2
+  XboxOneDescription: 
+  XboxOneLanguage:
+  - enus
+  XboxOneCapability: []
+  XboxOneGameRating: {}
+  XboxOneIsContentPackage: 0
+  XboxOneEnableGPUVariability: 1
+  XboxOneSockets: {}
+  XboxOneSplashScreen: {fileID: 0}
+  XboxOneAllowedProductIds: []
+  XboxOnePersistentLocalStorageSize: 0
+  XboxOneXTitleMemory: 8
+  XboxOneOverrideIdentityName: 
+  XboxOneOverrideIdentityPublisher: 
+  vrEditorSettings:
+    daydream:
+      daydreamIconForeground: {fileID: 0}
+      daydreamIconBackground: {fileID: 0}
+  cloudServicesEnabled:
+    UNet: 1
+  luminIcon:
+    m_Name: 
+    m_ModelFolderPath: 
+    m_PortalFolderPath: 
+  luminCert:
+    m_CertPath: 
+    m_SignPackage: 1
+  luminIsChannelApp: 0
+  luminVersion:
+    m_VersionCode: 1
+    m_VersionName: 
+  apiCompatibilityLevel: 6
+  cloudProjectId: 
+  framebufferDepthMemorylessMode: 0
+  projectName: 
+  organizationId: 
+  cloudEnabled: 0
+  enableNativePlatformBackendsForNewInputSystem: 0
+  disableOldInputManagerSupport: 0
+  legacyClampBlendShapeWeights: 0
diff --git a/PickUpandDelivery/ProjectSettings/ProjectVersion.txt b/PickUpandDelivery/ProjectSettings/ProjectVersion.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ae9c8eb06f742d9b7e103ee8f850877780afa0ed
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/ProjectVersion.txt
@@ -0,0 +1,2 @@
+m_EditorVersion: 2019.4.12f1
+m_EditorVersionWithRevision: 2019.4.12f1 (225e826a680e)
diff --git a/PickUpandDelivery/ProjectSettings/QualitySettings.asset b/PickUpandDelivery/ProjectSettings/QualitySettings.asset
new file mode 100644
index 0000000000000000000000000000000000000000..7b7658d6ebf4a0302c34bf5cc1e9d30813705a9e
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/QualitySettings.asset
@@ -0,0 +1,232 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!47 &1
+QualitySettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 5
+  m_CurrentQuality: 5
+  m_QualitySettings:
+  - serializedVersion: 2
+    name: Very Low
+    pixelLightCount: 0
+    shadows: 0
+    shadowResolution: 0
+    shadowProjection: 1
+    shadowCascades: 1
+    shadowDistance: 15
+    shadowNearPlaneOffset: 3
+    shadowCascade2Split: 0.33333334
+    shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
+    shadowmaskMode: 0
+    blendWeights: 1
+    textureQuality: 1
+    anisotropicTextures: 0
+    antiAliasing: 0
+    softParticles: 0
+    softVegetation: 0
+    realtimeReflectionProbes: 0
+    billboardsFaceCameraPosition: 0
+    vSyncCount: 0
+    lodBias: 0.3
+    maximumLODLevel: 0
+    streamingMipmapsActive: 0
+    streamingMipmapsAddAllCameras: 1
+    streamingMipmapsMemoryBudget: 512
+    streamingMipmapsRenderersPerFrame: 512
+    streamingMipmapsMaxLevelReduction: 2
+    streamingMipmapsMaxFileIORequests: 1024
+    particleRaycastBudget: 4
+    asyncUploadTimeSlice: 2
+    asyncUploadBufferSize: 16
+    asyncUploadPersistentBuffer: 1
+    resolutionScalingFixedDPIFactor: 1
+    excludedTargetPlatforms: []
+  - serializedVersion: 2
+    name: Low
+    pixelLightCount: 0
+    shadows: 0
+    shadowResolution: 0
+    shadowProjection: 1
+    shadowCascades: 1
+    shadowDistance: 20
+    shadowNearPlaneOffset: 3
+    shadowCascade2Split: 0.33333334
+    shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
+    shadowmaskMode: 0
+    blendWeights: 2
+    textureQuality: 0
+    anisotropicTextures: 0
+    antiAliasing: 0
+    softParticles: 0
+    softVegetation: 0
+    realtimeReflectionProbes: 0
+    billboardsFaceCameraPosition: 0
+    vSyncCount: 0
+    lodBias: 0.4
+    maximumLODLevel: 0
+    streamingMipmapsActive: 0
+    streamingMipmapsAddAllCameras: 1
+    streamingMipmapsMemoryBudget: 512
+    streamingMipmapsRenderersPerFrame: 512
+    streamingMipmapsMaxLevelReduction: 2
+    streamingMipmapsMaxFileIORequests: 1024
+    particleRaycastBudget: 16
+    asyncUploadTimeSlice: 2
+    asyncUploadBufferSize: 16
+    asyncUploadPersistentBuffer: 1
+    resolutionScalingFixedDPIFactor: 1
+    excludedTargetPlatforms: []
+  - serializedVersion: 2
+    name: Medium
+    pixelLightCount: 1
+    shadows: 1
+    shadowResolution: 0
+    shadowProjection: 1
+    shadowCascades: 1
+    shadowDistance: 20
+    shadowNearPlaneOffset: 3
+    shadowCascade2Split: 0.33333334
+    shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
+    shadowmaskMode: 0
+    blendWeights: 2
+    textureQuality: 0
+    anisotropicTextures: 1
+    antiAliasing: 0
+    softParticles: 0
+    softVegetation: 0
+    realtimeReflectionProbes: 0
+    billboardsFaceCameraPosition: 0
+    vSyncCount: 1
+    lodBias: 0.7
+    maximumLODLevel: 0
+    streamingMipmapsActive: 0
+    streamingMipmapsAddAllCameras: 1
+    streamingMipmapsMemoryBudget: 512
+    streamingMipmapsRenderersPerFrame: 512
+    streamingMipmapsMaxLevelReduction: 2
+    streamingMipmapsMaxFileIORequests: 1024
+    particleRaycastBudget: 64
+    asyncUploadTimeSlice: 2
+    asyncUploadBufferSize: 16
+    asyncUploadPersistentBuffer: 1
+    resolutionScalingFixedDPIFactor: 1
+    excludedTargetPlatforms: []
+  - serializedVersion: 2
+    name: High
+    pixelLightCount: 2
+    shadows: 2
+    shadowResolution: 1
+    shadowProjection: 1
+    shadowCascades: 2
+    shadowDistance: 40
+    shadowNearPlaneOffset: 3
+    shadowCascade2Split: 0.33333334
+    shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
+    shadowmaskMode: 1
+    blendWeights: 2
+    textureQuality: 0
+    anisotropicTextures: 1
+    antiAliasing: 0
+    softParticles: 0
+    softVegetation: 1
+    realtimeReflectionProbes: 1
+    billboardsFaceCameraPosition: 1
+    vSyncCount: 1
+    lodBias: 1
+    maximumLODLevel: 0
+    streamingMipmapsActive: 0
+    streamingMipmapsAddAllCameras: 1
+    streamingMipmapsMemoryBudget: 512
+    streamingMipmapsRenderersPerFrame: 512
+    streamingMipmapsMaxLevelReduction: 2
+    streamingMipmapsMaxFileIORequests: 1024
+    particleRaycastBudget: 256
+    asyncUploadTimeSlice: 2
+    asyncUploadBufferSize: 16
+    asyncUploadPersistentBuffer: 1
+    resolutionScalingFixedDPIFactor: 1
+    excludedTargetPlatforms: []
+  - serializedVersion: 2
+    name: Very High
+    pixelLightCount: 3
+    shadows: 2
+    shadowResolution: 2
+    shadowProjection: 1
+    shadowCascades: 2
+    shadowDistance: 70
+    shadowNearPlaneOffset: 3
+    shadowCascade2Split: 0.33333334
+    shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
+    shadowmaskMode: 1
+    blendWeights: 4
+    textureQuality: 0
+    anisotropicTextures: 2
+    antiAliasing: 2
+    softParticles: 1
+    softVegetation: 1
+    realtimeReflectionProbes: 1
+    billboardsFaceCameraPosition: 1
+    vSyncCount: 1
+    lodBias: 1.5
+    maximumLODLevel: 0
+    streamingMipmapsActive: 0
+    streamingMipmapsAddAllCameras: 1
+    streamingMipmapsMemoryBudget: 512
+    streamingMipmapsRenderersPerFrame: 512
+    streamingMipmapsMaxLevelReduction: 2
+    streamingMipmapsMaxFileIORequests: 1024
+    particleRaycastBudget: 1024
+    asyncUploadTimeSlice: 2
+    asyncUploadBufferSize: 16
+    asyncUploadPersistentBuffer: 1
+    resolutionScalingFixedDPIFactor: 1
+    excludedTargetPlatforms: []
+  - serializedVersion: 2
+    name: Ultra
+    pixelLightCount: 4
+    shadows: 2
+    shadowResolution: 2
+    shadowProjection: 1
+    shadowCascades: 4
+    shadowDistance: 150
+    shadowNearPlaneOffset: 3
+    shadowCascade2Split: 0.33333334
+    shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
+    shadowmaskMode: 1
+    blendWeights: 4
+    textureQuality: 0
+    anisotropicTextures: 2
+    antiAliasing: 2
+    softParticles: 1
+    softVegetation: 1
+    realtimeReflectionProbes: 1
+    billboardsFaceCameraPosition: 1
+    vSyncCount: 1
+    lodBias: 2
+    maximumLODLevel: 0
+    streamingMipmapsActive: 0
+    streamingMipmapsAddAllCameras: 1
+    streamingMipmapsMemoryBudget: 512
+    streamingMipmapsRenderersPerFrame: 512
+    streamingMipmapsMaxLevelReduction: 2
+    streamingMipmapsMaxFileIORequests: 1024
+    particleRaycastBudget: 4096
+    asyncUploadTimeSlice: 2
+    asyncUploadBufferSize: 16
+    asyncUploadPersistentBuffer: 1
+    resolutionScalingFixedDPIFactor: 1
+    excludedTargetPlatforms: []
+  m_PerPlatformDefaultQuality:
+    Android: 2
+    Lumin: 5
+    Nintendo 3DS: 5
+    Nintendo Switch: 5
+    PS4: 5
+    PSP2: 2
+    Stadia: 5
+    Standalone: 5
+    WebGL: 3
+    Windows Store Apps: 5
+    XboxOne: 5
+    iPhone: 2
+    tvOS: 2
diff --git a/PickUpandDelivery/ProjectSettings/TagManager.asset b/PickUpandDelivery/ProjectSettings/TagManager.asset
new file mode 100644
index 0000000000000000000000000000000000000000..1c92a7840ec11895c76785f65d949a3d20d53355
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/TagManager.asset
@@ -0,0 +1,43 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!78 &1
+TagManager:
+  serializedVersion: 2
+  tags: []
+  layers:
+  - Default
+  - TransparentFX
+  - Ignore Raycast
+  - 
+  - Water
+  - UI
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  - 
+  m_SortingLayers:
+  - name: Default
+    uniqueID: 0
+    locked: 0
diff --git a/PickUpandDelivery/ProjectSettings/TimeManager.asset b/PickUpandDelivery/ProjectSettings/TimeManager.asset
new file mode 100644
index 0000000000000000000000000000000000000000..558a017e1f50b2db73414a1abad3c033922774f8
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/TimeManager.asset
@@ -0,0 +1,9 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!5 &1
+TimeManager:
+  m_ObjectHideFlags: 0
+  Fixed Timestep: 0.02
+  Maximum Allowed Timestep: 0.33333334
+  m_TimeScale: 1
+  Maximum Particle Timestep: 0.03
diff --git a/PickUpandDelivery/ProjectSettings/UnityConnectSettings.asset b/PickUpandDelivery/ProjectSettings/UnityConnectSettings.asset
new file mode 100644
index 0000000000000000000000000000000000000000..fa0b146579fb787323d29e1d7b7768a0541031af
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/UnityConnectSettings.asset
@@ -0,0 +1,34 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!310 &1
+UnityConnectSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 1
+  m_Enabled: 0
+  m_TestMode: 0
+  m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
+  m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
+  m_ConfigUrl: https://config.uca.cloud.unity3d.com
+  m_TestInitMode: 0
+  CrashReportingSettings:
+    m_EventUrl: https://perf-events.cloud.unity3d.com
+    m_Enabled: 0
+    m_LogBufferSize: 10
+    m_CaptureEditorExceptions: 1
+  UnityPurchasingSettings:
+    m_Enabled: 0
+    m_TestMode: 0
+  UnityAnalyticsSettings:
+    m_Enabled: 0
+    m_TestMode: 0
+    m_InitializeOnStartup: 1
+  UnityAdsSettings:
+    m_Enabled: 0
+    m_InitializeOnStartup: 1
+    m_TestMode: 0
+    m_IosGameId: 
+    m_AndroidGameId: 
+    m_GameIds: {}
+    m_GameId: 
+  PerformanceReportingSettings:
+    m_Enabled: 0
diff --git a/PickUpandDelivery/ProjectSettings/VFXManager.asset b/PickUpandDelivery/ProjectSettings/VFXManager.asset
new file mode 100644
index 0000000000000000000000000000000000000000..3a95c98bec50cf72538061fd26eee95398f72128
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/VFXManager.asset
@@ -0,0 +1,12 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!937362698 &1
+VFXManager:
+  m_ObjectHideFlags: 0
+  m_IndirectShader: {fileID: 0}
+  m_CopyBufferShader: {fileID: 0}
+  m_SortShader: {fileID: 0}
+  m_StripUpdateShader: {fileID: 0}
+  m_RenderPipeSettingsPath: 
+  m_FixedTimeStep: 0.016666668
+  m_MaxDeltaTime: 0.05
diff --git a/PickUpandDelivery/ProjectSettings/XRSettings.asset b/PickUpandDelivery/ProjectSettings/XRSettings.asset
new file mode 100644
index 0000000000000000000000000000000000000000..482590c196f7a82116679f58176b9d1aff21d7f9
--- /dev/null
+++ b/PickUpandDelivery/ProjectSettings/XRSettings.asset
@@ -0,0 +1,10 @@
+{
+    "m_SettingKeys": [
+        "VR Device Disabled",
+        "VR Device User Alert"
+    ],
+    "m_SettingValues": [
+        "False",
+        "False"
+    ]
+}
\ No newline at end of file