Beispiel #1
0
class Environment(object):
    """
    - plays out the simulation as specified in the problem statement for one time unit
    - method to simulate an action on existing state
    - method to print current state (not equivalent to state representation of elevator in Elevator.py)
    """

    # CONSTANTS
    WAIT_TIME_COST_FACTOR = 2
    UP_DOWN_COST_FACTOR = 1

    def __init__(self, N, K, p, q, r, t_u):
        self.N = N  # number of floors
        self.K = K  # number of elevators
        self.p = p  # probability person arrives at a given time step
        self.q = q  # probability person arrives at first floor
        self.r = r  # probability person wants to get down at first floor
        self.t_u = t_u  # one time unit

        self.elev = Elevator(N, K)
        self.total_cost = 0
        self.total_people_served = 0
        self.people_in_sys = []

    def apply_action(self, action):
        """
        - action is a K length list with actions of the form 'AU', 'AD', 'AOU', 'AOD', 'AS' for each elevator
        - executes the action and simulates the next state
        - returns the new buttons pressed after simulation
        - updates the cost
        """

        # reset lights, will set depending on action
        self.elev.reset_lights()

        # update costs
        # cost for people carried over from last time step
        self.total_cost += Environment.WAIT_TIME_COST_FACTOR * \
            len(self.people_in_sys)
        self.total_cost += Environment.UP_DOWN_COST_FACTOR * \
            len([x for x in action if x == 'AU' or x == 'AD']
                )   # cost for all lifts moved

        new_buttons_pressed = ''

        # move lifts
        for k in range(self.K):
            if action[k] == 'AU':
                self.elev.modify_pos(k, 1)
            if action[k] == 'AD':
                self.elev.modify_pos(k, -1)
            if not 0 <= self.elev.pos[k] < self.N:
                return 'INVALID ACTION'

        # embarkation, disembarkation
        for k in range(self.K):
            # remove people with this dest, unpress floor and lift buttons
            if action[k] == 'AOU' or action[k] == 'AOD':
                self.people_in_sys = [
                    x for x in self.people_in_sys
                    if not (x.elev_num == k and x.dest == self.elev.pos[k])
                ]
                self.elev.modify_elevator_button(k, self.elev.pos[k], 0)
                self.elev.modify_floor_button(self.elev.pos[k], action[k][-1],
                                              0)

                # add people to the elevator who want to go in the direction of lift, press their buttons
                for i in range(len(self.people_in_sys)):
                    if (self.people_in_sys[i].elev_num == -1
                            and self.people_in_sys[i].start == self.elev.pos[k]
                            and self.people_in_sys[i].direction
                            == action[k][-1]):
                        self.people_in_sys[i].elev_num = k
                        unpressed = self.elev.modify_elevator_button(
                            k, self.people_in_sys[i].dest, 1)

                        if unpressed:  # may have been pressed by someone already in list, or multiple times by people entering => add once
                            new_buttons_pressed += 'B_' + \
                                str(self.people_in_sys[i].dest +
                                    1) + '_' + str(k+1) + ' '

            # set lights
            if action[k] == 'AOU':
                self.elev.modify_lights(k, 'U', 1)
            if action[k] == 'AOD':
                self.elev.modify_lights(k, 'D', 1)

        floor_button_pressed = False

        # person arrival
        if random.random() < self.p:  # person arrives
            self.total_people_served += 1
            new_person = Person(self.total_people_served, self.N, self.q,
                                self.r)
            unpressed = self.elev.modify_floor_button(new_person.start,
                                                      new_person.direction, 1)
            if unpressed:
                new_buttons_pressed = 'B' + new_person.direction + '_' + \
                    str(new_person.start+1) + ' ' + new_buttons_pressed
                floor_button_pressed = True

            self.people_in_sys.append(new_person)

        if not floor_button_pressed:
            new_buttons_pressed = '0 ' + new_buttons_pressed

        return new_buttons_pressed

    def __str__(self):
        """
        - returns a (hopefully kinda sorta pretty) text based representation of the current environment
        - notice that while this representation prints the number of people at each floor, it is not informed
          as part of the elevator state to the agent
        - e.g. if the BU3 has been pressed and another person comes in at the third floor to go up, BU3 will
          not be sent again to the agent
        """

        left_margin = 25
        lift_width = 5

        state = ''
        state += '-' * (left_margin + (lift_width + 1) * self.N + 24) + '\n'
        state += 'FLOOR' + ' ' * (left_margin - 5) + ' ' * (lift_width / 2 + 1)
        for i in range(self.N):
            # complex rule for accounting for different string lengths for more than 100 floors
            state += str(i + 1) + ' ' * (lift_width - len(str(i + 1)) -
                                         (len(str(i + 2)) - len(str(i + 1))) *
                                         ((len(str(i + 2)) - 1) / 2) + 1)
        state += '\n'

        # people waiting
        waiting_up = [0] * self.N
        waiting_down = [0] * self.N
        people_in_lift = [0] * self.K
        for person in self.people_in_sys:
            if person.elev_num == -1:
                if person.direction == 'U':
                    waiting_up[person.start] += 1
                else:
                    waiting_down[person.start] += 1
            else:
                people_in_lift[person.elev_num] += 1

        state += 'PEOPLE WAITING UP/DOWN' + ' ' * \
            (left_margin-22) + ' '*(lift_width/2)
        for u, d in zip(waiting_up, waiting_down):
            state += str(u) + '/' + str(d) + ' ' * \
                (lift_width-len(str(u)+str(d)))
        state += '\n'

        # up and down buttons
        state += 'FLOOR UP BUTTON' + ' ' * (left_margin + lift_width / 2 - 15)
        for i in range(self.N):
            if self.elev.BU[i]:
                state += '-->'
            else:
                state += ' ' * 3
            state += ' ' * (lift_width - 2)
        state += '\n'

        state += 'FLOOR DOWN BUTTON' + ' ' * \
            (left_margin + lift_width / 2 - 17)
        for i in range(self.N):
            if self.elev.BD[i]:
                state += '<--'
            else:
                state += ' ' * 3
            state += ' ' * (lift_width - 2)
        state += '\n'

        # lifts
        for i in range(self.K):
            state += ' ' * (left_margin + 1)
            for j in range(self.N):
                if self.elev.pos[i] == j and self.elev.LU[i]:
                    state += ' ' * (lift_width / 2 - 1) + \
                        '-->' + ' ' * (lift_width / 2)
                elif self.elev.pos[i] == j and self.elev.LD[i]:
                    state += ' ' * (lift_width / 2 - 1) + \
                        '<--' + ' ' * (lift_width / 2)
                else:
                    state += ' ' * (lift_width + 1)
            state += '\n'
            state += ' ' * left_margin + '-'
            for j in range(self.N):
                if self.elev.pos[i] == j and (self.elev.LU[i]
                                              or self.elev.LD[i]):
                    state += '-' * (lift_width / 2 -
                                    1) + ' ' * 3 + '-' * (lift_width / 2)
                else:
                    state += '-' * (lift_width + 1)
            state += '\n'
            state += 'ELEVATOR ' + str(i+1) + ' ' * \
                (left_margin - 9 - len(str(i+1)))

            for j in range(self.N):
                if self.elev.pos[i] == j:
                    state += '|' + ' '*(lift_width/2) + \
                        '.' + ' '*(lift_width/2)
                else:
                    state += '|' + ' ' * lift_width
            state += '|' + ' '*5 + 'PEOPLE IN LIFT : ' + \
                str(people_in_lift[i]) + '\n'

            state += ' ' * left_margin + '-' * \
                ((lift_width + 1) * self.N + 1) + '\n'
            state += 'BUTTONS PRESSED' + ' ' * \
                (left_margin-15 + lift_width/2 + 1)
            for j in range(self.N):
                if self.elev.BF[i][j]:
                    state += 'o' + ' ' * lift_width
                else:
                    state += ' ' * (lift_width + 1)
            state += '\n'

        state += '\n'
        state += 'TOTAL PEOPLE IN SYSTEM : ' + \
            str(len(self.people_in_sys)) + '\n'
        state += 'TOTAL CUMULATIVE COST  : ' + str(self.total_cost) + '\n'
        state += '-' * (left_margin + (lift_width + 1) * self.N + 24)

        return state
Beispiel #2
0
class Simulator(object):
    """
    - carries out the simulation as specified in the problem statement
    - method to simulate an action on existing state
    - method to print current state (not equivalent to state representation of elevator in Elevator.py)
    """

    # CONSTANTS
    WAIT_TIME_COST_FACTOR = 2
    UP_DOWN_COST_FACTOR = 1

    def __init__(self, N, K, p, q, r, t_u):
        self.N = N  # number of floors
        self.K = K  # number of elevators
        self.p = p  # probability person arrives at a given time step
        self.q = q  # probability person arrives at first floor
        self.r = r  # probability person wants to get down at first floor
        self.t_u = t_u  # one time unit

        self.elev = Elevator(N, K)
        self.total_cost = 0
        self.total_people_served = 0
        self.people_in_sys = []

    def apply_action(self, action):
        """
        - action is a K length list with actions of the form 'AU', 'AD', 'AOU', 'AOD', 'AS' for each elevator
        - executes the action and simulates the next state
        - returns the new buttons pressed after simulation
        - updates the cost
        """

        # reset lights, will set depending on action
        self.elev.reset_lights()

        # update costs
        self.total_cost += Simulator.WAIT_TIME_COST_FACTOR * len(
            self.people_in_sys
        )  # cost for people carried over from last time step
        self.total_cost += Simulator.UP_DOWN_COST_FACTOR * len([
            x for x in action if x == 'AU' or x == 'AD'
        ])  # cost for all lifts moved

        new_buttons_pressed = ''

        # move lifts
        for k in range(self.K):
            if action[k] == 'AU':
                self.elev.modify_pos(k, 1)
            if action[k] == 'AD':
                self.elev.modify_pos(k, -1)
            if not 0 <= self.elev.pos[k] < self.N:
                return 'INVALID ACTION'

        # embarkation, disembarkation
        for k in range(self.K):
            if action[k] == 'AOU' or action[
                    k] == 'AOD':  # remove people with this dest, unpress button
                self.people_in_sys = [
                    x for x in self.people_in_sys
                    if x.elev_num == k and x.dest == self.elev.pos[k]
                ]
                self.elev.modify_elevator_button(k, self.elev.pos[k], 0)

                # add people to the elevator who want to go in the direction of lift, press their buttons
                for i in range(self.people_in_sys):
                    if (self.people_in_sys[i].elev_id == -1
                            and self.people_in_sys[i].start == self.elev.pos[k]
                            and self.people_in_sys[i].direction
                            == action[k][-1]):
                        self.people_in_sys[i].elev_id = k
                        unpressed = self.elev.modify_elevator_button(
                            k, self.people_in_sys[i].dest, 1)

                        if unpressed:  # may have been pressed by someone already in list, or multiple times by people entering => add once
                            new_buttons_pressed += 'B' + str(
                                self.people_in_sys[i].dest + 1) + str(k +
                                                                      1) + ' '

            # set lights
            if action[k] == 'AOU':
                self.elev.modify_lights(k, 'U', 1)
            if action[k] == 'AOD':
                self.elev.modify_lights(k, 'D', 1)

        # person arrival
        if random.random() < self.p:  # person arrives
            self.total_people_served += 1
            new_person = Person(self.total_people_served, self.N, self.q,
                                self.r)
            unpressed = self.elev.modify_floor_button(new_person.start,
                                                      new_person.direction, 1)
            if unpressed:
                new_buttons_pressed = 'B' + new_person.direction + str(
                    new_person.start + 1) + ' ' + new_buttons_pressed

            self.people.append(new_person)
        else:
            new_buttons_pressed = '0 ' + new_buttons_pressed

        return new_buttons_pressed

    def __str__(self):
        """
        - returns a (hopefully pretty) text based representation of the current state
        """

        left_margin = 25
        lift_width = 5

        state = ''
        state += '-' * (left_margin + (lift_width + 1) * self.N + 24) + '\n'
        state += 'FLOOR' + ' ' * (left_margin - 5) + ' ' * (lift_width / 2 + 1)
        for i in range(self.N):
            state += str(i + 1) + ' ' * lift_width
        state += '\n'

        # people waiting
        waiting_up = [0] * self.N
        waiting_down = [0] * self.N
        for person in self.people_in_sys:
            if person.elev_num == -1:
                if person.direction == 'U':
                    waiting_up[person.start] += 1
                else:
                    waiting_down[person.start] += 1

        state += 'PEOPLE WAITING UP/DOWN' + ' ' * (left_margin -
                                                   22) + ' ' * (lift_width / 2)
        for u, d in zip(waiting_up, waiting_down):
            state += str(u) + '/' + str(d) + ' ' * (lift_width -
                                                    len(str(u) + str(d)))
        state += '\n'

        # up and down buttons
        state += 'FLOOR UP BUTTON' + ' ' * (left_margin + lift_width / 2 - 15)
        for i in range(self.N):
            if self.elev.BU[i]:
                state += '-->'
            else:
                state += ' ' * 3
            state += ' ' * (lift_width - 2)
        state += '\n'

        state += 'FLOOR DOWN BUTTON' + ' ' * (left_margin + lift_width / 2 -
                                              17)
        for i in range(self.N):
            if self.elev.BD[i]:
                state += '<--'
            else:
                state += ' ' * 3
            state += ' ' * (lift_width - 2)
        state += '\n'

        # lifts
        for i in range(self.K):
            state += '\n'
            state += ' ' * left_margin + '-' * (
                (lift_width + 1) * self.N + 1) + '\n'
            state += 'LIFT ' + str(i + 1) + ' ' * (left_margin - 5 -
                                                   len(str(i + 1)))

            for j in range(self.N):
                if self.elev.pos[i] == j:
                    state += '|' + ' ' * (lift_width /
                                          2) + '.' + ' ' * (lift_width / 2)
                else:
                    state += '|' + ' ' * lift_width
            state += '|' + ' ' * 5 + 'PEOPLE IN LIFT : ' + str(
                len([x for x in self.people_in_sys if x.elev_num == i])) + '\n'

            state += ' ' * left_margin + '-' * (
                (lift_width + 1) * self.N + 1) + '\n'
            state += 'BUTTONS PRESSED' + ' ' * (left_margin - 15 +
                                                lift_width / 2 + 1)
            for j in range(self.N):
                if self.elev.BF[i][j]:
                    state += 'o' + ' ' * lift_width
                else:
                    state += ' ' * (lift_width + 1)
            state += '\n'

        return state