diff --git a/examples/Simple_Realistic_Railway_Generator.py b/examples/Simple_Realistic_Railway_Generator.py
deleted file mode 100644
index a7f6a0bf4ceb89cafd2e803ca921f045263038db..0000000000000000000000000000000000000000
--- a/examples/Simple_Realistic_Railway_Generator.py
+++ /dev/null
@@ -1,613 +0,0 @@
-import copy
-import os
-import time
-import warnings
-
-import numpy as np
-
-from flatland.core.grid.grid4_utils import mirror
-from flatland.core.grid.rail_env_grid import RailEnvTransitions
-from flatland.core.transition_map import GridTransitionMap
-from flatland.envs.grid4_generators_utils import connect_from_nodes, connect_nodes, connect_rail_in_grid_map
-from flatland.envs.observations import GlobalObsForRailEnv
-from flatland.envs.rail_env import RailEnv
-from flatland.envs.rail_generators import RailGenerator, RailGeneratorProduct
-from flatland.envs.schedule_generators import sparse_schedule_generator
-from flatland.utils.rendertools import RenderTool
-
-
-class Vec2dOperations:
-    def subtract_pos(nodeA, nodeB):
-        """
-        vector operation : nodeA - nodeB
-
-        :param nodeA: tuple with coordinate (x,y) or 2d vector
-        :param nodeB: tuple with coordinate (x,y) or 2d vector
-        :return:
-            -------
-        tuple with coordinate (x,y) or 2d vector
-        """
-        return (nodeA[0] - nodeB[0], nodeA[1] - nodeB[1])
-
-    def add_pos(nodeA, nodeB):
-        """
-        vector operation : nodeA + nodeB
-
-        :param nodeA: tuple with coordinate (x,y) or 2d vector
-        :param nodeB: tuple with coordinate (x,y) or 2d vector
-        :return:
-            -------
-        tuple with coordinate (x,y) or 2d vector
-        """
-        return (nodeA[0] + nodeB[0], nodeA[1] + nodeB[1])
-
-    def make_orthogonal_pos(node):
-        """
-        vector operation : rotates the 2D vector +90°
-
-        :param node: tuple with coordinate (x,y) or 2d vector
-        :return:
-            -------
-        tuple with coordinate (x,y) or 2d vector
-        """
-        return (node[1], -node[0])
-
-    def get_norm_pos(node):
-        """
-        calculates the euclidean norm of the 2d vector
-
-        :param node: tuple with coordinate (x,y) or 2d vector
-        :return:
-            -------
-        tuple with coordinate (x,y) or 2d vector
-        """
-        return np.sqrt(node[0] * node[0] + node[1] * node[1])
-
-    def normalize_pos(node):
-        """
-        normalize the 2d vector = v/|v|
-
-        :param node: tuple with coordinate (x,y) or 2d vector
-        :return:
-            -------
-        tuple with coordinate (x,y) or 2d vector
-        """
-        n = Vec2dOperations.get_norm_pos(node)
-        if n > 0.0:
-            n = 1 / n
-        return Vec2dOperations.scale_pos(node, n)
-
-    def scale_pos(node, scalar):
-        """
-         scales the 2d vector = node * scale
-
-         :param node: tuple with coordinate (x,y) or 2d vector
-         :param scale: scalar to scale
-         :return:
-             -------
-         tuple with coordinate (x,y) or 2d vector
-         """
-        return (node[0] * scalar, node[1] * scalar)
-
-    def round_pos(node):
-        """
-         rounds the x and y coordinate and convert them to an integer values
-
-         :param node: tuple with coordinate (x,y) or 2d vector
-         :return:
-             -------
-         tuple with coordinate (x,y) or 2d vector
-         """
-        return (int(np.round(node[0])), int(np.round(node[1])))
-
-    def ceil_pos(node):
-        """
-         ceiling the x and y coordinate and convert them to an integer values
-
-         :param node: tuple with coordinate (x,y) or 2d vector
-         :return:
-             -------
-         tuple with coordinate (x,y) or 2d vector
-         """
-        return (int(np.ceil(node[0])), int(np.ceil(node[1])))
-
-    def bound_pos(node, min_value, max_value):
-        """
-         force the values x and y to be between min_value and max_value
-
-         :param node: tuple with coordinate (x,y) or 2d vector
-         :param min_value: scalar value
-         :param max_value: scalar value
-         :return:
-             -------
-         tuple with coordinate (x,y) or 2d vector
-         """
-        return (max(min_value, min(max_value, node[0])), max(min_value, min(max_value, node[1])))
-
-    def rotate_pos(node, rot_in_degree):
-        """
-         rotate the 2d vector with given angle in degree
-
-         :param node: tuple with coordinate (x,y) or 2d vector
-         :param rot_in_degree:  angle in degree
-         :return:
-             -------
-         tuple with coordinate (x,y) or 2d vector
-         """
-        alpha = rot_in_degree / 180.0 * np.pi
-        x0 = node[0]
-        y0 = node[1]
-        x1 = x0 * np.cos(alpha) - y0 * np.sin(alpha)
-        y1 = x0 * np.sin(alpha) + y0 * np.cos(alpha)
-        return (x1, y1)
-
-
-class Grid_Map_Op:
-    def min_max_cut(min_v, max_v, v):
-        return max(min_v, min(max_v, v))
-
-    def add_rail(width, height, grid_map, pt_from, pt_via, pt_to, bAddRemove=True):
-        gRCTrans = np.array([[-1, 0], [0, 1], [1, 0], [0, -1]])  # NESW in RC
-
-        lrcStroke = [[Grid_Map_Op.min_max_cut(0, height - 1, pt_from[0]),
-                      Grid_Map_Op.min_max_cut(0, width - 1, pt_from[1])],
-                     [Grid_Map_Op.min_max_cut(0, height - 1, pt_via[0]),
-                      Grid_Map_Op.min_max_cut(0, width - 1, pt_via[1])],
-                     [Grid_Map_Op.min_max_cut(0, height - 1, pt_to[0]),
-                      Grid_Map_Op.min_max_cut(0, width - 1, pt_to[1])]]
-
-        rc3Cells = np.array(lrcStroke[:3])  # the 3 cells
-        rcMiddle = rc3Cells[1]  # the middle cell which we will update
-        bDeadend = np.all(lrcStroke[0] == lrcStroke[2])  # deadend means cell 0 == cell 2
-
-        # get the 2 row, col deltas between the 3 cells, eg [[-1,0],[0,1]] = North, East
-        rc2Trans = np.diff(rc3Cells, axis=0)
-
-        # get the direction index for the 2 transitions
-        liTrans = []
-        for rcTrans in rc2Trans:
-            # gRCTrans - rcTrans gives an array of vector differences between our rcTrans
-            # and the 4 directions stored in gRCTrans.
-            # Where the vector difference is zero, we have a match...
-            # np.all detects where the whole row,col vector is zero.
-            # argwhere gives the index of the zero vector, ie the direction index
-            iTrans = np.argwhere(np.all(gRCTrans - rcTrans == 0, axis=1))
-            if len(iTrans) > 0:
-                iTrans = iTrans[0][0]
-                liTrans.append(iTrans)
-
-        # check that we have two transitions
-        if len(liTrans) == 2:
-            # Set the transition
-            # Set the transition
-            # If this transition spans 3 cells, it is not a deadend, so remove any deadends.
-            # The user will need to resolve any conflicts.
-            grid_map.set_transition((*rcMiddle, liTrans[0]),
-                                    liTrans[1],
-                                    bAddRemove,
-                                    remove_deadends=not bDeadend)
-
-            # Also set the reverse transition
-            # use the reversed outbound transition for inbound
-            # and the reversed inbound transition for outbound
-            grid_map.set_transition((*rcMiddle, mirror(liTrans[1])),
-                                    mirror(liTrans[0]), bAddRemove, remove_deadends=not bDeadend)
-
-
-def realistic_rail_generator(max_num_cities=5,
-                             city_size=10,
-                             allowed_rotation_angles=[0, 90],
-                             max_number_of_station_tracks=4,
-                             nbr_of_switches_per_station_track=2,
-                             connect_max_nbr_of_shortes_city=4,
-                             do_random_connect_stations=False,
-                             seed=1,
-                             print_out_info=True) -> RailGenerator:
-    """
-    This is a level generator which generates a realistic rail configurations
-
-    :param max_num_cities: Number of city node
-    :param city_size: Length of city measure in cells
-    :param allowed_rotation_angles: Rotate the city (around center)
-    :param max_number_of_station_tracks: max number of tracks per station
-    :param nbr_of_switches_per_station_track: number of switches per track (max)
-    :param connect_max_nbr_of_shortes_city: max number of connecting track between stations
-    :param do_random_connect_stations : if false connect the stations along the grid (top,left -> down,right), else rand
-    :param seed: Random Seed
-    :print_out_info : print debug info
-    :return:
-        -------
-    numpy.ndarray of type numpy.uint16
-        The matrix with the correct 16-bit bitmaps for each cell.
-    """
-
-    def do_generate_city_locations(width, height, intern_city_size, intern_max_number_of_station_tracks):
-
-        X = int(np.floor(max(1, height - 2 * intern_max_number_of_station_tracks - 1) / intern_city_size))
-        Y = int(np.floor(max(1, width - 2 * intern_max_number_of_station_tracks - 1) / intern_city_size))
-
-        max_num_cities = min(max_num_cities, X * Y)
-
-        cities_at = np.random.choice(X * Y, max_num_cities, False)
-        cities_at = np.sort(cities_at)
-        if print_out_info:
-            print("max nbr of cities with given configuration is:", max_num_cities)
-
-        x = np.floor(cities_at / Y)
-        y = cities_at - x * Y
-        xs = (x * intern_city_size + intern_max_number_of_station_tracks) + intern_city_size / 2
-        ys = (y * intern_city_size + intern_max_number_of_station_tracks) + intern_city_size / 2
-
-        generate_city_locations = [[(int(xs[i]), int(ys[i])), (int(xs[i]), int(ys[i]))] for i in range(len(xs))]
-        return generate_city_locations, max_num_cities
-
-    def do_orient_cities(generate_city_locations, intern_city_size, allowed_rotation_angles):
-        for i in range(len(generate_city_locations)):
-            # station main orientation  (horizontal or vertical
-            rot_angle = np.random.choice(allowed_rotation_angles)
-            add_pos_val = Vec2dOperations.scale_pos(Vec2dOperations.rotate_pos((1, 0), rot_angle),
-                                                    (max(1, (intern_city_size - 3) / 2)))
-            generate_city_locations[i][0] = Vec2dOperations.add_pos(generate_city_locations[i][1], add_pos_val)
-            add_pos_val = Vec2dOperations.scale_pos(Vec2dOperations.rotate_pos((1, 0), 180 + rot_angle),
-                                                    (max(1, (intern_city_size - 3) / 2)))
-            generate_city_locations[i][1] = Vec2dOperations.add_pos(generate_city_locations[i][1], add_pos_val)
-        return generate_city_locations
-
-    def create_stations_from_city_locations(rail_trans, rail_array, generate_city_locations,
-                                            intern_max_number_of_station_tracks):
-        nodes_added = []
-        start_nodes_added = [[] for i in range(len(generate_city_locations))]
-        end_nodes_added = [[] for i in range(len(generate_city_locations))]
-        station_slots = [[] for i in range(len(generate_city_locations))]
-        station_tracks = [[[] for j in range(intern_max_number_of_station_tracks)] for i in range(len(
-            generate_city_locations))]
-
-        station_slots_cnt = 0
-
-        for city_loop in range(len(generate_city_locations)):
-            # Connect train station to the correct node
-            number_of_connecting_tracks = np.random.choice(max(0, intern_max_number_of_station_tracks)) + 1
-            for ct in range(number_of_connecting_tracks):
-                org_start_node = generate_city_locations[city_loop][0]
-                org_end_node = generate_city_locations[city_loop][1]
-
-                ortho_trans = Vec2dOperations.make_orthogonal_pos(
-                    Vec2dOperations.normalize_pos(Vec2dOperations.subtract_pos(org_start_node, org_end_node)))
-                s = (ct - number_of_connecting_tracks / 2.0)
-                start_node = Vec2dOperations.ceil_pos(
-                    Vec2dOperations.add_pos(org_start_node, Vec2dOperations.scale_pos(ortho_trans, s)))
-                end_node = Vec2dOperations.ceil_pos(
-                    Vec2dOperations.add_pos(org_end_node, Vec2dOperations.scale_pos(ortho_trans, s)))
-
-                connection = connect_from_nodes(rail_trans, rail_array, start_node, end_node)
-                if len(connection) > 0:
-                    nodes_added.append(start_node)
-                    nodes_added.append(end_node)
-
-                    start_nodes_added[city_loop].append(start_node)
-                    end_nodes_added[city_loop].append(end_node)
-
-                    # place in the center of path a station slot
-                    station_slots[city_loop].append(connection[int(np.floor(len(connection) / 2))])
-                    station_slots_cnt += 1
-
-                    station_tracks[city_loop][ct] = connection
-
-        if print_out_info:
-            print("max nbr of station slots with given configuration is:", station_slots_cnt)
-
-        return nodes_added, station_slots, start_nodes_added, end_nodes_added, station_tracks
-
-    def create_switches_at_stations(width, height, grid_map, station_tracks, nodes_added,
-                                    intern_nbr_of_switches_per_station_track):
-        # generate switch based on switch slot list and connect them
-        for city_loop in range(len(station_tracks)):
-            datas = station_tracks[city_loop]
-            for data_loop in range(len(datas) - 1):
-                data = datas[data_loop]
-                data1 = datas[data_loop + 1]
-                if len(data) > 2 and len(data1) > 2:
-                    for i in np.random.choice(min(len(data1), len(data)) - 2,
-                                              intern_nbr_of_switches_per_station_track):
-                        Grid_Map_Op.add_rail(width, height, grid_map, data[i + 1], data1[i + 1], data1[i + 2], True)
-                        nodes_added.append(data[i + 1])
-                        nodes_added.append(data1[i + 1])
-                        nodes_added.append(data1[i + 2])
-
-        return nodes_added
-
-    def calc_nbr_of_graphs(graph):
-        for i in range(len(graph)):
-            for j in range(len(graph)):
-                a = graph[i]
-                b = graph[j]
-                connected = False
-                if a[0] == b[0] or a[1] == b[0]:
-                    connected = True
-                if a[0] == b[1] or a[1] == b[1]:
-                    connected = True
-
-                if connected:
-                    a = [graph[i][0], graph[i][1], graph[i][2]]
-                    b = [graph[j][0], graph[j][1], graph[j][2]]
-                    graph[i] = (graph[i][0], graph[i][1], min(np.min(a), np.min(b)))
-                    graph[j] = (graph[j][0], graph[j][1], min(np.min(a), np.min(b)))
-                else:
-                    a = [graph[i][0], graph[i][1], graph[i][2]]
-                    graph[i] = (graph[i][0], graph[i][1], np.min(a))
-                    b = [graph[j][0], graph[j][1], graph[j][2]]
-                    graph[j] = (graph[j][0], graph[j][1], np.min(b))
-
-        graph_ids = []
-        for i in range(len(graph)):
-            graph_ids.append(graph[i][2])
-        if print_out_info:
-            print("************* NBR of graphs:", len(np.unique(graph_ids)))
-        return graph, np.unique(graph_ids).astype(int)
-
-    def connect_sub_graphs(rail_trans, rail_array, org_s_nodes, org_e_nodes, city_edges, nodes_added):
-        _, graphids = calc_nbr_of_graphs(city_edges)
-        if len(graphids) > 0:
-            for i in range(len(graphids) - 1):
-                connection = []
-                cnt = 0
-                while len(connection) == 0 and cnt < 100:
-                    s_nodes = copy.deepcopy(org_s_nodes)
-                    e_nodes = copy.deepcopy(org_e_nodes)
-                    start_nodes = s_nodes[graphids[i]]
-                    end_nodes = e_nodes[graphids[i + 1]]
-                    start_node = start_nodes[np.random.choice(len(start_nodes))]
-                    end_node = end_nodes[np.random.choice(len(end_nodes))]
-                    rail_array[start_node] = 0
-                    rail_array[end_node] = 0
-                    connection = connect_rail_in_grid_map(rail_array, start_node, end_node, rail_trans)
-                    if len(connection) > 0:
-                        nodes_added.append(start_node)
-                        nodes_added.append(end_node)
-                    cnt += 1
-
-    def connect_stations(rail_trans, rail_array, org_s_nodes, org_e_nodes, nodes_added,
-                         inter_connect_max_nbr_of_shortes_city):
-
-        city_edges = []
-
-        s_nodes = copy.deepcopy(org_s_nodes)
-        e_nodes = copy.deepcopy(org_e_nodes)
-
-        for k in range(inter_connect_max_nbr_of_shortes_city):
-            for city_loop in range(len(s_nodes)):
-                sns = s_nodes[city_loop]
-                for start_node in sns:
-                    min_distance = np.inf
-                    end_node = None
-                    for city_loop_find_shortest in range(len(e_nodes)):
-                        if city_loop_find_shortest == city_loop:
-                            continue
-                        ens = e_nodes[city_loop_find_shortest]
-                        for en in ens:
-                            d = Vec2dOperations.get_norm_pos(Vec2dOperations.subtract_pos(en, start_node))
-                            if d < min_distance:
-                                min_distance = d
-                                end_node = en
-                                cl = city_loop_find_shortest
-
-                    if end_node is not None:
-                        tmp_trans_sn = rail_array[start_node]
-                        tmp_trans_en = rail_array[end_node]
-                        rail_array[start_node] = 0
-                        rail_array[end_node] = 0
-                        connection = connect_rail_in_grid_map(rail_array, start_node, end_node, rail_trans)
-                        if len(connection) > 0:
-                            s_nodes[city_loop].remove(start_node)
-                            e_nodes[cl].remove(end_node)
-                            a = (city_loop, cl, np.inf)
-                            if city_loop > cl:
-                                a = (cl, city_loop, np.inf)
-                            if not (a in city_edges):
-                                city_edges.append(a)
-                            nodes_added.append(start_node)
-                            nodes_added.append(end_node)
-                        else:
-                            rail_array[start_node] = tmp_trans_sn
-                            rail_array[end_node] = tmp_trans_en
-
-        connect_sub_graphs(rail_trans, rail_array, org_s_nodes, org_e_nodes, city_edges, nodes_added)
-
-    def connect_random_stations(rail_trans, rail_array, start_nodes_added, end_nodes_added, nodes_added,
-                                inter_connect_max_nbr_of_shortes_city):
-        x = np.arange(len(start_nodes_added))
-        random_city_idx = np.random.choice(x, len(x), False)
-
-        # cyclic connection
-        random_city_idx = np.append(random_city_idx, random_city_idx[0])
-
-        for city_loop in range(len(random_city_idx) - 1):
-            idx_a = random_city_idx[city_loop + 1]
-            idx_b = random_city_idx[city_loop]
-            s_nodes = start_nodes_added[idx_a]
-            e_nodes = end_nodes_added[idx_b]
-
-            max_input_output = max(len(s_nodes), len(e_nodes))
-            max_input_output = min(inter_connect_max_nbr_of_shortes_city, max_input_output)
-
-            if do_random_connect_stations:
-                idx_s_nodes = np.random.choice(np.arange(len(s_nodes)), len(s_nodes), False)
-                idx_e_nodes = np.random.choice(np.arange(len(e_nodes)), len(e_nodes), False)
-            else:
-                idx_s_nodes = np.arange(len(s_nodes))
-                idx_e_nodes = np.arange(len(e_nodes))
-
-            if len(idx_s_nodes) < max_input_output:
-                idx_s_nodes = np.append(idx_s_nodes, np.random.choice(np.arange(len(s_nodes)), max_input_output - len(
-                    idx_s_nodes)))
-            if len(idx_e_nodes) < max_input_output:
-                idx_e_nodes = np.append(idx_e_nodes,
-                                        np.random.choice(np.arange(len(idx_e_nodes)), max_input_output - len(
-                                            idx_e_nodes)))
-
-            if len(idx_s_nodes) > inter_connect_max_nbr_of_shortes_city:
-                idx_s_nodes = np.random.choice(idx_s_nodes, inter_connect_max_nbr_of_shortes_city, False)
-            if len(idx_e_nodes) > inter_connect_max_nbr_of_shortes_city:
-                idx_e_nodes = np.random.choice(idx_e_nodes, inter_connect_max_nbr_of_shortes_city, False)
-
-            for i in range(max_input_output):
-                start_node = s_nodes[idx_s_nodes[i]]
-                end_node = e_nodes[idx_e_nodes[i]]
-                new_trans = rail_array[start_node] = 0
-                new_trans = rail_array[end_node] = 0
-                connection = connect_nodes(rail_trans, rail_array, start_node, end_node)
-                if len(connection) > 0:
-                    nodes_added.append(start_node)
-                    nodes_added.append(end_node)
-
-    def generator(width, height, num_agents, num_resets=0) -> RailGeneratorProduct:
-        rail_trans = RailEnvTransitions()
-        grid_map = GridTransitionMap(width=width, height=height, transitions=rail_trans)
-        rail_array = grid_map.grid
-        rail_array.fill(0)
-        np.random.seed(seed + num_resets)
-
-        intern_city_size = city_size
-        if city_size < 3:
-            warnings.warn("min city_size requried to be > 3!")
-            intern_city_size = 3
-        if print_out_info:
-            print("intern_city_size:", intern_city_size)
-
-        intern_max_number_of_station_tracks = max_number_of_station_tracks
-        if max_number_of_station_tracks < 1:
-            warnings.warn("min max_number_of_station_tracks requried to be > 1!")
-            intern_max_number_of_station_tracks = 1
-        if print_out_info:
-            print("intern_max_number_of_station_tracks:", intern_max_number_of_station_tracks)
-
-        intern_nbr_of_switches_per_station_track = nbr_of_switches_per_station_track
-        if nbr_of_switches_per_station_track < 1:
-            warnings.warn("min intern_nbr_of_switches_per_station_track requried to be > 2!")
-            intern_nbr_of_switches_per_station_track = 2
-        if print_out_info:
-            print("intern_nbr_of_switches_per_station_track:", intern_nbr_of_switches_per_station_track)
-
-        inter_connect_max_nbr_of_shortes_city = connect_max_nbr_of_shortes_city
-        if connect_max_nbr_of_shortes_city < 1:
-            warnings.warn("min inter_connect_max_nbr_of_shortes_city requried to be > 1!")
-            inter_connect_max_nbr_of_shortes_city = 1
-        if print_out_info:
-            print("inter_connect_max_nbr_of_shortes_city:", inter_connect_max_nbr_of_shortes_city)
-
-        agent_start_targets_nodes = []
-
-        # ----------------------------------------------------------------------------------
-        # generate city locations
-        generate_city_locations, max_num_cities = do_generate_city_locations(width, height, intern_city_size,
-                                                                             intern_max_number_of_station_tracks)
-
-        # ----------------------------------------------------------------------------------
-        # apply orientation to cities (horizontal, vertical)
-        generate_city_locations = do_orient_cities(generate_city_locations, intern_city_size, allowed_rotation_angles)
-
-        # ----------------------------------------------------------------------------------
-        # generate city topology
-        nodes_added, train_stations, s_nodes, e_nodes, station_tracks = \
-            create_stations_from_city_locations(rail_trans, rail_array,
-                                                generate_city_locations,
-                                                intern_max_number_of_station_tracks)
-        # build switches
-        create_switches_at_stations(width, height, grid_map, station_tracks, nodes_added,
-                                    intern_nbr_of_switches_per_station_track)
-
-        # ----------------------------------------------------------------------------------
-        # connect stations
-        if True:
-            if do_random_connect_stations:
-                connect_random_stations(rail_trans, rail_array, s_nodes, e_nodes, nodes_added,
-                                        inter_connect_max_nbr_of_shortes_city)
-            else:
-                connect_stations(rail_trans, rail_array, s_nodes, e_nodes, nodes_added,
-                                 inter_connect_max_nbr_of_shortes_city)
-
-        # ----------------------------------------------------------------------------------
-        # fix all transition at starting / ending points (mostly add a dead end, if missing)
-        for i in range(len(nodes_added)):
-            grid_map.fix_transitions(nodes_added[i])
-
-        # ----------------------------------------------------------------------------------
-        # Slot availability in node
-        node_available_start = []
-        node_available_target = []
-        for node_idx in range(max_num_cities):
-            node_available_start.append(len(train_stations[node_idx]))
-            node_available_target.append(len(train_stations[node_idx]))
-
-        # Assign agents to slots
-        for agent_idx in range(num_agents):
-            avail_start_nodes = [idx for idx, val in enumerate(node_available_start) if val > 0]
-            avail_target_nodes = [idx for idx, val in enumerate(node_available_target) if val > 0]
-            if len(avail_target_nodes) == 0:
-                num_agents -= 1
-                continue
-            start_node = np.random.choice(avail_start_nodes)
-            target_node = np.random.choice(avail_target_nodes)
-            tries = 0
-            found_agent_pair = True
-            while target_node == start_node:
-                target_node = np.random.choice(avail_target_nodes)
-                tries += 1
-                # Test again with new start node if no pair is found (This code needs to be improved)
-                if (tries + 1) % 10 == 0:
-                    start_node = np.random.choice(avail_start_nodes)
-                if tries > 100:
-                    warnings.warn("Could not set trainstations, removing agent!")
-                    found_agent_pair = False
-                    break
-            if found_agent_pair:
-                node_available_start[start_node] -= 1
-                node_available_target[target_node] -= 1
-                agent_start_targets_nodes.append((start_node, target_node))
-            else:
-                num_agents -= 1
-
-        return grid_map, {'agents_hints': {
-            'num_agents': num_agents,
-            'agent_start_targets_nodes': agent_start_targets_nodes,
-            'train_stations': train_stations
-        }}
-
-    return generator
-
-
-for itrials in range(100):
-    print(itrials, "generate new city")
-    np.random.seed(int(time.time()))
-    env = RailEnv(width=40 + np.random.choice(100),
-                  height=40 + np.random.choice(100),
-                  rail_generator=realistic_rail_generator(max_num_cities=2 + np.random.choice(10),
-                                                          city_size=10 + np.random.choice(10),
-                                                          allowed_rotation_angles=[-90, -45, 0, 45, 90],
-                                                          max_number_of_station_tracks=np.random.choice(4) + 4,
-                                                          nbr_of_switches_per_station_track=np.random.choice(4) + 2,
-                                                          connect_max_nbr_of_shortes_city=np.random.choice(4) + 2,
-                                                          do_random_connect_stations=np.random.choice(1) == 0,
-                                                          # Number of cities in map
-                                                          seed=int(time.time()),  # Random seed
-                                                          print_out_info=False
-                                                          ),
-                  schedule_generator=sparse_schedule_generator(),
-                  number_of_agents=1000,
-                  obs_builder_object=GlobalObsForRailEnv())
-
-    env.reset()
-
-    env_renderer = RenderTool(env, gl="PILSVG", screen_width=1400, screen_height=1000)
-    cnt = 0
-    while cnt < 10:
-        env_renderer.render_env(show=True, show_observations=False, show_predictions=False)
-        cnt += 1
-
-    env_renderer.gl.save_image(
-        os.path.join(
-            "./../render_output/",
-            "flatland_frame_{:04d}_{:04d}.png".format(itrials, 0)
-        ))
-
-    env_renderer.close_window()
diff --git a/examples/complex_rail_benchmark.py b/examples/complex_rail_benchmark.py
index ecbbe8b4582fdb2047c52ac01c5aa3d9a330d30a..87f248ee223b061fca8375d56072ed81d5ad338c 100644
--- a/examples/complex_rail_benchmark.py
+++ b/examples/complex_rail_benchmark.py
@@ -24,28 +24,11 @@ def run_benchmark():
     action_dict = dict()
     action_prob = [0] * 4
 
-    def max_lt(seq, val):
-        """
-        Return greatest item in seq for which item < val applies.
-        None is returned if seq was empty or all items in seq were >= val.
-        """
-
-        idx = len(seq) - 1
-        while idx >= 0:
-            if seq[idx] < val and seq[idx] >= 0:
-                return seq[idx]
-            idx -= 1
-        return None
-
     for trials in range(1, n_trials + 1):
 
         # Reset environment
         obs, info = env.reset()
 
-        for a in range(env.get_num_agents()):
-            norm = max(1, max_lt(obs[a], np.inf))
-            obs[a] = np.clip(np.array(obs[a]) / norm, -1, 1)
-
         # Run episode
         for step in range(100):
             # Action
@@ -56,9 +39,6 @@ def run_benchmark():
 
             # Environment step
             next_obs, all_rewards, done, _ = env.step(action_dict)
-            for a in range(env.get_num_agents()):
-                norm = max(1, max_lt(next_obs[a], np.inf))
-                next_obs[a] = np.clip(np.array(next_obs[a]) / norm, -1, 1)
 
             if done['__all__']:
                 break
diff --git a/examples/custom_observation_example_02_SingleAgentNavigationObs.py b/examples/custom_observation_example_02_SingleAgentNavigationObs.py
index aa9da8494b4a7376a3468c16618e5459344a37f3..b1729296a199fded38270a63a527de06d9e7b329 100644
--- a/examples/custom_observation_example_02_SingleAgentNavigationObs.py
+++ b/examples/custom_observation_example_02_SingleAgentNavigationObs.py
@@ -35,7 +35,11 @@ class SingleAgentNavigationObs(ObservationBuilder):
     def get(self, handle: int = 0) -> List[int]:
         agent = self.env.agents[handle]
 
-        possible_transitions = self.env.rail.get_transitions(*agent.position, agent.direction)
+        if agent.position:
+            possible_transitions = self.env.rail.get_transitions(*agent.position, agent.direction)
+        else:
+            possible_transitions = self.env.rail.get_transitions(*agent.initial_position, agent.direction)
+
         num_transitions = np.count_nonzero(possible_transitions)
 
         # Start from the current orientation, and see which transitions are available;
diff --git a/examples/custom_railmap_example.py b/examples/custom_railmap_example.py
index bd662aa559abda3717e7be8ba050a15f8ec75fa5..ed263ef93e80f4d4a04db240d5e21c6e855806f8 100644
--- a/examples/custom_railmap_example.py
+++ b/examples/custom_railmap_example.py
@@ -7,7 +7,7 @@ from flatland.core.grid.rail_env_grid import RailEnvTransitions
 from flatland.core.transition_map import GridTransitionMap
 from flatland.envs.rail_env import RailEnv
 from flatland.envs.rail_generators import RailGenerator, RailGeneratorProduct
-from flatland.envs.schedule_generators import ScheduleGenerator, compute_max_episode_steps
+from flatland.envs.schedule_generators import ScheduleGenerator
 from flatland.envs.schedule_utils import Schedule
 from flatland.utils.rendertools import RenderTool
 
@@ -31,15 +31,14 @@ def custom_rail_generator() -> RailGenerator:
 
 
 def custom_schedule_generator() -> ScheduleGenerator:
-    def generator(rail: GridTransitionMap, num_agents: int, hints: Any = None) -> Schedule:
+    def generator(rail: GridTransitionMap, num_agents: int, hints: Any = None,
+                  num_resets: int = 0) -> Schedule:
         agents_positions = []
         agents_direction = []
         agents_target = []
         speeds = []
-        max_episode_steps = compute_max_episode_steps(width=rail.width, height=rail.height)
         return Schedule(agent_positions=agents_positions, agent_directions=agents_direction,
-                        agent_targets=agents_target, agent_speeds=speeds, agent_malfunction_rates=None,
-                        max_episode_steps=max_episode_steps)
+                        agent_targets=agents_target, agent_speeds=speeds, agent_malfunction_rates=None)
 
     return generator
 
diff --git a/examples/debugging_example_DELETE.py b/examples/debugging_example_DELETE.py
deleted file mode 100644
index 9de330c9bd17f8c07acb931b1ca4eff689c798a7..0000000000000000000000000000000000000000
--- a/examples/debugging_example_DELETE.py
+++ /dev/null
@@ -1,85 +0,0 @@
-import random
-import time
-from typing import List
-
-import numpy as np
-
-from flatland.core.env_observation_builder import ObservationBuilder
-from flatland.core.grid.grid4_utils import get_new_position
-from flatland.envs.rail_env import RailEnv
-from flatland.envs.rail_generators import complex_rail_generator
-from flatland.envs.schedule_generators import complex_schedule_generator
-from flatland.utils.rendertools import RenderTool
-
-random.seed(1)
-np.random.seed(1)
-
-
-class SingleAgentNavigationObs(ObservationBuilder):
-    """
-    We build a representation vector with 3 binary components, indicating which of the 3 available directions
-    for each agent (Left, Forward, Right) lead to the shortest path to its target.
-    E.g., if taking the Left branch (if available) is the shortest route to the agent's target, the observation vector
-    will be [1, 0, 0].
-    """
-
-    def __init__(self):
-        super().__init__()
-
-    def reset(self):
-        pass
-
-    def get(self, handle: int = 0) -> List[int]:
-        agent = self.env.agents[handle]
-
-        possible_transitions = self.env.rail.get_transitions(*agent.position, agent.direction)
-        num_transitions = np.count_nonzero(possible_transitions)
-
-        # Start from the current orientation, and see which transitions are available;
-        # organize them as [left, forward, right], relative to the current orientation
-        # If only one transition is possible, the forward branch is aligned with it.
-        if num_transitions == 1:
-            observation = [0, 1, 0]
-        else:
-            min_distances = []
-            for direction in [(agent.direction + i) % 4 for i in range(-1, 2)]:
-                if possible_transitions[direction]:
-                    new_position = get_new_position(agent.position, direction)
-                    min_distances.append(self.env.distance_map.get()[handle, new_position[0], new_position[1], direction])
-                else:
-                    min_distances.append(np.inf)
-
-            observation = [0, 0, 0]
-            observation[np.argmin(min_distances)] = 1
-
-        return observation
-
-
-env = RailEnv(width=14,
-              height=14,
-              rail_generator=complex_rail_generator(nr_start_goal=10, nr_extra=1, min_dist=5, max_dist=99999, seed=1),
-              schedule_generator=complex_schedule_generator(),
-              number_of_agents=2,
-              obs_builder_object=SingleAgentNavigationObs())
-
-obs, info = env.reset()
-env_renderer = RenderTool(env, gl="PILSVG")
-env_renderer.render_env(show=True, frames=True, show_observations=False)
-for step in range(100):
-    actions = {}
-    for i in range(len(obs)):
-        actions[i] = np.argmax(obs[i]) + 1
-
-    if step % 5 == 0:
-        print("Agent halts")
-        actions[0] = 4  # Halt
-
-    obs, all_rewards, done, _ = env.step(actions)
-    if env.agents[0].malfunction_data['malfunction'] > 0:
-        print("Agent 0 broken-ness: ", env.agents[0].malfunction_data['malfunction'])
-
-    env_renderer.render_env(show=True, frames=True, show_observations=False)
-    time.sleep(0.5)
-    if done["__all__"]:
-        break
-env_renderer.close_window()
diff --git a/flatland/envs/rail_env.py b/flatland/envs/rail_env.py
index 22bd21625fd4cc0fb50c592bf4533e60ced00546..125f8f13b445fba6b137bcf2ed521843f84bc278 100644
--- a/flatland/envs/rail_env.py
+++ b/flatland/envs/rail_env.py
@@ -729,7 +729,6 @@ class RailEnv(Environment):
                 (*agent.position, agent.direction),
                 new_direction)
 
-
         # only call cell_free() if new cell is inside the scene
         if new_cell_valid:
             # Check the new position is not the same as any of the existing agent positions
diff --git a/tests/test_utils.py b/tests/test_utils.py
index d9378fd38e6c87865c5fee69e3f8e6e21fcdd013..1a98c161829dedc429465b6606101fd19784cbaa 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -114,7 +114,12 @@ def run_replay_config(env: RailEnv, test_configs: List[ReplayConfig], rendering:
                     step, a, False, info_dict['action_required'][a])
 
             if replay.set_malfunction is not None:
+                # As we force malfunctions on the agents we have to set a positive rate that the env
+                # recognizes the agent as potentially malfuncitoning
+                # We also set next malfunction to infitiy to avoid interference with our tests
                 agent.malfunction_data['malfunction'] = replay.set_malfunction
+                agent.malfunction_data['malfunction_rate'] = max(agent.malfunction_data['malfunction_rate'], 1)
+                agent.malfunction_data['next_malfunction'] = np.inf
                 agent.malfunction_data['moving_before_malfunction'] = agent.moving
             _assert(a, agent.malfunction_data['malfunction'], replay.malfunction, 'malfunction')
         print(step)