# Situation
You have been hired by a company making electric garage doors. Accidents with the present product line have resulted in numerous damaged cars, broken limbs and several killed pets. Your mission is to write a safer version of their controller software.

# Specification
We always start with a closed door. The remote control has exactly one button, with the following behaviour.

+ If the door is closed, a push starts opening the door, and vice-versa
+ It takes 5 seconds for the door to open or close completely
+ While the door is moving, one push pauses movement, another push resumes movement in the same direction

In order to make the door safer, it has been equiped with resistance-based obstacle detection. When the door detects an obstacle, it must immediately reverse the direction of movement.

# Input
A string where each character represents one second, with the following possible values.

* ```'.'``` No event
* ```'P'``` Button has been pressed
* ```'O'``` Obstacle has been detected (supersedes P)

As an example, ```'..P....'``` means that nothing happens for two seconds, then the button is pressed, then no further events.

# Output
A string where each character represents one second and indicates the position of the door (0 if fully closed and 5 fully open). The door starts moving immediately, hence its position changes at the same second as the event.

# Example
```..P...O.....``` as input should yield
```001234321000``` as output

Difficulty: introductory

Starter code:

def controller(events):
	

Solutions:
def controller(events):

    out, state, dir, moving = [], 0, 1, False
    
    for c in events:
        if   c == 'O':      dir *= -1
        elif c == 'P':      moving = not moving
        if moving:          state += dir
        if state in [0,5]:  moving, dir = False, 1 if state == 0 else -1
        out.append(str(state))
        
    return ''.join(out)

def controller(events):
    state = 0
    movement = False
    direction = True
    output = ''
    for event in events:
        if event is 'P':
            movement = not movement
        if event is 'O':
            direction = not direction
        state = state + (-1, 1)[direction] * movement
        if state in (0, 5):
            direction = not state
            movement  = False
        output += str(state)
    return output

def controller(s):
    current, pause, door, output, i = 0, 0, 0, [], 0
    for symbol in s:
        if symbol == 'P':
            if pause : pause = False
            elif not door and not current : door = True
            elif door and current == 5 : door = False
            else : pause = True
        elif symbol == 'O' : door ^= 1
        current +=[[[0,-1][current>0],[0,1][current<5]][door],0][pause]
        output.append(str(current))
    return ''.join(output)

def controller(events):
    position, move, resume, positions = 0, 0, 0, []
    for event in events:
        if event == "P":
            if position == 0:
                move = 1
            elif position == 5:
                move = -1
            elif move:
                resume, move = move, 0
            else:
                move, resume = resume, 0
        elif event == "O":
            move = -move
        position = min(5, max(0, position + move))
        if position == 0 or position == 5:
            move = 0
        positions.append(str(position))
    return "".join(positions)

def controller(events):
    result = []
    pos, moving, direction = 0, False, 1
    for e in events:
        if e == 'P':
            moving = not moving
        elif e == 'O':
            direction *= -1
        if moving:
            pos += direction
            if not (0 < pos < 5):
                direction *= -1
                moving = False
        result.append(pos)
    return ''.join(map(str, result))


class State:
    def __init__(self):
        pass
class PausedIncreasing(State):
    @classmethod
    def handle(cls, e, val):
        nextstate = cls
        if e == '.':
            pass
        elif e == 'P':
            val += 1
            nextstate = MovingIncreasing
        elif e == 'O':
            nextstate = PausedDecreasing
        return val, nextstate
class PausedDecreasing(State):
    @classmethod
    def handle(cls, e, val):
        nextstate = cls
        if e == '.':
            pass
        elif e == 'P':
            val -= 1
            nextstate = MovingDecreasing
        elif e == 'O':
            nextstate = PausedIncreasing
        return val, nextstate
class MovingIncreasing(State):
    @classmethod
    def handle(cls, e, val):
        nextstate = cls
        if e == '.':
            val += 1
        elif e == 'P':
            nextstate = PausedIncreasing
        elif e == 'O':
            val -= 1
            nextstate = MovingDecreasing
        return val, nextstate
class MovingDecreasing(State):
    @classmethod
    def handle(cls, e, val):
        nextstate = cls
        if e == '.':
            val -= 1
        elif e == 'P':
            nextstate = PausedDecreasing
        elif e == 'O':
            val += 1
            nextstate = MovingIncreasing
        return val, nextstate

class GarageDoor:
    def __init__(self):
        self.val = 0
        self.state = PausedIncreasing
    def handle(self, e):
        self.val, self.state = self.state.handle(e, self.val)
        if self.val == 0:
            self.state = PausedIncreasing
        elif self.val == 5:
            self.state = PausedDecreasing
        return str(self.val)
    def get_output(self, events):
        return ''.join(str(self.handle(e)) for e in events)

def controller(events):
    gd = GarageDoor()
    return gd.get_output(events)

def controller(events: str):
    positions = []
    p = 0
    movement = False
    up = True
    for e in events:
        if e == 'P':
            movement = not movement
        if e == 'O' and movement:
            up = not up
        if movement:
            if up:
                p += 1
                if p == 5:
                    up = False
                    movement = False
            else:
                p -= 1
                if p == 0:
                    up = True
                    movement = False
        positions += [p]
    return ''.join(str(p) for p in positions)

def controller(events):
    r=''
    h=o=p=0
    for c in events:
        if c=='P':
            if not o:
                o=1 if h==0 else -1
            else:p^=1
        elif c=='O':
            o=-o
        if not p:
            h+=o
            if h in(0,5):o=0
        r+=f'{h}'
    return r

def controller(events):
    d,m,opening=0,0,True
    r=''
    for e in events:
        if e=='P':
            if m==0:
                if d==0:
                    m=1
                    opening=True
                elif d==5:
                    m=-1
                    opening=False
                elif opening:
                    m=1
                else:
                    m=-1
            else:
                m=0
        elif e=='O':
            opening=not opening
            m*=-1
        d+=m
        if (m==1 and d==5) or (m==-1 and d==0):
            m=0
        r+=str(d)
    return r

def controller(s):
    h,v,r,m = 0,0,'',1
    for i in s:
        if i == 'P':
            v = m if v==0 else -1 if h==5 else 1 if h==0 else 0
            
        if i =='O':
            v = -1 if v>0 else 1 if v<0 else 0

        if v < 0:
            m = -1
        if v > 0:
            m = 1

        h += v
        h = 0 if h<0 else 5 if h>5 else h
        r += str(h)
    return r