diff --git a/cooperative_cuisine/configs/agents/random_agent.py b/cooperative_cuisine/configs/agents/random_agent.py
index 3b1b5832b32f74367582d93846681e7d9562b1b0..e1db06bfb20f925815b81016a2afb49a8a0377e6 100644
--- a/cooperative_cuisine/configs/agents/random_agent.py
+++ b/cooperative_cuisine/configs/agents/random_agent.py
@@ -7,25 +7,53 @@ import time
 from collections import defaultdict
 from datetime import datetime, timedelta
 
+import networkx
 import numpy as np
+import numpy.typing as npt
 from websockets import connect
 
 from cooperative_cuisine.action import ActionType, InterActionData, Action
+from cooperative_cuisine.state_representation import (
+    create_movement_graph,
+    astar_heuristic,
+    restrict_movement_graph,
+)
 from cooperative_cuisine.utils import custom_asdict_factory
 
 TIME_TO_STOP_ACTION = 3.0
 
+ADD_RANDOM_MOVEMENTS = False
+DIAGONAL_MOVEMENTS = True
+AVOID_OTHER_PLAYERS = True
+
+
+def get_free_neighbours(
+    state: dict, counter_pos: list[float] | tuple[float, float] | npt.NDArray
+) -> list[tuple[float, float]]:
+    width, height = state["kitchen"]["width"], state["kitchen"]["height"]
+    free_space = np.ones((width, height), dtype=bool)
+    for counter in state["counters"]:
+        grid_idx = np.array(counter["pos"]).astype(int)
+        free_space[grid_idx[0], grid_idx[1]] = False
+    i, j = np.array(counter_pos).astype(int)
+    free = []
+
+    for x, y in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
+        if 0 < x < width and 0 < y < height and free_space[x, y]:
+            free.append((x, y))
+    return free
+
 
 async def agent():
     parser = argparse.ArgumentParser("Random agent")
     parser.add_argument("--uri", type=str)
     parser.add_argument("--player_id", type=str)
     parser.add_argument("--player_hash", type=str)
-    parser.add_argument("--step_time", type=float, default=0.5)
+    parser.add_argument("--step_time", type=float, default=0.1)
 
     args = parser.parse_args()
 
-    async with connect(args.uri) as websocket:
+    async with (connect(args.uri) as websocket):
         await websocket.send(
             json.dumps({"type": "ready", "player_hash": args.player_hash})
         )
@@ -34,6 +62,9 @@ async def agent():
         ended = False
 
         counters = None
+        all_counters = None
+
+        movement_graph = None
 
         player_info = {}
         current_agent_pos = None
@@ -60,10 +91,16 @@ async def agent():
             if not state["all_players_ready"]:
                 continue
 
+            if movement_graph is None:
+                movement_graph = create_movement_graph(
+                    state, diagonal=DIAGONAL_MOVEMENTS
+                )
+
             if counters is None:
                 counters = defaultdict(list)
                 for counter in state["counters"]:
                     counters[counter["type"]].append(counter)
+                all_counters = state["counters"]
 
             for player in state["players"]:
                 if player["id"] == args.player_id:
@@ -125,10 +162,77 @@ async def agent():
                     task_type = None
                 match task_type:
                     case "GOTO":
-                        diff = np.array(task_args) - np.array(current_agent_pos)
-                        dist = np.linalg.norm(diff)
-                        if dist > 1.2:
-                            if dist != 0:
+                        target_diff = np.array(task_args) - np.array(current_agent_pos)
+                        target_dist = np.linalg.norm(target_diff)
+
+                        source = tuple(
+                            np.round(np.array(current_agent_pos)).astype(int)
+                        )
+                        target = tuple(np.array(task_args).astype(int))
+                        target_free_spaces = get_free_neighbours(state, target)
+                        paths = []
+                        for free in target_free_spaces:
+                            try:
+                                path = networkx.astar_path(
+                                    restrict_movement_graph(
+                                        graph=movement_graph,
+                                        player_positions=[
+                                            p["pos"]
+                                            for p in state["players"]
+                                            if p["id"] != args.player_id
+                                        ],
+                                    )
+                                    if AVOID_OTHER_PLAYERS
+                                    else movement_graph,
+                                    source,
+                                    free,
+                                    heuristic=astar_heuristic,
+                                )
+                                paths.append(path)
+                            except networkx.exception.NetworkXNoPath:
+                                pass
+                            except networkx.exception.NodeNotFound:
+                                pass
+
+                        if paths:
+                            shortest_path = paths[np.argmin([len(p) for p in paths])]
+                            if len(shortest_path) > 1:
+                                node_diff = shortest_path[1] - np.array(
+                                    current_agent_pos
+                                )
+                                node_dist = np.linalg.norm(node_diff)
+                                movement = node_diff / node_dist
+                            else:
+                                movement = target_diff / target_dist
+                            do_movement = True
+                        else:
+                            # no paths available
+                            print("NO PATHS")
+
+                            # task_type = None
+                            # task_args = None
+                            do_movement = False
+
+                        if target_dist > 1.2 and do_movement:
+                            if target_dist != 0:
+                                if ADD_RANDOM_MOVEMENTS:
+                                    random_small_rotation_angle = (
+                                        np.random.random() * np.pi * 0.1
+                                    )
+                                    rotation_matrix = np.array(
+                                        [
+                                            [
+                                                np.cos(random_small_rotation_angle),
+                                                -np.sin(random_small_rotation_angle),
+                                            ],
+                                            [
+                                                np.sin(random_small_rotation_angle),
+                                                np.cos(random_small_rotation_angle),
+                                            ],
+                                        ]
+                                    )
+                                    movement = rotation_matrix @ movement
+
                                 await websocket.send(
                                     json.dumps(
                                         {
@@ -137,7 +241,7 @@ async def agent():
                                                 Action(
                                                     args.player_id,
                                                     ActionType.MOVEMENT,
-                                                    (diff / dist).tolist(),
+                                                    movement.tolist(),
                                                     args.step_time + 0.01,
                                                 ),
                                                 dict_factory=custom_asdict_factory,
@@ -148,6 +252,8 @@ async def agent():
                                 )
                                 await websocket.recv()
                         else:
+                            # Target reached here.
+                            print("TARGET REACHED")
                             task_type = None
                             task_args = None
                     case "INTERACT":
@@ -204,12 +310,23 @@ async def agent():
                         ...
 
             if not task_type:
-                task_type = random.choice(["GOTO", "PUT", "INTERACT"])
+                # task_type = random.choice(["GOTO", "PUT", "INTERACT"])
+                task_type = random.choice(["GOTO"])
                 threshold = datetime.now() + timedelta(seconds=TIME_TO_STOP_ACTION)
                 if task_type == "GOTO":
-                    counter_type = random.choice(list(counters.keys()))
-                    task_args = random.choice(counters[counter_type])["pos"]
-                    print(args.player_hash, args.player_id, task_type, counter_type)
+                    # counter_type = random.choice(list(counters.keys()))
+                    # task_args = random.choice(counters[counter_type])["pos"]
+
+                    random_counter = random.choice(all_counters)
+                    counter_type = random_counter["type"]
+                    task_args = random_counter["pos"]
+                    print(
+                        args.player_hash,
+                        args.player_id,
+                        task_type,
+                        counter_type,
+                        task_args,
+                    )
                 else:
                     print(args.player_hash, args.player_id, task_type)
                     task_args = None
diff --git a/cooperative_cuisine/configs/environment_config_no_validation.yaml b/cooperative_cuisine/configs/environment_config_no_validation.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1802c28a539cd92d7879ea14643f545bcebd3c99
--- /dev/null
+++ b/cooperative_cuisine/configs/environment_config_no_validation.yaml
@@ -0,0 +1,208 @@
+plates:
+  clean_plates: 2
+  dirty_plates: 1
+  plate_delay: [ 5, 10 ]
+  # range of seconds until the dirty plate arrives.
+
+game:
+  time_limit_seconds: 300
+  undo_dispenser_pickup: true
+  validate_recipes: false
+
+
+layout_chars:
+  _: Free
+  hash: Counter  # #
+  A: Agent
+  pipe: Extinguisher
+  P: PlateDispenser
+  C: CuttingBoard
+  X: Trashcan
+  $: ServingWindow
+  S: Sink
+  +: SinkAddon
+  at: Plate  # @ just a clean plate on a counter
+  U: Pot  # with Stove
+  Q: Pan  # with Stove
+  O: Peel  # with Oven
+  F: Basket  # with DeepFryer
+  T: Tomato
+  N: Onion  # oNioN
+  L: Lettuce
+  K: Potato  # Kartoffel
+  I: Fish  # fIIIsh
+  D: Dough
+  E: Cheese  # chEEEse
+  G: Sausage  # sausaGe
+  B: Bun
+  M: Meat
+  question: Counter  # ? mushroom
+  ↓: Counter
+  ^: Counter
+  right: Counter
+  left: Counter
+  wave: Free  # ~ Water
+  minus: Free  # - Ice
+  dquote: Counter  # " wall/truck
+  p: Counter # second plate return ??
+
+
+orders:
+  meals:
+    all: true
+    # if all: false -> only orders for these meals are generated
+    # TODO: what if this list is empty?
+    list:
+      #      - TomatoSoup
+      #      - OnionSoup
+      #      - Salad
+      - FriedFish
+  order_gen_class: !!python/name:cooperative_cuisine.orders.RandomOrderGeneration ''
+  # the class to that receives the kwargs. Should be a child class of OrderGeneration in orders.py
+  order_gen_kwargs:
+    order_duration_random_func:
+      # how long should the orders be alive
+      # 'random' library call with getattr, kwargs are passed to the function
+      func: uniform
+      kwargs:
+        a: 40
+        b: 60
+    max_orders: 6
+    # maximum number of active orders at the same time
+    num_start_meals: 2
+    # number of orders generated at the start of the environment
+    sample_on_dur_random_func:
+      # 'random' library call with getattr, kwargs are passed to the function
+      func: uniform
+      kwargs:
+        a: 10
+        b: 20
+    sample_on_serving: false
+    # Sample the delay for the next order only after a meal was served.
+  serving_not_ordered_meals: true
+  # can meals that are not ordered be served / dropped on the serving window
+
+player_config:
+  radius: 0.4
+  speed_units_per_seconds: 6
+  interaction_range: 1.6
+  restricted_view: False
+  view_angle: 70
+  view_range: 4  # in grid units, can be "null"
+
+effect_manager:
+  FireManager:
+    class: !!python/name:cooperative_cuisine.effects.FireEffectManager ''
+    kwargs:
+      spreading_duration: [ 5, 10 ]
+      fire_burns_ingredients_and_meals: true
+
+
+hook_callbacks:
+  # # ---------------  Scoring  ---------------
+  orders:
+    hooks: [ completed_order ]
+    callback_class: !!python/name:cooperative_cuisine.scores.ScoreViaHooks ''
+    callback_class_kwargs:
+      static_score: 20
+      score_on_specific_kwarg: meal_name
+      score_map:
+        Burger: 15
+        OnionSoup: 10
+        Salad: 5
+        TomatoSoup: 10
+  not_ordered_meals:
+    hooks: [ serve_not_ordered_meal ]
+    callback_class: !!python/name:cooperative_cuisine.scores.ScoreViaHooks ''
+    callback_class_kwargs:
+      static_score: 2
+  trashcan_usages:
+    hooks: [ trashcan_usage ]
+    callback_class: !!python/name:cooperative_cuisine.scores.ScoreViaHooks ''
+    callback_class_kwargs:
+      static_score: -5
+  expired_orders:
+    hooks: [ order_expired ]
+    callback_class: !!python/name:cooperative_cuisine.scores.ScoreViaHooks ''
+    callback_class_kwargs:
+      static_score: -10
+    # --------------- Recording ---------------
+  #  json_states:
+  #    hooks: [ json_state ]
+  #    callback_class: !!python/name:cooperative_cuisine.recording.FileRecorder ''
+  #    callback_class_kwargs:
+  #      record_path: USER_LOG_DIR/ENV_NAME/json_states.jsonl
+  actions:
+    hooks: [ pre_perform_action ]
+    callback_class: !!python/name:cooperative_cuisine.recording.FileRecorder ''
+    callback_class_kwargs:
+      record_path: USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl
+  random_env_events:
+    hooks: [ order_duration_sample, plate_out_of_kitchen_time ]
+    callback_class: !!python/name:cooperative_cuisine.recording.FileRecorder ''
+    callback_class_kwargs:
+      record_path: USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl
+      add_hook_ref: true
+  env_configs:
+    hooks: [ env_initialized, item_info_config ]
+    callback_class: !!python/name:cooperative_cuisine.recording.FileRecorder ''
+    callback_class_kwargs:
+      record_path: USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl
+      add_hook_ref: true
+
+  # Game event recording
+  game_events:
+    hooks:
+      - post_counter_pick_up
+      - post_counter_drop_off
+      - post_dispenser_pick_up
+      - cutting_board_100
+      - player_start_interaction
+      - player_end_interact
+      - post_serving
+      - no_serving
+      - dirty_plate_arrives
+      - trashcan_usage
+      - plate_cleaned
+      - added_plate_to_sink
+      - drop_on_sink_addon
+      - pick_up_from_sink_addon
+      - serve_not_ordered_meal
+      - serve_without_plate
+      - completed_order
+      - new_orders
+      - order_expired
+      - action_on_not_reachable_counter
+      - new_fire
+      - fire_spreading
+      - drop_off_on_cooking_equipment
+      - players_collide
+      - post_plate_dispenser_pick_up
+      - post_plate_dispenser_drop_off
+      - on_item_transition
+      - progress_started
+      - progress_finished
+      - content_ready
+      - dispenser_item_returned
+
+    callback_class: !!python/name:cooperative_cuisine.recording.FileRecorder ''
+    callback_class_kwargs:
+      record_path: USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl
+      add_hook_ref: true
+
+
+#  info_msg:
+#    func: !!python/name:cooperative_cuisine.hooks.hooks_via_callback_class ''
+#    kwargs:
+#      hooks: [ cutting_board_100 ]
+#      callback_class: !!python/name:cooperative_cuisine.info_msg.InfoMsgManager ''
+#      callback_class_kwargs:
+#        msg: Glückwunsch du hast was geschnitten!
+#  fire_msg:
+#    func: !!python/name:cooperative_cuisine.hooks.hooks_via_callback_class ''
+#    kwargs:
+#      hooks: [ new_fire ]
+#      callback_class: !!python/name:cooperative_cuisine.info_msg.InfoMsgManager ''
+#      callback_class_kwargs:
+#        msg: Feuer, Feuer, Feuer
+#        level: Warning
diff --git a/cooperative_cuisine/configs/layouts_archive/test_layouts/large.layout b/cooperative_cuisine/configs/layouts/large.layout
similarity index 100%
rename from cooperative_cuisine/configs/layouts_archive/test_layouts/large.layout
rename to cooperative_cuisine/configs/layouts/large.layout
diff --git a/cooperative_cuisine/configs/layouts_archive/test_layouts/large_t.layout b/cooperative_cuisine/configs/layouts/large_t.layout
similarity index 100%
rename from cooperative_cuisine/configs/layouts_archive/test_layouts/large_t.layout
rename to cooperative_cuisine/configs/layouts/large_t.layout
diff --git a/cooperative_cuisine/movement.py b/cooperative_cuisine/movement.py
index b0c9d50a034d83f82f0736d2213bdb71e4d6c11d..2523e50f871758f6e9e3049a2b8ca60f0d59e042 100644
--- a/cooperative_cuisine/movement.py
+++ b/cooperative_cuisine/movement.py
@@ -193,32 +193,37 @@ class Movement:
             updated_movement * (self.player_movement_speed * d_time)
         )
 
-        # Check collisions with counters
+        # check if players collided with counters through movement or through being pushed
         (
             collided,
             relevant_axes,
             nearest_counter_to_player,
         ) = self.get_counter_collisions(new_targeted_positions)
 
-        # Check if sliding against counters is possible
-        for idx, player in enumerate(player_positions):
-            axis = relevant_axes[idx]
-            if collided[idx]:
-                # collide with counter left or top
-                if nearest_counter_to_player[idx][axis] > 0:
-                    updated_movement[idx, axis] = np.max(
-                        [updated_movement[idx, axis], 0]
-                    )
-                # collide with counter right or bottom
-                if nearest_counter_to_player[idx][axis] < 0:
-                    updated_movement[idx, axis] = np.min(
-                        [updated_movement[idx, axis], 0]
-                    )
-        new_positions = player_positions + (
-            updated_movement * (self.player_movement_speed * d_time)
+        # If collided, check if the players could still move along the axis, starting with x
+        # This leads to players beeing able to slide along counters, which feels alot nicer.
+        projected_x = updated_movement.copy()
+        projected_x[collided, 1] = 0
+        new_targeted_positions[collided] = player_positions[collided] + (
+            projected_x[collided] * (self.player_movement_speed * d_time)
+        )
+        # checking collisions again
+        (
+            collided,
+            relevant_axes,
+            nearest_counter_to_player,
+        ) = self.get_counter_collisions(new_targeted_positions)
+        new_targeted_positions[collided] = player_positions[collided]
+        # and now y axis collisions
+        projected_y = updated_movement.copy()
+        projected_y[collided, 0] = 0
+        new_targeted_positions[collided] = player_positions[collided] + (
+            projected_y[collided] * (self.player_movement_speed * d_time)
         )
+        new_positions = new_targeted_positions
 
-        # Check collisions with counters again, now absolute with no sliding possible
+        # Check collisions with counters a final time, now absolute with no sliding possible.
+        # Players should never be able to enter counters this way.
         (
             collided,
             relevant_axes,
@@ -226,7 +231,7 @@ class Movement:
         ) = self.get_counter_collisions(new_positions)
         new_positions[collided] = player_positions[collided]
 
-        # Collisions player world borders
+        # Collisions of players with world borders
         new_positions = np.clip(
             new_positions,
             self.world_borders_lower + self.player_radius,
diff --git a/cooperative_cuisine/player.py b/cooperative_cuisine/player.py
index 4da8e8b1e3e757616a1c535f71c5cc5ad3fd510c..2a350bfc13c186f78dd3c0d84dd3022d21a3b537 100644
--- a/cooperative_cuisine/player.py
+++ b/cooperative_cuisine/player.py
@@ -134,7 +134,9 @@ class Player:
     def update_facing_point(self):
         """Update facing point on the player border circle based on the radius."""
         self.facing_point = self.pos + (
-            self.facing_direction * self.player_config.radius * 0.5
+            self.facing_direction
+            * self.player_config.radius
+            * self.player_config.interaction_range
         )
 
     def can_reach(self, counter: Counter) -> bool:
diff --git a/cooperative_cuisine/pygame_2d_vis/drawing.py b/cooperative_cuisine/pygame_2d_vis/drawing.py
index 12596f6e67106b9d29d137a22f5d5fce80f24b30..6efd7f6faca5658e46178abefdf0b26a1dc57f49 100644
--- a/cooperative_cuisine/pygame_2d_vis/drawing.py
+++ b/cooperative_cuisine/pygame_2d_vis/drawing.py
@@ -149,7 +149,7 @@ class Visualizer:
             grid_size,
         )
 
-        for idx, col in zip(controlled_player_idxs, [colors["blue"], colors["red"]]):
+        for idx, col in zip(controlled_player_idxs, [ colors["red"], colors["blue"]]):
             pygame.draw.circle(
                 screen,
                 col,
diff --git a/cooperative_cuisine/state_representation.py b/cooperative_cuisine/state_representation.py
index 277be355dcf54fc66cc51d9a923ced451d37f897..209bf7d98ad3157f093071b23a479fd89563a637 100644
--- a/cooperative_cuisine/state_representation.py
+++ b/cooperative_cuisine/state_representation.py
@@ -6,6 +6,10 @@ from datetime import datetime
 from enum import Enum
 from typing import Any
 
+import networkx
+import numpy as np
+import numpy.typing as npt
+from networkx import Graph
 from pydantic import BaseModel
 from typing_extensions import Literal, TypedDict
 
@@ -186,6 +190,90 @@ class StateRepresentation(BaseModel):
     """Added by the game server, indicate if all players are ready and actions are passed to the environment."""
 
 
+def astar_heuristic(x, y):
+    """Heuristic distance function used in astar algorithm."""
+    return np.linalg.norm(np.array(x) - np.array(y))
+
+
+def create_movement_graph(state: StateRepresentation, diagonal=True) -> Graph:
+    """
+    Creates a graph which represents the connections of empty kitchen tiles and such
+    possible coarse movements of an agent.
+    Args:
+        state: State representation to determine the graph to.
+        diagonal: if True use 8 way connection, i.e. diagonal connections between the spaces.
+
+    Returns: Graph representing the connections between empty kitchen tiles.
+    """
+    width, height = state["kitchen"]["width"], state["kitchen"]["height"]
+    free_space = np.ones((width, height), dtype=bool)
+    for counter in state["counters"]:
+        grid_idx = np.array(counter["pos"]).round().astype(int)
+        free_space[grid_idx[0], grid_idx[1]] = False
+
+    graph = networkx.Graph()
+    for i in range(width):
+        for j in range(height):
+            if free_space[i, j]:
+                graph.add_node((i, j))
+
+                if diagonal:
+                    for di in range(-1, 2):
+                        for dj in range(-1, 2):
+                            x, y = i + di, j + dj
+                            if (
+                                0 <= x < width
+                                and 0 < y < height
+                                and free_space[x, y]
+                                and (di, dj) != (0, 0)
+                            ):
+                                if np.sum(np.abs(np.array([di, dj]))) == 2:
+                                    if free_space[i + di, j] and free_space[i, j + dj]:
+                                        graph.add_edge(
+                                            (i, j),
+                                            (x, y),
+                                            weight=np.linalg.norm(
+                                                np.array([i - x, j - y])
+                                            ),
+                                        )
+                                else:
+                                    graph.add_edge(
+                                        (i, j),
+                                        (x, y),
+                                        weight=np.linalg.norm(np.array([i - x, j - y])),
+                                    )
+                else:
+                    for x, y in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
+                        if 0 <= x < width and 0 <= y < height and free_space[x, y]:
+                            graph.add_edge(
+                                (i, j),
+                                (x, y),
+                                weight=1,
+                            )
+    return graph
+
+
+def restrict_movement_graph(
+    graph: Graph,
+    player_positions: list[tuple[float, float] | list[float]] | npt.NDArray[float],
+) -> Graph:
+    """Modifies a given movement graph. Removed the nodes of spaces on which players stand.
+
+    Args:
+        graph: The graph to modify.
+        player_positions: Positions of players.
+
+    Returns: The modified graph without nodes where players stand.
+
+    """
+    copied = graph.copy()
+    for pos in player_positions:
+        tup = tuple(np.array(pos).round().astype(int))
+        if tup in copied.nodes.keys():
+            copied.remove_node(tup)
+    return copied
+
+
 def create_json_schema() -> dict[str, Any]:
     """Create a json scheme of the state representation of an environment."""
     return StateRepresentation.model_json_schema()
diff --git a/tests/test_start.py b/tests/test_start.py
index 4bb89d7dc54f02f4f091dac84b271b2aa817b420..6fe0c0187b494a7a6bc2c24ef432ab1c5ca8b5e9 100644
--- a/tests/test_start.py
+++ b/tests/test_start.py
@@ -43,8 +43,11 @@ from cooperative_cuisine.utils import create_init_env_time, get_touching_counter
 
 layouts_folder = ROOT_DIR / "configs" / "layouts"
 environment_config_path = ROOT_DIR / "configs" / "environment_config.yaml"
+environment_config_no_validation_path = (
+    ROOT_DIR / "configs" / "environment_config_no_validation.yaml"
+)
 layout_path = ROOT_DIR / "configs" / "layouts" / "basic.layout"
-layout_empty_path = ROOT_DIR / "configs" / "layouts" / "basic.layout"
+layout_empty_path = ROOT_DIR / "configs" / "layouts" / "empty.layout"
 item_info_path = ROOT_DIR / "configs" / "item_info.yaml"
 
 # TODO: TESTs are in absolute pixel coordinates still.
@@ -54,6 +57,9 @@ item_info_path = ROOT_DIR / "configs" / "item_info.yaml"
 def test_file_availability():
     assert layouts_folder.is_dir(), "layouts folder does not exists"
     assert environment_config_path.is_file(), "environment config file does not exists"
+    assert (
+        environment_config_no_validation_path.is_file()
+    ), "environment config file does not exists"
     assert layout_path.is_file(), "layout config file does not exists"
     assert layout_empty_path.is_file(), "layout empty config file does not exists"
     assert item_info_path.is_file(), "item info config file does not exists"
@@ -67,6 +73,13 @@ def env_config():
     return env_config
 
 
+@pytest.fixture
+def env_config_no_validation():
+    with open(environment_config_no_validation_path, "r") as file:
+        env_config = file.read()
+    return env_config
+
+
 @pytest.fixture
 def layout_config():
     with open(layout_path, "r") as file:
@@ -76,7 +89,7 @@ def layout_config():
 
 @pytest.fixture
 def layout_empty_config():
-    with open(layout_path, "r") as file:
+    with open(layout_empty_path, "r") as file:
         layout = file.read()
     return layout
 
@@ -101,8 +114,10 @@ def test_player_registration(env_config, layout_config, item_info):
         env.add_player("2")
 
 
-def test_movement(env_config, layout_empty_config, item_info):
-    env = Environment(env_config, layout_empty_config, item_info, as_files=False)
+def test_movement(env_config_no_validation, layout_empty_config, item_info):
+    env = Environment(
+        env_config_no_validation, layout_empty_config, item_info, as_files=False
+    )
     player_name = "1"
     start_pos = np.array([3, 4])
     env.add_player(player_name, start_pos)
@@ -122,8 +137,12 @@ def test_movement(env_config, layout_empty_config, item_info):
     ), "Performed movement do not move the player as expected."
 
 
-def test_player_movement_speed(env_config, layout_empty_config, item_info):
-    env = Environment(env_config, layout_empty_config, item_info, as_files=False)
+def test_player_movement_speed(
+    env_config_no_validation, layout_empty_config, item_info
+):
+    env = Environment(
+        env_config_no_validation, layout_empty_config, item_info, as_files=False
+    )
     player_name = "1"
     start_pos = np.array([3, 4])
     env.add_player(player_name, start_pos)
@@ -148,8 +167,10 @@ def test_player_movement_speed(env_config, layout_empty_config, item_info):
     ), "json state does not match expected StateRepresentation."
 
 
-def test_player_reach(env_config, layout_empty_config, item_info):
-    env = Environment(env_config, layout_empty_config, item_info, as_files=False)
+def test_player_reach(env_config_no_validation, layout_empty_config, item_info):
+    env = Environment(
+        env_config_no_validation, layout_empty_config, item_info, as_files=False
+    )
 
     counter_pos = np.array([2, 2])
     counter = Counter(pos=counter_pos, hook=Hooks(env))
diff --git a/tests/test_utils.py b/tests/test_utils.py
index ad9fb6b67b7af5a3a281072cfe59ea838ae9c38e..2802bb3a73f7deea7d1ee169adc0eb132b399096 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -1,5 +1,15 @@
+import json
 from argparse import ArgumentParser
 
+import networkx
+import pytest
+
+from cooperative_cuisine.environment import Environment
+from cooperative_cuisine.state_representation import (
+    create_movement_graph,
+    restrict_movement_graph,
+    astar_heuristic,
+)
 from cooperative_cuisine.utils import (
     url_and_port_arguments,
     add_list_of_manager_ids_arguments,
@@ -9,6 +19,8 @@ from cooperative_cuisine.utils import (
     create_layout_with_counters,
     setup_logging,
 )
+from tests.test_start import env_config_no_validation
+from tests.test_start import layout_empty_config, item_info
 
 
 def test_parser_gen():
@@ -44,3 +56,92 @@ def test_layout_creation():
 
 def test_setup_logging():
     setup_logging()
+
+
+def test_movement_graph(env_config_no_validation, layout_empty_config, item_info):
+    env = Environment(
+        env_config_no_validation, layout_empty_config, item_info, as_files=False
+    )
+    player_name = "0"
+    env.add_player(player_name)
+
+    state_string = env.get_json_state(player_id=player_name)
+    state = json.loads(state_string)
+    graph_diag = create_movement_graph(state, diagonal=True)
+
+    graph = create_movement_graph(
+        json.loads(env.get_json_state(player_id=player_name)), diagonal=False
+    )
+    path = networkx.astar_path(
+        graph,
+        source=(0, 0),
+        target=(3, 3),
+        heuristic=astar_heuristic,
+    )
+    assert len(path) != 0, "No path found, but should have."
+
+    graph_restricted = restrict_movement_graph(graph_diag, [(1, 0), (0, 1), (1, 1)])
+    with pytest.raises(networkx.exception.NetworkXNoPath) as e_info:
+        path = networkx.astar_path(
+            graph_restricted,
+            source=(0, 0),
+            target=(3, 3),
+            heuristic=astar_heuristic,
+        )
+    with pytest.raises(networkx.exception.NodeNotFound) as e_info:
+        path = networkx.astar_path(
+            graph_restricted,
+            source=(20, 20),
+            target=(40, 40),
+            heuristic=astar_heuristic,
+        )
+
+    path = networkx.astar_path(
+        restrict_movement_graph(
+            graph=graph_diag,
+            player_positions=[],
+        ),
+        source=(0, 0),
+        target=(5, 5),
+        heuristic=astar_heuristic,
+    )
+    assert len(path) != 0, "No path found, but should have."
+
+    # now with diagonal movement
+    graph = create_movement_graph(
+        json.loads(env.get_json_state(player_id=player_name)), diagonal=True
+    )
+    path = networkx.astar_path(
+        graph,
+        source=(0, 0),
+        target=(3, 3),
+        heuristic=astar_heuristic,
+    )
+    assert len(path) != 0, "No path found, but should have."
+
+    graph_restricted = restrict_movement_graph(graph_diag, [(1, 0), (0, 1), (1, 1)])
+    with pytest.raises(networkx.exception.NetworkXNoPath) as e_info:
+        path = networkx.astar_path(
+            graph_restricted,
+            source=(0, 0),
+            target=(3, 3),
+            heuristic=astar_heuristic,
+        )
+    with pytest.raises(networkx.exception.NodeNotFound) as e_info:
+        path = networkx.astar_path(
+            graph_restricted,
+            source=(20, 20),
+            target=(40, 40),
+            heuristic=astar_heuristic,
+        )
+
+    path = networkx.astar_path(
+        restrict_movement_graph(
+            graph=graph_diag,
+            player_positions=[],
+        ),
+        source=(0, 0),
+        target=(5, 5),
+        heuristic=astar_heuristic,
+    )
+    assert len(path) != 0, "No path found, but should have."