diff --git a/examples/Simple_Realistic_Railway_Generator.py b/examples/Simple_Realistic_Railway_Generator.py
index d5064d61c26a2a81b82b13dbe571fffc9ca8e9fc..bc030182e1ff331833636be7511ab8a36d78542b 100644
--- a/examples/Simple_Realistic_Railway_Generator.py
+++ b/examples/Simple_Realistic_Railway_Generator.py
@@ -1,8 +1,11 @@
+import time
+import warnings
+
 import numpy as np
 
 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
+from flatland.envs.grid4_generators_utils import connect_from_nodes, connect_nodes
 from flatland.envs.observations import GlobalObsForRailEnv
 from flatland.envs.rail_env import RailEnv
 from flatland.envs.rail_generators import RailGenerator, RailGeneratorProduct
@@ -10,7 +13,7 @@ from flatland.envs.schedule_generators import sparse_schedule_generator
 from flatland.utils.rendertools import RenderTool
 
 
-def realistic_rail_generator(num_cities=5, city_size=10, max_number_of_station_tracks=4,
+def realistic_rail_generator(num_cities=5, city_size=10,allowed_rotation_angles=[0,90],
                              max_number_of_connecting_tracks=4,
                              seed=0, print_out_info=True) -> RailGenerator:
     """
@@ -54,65 +57,127 @@ def realistic_rail_generator(num_cities=5, city_size=10, max_number_of_station_t
     def bound_pos(node, min_value, max_value):
         return (max(min_value, min(max_value, node[0])), max(min_value, min(max_value, node[1])))
 
-    def do_generate_city_locations(width, height):
+    def rotate_pos(node, rot_in_degree):
+        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)
+
+    def do_generate_city_locations(width, height, intern_city_size, intern_max_number_of_connecting_tracks):
 
-        X = int(np.floor(max(1, width - 2 * max_number_of_connecting_tracks - 1) / city_size))
-        Y = int(np.floor(max(1, height - 2 * max_number_of_connecting_tracks - 1) / city_size))
+        X = int(np.floor(max(1, width - 2 * intern_max_number_of_connecting_tracks - 1) / intern_city_size))
+        Y = int(np.floor(max(1, height - 2 * intern_max_number_of_connecting_tracks - 1) / intern_city_size))
 
         max_num_cities = min(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)
+            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 * city_size + max_number_of_connecting_tracks)
-        ys = (y * city_size + max_number_of_connecting_tracks)
+        xs = (x * intern_city_size + intern_max_number_of_connecting_tracks) + intern_city_size / 2
+        ys = (y * intern_city_size + intern_max_number_of_connecting_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):
+    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
-            add_pos_val = (city_size, 0)
-            if np.random.choice(2) == 0:
-                add_pos_val = (0, city_size)
+            rot_angle = np.random.choice(allowed_rotation_angles)
+            add_pos_val = scale_pos(rotate_pos((1,0),rot_angle),(max(1, (intern_city_size - 3) / 2)))
+            generate_city_locations[i][0] = add_pos(generate_city_locations[i][1], add_pos_val)
+            add_pos_val = scale_pos(rotate_pos((1,0),180+rot_angle),(max(1, (intern_city_size - 3) / 2)))
             generate_city_locations[i][1] = add_pos(generate_city_locations[i][1], add_pos_val)
         return generate_city_locations
 
-    def do_tracks_between_start_end_points(rail_trans, rail_array, generate_city_locations):
-        nodes_to_added = []
+    def create_stations_from_city_locations(rail_trans, rail_array, generate_city_locations,
+                                            intern_max_number_of_connecting_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))]
+        switch_slots = [[] 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, max_number_of_connecting_tracks)) + 1
-
+            number_of_connecting_tracks = np.random.choice(max(0, intern_max_number_of_connecting_tracks)) + 1
             for ct in range(number_of_connecting_tracks):
-                for kLoop in range(2):
-                    org_start_node = generate_city_locations[city_loop][kLoop]
+                org_start_node = generate_city_locations[city_loop][0]
+                org_end_node = generate_city_locations[city_loop][1]
+
+                ortho_trans = make_orthogonal_pos(normalize_pos(subtract_pos(org_start_node, org_end_node)))
+                s = (ct - number_of_connecting_tracks / 2.0)
+                start_node = ceil_pos(add_pos(org_start_node, scale_pos(ortho_trans, s)))
+                end_node = ceil_pos(add_pos(org_end_node, 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
+                    if len(connection) - 3 > 0:
+                        idxs = np.random.choice(len(connection) - 2, 1 + np.random.choice(len(connection) - 3), False)
+                        for idx in idxs:
+                            switch_slots[city_loop].append(connection[idx + 1])
+
+        for city_loop in range(len(switch_slots)):
+            data = switch_slots[city_loop]
+            for i in range(len(data) - 1):
+                start_node = data[i]
+                end_node = data[i + 1]
+                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)
 
-                    a = generate_city_locations[city_loop][0]
-                    b = generate_city_locations[city_loop][1]
-                    org_end_node = scale_pos(add_pos(a, b), 0.5)
-
-                    ortho_trans = make_orthogonal_pos(normalize_pos(subtract_pos(a, b)))
-                    s = (ct - number_of_connecting_tracks / 2.0)
-                    start_node = ceil_pos(add_pos(org_start_node, scale_pos(ortho_trans, s)))
-                    end_node = ceil_pos(org_end_node)
-                    end_node = ceil_pos(add_pos(org_end_node, scale_pos(ortho_trans, s)))
-
-                    connection = connect_from_nodes(rail_trans, rail_array, start_node, end_node)
-                    if len(connection) > 0:
-                        nodes_to_added.append(start_node)
-                        nodes_to_added.append(end_node)
-                        # place in the center of path a station slot
-                        station_slots[city_loop].append(connection[int(np.floor(len(connection)/2))])
-
-        return nodes_to_added, station_slots,
+        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
+
+    def connect_stations(rail_trans, rail_array, start_nodes_added, end_nodes_added, nodes_added):
+        x = np.arange(len(start_nodes_added))
+        random_city_idx = np.random.choice(x, len(x), False)
+        for city_loop in range(len(random_city_idx) - 1):
+            idx_a = random_city_idx[city_loop]
+            idx_b = random_city_idx[city_loop + 1]
+            s_nodes = start_nodes_added[idx_a]
+            e_nodes = end_nodes_added[idx_b]
+
+            max_input_output = max(len(s_nodes), len(e_nodes))
+
+            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)
+            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)))
+
+            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()
@@ -121,25 +186,38 @@ def realistic_rail_generator(num_cities=5, city_size=10, max_number_of_station_t
         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_connecting_tracks = max_number_of_connecting_tracks
+        if max_number_of_connecting_tracks < 1:
+            warnings.warn("min max_number_of_connecting_tracks requried to be > 1!")
+            intern_max_number_of_connecting_tracks = 1
+        if print_out_info:
+            print("intern_max_number_of_connecting_tracks:", intern_max_number_of_connecting_tracks)
+
         agent_start_targets_nodes = []
         # generate city locations
-        generate_city_locations, max_num_cities = do_generate_city_locations(width, height)
+        generate_city_locations, max_num_cities = do_generate_city_locations(width, height, intern_city_size,
+                                                                             intern_max_number_of_connecting_tracks)
         # apply orientation to cities (horizontal, vertical)
-        generate_city_locations = do_orient_cities(generate_city_locations)
+        generate_city_locations = do_orient_cities(generate_city_locations, intern_city_size,allowed_rotation_angles)
         # generate city topology
-        nodes_to_added, station_slots = do_tracks_between_start_end_points(rail_trans,
-                                                                                    rail_array,
-                                                                                    generate_city_locations)
-
-        train_stations = [[] for i in range(max_num_cities)]
-        for i in range(max_num_cities):
-            for j in range(len(station_slots[i])):
-                train_stations[i].append(station_slots[i][j])
+        nodes_added, train_stations, s_nodes, e_nodes = \
+            create_stations_from_city_locations(rail_trans, rail_array,
+                                                generate_city_locations,
+                                                intern_max_number_of_connecting_tracks)
+        # connect stations
+        connect_stations(rail_trans, rail_array, s_nodes, e_nodes, nodes_added)
 
         # ----------------------------------------------------------------------------------
         # fix all transition at starting / ending points (mostly add a dead end, if missing)
-        for i in range(len(nodes_to_added)):
-            grid_map.fix_transitions(nodes_to_added[i])
+        for i in range(len(nodes_added)):
+            grid_map.fix_transitions(nodes_added[i])
 
         # ----------------------------------------------------------------------------------
         # Slot availability in node
@@ -153,6 +231,9 @@ def realistic_rail_generator(num_cities=5, city_size=10, max_number_of_station_t
         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
@@ -183,18 +264,26 @@ def realistic_rail_generator(num_cities=5, city_size=10, max_number_of_station_t
     return generator
 
 
-env = RailEnv(width=70,
-              height=70,
-              rail_generator=realistic_rail_generator(num_cities=100,  # Number of cities in map
-                                                      seed=0  # Random seed
-                                                      ),
-              schedule_generator=sparse_schedule_generator(),
-              number_of_agents=5,
-              obs_builder_object=GlobalObsForRailEnv())
-
-# reset to initialize agents_static
-env_renderer = RenderTool(env, gl="PILSVG", screen_width=1400, screen_height=1000)
-while True:
-    env_renderer.render_env(show=True, show_observations=False, show_predictions=False)
-
-env_renderer.close_window()
+for itrials in range(100):
+    print(itrials, "generate new city")
+    np.random.seed(int(time.time()))
+    env = RailEnv(width=70,
+                  height=70,
+                  rail_generator=realistic_rail_generator(num_cities=np.random.choice(40) + 2,
+                                                          city_size=np.random.choice(20) + 10,
+                                                          allowed_rotation_angles = np.random.choice([0,15,30,45,90],2),
+                                                          max_number_of_connecting_tracks=np.random.choice(4),
+                                                          # Number of cities in map
+                                                          seed=int(time.time())  # Random seed
+                                                          ),
+                  schedule_generator=sparse_schedule_generator(),
+                  number_of_agents=89,
+                  obs_builder_object=GlobalObsForRailEnv())
+
+    # reset to initialize agents_static
+    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.close_window()