Beispiel #1
0
class Simulator():
    time_steps_per_hours = 36000
    # short refers to closest exit and long to exit furthest away
    time_car_drive_short = 30
    time_car_drive_straight = 45
    time_car_drive_long = 60
    # it takes 50% less time to pass if the car in front is moving
    time_rolling_multiplier = 0.5
    time_between_rolling = 5

    # not occupied if 0
    occupied_upper_left = 0
    occupied_upper_right = 0
    occupied_lower_left = 0
    occupied_lower_right = 0

    previous_green = Direction.SOUTH

    def __init__(self, *args, **kwargs):
        self.south = Lane("south")
        self.north = Lane("north")
        self.west = Lane("west")
        self.east = Lane("east")
        self.traffic_probability = self.fit_curve(False)
        self.time = 0
        #self.setup_GUI()

    def setup_GUI(self):
        self.root = tkinter.Tk()
        self.ul = tkinter.IntVar()
        self.ul.set(0)
        self.ur = tkinter.IntVar()
        self.ur.set(0)
        self.ll = tkinter.IntVar()
        self.ll.set(0)
        self.lr = tkinter.IntVar()
        self.lr.set(0)
        l = tkinter.Label(self.root, textvariable="Testing")
        l.pack()
        #tkinter.Label(self.root, textvariable=self.ul).grid(row = 0, column=0)
        #tkinter.Label(self.root, textvariable=self.ur).grid(row = 0, column=1)
        #tkinter.Label(self.root, textvariable=self.ll).grid(row = 1, column=0)
        #tkinter.Label(self.root, textvariable=self.lr).grid(row = 1, column=1)

    def set_values(self, ul, ur, ll, lr):
        self.ul.set(ul)
        self.ur.set(ur)
        self.ll.set(ll)
        self.lr.set(lr)

    def fit_curve(self, graph):
        """
        Fit a curve to traffic data points.

        Parameters
        ----------
        graph : bool
            show curve graph or not

        Returns
        -------
        function
            function that calculates traffic probability
        """
        points = np.array([
            (0, 50.), (1, 40), (2, 30), (3, 25), (4, 30), (5, 35), (6, 60),
            (7, 150), (8, 500), (9, 520), (10, 600), (11, 600), (12, 475),
            (13, 380), (14, 350), (15, 400), (16, 500), (17, 550), (18, 550),
            (19, 350), (20, 275), (21, 190), (22, 150), (23, 125), (24, 90)
        ])
        points = self.normalize_tuple_y(points)
        # get x and y vectors
        x = points[:, 0]
        y = points[:, 1]

        # calculate polynomial
        z = np.polyfit(x, y, 11)
        f = np.poly1d(z)
        # calculate new x's and y's
        if (graph):
            x_new = np.linspace(x[0], x[-1], 50)
            y_new = f(x_new)

            plt.plot(x, y, 'o', x_new, y_new)
            plt.xlim([x[0] - 1, x[-1] + 1])
            plt.show()
        return f

    def normalize_tuple_y(self, tuple_list):
        """
        Normalize the second value (y value) in the tuple.

        Parameters
        ----------
        tuple_list : list
            list of tuples

        Returns
        -------
        list
            list of y normalized tuples
        """
        max = 0
        for element in tuple_list:
            if (element[1] > max):
                max = element[1]
        for element in tuple_list:
            element[1] = element[1] / max
        return tuple_list

    def stochastic_add(self, hour):
        """
        Add car to a random lane following traffic probability function.

        Parameters
        ----------
        hour : float
            hour of day
        """
        r_number = random.uniform(0, 1)
        if (r_number <= self.traffic_probability(hour)):
            r_number = randint(0, 3)
            if (r_number == 0):
                self.west.add_car(
                    Car(self.get_random_direction(Direction.WEST), self.time))
            elif (r_number == 1):
                self.south.add_car(
                    Car(self.get_random_direction(Direction.SOUTH), self.time))
            elif (r_number == 2):
                self.north.add_car(
                    Car(self.get_random_direction(Direction.NORTH), self.time))
            elif (r_number == 3):
                self.east.add_car(
                    Car(self.get_random_direction(Direction.EAST), self.time))

    def add_direction(self, direction):
        if (direction == Direction.WEST):
            self.west.add_car(
                Car(self.get_random_direction(Direction.WEST), self.time))
            #print('Car added west')
        elif (direction == Direction.SOUTH):
            self.south.add_car(
                Car(self.get_random_direction(Direction.SOUTH), self.time))
            #print('Car added south')
        elif (direction == Direction.NORTH):
            self.north.add_car(
                Car(self.get_random_direction(Direction.NORTH), self.time))
            #print('Car added north')
        elif (direction == Direction.EAST):
            self.east.add_car(
                Car(self.get_random_direction(Direction.EAST), self.time))
            #print('Car added east')

    def get_random_direction(self, direction_from):
        r_number = randint(0, 2)
        if (direction_from == Direction.NORTH):
            if (r_number == 0):
                return Direction.SOUTH
            elif (r_number == 1):
                return Direction.EAST
            elif (r_number == 2):
                return Direction.WEST
        elif (direction_from == Direction.SOUTH):
            if (r_number == 0):
                return Direction.NORTH
            elif (r_number == 1):
                return Direction.EAST
            elif (r_number == 2):
                return Direction.WEST
        elif (direction_from == Direction.EAST):
            if (r_number == 0):
                return Direction.SOUTH
            elif (r_number == 1):
                return Direction.NORTH
            elif (r_number == 2):
                return Direction.WEST
        elif (direction_from == Direction.WEST):
            if (r_number == 0):
                return Direction.SOUTH
            elif (r_number == 1):
                return Direction.EAST
            elif (r_number == 2):
                return Direction.NORTH

    def green(self, lane):
        # TODO check occupancy can be false if from the same lane
        # TODO A function that update_occupancy(from, to) w/ time variables
        if (lane == Direction.NORTH):
            car = self.north.peek_car()
            # car can go
            #print(self.previous_green)
            #print(self.previous_green == lane)
            #print(self.check_occupancy(lane, car.direction))
            if car != None and ((self.check_occupancy(lane, car.direction)
                                 or self.previous_green == lane)):
                self.set_occupancy(lane, car.direction,
                                   self.previous_green == lane)
                if (self.previous_green == lane):
                    if (self.north.time_since_green >=
                            self.time_between_rolling):
                        self.north.green()
                        self.previous_green = lane
                else:
                    self.north.green()
                    self.previous_green = lane
        elif (lane == Direction.SOUTH):
            car = self.south.peek_car()
            # car can go
            if (car != None and (self.check_occupancy(lane, car.direction)
                                 or self.previous_green == lane)):
                self.set_occupancy(lane, car.direction,
                                   self.previous_green == lane)
                if (self.previous_green == lane):
                    if (self.south.time_since_green >=
                            self.time_between_rolling):
                        self.south.green()
                        self.previous_green = lane
                else:
                    self.south.green()
                    self.previous_green = lane
        elif (lane == Direction.WEST):
            car = self.west.peek_car()
            # car can go
            if (car != None and (self.check_occupancy(lane, car.direction)
                                 or self.previous_green == lane)):
                self.set_occupancy(lane, car.direction,
                                   self.previous_green == lane)
                if (self.previous_green == lane):
                    if (self.west.time_since_green >=
                            self.time_between_rolling):
                        self.west.green()
                        self.previous_green = lane
                else:
                    self.west.green()
                    self.previous_green = lane
        elif (lane == Direction.EAST):
            car = self.east.peek_car()
            # car can go
            if (car != None and (self.check_occupancy(lane, car.direction)
                                 or self.previous_green == lane)):
                self.set_occupancy(lane, car.direction,
                                   self.previous_green == lane)
                if (self.previous_green == lane):
                    if (self.east.time_since_green >=
                            self.time_between_rolling):
                        self.east.green()
                        self.previous_green = lane
                else:
                    self.east.green()
                    self.previous_green = lane

    def check_occupancy(self, direction_from, direction_to):
        if (direction_from == Direction.NORTH):
            if (direction_to == Direction.WEST):
                return self.occupied_upper_left == 0
            elif (direction_to == Direction.EAST):
                return (self.occupied_upper_left == 0
                        and self.occupied_lower_left == 0
                        and self.occupied_lower_right == 0)
            elif (direction_to == Direction.SOUTH):
                return (self.occupied_upper_left == 0
                        and self.occupied_lower_left == 0)
        elif (direction_from == Direction.SOUTH):
            if (direction_to == Direction.WEST):
                return (self.occupied_upper_left == 0
                        and self.occupied_upper_right == 0
                        and self.occupied_lower_right == 0)
            elif (direction_to == Direction.EAST):
                return self.occupied_lower_right == 0
            elif (direction_to == Direction.NORTH):
                return (self.occupied_upper_right == 0
                        and self.occupied_lower_right == 0)
        elif (direction_from == Direction.WEST):
            if (direction_to == Direction.NORTH):
                return (self.occupied_lower_left == 0
                        and self.occupied_lower_right == 0
                        and self.occupied_upper_right == 0)
            elif (direction_to == Direction.SOUTH):
                return self.occupied_lower_left == 0
            elif (direction_to == Direction.EAST):
                return (self.occupied_lower_left == 0
                        and self.occupied_lower_right == 0)
        elif (direction_from == Direction.EAST):
            if (direction_to == Direction.SOUTH):
                return (self.occupied_upper_left == 0
                        and self.occupied_upper_right == 0
                        and self.occupied_lower_left == 0)
            elif (direction_to == Direction.NORTH):
                return self.occupied_upper_left == 0
            elif (direction_to == Direction.WEST):
                return (self.occupied_upper_left == 0
                        and self.occupied_upper_right == 0)

    def set_occupancy(self, direction_from, direction_to, reduced):
        multiplier = 1
        if (reduced):
            multiplier = self.time_rolling_multiplier
        # literally puke, is there a neater way to do this?..
        if (direction_from == Direction.NORTH):
            if (direction_to == Direction.WEST):
                if (self.time_car_drive_short * multiplier >
                        self.occupied_upper_left):
                    self.occupied_upper_left = self.time_car_drive_short * multiplier
            elif (direction_to == Direction.EAST):
                if (self.time_car_drive_long * multiplier >
                        self.occupied_upper_left):
                    self.occupied_upper_left = self.time_car_drive_long * multiplier
                if (self.time_car_drive_long * multiplier >
                        self.occupied_lower_left):
                    self.occupied_lower_left = self.time_car_drive_long * multiplier
                if (self.time_car_drive_long * multiplier >
                        self.occupied_lower_right):
                    self.occupied_lower_right = self.time_car_drive_long * multiplier
            elif (direction_to == Direction.SOUTH):
                if (self.time_car_drive_straight * multiplier >
                        self.occupied_upper_left):
                    self.occupied_upper_left = self.time_car_drive_straight * multiplier
                if (self.time_car_drive_straight * multiplier >
                        self.occupied_lower_left):
                    self.occupied_lower_left = self.time_car_drive_straight * multiplier
        elif (direction_from == Direction.SOUTH):
            if (direction_to == Direction.WEST):
                if (self.time_car_drive_long * multiplier >
                        self.occupied_upper_left):
                    self.occupied_upper_left = self.time_car_drive_long * multiplier
                if (self.time_car_drive_long * multiplier >
                        self.occupied_upper_right):
                    self.occupied_upper_right = self.time_car_drive_long * multiplier
                if (self.time_car_drive_long * multiplier >
                        self.occupied_lower_right):
                    self.occupied_lower_right = self.time_car_drive_long * multiplier
            elif (direction_to == Direction.EAST):
                if (self.time_car_drive_short * multiplier >
                        self.occupied_lower_right):
                    self.occupied_lower_right = self.time_car_drive_short * multiplier
            elif (direction_to == Direction.NORTH):
                if (self.time_car_drive_straight * multiplier >
                        self.occupied_upper_right):
                    self.occupied_upper_right = self.time_car_drive_straight * multiplier
                if (self.time_car_drive_straight * multiplier >
                        self.occupied_lower_right):
                    self.occupied_lower_right = self.time_car_drive_straight * multiplier
        elif (direction_from == Direction.WEST):
            if (direction_to == Direction.NORTH):
                if (self.time_car_drive_long * multiplier >
                        self.occupied_lower_left):
                    self.occupied_lower_left = self.time_car_drive_long * multiplier
                if (self.time_car_drive_long * multiplier >
                        self.occupied_lower_right):
                    self.occupied_lower_right = self.time_car_drive_long * multiplier
                if (self.time_car_drive_long * multiplier >
                        self.occupied_upper_right):
                    self.occupied_upper_right = self.time_car_drive_long * multiplier
            elif (direction_to == Direction.SOUTH):
                if (self.time_car_drive_short * multiplier >
                        self.occupied_lower_left):
                    self.occupied_lower_left = self.time_car_drive_short * multiplier
            elif (direction_to == Direction.EAST):
                if (self.time_car_drive_straight * multiplier >
                        self.occupied_lower_left):
                    self.occupied_lower_left = self.time_car_drive_straight * multiplier
                if (self.time_car_drive_straight * multiplier >
                        self.occupied_lower_right):
                    self.occupied_lower_right = self.time_car_drive_straight * multiplier
        elif (direction_from == Direction.EAST):
            if (direction_to == Direction.SOUTH):
                if (self.time_car_drive_long * multiplier >
                        self.occupied_upper_left):
                    self.occupied_upper_left = self.time_car_drive_long * multiplier
                if (self.time_car_drive_long * multiplier >
                        self.occupied_upper_right):
                    self.occupied_upper_right = self.time_car_drive_long * multiplier
                if (self.time_car_drive_long * multiplier >
                        self.occupied_lower_left):
                    self.occupied_lower_left = self.time_car_drive_long * multiplier
            elif (direction_to == Direction.NORTH):
                if (self.time_car_drive_short * multiplier >
                        self.occupied_upper_left):
                    self.occupied_upper_left = self.time_car_drive_short * multiplier
            elif (direction_to == Direction.WEST):
                if (self.time_car_drive_straight * multiplier >
                        self.occupied_upper_left):
                    self.occupied_upper_left = self.time_car_drive_straight * multiplier
                if (self.time_car_drive_straight * multiplier >
                        self.occupied_upper_right):
                    self.occupied_upper_right = self.time_car_drive_straight * multiplier

    def __str__(self):
        string = '======================================================================'
        string += '\nNorth: \n'
        for car in self.north.get_cars():
            string += car.__str__() + '\n'
        string += '======================================================================'
        string += '\nSouth: \n'
        for car in self.south.get_cars():
            string += car.__str__() + '\n'
        string += '======================================================================'
        string += '\nWest: \n'
        for car in self.west.get_cars():
            string += car.__str__() + '\n'
        string += '======================================================================'
        string += '\nEast: \n'
        for car in self.east.get_cars():
            string += car.__str__() + '\n'
        string += '======================================================================'
        return string

    def run(self, scheduler):
        count = 0
        X = []
        nY = []
        sY = []
        wY = []
        eY = []
        while (count < self.time_steps_per_hours * 24):
            #time.sleep(2)
            hour = count / self.time_steps_per_hours
            #self.add_direction(Direction.SOUTH)
            if (count % 20 == 0):
                #self.stochastic_add(hour)
                self.add_direction(Direction.SOUTH)
                self.add_direction(Direction.NORTH)
                self.add_direction(Direction.WEST)
                self.add_direction(Direction.EAST)
                pass
            #self.green(Direction.SOUTH)
            scheduler.schedule()
            count += 1

            # save statistics
            X.append(hour)
            nY.append(self.north.size())
            sY.append(self.south.size())
            wY.append(self.west.size())
            eY.append(self.east.size())
            """
            self.set_values(self.occupied_upper_left, self.occupied_upper_right, 
                            self.occupied_lower_left, self.occupied_lower_right)
            self.root.update_idletasks()
            """

            # time passes
            self.time += 1
            if (self.occupied_upper_left > 0):
                self.occupied_upper_left -= 1
            if (self.occupied_upper_right > 0):
                self.occupied_upper_right -= 1
            if (self.occupied_lower_left > 0):
                self.occupied_lower_left -= 1
            if (self.occupied_lower_right > 0):
                self.occupied_lower_right -= 1
            self.north.update()
            self.south.update()
            self.west.update()
            self.east.update()

            #print('upper left: ' + str(self.occupied_upper_left))
            #print('upper right: ' + str(self.occupied_upper_right))
            #print('lower left: ' + str(self.occupied_lower_left))
            #print('lower right: ' + str(self.occupied_lower_right))

        plt.subplot(1, 1, 1)
        plt.plot(X, nY, label='North')
        plt.plot(X, sY, label='South')
        plt.plot(X, wY, label='West')
        plt.plot(X, eY, label='East')
        plt.legend(loc='upper left')
        plt.show()