"""This module creates BNG Prefab and Lua files from XML files."""

from beamngpy import BeamNGpy, Scenario, Road, StaticObject, Vehicle
from beamngpy.beamngcommon import ENV
from os.path import join
from math import radians, sin, cos
from shapely.geometry import LineString
from numpy import asarray, clip, concatenate, arange, linspace, array, around, dot
from scipy.interpolate import splev
from re import findall

from utils.utility_functions import multilinestrings_to_linestring

NUM_NODES = 100     # Number of interpolation samples

def _calc_rot_matrix(rad_x, rad_y, rad_z):
    """Calculates the rotation matrix which is required for BNG.
    :param rad_x: Radians in x direction.
    :param rad_y: Radians in y direction.
    :param rad_z: Radians in z direction.
    :return: Rotation matrix.
    """
    rot_matrix_x = [[1, 0, 0], [0, cos(rad_x), sin(rad_x)], [0, -sin(rad_x), cos(rad_x)]]
    rot_matrix_y = [[cos(rad_y), 0, -sin(rad_y)], [0, 1, 0], [sin(rad_y), 0, cos(rad_y)]]
    rot_matrix_z = [[cos(rad_z), sin(rad_z), 0], [-sin(rad_z), cos(rad_z), 0], [0, 0, 1]]
    rot_matrix = dot(rot_matrix_z, rot_matrix_y)
    rot_matrix = dot(rot_matrix, rot_matrix_x)
    return rot_matrix

def _get_nodes(linestring, road_segments, fac, width=0.2):
    """Takes a LineString and creates a list with node coordinates and width parameter.
    :param linestring: Linestring of the road.
    :param road_segments: List of road segments.
    :param fac: Skips every x nodes of the road_segments list.
    :param width: Width of the road.
    :return: List with node coordinates and width.
    """
    nodes = list()
    i = 0
    while i < len(list(linestring.coords)):
        index = int(round(fac * i))
        if index >= len(road_segments):
            index = len(road_segments) - 1
        z = road_segments[index].attrib.get("z")
        if z is None:
            z = 0.01
        else:
            z = (int(z))
        nodes.append((list(linestring.coords)[i][0], list(linestring.coords)[i][1], z, width))
        i += 1
    return nodes

def _get_offset_nodes(road_segments, line, offset, direction):
    """Creates a offset linestring and returns the nodes of it.
    :param road_segments: List of road segments.
    :param line: Calculate the offset linestring of this line.
    :param offset: The amount of offset which should be applied.
    :param direction: Left or right as a string.
    :return: List of nodes of the offset line.
    """
    outer_line = line.parallel_offset(offset, direction)
    outer_line = multilinestrings_to_linestring(outer_line)
    fac = len(road_segments) / len(list(outer_line.coords))
    nodes = _get_nodes(outer_line, road_segments, fac)
    if direction == "right":
        nodes = nodes[::-1]
    return nodes

def b_spline(old_coords, samples=NUM_NODES, degree=2):
    """Calculate {@code samples} samples on a bspline. This is the road representation function.
    :param samples: Number of samples to return.
    :param old_coords: List of tuples.
    :param degree: Degree of the spline curve. 2 is the lowest with the best interpolation. Higher degrees has worse
     interpolation.
    :return: Array with samples, representing a bspline of the given control points of the roads.
    """
    old_coords = asarray(old_coords)
    count = len(old_coords)
    degree = clip(degree, 0, count - 1)
    kv = concatenate(([0] * degree, arange(count - degree + 1), [count - degree] * degree))
    u = linspace(False, (count - degree), samples)
    splines = around(array(splev(u, (kv, old_coords.T, degree))).T, 3)
    return splines

class Converter:
    """This class provides functions to generate Prefab and Lua files for BeamNG out of XML files."""
    def __init__(self, dbc_root, dbe_root, index):
        """Initialize class specific variables.
        :param dbc_root: Root tag of the criteria XML file.
        :param dbe_root: Root tag of the environment XML file.
        :param index: Unique identifier for the test case.
        """
        self.dbc_root = dbc_root        # Root tag of the criteria XML file.
        self.dbe_root = dbe_root        # Root tag of the environment XML file.
        self.index = index              # Unique identifier of the simulation file as Integer.
        self.lines = list()             # List of waypoints and speed values for each participant.
        self.lights = list()            # List of dicts with "id" and "pos" (position) of traffic lights.
        self.light_content = list()     # List containing Strings for adding traffic lights to the Prefab file.
        self.traffic_lights = list()    # Similar to self.lines list, but different format.
        self.light_index = 0            # Unique identifier for traffic lights.
        self.success_point = None       # Success point coordinates.
        self.traffic_triggers = list()  # List containing trigger points for switching traffic lights.
        self.weather = None             # Weather preset.

    def _init(self):
        """Creates BeamNG and Scenario object.
        :return: Void.
        """
        self.bng = BeamNGpy('localhost', 64255)
        self.scenario = Scenario('urban', 'urban_{}'.format(self.index))

    def _finalize_prefab(self):
        """Calls several methods to add information to the Prefab file.
        :return: Void.
        """
        self.bng.user = None
        self.scenario.make(self.bng)
        self._get_weather()
        self._change_object_options()
        self._add_lights_to_prefab()
        self._add_waypoints()
        self._write_lua_file()
        self._get_success_point()
        self._get_traffic_triggers()

    def _get_weather(self):
        """Stores the weather of the environment file to the class variable.
        :return: Void.
        """
        weather = self.dbe_root.find("weather")
        if weather is not None:
            self.weather = weather.text

    def add_to_prefab(self):
        """Method to create a valid Prefab file.
        :return: Void.
        """
        self._init()
        self._add_roads()
        self._add_obstacles()
        self._add_participants()
        self._finalize_prefab()

    def _get_traffic_triggers(self):
        """Stores traffic light trigger points in a class specific list variable.
        :return: Void.
        """
        trigger_points = self.dbc_root.findall("triggerPoints/triggerPoint")
        for trigger in trigger_points:
            if trigger.attrib.get("action") == "switchLights":
                self.traffic_triggers.append(trigger.attrib)

    def get_traffic_lights_position(self):
        """Gets all traffic lights that the ego-car faces.
        :return: List of traffic light attributes.
        """
        obstacles = self.dbe_root.find("obstacles")
        if obstacles is None:
            obstacles = list()
        traffic_light_positions = list()
        for obstacle in obstacles:
            attr = obstacle.attrib
            if obstacle.tag.startswith("trafficlight") and attr.get("facingEgo") is not None and attr.get("facingEgo"):
                traffic_light_positions.append(attr)
        return traffic_light_positions

    def _get_success_point(self):
        """Stores all success points in a class specific list.
        :return: Void.
        """
        success_points = self.dbc_root.findall("success/scPosition")
        self.success_point = (float(success_points[0].get("x")), float(success_points[0].get("y")))

    def _add_roads(self):
        """Adds roads and road markings to the prefab file.
        :return: Void.
        """
        roads = self.dbe_root.findall("roads/road")
        rid = 0
        for road in roads:
            self._add_road(road, rid)
            if bool(road.attrib.get("markings")):
                self._add_road_markings(road, rid)
            rid += 1

    def _add_road(self, road, rid):
        """Adds a single road to the Prefab file.
        :param road: Road with road segments.
        :param rid: Road ID (Integer).
        :return: Void.
        """
        road_bng = Road(material='road_rubber_sticky', rid='road_{}'.format(rid), interpolate=False, texture_length=2.5,
                        drivability=1)
        nodes = list()
        tuples = list()
        road_segments = road.findall("roadSegment")
        width = None
        for segment in road_segments:
            d = segment.attrib
            width = float(d.get("width"))
            tuples.append((float(d.get("x")), float(d.get("y"))))
        tuples = b_spline(tuples)       # Interpolate nodes
        for coords in tuples:
            nodes.append((coords[0], coords[1], 0.01, width))
        road_bng.nodes.extend(nodes)
        self.scenario.add_road(road_bng)        # Add to Prefab

    def _add_road_markings(self, road, rid):
        """Add road markings to the Prefab file.
        :param road: Road of the XML file.
        :param rid: Road ID (Integer).
        :return: Void.
        """
        linestring_nodes = list()
        widths = list()
        road_segments = road.findall("roadSegment")
        for segment in road_segments:
            d = segment.attrib
            linestring_nodes.append((float(d.get("x")), float(d.get("y"))))
            widths.append(float(d.get("width")))
        linestring_nodes = b_spline(linestring_nodes)
        line = LineString(linestring_nodes)
        coords = line.coords
        if not line.is_simple:
            temp_coords = list(around(list(line.coords), 2))
            coords = list()
            for coord in temp_coords:
                coords.append(tuple(coord))
            coords = list(set(coords))
            if len(coords) > 1:
                line.coords = coords
        if len(coords) > 1:
            outer_offset = int(road_segments[0].attrib.get("width")) / 2 - 0.4
            self._add_outer_marking(road_segments, rid, line, outer_offset, "left")
            self._add_outer_marking(road_segments, rid, line, outer_offset, "right")
            left_lanes = int(road.attrib.get("leftLanes"))
            right_lanes = int(road.attrib.get("rightLanes"))
            if left_lanes != 0 and right_lanes != 0:
                self._add_yellow_divider_line(road_segments, rid, line, left_lanes, right_lanes)
            if left_lanes > 1:
                self._add_separator_lines(road_segments, rid, line, left_lanes, right_lanes,
                                          int(road_segments[0].attrib.get("width")), "left")
            if right_lanes > 1:
                self._add_separator_lines(road_segments, rid, line, left_lanes, right_lanes,
                                          int(road_segments[0].attrib.get("width")), "right")

    def _add_outer_marking(self, road_segments, rid, line, offset, direction):
        """Adds one road line marking on one side.
        :param road_segments: List with road segments.
        :param rid: Road ID as String.
        :param line: Center line of the road as LineString.
        :param offset: Distance to shift the line to the side as Float.
        :param direction: "left" or "right", where to draw the line.
        :return: Void.
        """
        nodes = _get_offset_nodes(road_segments, line, offset, direction)
        road = Road(material='line_white', rid='road_{}_{}_line'.format(rid, direction), interpolate=False,
                    texture_length=16, drivability=-1)
        road.nodes.extend(nodes)
        self.scenario.add_road(road)

    def _add_yellow_divider_line(self, road_segments, rid, line, left_lanes, right_lanes):
        """Adds the yellow divider line between two opposite lanes.
        :param road_segments: List of road segments.
        :param rid: Road ID as String.
        :param line: Center line of the road as LineString.
        :param left_lanes: Number of left lanes.
        :param right_lanes: Number of right lanes.
        :return: Void.
        """
        mid = int(road_segments[0].attrib.get("width")) / 2
        road_width = int(road_segments[0].attrib.get("width")) / (left_lanes + right_lanes)
        nodes = []
        if left_lanes == right_lanes:
            for node in road_segments:
                d = node.attrib
                z = 0.01 if d.get("z") is None else d.get("z")
                nodes.append((d.get("x"), d.get("y"), z, 0.3))
        else:
            if left_lanes > right_lanes:
                offset = left_lanes * road_width - mid
                direction = "right"
            elif left_lanes < right_lanes:
                offset = right_lanes * road_width - mid
                direction = "left"
            else:
                raise TypeError("leftLanes and rightLanes must be Integers.")
            nodes = _get_offset_nodes(road_segments, line, offset, direction)
        road = Road(material='line_yellow_double', rid='road_{}_left_right_divider'.format(rid), interpolate=False,
                    texture_length=16, drivability=-1)
        road.nodes.extend(nodes)
        self.scenario.add_road(road)

    def _add_separator_lines(self, road_segments, rid, line, left_lanes, right_lanes, width, direction):
        """Add white separator lines between all lanes of one direction.
        :param road_segments: List of road segments.
        :param rid: Road ID as String.
        :param line: Center line of the road as LineString.
        :param left_lanes: Number of left lanes.
        :param right_lanes: Number of right lanes.
        :param width: Total width of the road.
        :param direction: "left" or "right", where to draw the lines..
        :return: Void.
        """
        separators = left_lanes - 1 if direction == "left" else right_lanes - 1
        width_per_lane = width / (left_lanes + right_lanes)
        iterator = 1
        mid = width / 2
        while iterator <= separators:
            position = iterator * width_per_lane if direction == "left" else width - (iterator * width_per_lane)
            offset = mid - position if direction == "left" else position - mid
            nodes = _get_offset_nodes(road_segments, line, offset, direction)
            road = Road(material='line_dashed_short', rid='road_{}_{}_separator_{}'.format(rid, direction,
                                                                                iterator - 1),
                        interpolate=False, texture_length=16, drivability=-1)
            road.nodes.extend(nodes)
            self.scenario.add_road(road)
            iterator += 1

    def _change_object_options(self):
        """Changes several values inside the Prefab file because they can't be set/modified in another way.
        :return: Void.
        """
        prefab_path = join(ENV["BNG_HOME"], "levels", "urban", "scenarios", "urban_{}.prefab".format(self.index))
        prefab_file = open(prefab_path, "r")
        original_content = prefab_file.readlines()
        prefab_file.close()
        new_content = list()
        for line in original_content:
            if "overObjects" in line:
                line = line.replace("0", "1")
                new_content.append("        annotation = \"STREET\";\n")
            if "breakAngle" in line:
                line = "        breakAngle = \"3\";\n"
            if "renderPriority" in line:
                line = ""
            if "distanceFade" in line:
                line = ""
            if "Material" in line:
                if "road_rubber_sticky" in line:
                    new_content.append("        distanceFade = \"1000 1000\";\n")
                    new_content.append("        renderPriority = \"10\";\n")
                else:
                    new_content.append("        distanceFade = \"0 0\";\n")
                    new_content.append("        renderPriority = \"9\";\n")
            new_content.append(line)
        prefab_file = open(prefab_path, "w")
        prefab_file.writelines(new_content)
        prefab_file.close()

    def _add_obstacles(self):
        """Adds obstacles to the Prefab file.
        :return: Void.
        """

        def calc_coords_after_rot(coords, ref_coords, my_rot_matrix):
            """Calculates the coordinates of objects after rotation, e.g. traffic lights are attached on a horizontal
             pole and the lights have a different position dependent on the rotation of the vertical pole.
            :param coords: Coordinates of the object when rotation is zero.
            :param ref_coords: Position of the rotation origin.
            :param my_rot_matrix: Rotation matrix, e.g. by calling calc_coords_after_rot() method.
            :return: Coordinates after rotation.
            """
            coords = dot(my_rot_matrix, coords)
            coords = (coords[0] + ref_coords[0], coords[1] + ref_coords[1], coords[2] + ref_coords[2])
            return coords

        def add_sign_to_traffic_light(my_sign):
            """Attaches a traffic sign on the pole of a traffic light and adds it to the Prefab file.
            :param my_sign: Sign to attach as String.
            :return: Void.
            """
            sign_name = my_sign + "_traffic_light_" + str(id_number)
            my_shape = '/levels/urban/art/objects/' + my_sign + '_without_pole.dae'
            sign_coords = (0, 0.12, 0.66)
            my_rot = (float(x_rot), float(y_rot), -float(z_rot) + 90)
            my_rot_matrix = _calc_rot_matrix(radians(rot[0]), radians(rot[1]), radians(rot[2]))
            sign_coords = calc_coords_after_rot(sign_coords, pole_coords, my_rot_matrix)
            my_sign = StaticObject(name=sign_name, pos=sign_coords, rot=my_rot, scale=(1.7, 1.7, 1.7), shape=my_shape)
            self.scenario.add_object(my_sign)

        obstacles = self.dbe_root.find("obstacles")
        if obstacles is None:
            obstacles = list()
        id_number = 0   # Unique ID of the obstacle.
        first_golf = True
        for obstacle in obstacles:
            obstacle_attr = obstacle.attrib
            z = 0 if obstacle_attr.get("z") is None else obstacle_attr.get("z")
            x_rot = 0 if obstacle_attr.get("xRot") is None else obstacle_attr.get("xRot")
            y_rot = 0 if obstacle_attr.get("yRot") is None else obstacle_attr.get("yRot")
            z_rot = 0 if obstacle_attr.get("zRot") is None else obstacle_attr.get("zRot")
            assert obstacle_attr.get("x") is not None, "x Value for a {} object is None.".format(obstacle.tag)
            assert obstacle_attr.get("y") is not None, "y Value for a {} object is None.".format(obstacle.tag)
            pos = (float(obstacle_attr.get("x")), float(obstacle_attr.get("y")), float(z))
            rot = (float(x_rot), float(y_rot), float(z_rot))
            sign = obstacle_attr.get("sign")
            mode = obstacle_attr.get("mode")
            oid = obstacle_attr.get("oid")      # Unique traffic light ID.
            if obstacle.tag == "stopsign":
                rot = (rot[0], rot[1], 90 - rot[2])
                name_sign = "stopsign_" + str(id_number)
                stopsign = StaticObject(pos=pos, rot=rot, name=name_sign,
                                        scale=(1.9, 1.9, 1.9), shape='/levels/urban/art/objects/stopsign.dae')
                self.scenario.add_object(stopsign)
            elif obstacle.tag == "prioritysign":
                rot = (rot[0], rot[1], 90 - rot[2])
                name_sign = "prioritysign_" + str(id_number)
                prioritysign = StaticObject(pos=pos, rot=rot, name=name_sign,
                                            scale=(1.2, 1.2, 1.2), shape='/levels/urban/art/objects/priority.dae')
                self.scenario.add_object(prioritysign)
            elif obstacle.tag == "parkedCar":
                rot = (rot[0], rot[1], 90 - rot[2])
                name_car = "Golf_" + str(id_number)
                golf = StaticObject(pos=pos, rot=rot, name=name_car,
                                    scale=(1.2, 1.2, 1.2), shape='/vehicles/87Golf/87Golf.dae')
                self.scenario.add_object(golf)
                if first_golf:
                    # Set the color of all cars to first one by overwriting the color properties of materials.cs.
                    color = findall("\d+\.\d+", obstacle_attr.get("color"))
                    materials_path = join(ENV['BNG_HOME'], "levels", "urban", "art", "objects", "materials.cs")
                    materials = open(materials_path, "r")
                    original_content = materials.readlines()
                    materials.close()
                    for idx, line in enumerate(original_content):
                        if "Player-Generated Color" in line:
                            original_content[idx + 1] = "   diffuseColor[2] = \"{} {} {} {}\";\n" \
                                .format(color[0], color[1], color[2], color[3])
                    first_golf = False
                    materials = open(materials_path, "w")
                    materials.writelines(original_content)
                    materials.close()
            elif obstacle.tag == "trafficlightsingle":
                name_light = "trafficlightsingle_" + str(id_number)
                name_pole = "polesingle_" + str(id_number)
                rot = (rot[0], rot[1], -rot[2] - 90)
                rad_x = radians(rot[0])
                rad_y = radians(rot[1])
                rad_z = radians(rot[2])
                pole_coords = (pos[0], pos[1], pos[2])
                rot_matrix = _calc_rot_matrix(rad_x, rad_y, rad_z)
                traffic_light_coords = (0, 0, 4.62)  # x y z coordinates when pole is placed at (0,0,0).
                traffic_light_coords = dot(rot_matrix, traffic_light_coords)
                traffic_light_coords = (
                    traffic_light_coords[0] + pole_coords[0], traffic_light_coords[1] + pole_coords[1],
                    traffic_light_coords[2] + pole_coords[2])
                if mode is not None and mode == "flashing":
                    self._add_flashing_traffic_lights(traffic_light_coords)
                if mode is not None and mode == "manual":
                    self._add_traffic_lights(traffic_light_coords, oid, 0)
                if mode is not None and mode == "off":
                    shape = '/levels/urban/art/objects/trafficlight1a_off.dae'
                else:
                    shape = '/levels/urban/art/objects/trafficlight1a.dae'
                traffic_light = StaticObject(name=name_light, pos=traffic_light_coords, rot=rot, scale=(1, 1, 1),
                                             shape=shape)
                self.scenario.add_object(traffic_light)
                pole = StaticObject(name=name_pole, pos=pole_coords, rot=rot, scale=(1, 1, 1.1),
                                    shape='/levels/urban/art/objects/pole_traffic1.dae')
                self.scenario.add_object(pole)
                add_sign_to_traffic_light(sign)
            elif obstacle.tag == "trafficlightdouble":
                rot = (rot[0], rot[1], -(rot[2] + 90))
                name_light1 = "trafficlightdouble" + str(id_number)
                name_light2 = "trafficlightdouble" + str(id_number) + 'a'
                name_pole = "poledouble" + str(id_number)
                rad_x = radians(rot[0])
                rad_y = radians(rot[1])
                rad_z = radians(rot[2])
                pole_coords = (pos[0], pos[1], pos[2])
                traffic_light1_coords = (5.7, 0.17, 5.9)  # x y z coordinates when pole is placed at (0,0,0)
                traffic_light2_coords = (2.1, 0.17, 5.5)
                rot_matrix = _calc_rot_matrix(rad_x, rad_y, rad_z)
                traffic_light1_coords = calc_coords_after_rot(traffic_light1_coords, pole_coords, rot_matrix)
                traffic_light2_coords = calc_coords_after_rot(traffic_light2_coords, pole_coords, rot_matrix)
                if mode is not None and (mode == "flashing" or mode == "manual"):
                    rot_matrix = _calc_rot_matrix(rad_x, rad_y, radians(-float(z_rot)))
                    light_pos_1 = (-0.25, 2.09, 5.48)
                    light_pos_2 = (-0.25, 5.72, 5.89)
                    light_pos_1 = calc_coords_after_rot(light_pos_1, pole_coords, rot_matrix)
                    light_pos_2 = calc_coords_after_rot(light_pos_2, pole_coords, rot_matrix)
                    if mode == "flashing":
                        self._add_flashing_traffic_lights(light_pos_1)
                        self._add_flashing_traffic_lights(light_pos_2)
                    else:
                        self._add_traffic_lights(light_pos_1, oid, 0)
                        self._add_traffic_lights(light_pos_2, oid, 1)
                if mode is not None and mode == "off":
                    shape = '/levels/urban/art/objects/trafficlight2a_off.dae'
                else:
                    shape = '/levels/urban/art/objects/trafficlight2a.dae'
                pole = StaticObject(name=name_pole, pos=pole_coords, rot=rot, scale=(0.75, 0.75, 0.75),
                                    shape='/levels/urban/art/objects/pole_light_signal1.dae')
                self.scenario.add_object(pole)
                traffic_light1 = StaticObject(name=name_light1, pos=traffic_light1_coords, rot=rot, scale=(1, 1, 1),
                                              shape=shape)
                self.scenario.add_object(traffic_light1)
                traffic_lights2 = StaticObject(name=name_light2, pos=traffic_light2_coords, rot=rot, scale=(1, 1, 1),
                                               shape=shape)
                self.scenario.add_object(traffic_lights2)
                add_sign_to_traffic_light(sign)
            else:
                raise NotImplementedError("Error. Object type \"{}\" is not supported.".format(obstacle.tag))
            id_number += 1

    def _add_flashing_traffic_lights(self, pos):
        """Adds flashing behaviour to the traffic light.
        :param pos: Position of the traffic light (not the pole!).
        :return: Void.
        """
        light = "   new PointLight(traffic_flashing_" + str(self.light_index) + "){\n" \
                "       radius = \"0.300000012\";\n" \
                "       isEnabled = \"1\";\n" \
                "       color = \"1 0.662744999 0 2\";\n" \
                "       brightness = \"10\";\n" \
                "       castShadows = \"0\";\n" \
                "       priority = \"1\";\n" \
                "       animate = \"0\";\n" \
                "       animationPeriod = \"1\";\n" \
                "       animationPhase = \"1\";\n" \
                "       flareType = \"BNG_Sunflare_2\";\n" \
                "       flareScale = \"0.400000006\";\n" \
                "       attenuationRatio = \"0 1 1\";\n" \
                "       shadowType = \"DualParaboloidSinglePass\";\n" \
                "       texSize = \"512\";\n" \
                "       overDarkFactor = \"2000 1000 500 100\";\n" \
                "       shadowDistance = \"400\";\n" \
                "       shadowSoftness = \"0.150000006\";\n" \
                "       numSplits = \"1\";\n" \
                "       logWeight = \"0.910000026\";\n" \
                "       fadeStartDistance = \"0\";\n" \
                "       lastSplitTerrainOnly = \"0\";\n" \
                "       representedInLightmap = \"0\";\n" \
                "       shadowDarkenColor = \"0 0 0 -1\";\n" \
                "       includeLightmappedGeometryInShadow = \"0\";\n" \
                "       position = \"" + str(pos[0]) + " " + str(pos[1]) + " " + str(pos[2]) + "\";\n" \
                "       rotationMatrix = \"1 0 0 0 0.999999762 -0.000690533896 0 0.000690533896 0.999999762\";\n" \
                "       mode = \"Ignore\";\n" \
                "       canSave = \"1\";\n" \
                "       canSaveDynamicFields = \"1\";\n" \
                "   };\n"
        self.light_content.append(light)
        self.lights.append({"id": "traffic_flashing_{}".format(self.light_index),
                            "position": (pos[0], pos[1], pos[2])})
        self.light_index += 1

    def _add_traffic_lights(self, pos, oid, index):
        """Adds traffic lights and their light objects to the prefab file. Z-position is -33 to make it invisible at
         simulation start.
        :param pos: Position of the traffic light (not the pole!).
        :param oid: Object ID as String.
        :param index: Unique ID as Integer.
        :return: Void.
        """
        green = "   new PointLight(" + oid + "_green_" + str(index) + "){\n" \
                "       radius = \"0.300000012\";\n" \
                "       isEnabled = \"1\";\n" \
                "       color = \"0 0.852744999 0 2\";\n" \
                "       brightness = \"10\";\n" \
                "       castShadows = \"0\";\n" \
                "       priority = \"1\";\n" \
                "       animate = \"0\";\n" \
                "       animationPeriod = \"1\";\n" \
                "       animationPhase = \"1\";\n" \
                "       flareType = \"BNG_Sunflare_2\";\n" \
                "       flareScale = \"0.400000006\";\n" \
                "       attenuationRatio = \"0 1 1\";\n" \
                "       shadowType = \"DualParaboloidSinglePass\";\n" \
                "       texSize = \"512\";\n" \
                "       overDarkFactor = \"2000 1000 500 100\";\n" \
                "       shadowDistance = \"400\";\n" \
                "       shadowSoftness = \"0.150000006\";\n" \
                "       numSplits = \"1\";\n" \
                "       logWeight = \"0.910000026\";\n" \
                "       fadeStartDistance = \"0\";\n" \
                "       lastSplitTerrainOnly = \"0\";\n" \
                "       representedInLightmap = \"0\";\n" \
                "       shadowDarkenColor = \"0 0 0 -1\";\n" \
                "       includeLightmappedGeometryInShadow = \"0\";\n" \
                "       position = \"" + str(pos[0]) + " " + str(pos[1]) + " " + str(-33) + "\";\n" \
                "       rotationMatrix = \"1 0 0 0 0.999999762 -0.000690533896 0 0.000690533896 0.999999762\";\n" \
                "       mode = \"Ignore\";\n" \
                "       canSave = \"1\";\n" \
                "       canSaveDynamicFields = \"1\";\n" \
                "   };\n"
        yellow = "   new PointLight(" + oid + "_yellow_" + str(index) + "){\n" \
                 "       radius = \"0.300000012\";\n" \
                 "       isEnabled = \"1\";\n" \
                 "       color = \"1 0.662744999 0 2\";\n" \
                 "       brightness = \"10\";\n" \
                 "       castShadows = \"0\";\n" \
                 "       priority = \"1\";\n" \
                 "       animate = \"0\";\n" \
                 "       animationPeriod = \"1\";\n" \
                 "       animationPhase = \"1\";\n" \
                 "       flareType = \"BNG_Sunflare_2\";\n" \
                 "       flareScale = \"0.400000006\";\n" \
                 "       attenuationRatio = \"0 1 1\";\n" \
                 "       shadowType = \"DualParaboloidSinglePass\";\n" \
                 "       texSize = \"512\";\n" \
                 "       overDarkFactor = \"2000 1000 500 100\";\n" \
                 "       shadowDistance = \"400\";\n" \
                 "       shadowSoftness = \"0.150000006\";\n" \
                 "       numSplits = \"1\";\n" \
                 "       logWeight = \"0.910000026\";\n" \
                 "       fadeStartDistance = \"0\";\n" \
                 "       lastSplitTerrainOnly = \"0\";\n" \
                 "       representedInLightmap = \"0\";\n" \
                 "       shadowDarkenColor = \"0 0 0 -1\";\n" \
                 "       includeLightmappedGeometryInShadow = \"0\";\n" \
                 "       position = \"" + str(pos[0]) + " " + str(pos[1]) + " " + str(-33) + "\";\n" \
                 "       rotationMatrix = \"1 0 0 0 0.999999762 -0.000690533896 0 0.000690533896 0.999999762\";\n" \
                 "       mode = \"Ignore\";\n" \
                 "       canSave = \"1\";\n" \
                 "       canSaveDynamicFields = \"1\";\n" \
                 "   };\n"
        red = "   new PointLight(" + oid + "_red_" + str(index) + "){\n" \
              "       radius = \"0.300000012\";\n" \
              "       isEnabled = \"1\";\n" \
              "       color = \"0.88 0 0 2\";\n" \
              "       brightness = \"10\";\n" \
              "       castShadows = \"0\";\n" \
              "       priority = \"1\";\n" \
              "       animate = \"0\";\n" \
              "       animationPeriod = \"1\";\n" \
              "       animationPhase = \"1\";\n" \
              "       flareType = \"BNG_Sunflare_2\";\n" \
              "       flareScale = \"0.400000006\";\n" \
              "       attenuationRatio = \"0 1 1\";\n" \
              "       shadowType = \"DualParaboloidSinglePass\";\n" \
              "       texSize = \"512\";\n" \
              "       overDarkFactor = \"2000 1000 500 100\";\n" \
              "       shadowDistance = \"400\";\n" \
              "       shadowSoftness = \"0.150000006\";\n" \
              "       numSplits = \"1\";\n" \
              "       logWeight = \"0.910000026\";\n" \
              "       fadeStartDistance = \"0\";\n" \
              "       lastSplitTerrainOnly = \"0\";\n" \
              "       representedInLightmap = \"0\";\n" \
              "       shadowDarkenColor = \"0 0 0 -1\";\n" \
              "       includeLightmappedGeometryInShadow = \"0\";\n" \
              "       position = \"" + str(pos[0]) + " " + str(pos[1]) + " " + str(-33) + "\";\n" \
              "       rotationMatrix = \"1 0 0 0 0.999999762 -0.000690533896 0 0.000690533896 0.999999762\";\n" \
              "       mode = \"Ignore\";\n" \
              "       canSave = \"1\";\n" \
              "       canSaveDynamicFields = \"1\";\n" \
              "   };\n"
        self.light_content.append(green)
        self.light_content.append(yellow)
        self.light_content.append(red)
        self.traffic_lights.append([{"id": oid + "_green_" + str(index), "position": (pos[0], pos[1], pos[2] - 0.5)},
                                    {"id": oid + "_yellow_" + str(index), "position": (pos[0], pos[1], pos[2])},
                                    {"id": oid + "_red_" + str(index), "position": (pos[0], pos[1], pos[2] + 0.5)}])

    def _add_lights_to_prefab(self):
        """Writes traffic light content to the Prefab file.
        :return: Void.
        """
        prefab_path = join(ENV["BNG_HOME"], "levels", "urban", "scenarios", "urban_{}.prefab".format(self.index))
        prefab_file = open(prefab_path, "r")
        original_content = prefab_file.readlines()
        prefab_file.close()
        original_content[-1] = ""
        for light in self.light_content:
            original_content.append(light)
        prefab_file = open(prefab_path, "w")
        prefab_file.writelines(original_content)
        prefab_file.close()

    def _add_participants(self):
        """Writes participant content to the Prefab file.
        :return: Void.
        """
        participants = self.dbc_root.findall("participants/participant")
        for participant in participants:
            attr = participant.attrib
            assert attr.get("id") is not None, "Vehicles needs a ID."
            model = "ETK800" if attr.get("model") is None else attr.get("model")
            color = "White" if attr.get("color") is None else attr.get("color")
            vehicle = Vehicle(attr.get("id"), color=color, model=model)
            init_state = participant.find("initialState")
            x = init_state.get("x")
            y = init_state.get("y")
            assert x is not None and y is not None, "x and y coordinates of traffic participants must be set."
            z = 0 if init_state.get("z") is None else init_state.get("z")
            x_rot = 0 if init_state.get("x_rot") is None else init_state.get("x_rot")
            y_rot = 0 if init_state.get("y_rot") is None else init_state.get("y_rot")
            z_rot = -90 if init_state.get("orientation") is None else -float(init_state.get("orientation")) - 90
            pos = (x, y, z)
            rot = (x_rot, y_rot, z_rot)
            self.scenario.add_vehicle(vehicle=vehicle, pos=pos, rot=rot)

    def _add_waypoints(self):
        """Adds waypoints to the Prefab file.
        :return: Void.
        """
        prefab_path = join(ENV["BNG_HOME"], "levels", "urban", "scenarios", "urban_{}.prefab".format(self.index))
        prefab_file = open(prefab_path, "r")
        original_content = prefab_file.readlines()
        prefab_file.close()
        participants = self.dbc_root.findall("participants/participant")
        for participant in participants:
            waypoints = participant.findall("movement/waypoint")
            if len(waypoints) == 0:
                continue
            lines = list()
            line = list()
            vid = participant.get("id")
            i = 0
            current_index = int(waypoints[0].attrib.get("road"))
            while i < len(waypoints):
                attr = waypoints[i].attrib
                # I'm not using BNG waypoints because participants can't keep lanes and you can't control speed,
                # e.g. forcing cars to stop. I'm calling setAiLine for this purpose.
                """
                z = 0 if attr.get("z") is None else attr.get("z")
                original_content.extend([
                    "    new BeamNGWaypoint(wp_{}_{}){{\n".format(vid, i),
                    "        drawDebug = \"0\";\n",
                    "        directionalWaypoint = \"0\";\n",
                    "        position = \"" + attr.get("x") + " " + attr.get("y") + " " + str(z) + "\";\n",
                    "        scale = \"" + attr.get("tolerance") + " " + attr.get("tolerance") + " "
                    + attr.get("tolerance") + "\";\n",
                    "        rotationMatrix = \"1 0 0 0 1 0 0 0 1\";\n",
                    "        mode = \"Ignore\";\n",
                    "        canSave = \"1\";\n",
                    "        canSaveDynamicFields = \"1\";\n",
                    "    };\n"
                ])
                """
                if int(attr.get("road")) != current_index:
                    current_index = int(attr.get("road"))
                    lines.append(line)
                    line = list()
                z = 0 if attr.get("z") is None else attr.get("z")
                line.append({"pos": (float(attr.get("x")), float(attr.get("y")), float(z)),
                             'speed': float(attr.get("speed"))})
                if i == len(waypoints) - 1:
                    lines.append(line)
                i += 1
            self.lines.append({"vid": vid, "lines": lines})
        original_content.append("};")
        prefab_file = open(prefab_path, "w")
        prefab_file.writelines(original_content)
        prefab_file.close()

    def _get_on_race_start_line_content(self):
        """Adds content of participants to the onRaceStart method, so when the simulation starts, vehicles starts
         driving.
        :return: List of content for the Prefab file.
        """
        participants = self.dbc_root.findall("participants/participant")
        content = ""
        for participant in participants:
            vid = participant.get("id")
            if vid == "other_0":
                # Exclude participant spawning only at intersections. Needs a better way to check whether cars should
                # drive at simulation start or not.
                continue
            lines = None
            for entry in self.lines:
                if entry.get("vid") == vid:
                    lines = entry.get("lines")
                    break
            if lines is None:
                continue
            content += '  vehicleName = \'' + vid + '\'\n'\
                       '  arg = {line = {\n                 '
            i = 0
            while i < len(lines[0]):
                pos = lines[0][i].get("pos")
                speed = lines[0][i].get("speed")
                content += "{pos = {" + str(pos[0]) + ", " + str(pos[1]) + ", " + str(pos[2]) + "}, speed = " \
                           + str(speed) + "}"
                if i + 1 == len(lines[0]):
                    content += "\n                }"
                else:
                    content += ", \n                 "
                i += 1
            content += '}\n'\
                       '  sh.setAiLine(vehicleName, arg)\n'
        return content

    def _write_lua_file(self):
        """Creates a Lua file for traffic light switches and makes participants drive a certain route with at a certain
         speed.
        :return: Void.
        """
        triggers = self.dbc_root.find("triggerPoints")
        if triggers is None:
            triggers = list()
        trigger_content = ""
        trigger_list = list()
        trigger_points = list()
        spawn_points = list()
        teleport_triggers = list()
        traffic_triggers = list()
        stop_triggers = list()
        for trigger in triggers:
            if trigger.attrib.get("action") == "spawnAndStart":
                teleport_triggers.append(trigger)
            elif trigger.attrib.get("action") == "switchLights":
                traffic_triggers.append(trigger.attrib)
            elif trigger.attrib.get("action") == "stop":
                stop_triggers.append(trigger.attrib)
        for idx, trigger in enumerate(teleport_triggers):
            # Adds trigger points for spawning participants. trigger_idx is the position of the trigger point,
            # triggered_teleport_idx is a flag whether the trigger point was entered or not.
            spawn_point = trigger.find("spawnPoint").attrib
            spawn_points.append(spawn_point)
            trigger_point = trigger.attrib
            trigger_points.append(trigger_point)
            z = 0 if trigger_point.get("z") is None else trigger_point.get("z")
            trigger_content += "local trigger_" + str(idx) + " = Point3F(" + str(trigger_point.get("x")) + ", " \
                               + str(trigger_point.get("y")) + ", " + str(z) + ")\n" \
                               "local triggered_teleport_" + str(idx) + " = 0\n"
            trigger_list.append("trigger_" + str(idx))

        for idx, trigger in enumerate(stop_triggers):
            # Adds trigger points to stop participants. ego_time is the current duration of standing, triggered_stop is
            # a flag whether the trigger point was entered or not, trigger_stop is the position of the trigger point.
            z = 0 if trigger.get("z") is None else trigger.get("z")
            trigger_content += "local ego_time_" + str(idx) + " = 0\n" \
                               "local triggered_stop_" + str(idx) + " = 0\n" \
                               "local trigger_stop_" + str(idx) + " = Point3F(" + str(trigger.get("x")) + ", " \
                               + str(trigger.get("y")) + ", " + str(z) + ")\n"

        for idx, trigger in enumerate(traffic_triggers):
            # Adds trigger points for traffic light switching. trigger_traffic_idx is the position of the trigger
            # point, triggered_traffic_idx is a flag whether the trigger point was entered, traffic time_idx is a time
            # variable which starts counting when the trigger point was entered, yellow_triggered_idx is a flag whether
            # the yellow light is visible or not.
            z = 0 if trigger.get("z") is None else trigger.get("z")
            trigger_content += "local trigger_traffic_" + str(idx) + " = Point3F(" + str(trigger.get("x")) + ", " \
                               + str(trigger.get("y")) + ", " + str(z) + ")\n" \
                               "local triggered_traffic_" + str(idx) + " = 0\n" \
                               "local traffic_time_" + str(idx) + " = 0\n" \
                               "local yellow_triggered_" + str(idx) + " = 0\n"

        # points_1 is the list with invisible points, points_2 is the list with visible points, for traffic lights.
        content = "local M = {}\n" \
                  "local points_1 = {}\n" \
                  "local points_2 = {}\n" \
                  "local time = 0\n" \
                  "local sh = require(\'ge/extensions/scenario/scenariohelper\')\n" \
                  "local ego = nil\n" \

        for idx, trigger in enumerate(self.traffic_lights):
            for idx_1, light in enumerate(trigger):
                # Add light bulb objects to the points lists.
                pos = light.get("position")
                content += "local " + light.get("id") + " = nil\n" \
                           "points_1[" + str(3 * idx + idx_1 + 1) + "] = Point3F(" + str(pos[0]) + ", " \
                           + str(pos[1]) + ", -33)\n"\
                           "points_2[" + str(3 * idx + idx_1 + 1) + "] = Point3F(" + str(pos[0]) + ", " \
                           + str(pos[1]) + ", " + str(pos[2]) + ")\n"

        content += "\nlocal function onRaceStart()\n" \
                   "  ego = scenetree.findObject(\"ego\")\n" \
                   "  local vehicleName = nil\n" \
                   "  local arg = nil\n" \
                   + self._get_on_race_start_line_content()

        for idx, trigger in enumerate(self.traffic_lights):
            for idx_1, light in enumerate(trigger):
                # Find all point light objects (the traffic light bulbs).
                content += "  " + light.get("id") + " = scenetree.findObject(\"" + light.get("id") + "\")\n"

        for light_trigger in traffic_triggers:
            for idx, light in enumerate(self.traffic_lights):
                # Initialize traffic lights on simulation start.
                if light[0].get("id").startswith(light_trigger.get("triggers")):
                    init_state = light_trigger.get("initState")
                    i = 0 if init_state == "green" else 2
                    content += "  " + light[i].get("id") + ":setPosition(points_2[" + str(3 * idx + i + 1) + "])\n"

        content += "end\n\n"
        content += trigger_content

        # Function which gets executed every 250ms.
        content += "\nlocal function onRaceTick(raceTickTime)\n" \
                   "  time = time + raceTickTime\n" \
                   "  local pos = ego:getPosition()\n"
        line_index = 0
        prev_vehicle = ""
        for idx, trigger_point in enumerate(trigger_list):
            # Add trigger points for spawning and starting participants to drive.
            spawn_point = spawn_points[idx]
            z = 0 if spawn_point.get("z") is None else spawn_point.get("z")
            z_rot_spawn = -90 if spawn_point.get("orientation") is None \
                else -float(spawn_point.get("orientation")) - 90
            vehicle_name = trigger_points[idx].get("triggers")

            lines = None
            for entry in self.lines:
                if entry.get("vid") == vehicle_name:
                    lines = entry.get("lines")
                    break
            assert lines is not None, "Missing line of vehicle \"" + vehicle_name + "\"."
            if vehicle_name != prev_vehicle:
                prev_vehicle = vehicle_name
                line_index = 0

            lines = lines[line_index]
            if vehicle_name == prev_vehicle:
                line_index += 1
            line_content = '    local arg = {line = {\n                 '
            i = 0
            while i < len(lines):
                pos = lines[i].get("pos")
                speed = lines[i].get("speed")
                line_content += "{pos = {" + str(pos[0]) + ", " + str(pos[1]) + ", " + str(pos[2]) + "}, speed = " \
                                + str(speed) + "}"
                if i + 1 == len(lines):
                    line_content += "\n                }"
                else:
                    line_content += ", \n                 "
                i += 1
            line_content += '}\n' \
                            '    sh.setAiLine(vehicleName, arg)\n'

            content += "  if math.sqrt((" + trigger_point + ".x - pos.x) ^ 2 + (" \
                       + trigger_point + ".y - pos.y) ^ 2) <= " + str(float(trigger_points[idx].get("tolerance"))*4) \
                       + " and triggered_teleport_" + str(idx) + " == 0 then\n" \
                       "    triggered_teleport_" + str(idx) + " = 1\n" \
                       "    local vehicleName = \"" + vehicle_name + "\"\n" \
                       "    TorqueScript.eval(vehicleName..\'.position = \"" + spawn_point.get("x") + " " \
                       + spawn_point.get("y") + " " + str(z) + "\";\')\n" \
                       "    TorqueScript.eval(vehicleName..\'.rotation = \"0 0 01 " + str(z_rot_spawn) + "\";\')\n"
            content += line_content
            content += "  end\n\n"

        lines = list()
        for entry in self.lines:
            if entry.get("vid") == "ego":
                lines = entry.get("lines")
                break
        if len(lines) != 0:
            for idx, trigger in enumerate(stop_triggers):
                # Adds triggers to stop the ego car.
                content += "  if math.sqrt((trigger_stop_" + str(idx) + ".x - pos.x) ^ 2 + (trigger_stop_" + str(idx) \
                           + ".y - pos.y) ^ 2) <= " + str(float(trigger.get("tolerance"))*4) \
                           + " and triggered_stop_" + str(idx) + " == 0 then\n" \
                           "    triggered_stop_" + str(idx) + " = 1\n" \
                           "  end\n" \
                           "  if triggered_stop_" + str(idx) + " == 1 then\n" \
                           "    ego_time_" + str(idx) + " = ego_time_" + str(idx) + " + raceTickTime\n" \
                           "  end\n"
                content += '    if ego_time_' + str(idx) + ' == 7 then\n' \
                           '      local vehicleName = \"ego\"\n'\
                           '      local arg = {line = {\n                 '
                i = 0
                while idx + 1 < len(lines) and i < len(lines[idx+1]):
                    pos = lines[idx+1][i].get("pos")
                    speed = lines[idx+1][i].get("speed")
                    content += "{pos = {" + str(pos[0]) + ", " + str(pos[1]) + ", " + str(pos[2]) + "}, speed = " \
                               + str(speed) + "}"
                    if i + 1 == len(lines[idx+1]):
                        content += "\n                  }"
                    else:
                        content += ", \n                   "
                    i += 1
                content += '}\n' \
                           '      sh.setAiLine(vehicleName, arg)\n' \
                           '    end\n'

        for idx, light in enumerate(self.lights):
            # Position of visible and invisible point lights (traffic light bulbs).
            pos = light.get("position")
            content += "  local light_" + str(idx) + " = scenetree.findObject(\"" + light.get("id") + "\")\n" \
                       "  local p1_" + str(idx) + " = Point3F(" + str(pos[0]) + ", " + str(pos[1]) + ", -33)\n" \
                       "  local p2_" + str(idx) + " = Point3F(" + str(pos[0]) + ", " + str(pos[1]) \
                       + ", " + str(pos[2]) + ")\n"

        # Add flashing behaviour to traffic light mode "flashing". The yellow light gets teleported each second.
        if len(self.lights) != 0:
            content += "  if time == math.floor(time) then\n" \
                       "    if time % 2 == 0 then\n"
            for idx, light in enumerate(self.lights):
                content += "      light_" + str(idx) + ":setPosition(p1_" + str(idx) + ")\n"
            content += "    else\n"
            for idx, light in enumerate(self.lights):
                content += "      light_" + str(idx) + ":setPosition(p2_" + str(idx) + ")\n"
            content += "    end\n" \
                       "  end\n"

        # Adds behaviour for the traffic lights.
        for idx, trigger in enumerate(traffic_triggers):
            # Adds the condition to the LUA file as well as the flag that this condition was once entered.
            init_state = trigger.get("initState")
            multiplicator = 5 if init_state == "green" else 9
            content += "  if math.sqrt((trigger_traffic_" + str(idx) + ".x - pos.x) ^ 2 + (" \
                       + "trigger_traffic_" + str(idx) + ".y - pos.y) ^ 2) <= " \
                       + str(float(trigger.get("tolerance"))*multiplicator) \
                       + " and triggered_traffic_" + str(idx) + " == 0 then\n" \
                         "    triggered_traffic_" + str(idx) + " = 1\n"

            # Tells which light should be switched on and which should disappear when the car enters the trigger point.
            for idx_1, traffic_light in enumerate(self.traffic_lights):
                if traffic_light[0].get("id").startswith(trigger.get("triggers")):
                    if init_state == "green":
                        new = 0 if init_state == "red" else 2
                        content += "    " + traffic_light[1].get("id") + ":setPosition(points_1[" \
                                   + str(3 * idx_1 + 2) + "])\n"
                        content += "    " + traffic_light[new].get("id") + ":setPosition(points_2[" \
                                   + str(3 * idx_1 + new + 1) + "])\n"
                    else:
                        content += "    " + traffic_light[1].get("id") + ":setPosition(points_2[" \
                                   + str(3 * idx_1 + 2) + "])\n"

            content += "  end\n" \
                       "  if triggered_traffic_" + str(idx) + " == 1 then\n" \
                       "    traffic_time_" + str(idx) + " = traffic_time_" + str(idx) \
                       + " + raceTickTime\n" \
                       "  end\n" \
                       "  if traffic_time_" + str(idx) + " == 8 then\n"

            for idx_1, traffic_light in enumerate(self.traffic_lights):
                old = 0 if init_state == "green" else 2
                new = 0 if old == 2 else 2
                if traffic_light[0].get("id").startswith(trigger.get("triggers")):
                    content += "    " + traffic_light[new].get("id") + ":setPosition(points_1[" \
                               + str(3 * idx_1 + new + 1) + "])\n"
                    content += "    " + traffic_light[old].get("id") + ":setPosition(points_2[" \
                               + str(3 * idx_1 + old + 1) + "])\n"
            content += "  end\n"

            # Make green light visible and red/yellow light invisible after one second.
            if init_state == "red":
                for idx_1, traffic_light in enumerate(self.traffic_lights):
                    if traffic_light[0].get("id").startswith(trigger.get("triggers")):
                        content += "  if traffic_time_" + str(idx) + " == 1.5 then\n" \
                                   "    " + traffic_light[1].get("id") + ":setPosition(points_1[" \
                                   + str(3 * idx_1 + 2) + "])\n" \
                                   "    " + traffic_light[2].get("id") + ":setPosition(points_1[" \
                                   + str(3 * idx_1 + 3) + "])\n" \
                                   "    " + traffic_light[0].get("id") + ":setPosition(points_2[" \
                                   + str(3 * idx_1 + 1) + "])\n" \
                                   + "  end\n"

            if init_state != "red":
                content += "  if traffic_time_" + str(idx) + " == 7 then\n"
                for idx_1, traffic_light in enumerate(self.traffic_lights):
                    if traffic_light[0].get("id").startswith(trigger.get("triggers")):
                        content += "    " + traffic_light[1].get("id") + ":setPosition(points_2[" \
                                   + str(3 * idx_1 + 2) + "])\n"
                content += "  end\n"
                content += "  if traffic_time_" + str(idx) + " == 8 then\n"
                for idx_1, traffic_light in enumerate(self.traffic_lights):
                    if traffic_light[0].get("id").startswith(trigger.get("triggers")):
                        content += "    " + traffic_light[1].get("id") + ":setPosition(points_1[" \
                                   + str(3 * idx_1 + 2) + "])\n"
                content += "  end\n"

            content += "  if math.sqrt((trigger_traffic_" + str(idx) + ".x - pos.x) ^ 2 + (" \
                       + "trigger_traffic_" + str(idx) + ".y - pos.y) ^ 2) <= " \
                       + str(float(trigger.get("tolerance")) * 15) \
                       + " and yellow_triggered_" + str(idx) + " == 0 then\n" \
                       "    yellow_triggered_" + str(idx) + " = 1\n"
            for idx_1, traffic_light in enumerate(self.traffic_lights):
                if traffic_light[0].get("id").startswith(trigger.get("triggers")) and init_state == "green":
                    content += "    " + traffic_light[0].get("id") + ":setPosition(points_1[" \
                               + str(3 * idx_1 + 1) + "])\n"
                    content += "    " + traffic_light[1].get("id") + ":setPosition(points_2[" \
                               + str(3 * idx_1 + 2) + "])\n"
            content += "  end\n"

        content += "end\n\n" \
                   "M.onRaceTick = onRaceTick\n" \
                   "M.onRaceStart = onRaceStart\n" \
                   "return M"
        with open("urban_{}.lua".format(self.index), "w") as lua_file:
            print(content, file=lua_file)


from __future__ import absolute_import

from django.core.urlresolvers import reverse

from sentry.plugins import plugins
from sentry.testutils import APITestCase

class OrganizationPluginsTest(APITestCase):
    def test_exposes_plugins_across_all_org_projects(self):
        projectA = self.create_project()
        projectB = self.create_project(organization=projectA.organization)

        plugins.get('webhooks').enable(projectA)
        plugins.get('mail').enable(projectB)

        self.login_as(user=self.user)

        url = reverse(
            'sentry-api-0-organization-plugins',
            kwargs={'organization_slug': projectA.organization.slug}
        )

        response = self.client.get(url)

        assert response.status_code == 200, \
            (response.status_code, response.content)

        enabled_plugins = [
            (p['project']['id'], p['slug']) for p in
            filter(lambda p: p['enabled'], response.data)
        ]

        assert (projectA.id, 'webhooks') in enabled_plugins
        assert (projectB.id, 'mail') in enabled_plugins


from flask import Flask, request, abort
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import *
import urllib.request as req
import bs4
import urllib.parse

app = Flask(__name__)

line_bot_api = LineBotApi('LqpT9ZRYCkihkthoMOE9EroQxrHkLzMd1akokISMcotRbwudTnKI+RzOAGjL61pD6CqXS3JoDU+CL+Eh4Vgh3/gZyWK6RXvAbYLJ/xwawqT7pNoOH2+C7ZZpDK6St+s9awNIBaI4dwEVezNOS70DqQdB04t89/1O/w1cDnyilFU=')
handler = WebhookHandler('3cffb42cd89f2d190379032174907bfb')

@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)
    return 'OK'

# @handler.add(MessageEvent, message=TextMessage)
# def handle_message(event):
#     if isinstance(event, MessageEvent):  # 如果有訊息事件
#         if event.message.text in ['桃園市', '桃園', '桃園縣',
#                                   'Taoyuan', 'taoyuan', 'Taoyuan City']:
#             area = "桃園市"
#         elif event.message.text in ['台北市', '台北', '臺北市', '臺北',
#                                     'Taipei', 'taipei', 'Taipei City']:
#             area = "台北市"
#         elif event.message.text in ['新北市', '新北']:
#             area = "新北市"
#         elif event.message.text in ['新竹市', '新竹', 'Hsinchu', 'hsinchu']:
#             area = "新竹市"
#         elif event.message.text in ['新竹縣']:
#             area = "新竹縣"
#         elif event.message.text in ['台中市', '台中', '臺中市', '臺中']:
#             area = "台中市"
#         elif event.message.text in ['台南市', '台南', '臺南市', '臺南']:
#             area = "台南市"
#         elif event.message.text in ['台東線', '台東', '臺東市', '臺東']:
#             area = "台東縣"
#         elif event.message.text in ['高雄市', '高雄']:
#             area = "高雄市"
#         elif event.message.text in ['基隆市', '基隆']:
#             area = "基隆市"
#         elif event.message.text in ['宜蘭縣', '宜蘭']:
#             area = "宜蘭縣"
#         elif event.message.text in ['苗栗縣', '苗栗']:
#             area = "苗栗縣"
#         elif event.message.text in ['彰化縣', '彰化']:
#             area = "彰化縣"
#         elif event.message.text in ['嘉義縣', '嘉義']:
#             area = "嘉義縣"
#         elif event.message.text in ['雲林縣', '雲林']:
#             area = "雲林縣"
#         elif event.message.text in ['嘉義市', '嘉義']:
#             area = "嘉義市"
#         elif event.message.text in ['屏東縣', '屏東']:
#             area = "屏東縣"
#         elif event.message.text in ['花蓮縣', '花蓮']:
#             area = "花蓮縣"
#         elif event.message.text in ['南投縣', '南投']:
#             area = "南投縣"
#         elif event.message.text in ['澎湖縣', '澎湖']:
#             area = "澎湖縣"
#         elif event.message.text in ['金門縣', '金門']:
#             area = "金門縣"
#         else:
#             line_bot_api.reply_message(
#                 event.reply_token,
#                 TextSendMessage(text="請輸入台灣縣市名稱，我才能推薦餐廳給你!"))
#         area = urllib.parse.quote(area)
#         url = "https://ifoodie.tw/explore/" + area + "/list?sortby=popular&opening=true"
#         # 建立request物件，附加headers資訊
#         requests = req.Request(url, headers={
#             "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N)"
#                           " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/"
#                           "91.0.4472.124 Mobile Safari/537.36 Edg/91.0.864.67"
#         })
#         with req.urlopen(requests) as response:
#             data = response.read().decode("utf-8")
#         root = bs4.BeautifulSoup(data, "html.parser")
#
#         # 爬取前五筆餐廳卡片資料
#         cards = root.find_all("div", class_="jsx-3757653001 info-rows", limit=5)
#
#         content = ""
#         for card in cards:
#             name = card.find("a", class_="jsx-3757653001 title-text").getText()  # 餐廳名稱
#             rate = card.find("div", class_="jsx-1207467136 text").getText()  # 餐廳評價
#             address = card.find("div", class_="jsx-3757653001 address-row").getText()  # 餐廳地址
#             content += f"{name} \n{rate}顆星 \n{address} \n\n"
#             # 將取得的餐廳名稱、評價及地址連結一起，並且指派給content變數
#
#         line_bot_api.reply_message(
#             event.reply_token,
#             TextSendMessage(text=content))

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    TextSendMessage(text='分享地址讓我們為你推薦餐廳！',
                    quick_reply=QuickReply(items=[
                       QuickReplyButton(action=LocationAction(label="label", text="分享地點")),
                        QuickReplyButton(action=MessageAction(label="label", text="test"))
                   ]))
    # work as the user submit the location message
    if isinstance(event, MessageEvent):
        if event.message.type =="location":
            latitude = event.message.latitude
            longitude = event.message.lontitude
            content = latitude + longitude
            TextMessage(text=content)
        else:
            TextMessage(text="請輸入地址")

if __name__ == "__main__":
    app.run()


import numpy as np
import time

def euclidean_distance(x1, x2):
    return np.sqrt(np.sum((x1-x2)**2))

def mean_shift(X, radius):
    # Inizializzazione dei centroidi
    centroids = X.copy()
    # Numero di dati di input
    m = X.shape[0]
    # Lista per tenere traccia delle etichette di clustering
    labels = np.zeros(m)
    # Ciclo fino alla convergenza dei centroidi
    while True:
        # Lista per tenere traccia dei nuovi centroidi
        new_centroids = []
        # Ciclo su tutti i centroidi attuali
        for i, centroid in enumerate(centroids):
            # Lista per tenere traccia dei punti all'interno del raggio di banda
            within_radius = []
            # Ciclo su tutti i dati di input
            for j, point in enumerate(X):
                # Calcola la distanza euclidea tra il punto e il centroide
                distance = euclidean_distance(point, centroid)
                # Se il punto e' all'interno del raggio di banda, aggiungilo alla lista within_radius
                if distance <= radius:
                    within_radius.append(j)
            # Calcola il nuovo centroide come la media dei punti all'interno del raggio di banda
            if within_radius:
                new_centroid = np.mean(X[within_radius], axis=0)
                new_centroids.append(new_centroid)
            else:
                new_centroids.append(centroid)
        # Convergenza raggiunta se i centroidi non cambiano
        if np.allclose(np.array(new_centroids), np.array(centroids)):
            break
        centroids = new_centroids.copy()
    # Assegna un'etichetta di clustering a ciascun dato di input in base al centroide piu' vicino
    for i, point in enumerate(X):
        distances = [euclidean_distance(point, centroid) for centroid in centroids]
        cluster = np.argmin(distances)
        labels[i] = cluster
    return labels, centroids

# Legge file di input
with open("sample_1000.txt", "r") as file:
        # legge l'intera riga dal file
    data  = file.read().split(',')
data = [float(d.strip()) for d in data]

X = np.array(data).reshape(-1,2)

# Inizializzazione del raggio di banda
radius = 0.01

# Calcolo del tempo di esecuzione
start_time = time.time()

# Effettua il clustering
labels, centroids = mean_shift(X, radius)

# Calcolo del tempo di esecuzione
end_time = time.time()
elapsed_time = end_time - start_time

# Stampa i risultati
print("Tempo di elaborazione: ", elapsed_time)


from aeropy.geometry.parametric import poly
from aeropy.structural.stable_solution import (structure, mesh_1D, properties,
                                               boundary_conditions)
from aeropy.xfoil_module import output_reader

from matplotlib.colors import LogNorm
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
from optimization_tools.DOE import DOE
import pickle

def input_function(x):
    return np.array([0,0] + list(x))

np.set_printoptions(precision=5)

# Results from Abaqus
abaqus_data = pickle.load(open('neutral_line.p', 'rb'))

# Beam properties
bp = properties()
bc = boundary_conditions(load=np.array([[0, -1], ]))
EB_solution = bc.concentrated_load[0][1]/(6*bp.young*bp.inertia) * \
    np.array([0, 0, 3, -1])

mesh = mesh_1D(mesh_n=11, alpha=[1, 1],
               alpha_nodes=[0, 1])
curve_parent = poly(a=[0, 0, 0, 0])
curve_child = poly(a=EB_solution)

beam = structure(curve_parent, curve_child, mesh, bp, bc)
beam.calculate_position()
eulerBernoulle = beam.r_c

# DOE setup
n = 10
problem = DOE(levels=n, driver='Full Factorial')
problem.add_variable('a2', lower=-0.010, upper=-0.007, type=float)
problem.add_variable('a3', lower=0.002, upper=.005, type=float)
problem.define_points()

print(problem.domain)
coefficient_matrix = np.array(list(zip(problem.domain['a2'],
                                       problem.domain['a3'])))
# Doe itself
energy, residual = beam.sweep_geometries(coefficient_matrix,
                                         input_function = input_function,
                                         reorder = (n, n))
# Find my optimal
bounds = np.array(((-0.010,0.005),
                  (-0.005,0.005)))
print('Calculating minimum')
sol, fun = beam.find_stable(EB_solution[2:4], bounds=bounds,
                         input_type = 'Geometry',
                         loading_condition='plane_stress',
                         input_function = input_function)

fig = plt.figure()
x = np.resize(coefficient_matrix[:, 0], (n, n))
y = np.resize(coefficient_matrix[:, 1], (n, n))
print('x', x)
print('y', y)
print('residual', residual)
# residual_log = x_log_modulus_transform= np.sign(residual)*(np.log10(np.abs(residual)+1))
plt.contourf(x, y, residual, levels=100)
cbar = plt.colorbar()
cbar.set_label('Residual')
plt.scatter(sol[0], sol[1], marker = 'o', color='white', label='Energy minimum')
plt.scatter(EB_solution[2], EB_solution[3], marker = '^', color='white',
            label='Euler-bernoulli')
plt.xlabel(r'$A_2$')
plt.ylabel(r'$A_3$')

plt.legend()
plt.show()


#!/usr/bin/env python3
#
# This is used to train a recommendation system based on
# collaborative filtering.
import logging
import os.path
from docopt import docopt
import numpy as np
import pandas as pd
import surprise as sp

# Setup logging format.
logging.basicConfig(
    format='%(asctime)s:[%(levelname)s]:%(message)s', level=logging.INFO)

# Default number of n-folded.
NUM_FOLD = 3

usage = """
Usage:
    train_rec.py [options]

Options:
    --data=DIR  The directory contains images [default: ./ml-latest-small/]
"""
if __name__ == '__main__':
    args = docopt(usage, help=True)
    data_dir = args['--data']

    movie_csv_file = os.path.join(data_dir, 'movies.csv')
    rating_csv_file = os.path.join(data_dir, 'ratings.csv')
    rec_model_file = os.path.join(data_dir, 'rec.model')

    # Load movies data. Note that we user empty string for the movies
    # without genres.
    movies = pd.read_csv(movie_csv_file, sep=',')
    movies['genres'] = np.where(movies['genres'] == '(no genres listed)', '',
                                movies['genres'])

    # Load rating data.
    ratings = pd.read_csv(rating_csv_file, sep=',')

    df = ratings.join(
        movies[['movieId', 'title']].set_index('movieId'),
        on='movieId').reset_index()

    logging.info('Begin to read data: {}'.format(movie_csv_file))
    reader = sp.Reader(rating_scale=(1, 5))
    data = sp.Dataset.load_from_df(df[['userId', 'movieId', 'rating']], reader)
    data.split(n_folds=NUM_FOLD)

    sim_options = {
        'name': 'pearson_baseline',
        'user_based': False,
    }
    alg = sp.KNNBaseline(sim_options=sim_options)
    counter = 0
    logging.info('Begin to enter the training procedure.')
    for train_set, test_set in data.folds():
        logging.info('Training {}/{} data'.format(counter, NUM_FOLD))
        alg.train(train_set)

        logging.info('Evaluating {}/{} data'.format(counter, NUM_FOLD))
        sp.accuracy.rmse(alg.test(test_set), verbose=True)
        counter += 1

    sp.dump.dump(rec_model_file, algo=alg)


def compute_range(nums, distance):
    """
    compute how many distances are smaller then distance
    and how many distances are equal to distance, among all
    possible distances in nums, time complexity O(len(nums))

    Arg:
        distance : (int), the distance to query
    Returns:
        first, last : zero-based indexes of first (inclusive) and last
        (exclusive) element equal to distance in the sorted
        list of distances in nums: [first, last)
    """
    less, equal = 0, 0
    a, b = 0, 0  # a, b are the extremes of the segment of less distances
    c, d = 0, 0  # c, d are the extremes of the segment of less/equal distances
    prev = None
    for num in nums[:-1]:
        if num != prev:
            while c < len(nums) and nums[c] + distance < num: c += 1
            a = c
            while a < len(nums) and nums[a] + distance == num: a += 1
            while b < len(nums) - 1 and nums[b + 1] - distance < num: b += 1
            d = b
            while d < len(nums) - 1 and nums[d + 1] - distance == num: d += 1
        prev = num

        less += b - a
        equal += d - c

    return max(0, less/2), equal/2

class Solution(object):
    def smallestDistancePair(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        k, sorted_nums = k-1, sorted(nums)
        b = sorted_nums[-1] - sorted_nums[0]
        a = min([sorted_nums[i+1] - sorted_nums[i] for i in xrange(len(nums) - 1)])
        sorted_nums.append(1e9)
        while True:
            m = (b-a)/2 + a
            start, end = compute_range(sorted_nums, m)
            if start <= k < end: return m
            elif k >= end: a = m + 1
            else: b = m - 1


import parameters
import internal
import pickle
from medoids import k_medoids
import numpy as np
import snake_game

def crossover(genome1, genome2):
    """Implements the crossover functionality of the NEAT algorithm."""
    if np.random.rand() < 0.5:  # Increase randomness
        genome1, genome2 = genome2, genome1

    if genome2.fitness > genome1.fitness:
        genome1, genome2, = genome2, genome1

    genes1 = genome1.genes
    genes2 = genome2.genes
    composite_genes = {}
    composite_nodes = {}

    assert genome1.fitness >= genome2.fitness

    # Composite genome has the same connections as the more fit genome
    for g in genes1:
        if g not in genes2:
            composite_genes[g] = genes1[g].copy()
        else:
            composite_genes[g] = np.random.choice([genes1[g], genes2[g]]).copy()
            if not genes1[g].enable and not genes2[g].enable and \
                            np.random.rand() < parameters.p_enable_if_both_parents_disabled:
                composite_genes[g].enable = True

    # Composite genome has the same nodes as the more fit genome
    for n in genome1.nodes:
        composite_nodes[n] = genome1.nodes[n].copy()
        composite_nodes[n].incoming_genes = []
        for incoming in genome1.nodes[n].incoming_genes:
            incoming_key = incoming.number
            composite_nodes[n].incoming_genes.append(composite_genes[incoming_key])
        if n in genome1.nodes and n in genome2.nodes:
            composite_nodes[n].bias = np.random.choice([genome1.nodes[n], genome2.nodes[n]]).bias

    return internal.Genome(composite_nodes, composite_genes)

def delta(genome1, genome2):
    """This is the delta function used to determine the similarity between two
    genomes. The higher the result, the more dissimilar the two genomes are. """
    if max(genome2.genes.keys()) > max(genome1.genes.keys()):
        genome1, genome2 = genome2, genome1
    assert (max(genome1.genes.keys()) >= max(genome2.genes.keys()))

    g1 = set(genome1.genes.keys())
    g2 = set(genome2.genes.keys())
    excess_cutoff = max(g2)
    excess = 0
    disjoint = 0
    sum_of_differences = 0
    N = max(len(g1), len(g2))

    for g in g1:
        if g in g2:
            sum_of_differences += abs(genome1.genes[g].weight - genome2.genes[g].weight)
        else:
            if g > excess_cutoff:
                excess += 1
            else:
                disjoint += 1
    for g in g2:
        if g not in g1:
            disjoint += 1

    return parameters.c1 * excess / N + parameters.c2 * disjoint / N + parameters.c3 * sum_of_differences / N

def find_species(population, genome):
    """population is a list of species. Returns the species that the genome belongs to. If
    there aren't any species that it belongs to, it creates a new species. """
    for s in population:
        if delta(s.representative, genome) < parameters.delta_threshold:
            # print(delta(s.representative, genome), end='')
            # print("(" + str(len(genome.nodes)) + ", " + str(len(genome.genes)) + ")")
            return s
    new_species = internal.Species(genome)
    population.append(new_species)
    return new_species

def run_genome_in_game(genome, display_graphics=False):
    """Evaluates the fitness of a genome by using it in the snake game. """
    nn = internal.NeuralNetwork(genome)
    game = snake_game.Game(nn.evaluate, display_graphics)
    game_time = 0
    while game_time < 10000 and game.get_continue_status():  # Run the game
        game.step()
        genome.fitness = 15 * game.snake.fitness + 0.5 * (game.manhattan_distance_to_food())
        # genome.fitness = game_time
        game_time += 1
    return genome.fitness

def evaluate_population(population):
    """Finds the fitness for all genomes in the population. The population is given as
    a list of species."""
    max_fitness = float("-inf")
    average_fitness = 0
    best_genome = None
    for species in population:
        for genome in species.genomes:
            current = run_genome_in_game(genome)
            average_fitness += current
            if current > max_fitness:
                max_fitness = current
                best_genome = genome
    average_fitness /= parameters.population_size
    return max_fitness, average_fitness, best_genome

def init_population():
    """Returns a one-element list of one species. This species contains the entire population
    for the first generation. """
    all_genomes = []
    for _ in range(parameters.population_size):
        genome = internal.Genome()
        all_genomes.append(genome)
    species = internal.Species(np.random.choice(all_genomes))
    species.genomes = all_genomes
    return [species]

def update_spawn_amounts(population):
    """Finding spawn amounts. Each species' spawn amount is proportional to the sum of its
    genomes' adjusted fitness."""
    stagnated = set()
    total_sum_adj_fitness = 0
    for species in population:
        N = len(species.genomes)
        for genome in species.genomes:
            species.sum_adj_fitness += genome.fitness / N

        species.best_genome = max(species.genomes, key=lambda x: x.fitness)
        max_fitness = species.best_genome.fitness
        if max_fitness <= species.best_fitness:  # Species didn't improve
            species.stagnate_generations += 1
        else:
            species.stagnate_generations = 0  # Restart stagnate count
            species.best_fitness = max_fitness
        if species.stagnate_generations >= parameters.stagnate_threshold:  # Species has stagnated
            stagnated.add(species)
            print("STAGNATED: Removed 1 species.")
        else:
            total_sum_adj_fitness += species.sum_adj_fitness

    for species in stagnated:
        population.remove(species)
    for species in population:
        species.spawn_amount = max(3, int(
            parameters.population_size * species.sum_adj_fitness / total_sum_adj_fitness))
    return population

def next_generation_species(species):
    """Returns the next generation (list) of genomes given the species. The size of the next generation
    will be species.spawn_amount"""
    spawn_amount = species.spawn_amount
    sorted_genomes = sorted(species.genomes, key=lambda g: g.fitness, reverse=True)
    probability_chosen = np.array([g.fitness for g in species.genomes])
    probability_chosen = probability_chosen / sum(probability_chosen)  # Normalize

    N = len(species.genomes)
    new_generation = sorted_genomes[0:max(2, int(parameters.keep_best_amount * N))]  # Keep top fraction of species
    while len(new_generation) < spawn_amount:
        g1 = np.random.choice(species.genomes, p=probability_chosen)
        g2 = np.random.choice(species.genomes, p=probability_chosen)
        new_generation.append(crossover(g1, g2))

    for i in range(2, len(new_generation)):  # The top 2 genomes do not get mutated
        new_generation[i].mutate()
    return new_generation

def next_generation_population(population):
    """Returns the next generation's list of species given this generation's list of species. """
    next_genomes = []  # Contains a list of all genomes
    for species in population:
        next_genomes += next_generation_species(species)
        species.genomes = []

    # Assign each genome to a species
    for genome in next_genomes:
        best_fit = find_species(population, genome)
        best_fit.genomes.append(genome)
    next_population = []
    for species in population:
        if species.genomes:  # If the species still has something assigned to it.
            next_population.append(species)
    population = next_population

    # Update representatives for each genome
    for species in population:
        species.representative = np.random.choice(species.genomes)
    return population

def evolution():
    """Puts everything together to evolve the snake AI. """
    population = init_population()
    best_fitness_overall = float("-inf")
    for gen_number in range(parameters.num_generations):
        total_size_population = 0
        print("=================Generation " + str(gen_number) + "===================")
        best_fitness_population, average_fitness, best_genome = evaluate_population(population)
        if best_fitness_population > best_fitness_overall:
            best_fitness_overall = best_fitness_population
            with open("genomes/generation " + str(gen_number) + " fitness " + str(best_genome.fitness),
                      'wb') as output:
                pickle.dump(best_genome, output, pickle.HIGHEST_PROTOCOL)
        print("Number of species: " + str(len(population)))
        print("Sizes: ", end='')
        for species in population:
            print(len(species.genomes), " ", end='')
            total_size_population += len(species.genomes)
        print()
        print("Total size: " + str(total_size_population))
        print("Best fitness: " + str(best_fitness_population))
        print("Average fitness: " + str(average_fitness))
        # print()
        internal.Genome.node_innovation_lookup = {}
        # internal.Genome.gene_innovation_lookup = {}
        population = update_spawn_amounts(population)
        population = next_generation_population(population)

def test_genome_in_game(filename):
    """Loads the genome from file, and displays the snake AI as played by the
    genome. """
    with open(filename, 'rb') as file:
        genome = pickle.load(file)
    fitness = run_genome_in_game(genome, display_graphics=True)
    print("fitness: " + str(fitness))

np.random.seed(20)  # For debugging purposes
evolution()
# test_genome_in_game("samples2/generation 203 fitness 376.0")
# show_genome_capabilities("genomes/generation 78 fitness 92.5")


#Made by kahootbird for project euler #18
#Get the test cases a loop for them
a = int(raw_input())

while (a > 0):
	a = a - 1
	row = []
	b = raw_input()
	b = int(b)
	#Get input and convert to ints including negatives
	while (b > 0):
	    string_value = raw_input()
	    row.append(map(int, string_value.split(' ')))
	    b = b - 1
	#Now to the meat of the problem - start at the bottom and sum each direction to the top
	loopvar = len(row);
	for index, value in enumerate(row):
		if (loopvar != 1):
			loopvar = loopvar-1;
			#Crazy python comprehension to add the max of each row to the row above it.
			row[loopvar-1] = [row[loopvar-1][x]+max(row[loopvar][x],row[loopvar][x+1]) for x in range(0,loopvar)]
	#Print result
	print("" + str(row[0][0]))


# 리스트 생성
input_list = []

# 입력값 받기
while(True):
    a = int(input())
    if(a == 0):
        break
    else:
        input_list.append(a)

if input_list is not None:
    # 처음에는 바로 반복문을 사용해서 구현했더니
    # 계산 시간이 너무 길어서 오류 발생
    # 따라서 input_list 내에서 가장 큰 값으로
    # prime_arr를 만들기로 결정함.
    max = input_list[0]
    for i in input_list[0:]:
        if max < i:
            max = i

    # 에라토스테네스의 체 활용

    # 소수인지 판별하기 위한 배열 생성(주어지는 수는 1000이하의 자연수임.)
    prime_arr = [True]*(2*max+1)
    prime_arr[0] = False
    prime_arr[1] = False

    # 반복문을 통해서 소수를 모두 찾아냄
    for i in range(2, 2*max+1):
        if prime_arr[i] == True: #특정 값이 아직까지 소수인 경우
            j = 2
            while(i*j) <= 2*max:
                prime_arr[i*j] = False # i의 배수 값을 소수가 아니라고 판별
                j += 1

    # n부터 2n까지의 소수를 출력
    for n in input_list[0:]:
        num = 0 # 소수의 개수 초기값
        for i in range(n+1, 2*n+1):
            if prime_arr[i]:
                num += 1
        print(num)

solution/bang/1차시 - 수학/04. 베르트랑 공준 (4948).py


from matplotlib import pyplot as plt
import numpy as np
import csv
from collections import Counter
import ast
import pandas as pd
from textblob import TextBlob
import re
from textblob.sentiments import NaiveBayesAnalyzer

def clean_tweet(tweet):
    return ' '.join(re.sub("(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)", " ", tweet).split()) #removing hyperlinks and special charaters

def analyse_tweet(tweet):
    analysis = TextBlob(tweet)
    if analysis.sentiment.polarity > 0: # positive
        return "positive"
    elif analysis.sentiment.polarity == 0: # neutral / we don't know
        pass
    else: # negative
        return "negative"

with open('twitterData_public_tweets.csv') as file:
    csv_reader =  csv.DictReader(file)

    sentiments = []
    num = []

    for row in csv_reader:
        sentiments.append(analyse_tweet(row['content']))
        num.append(TextBlob(row['content']).sentiment.polarity)

data = {'Sentiment':sentiments,'Value':num}
data_pd = pd.DataFrame(data)

data_pd.boxplot(by='Sentiment', column='Value')
plt.xlabel('Sentiment of tweets')
plt.ylabel('Polarity value')
plt.show()