**See Also**
* [Traffic Lights - one car](.)
* [Traffic Lights - multiple cars](https://www.codewars.com/kata/5d230e119dd9860028167fa5)

---

# Overview

A character string represents a city road.

Cars travel on the road obeying the traffic lights..

Legend:
* `.` = Road
* `C` = Car
* `G` = GREEN traffic light
* `O` = ORANGE traffic light
* `R` = RED traffic light

Something like this:


C...R............G......


# Rules

## Simulation

At each iteration:

1. the lights change, according to the traffic light rules... then
2. the car moves, obeying the car rules

## Traffic Light Rules

Traffic lights change colour as follows:
* GREEN for `5` time units... then 
* ORANGE for `1` time unit... then
* RED for `5` time units....
* ... and repeat the cycle

## Car Rules

* Cars travel left to right on the road, moving 1 character position per time unit

* Cars can move freely until they come to a traffic light. Then:
 * if the light is GREEN they can move forward (temporarily occupying the same cell as the light)
 * if the light is ORANGE then they must stop (if they have already entered the intersection they can continue through)
 * if the light is RED the car must stop until the light turns GREEN again

# Kata Task

Given the initial state of the road, return the states for all iterations of the simiulation.

## Input

* `road` = the road array
* `n` = how many time units to simulate (n >= 0)

## Output

* An array containing the road states at every iteration (including the initial state)
 * Note: If a car occupies the same position as a traffic light then show only the car

## Notes

* There is only one car
* For the initial road state
 * the car is always at the first character position
 * traffic lights are either GREEN or RED, and are at the beginning of their countdown cycles
* There are no reaction delays - when the lights change the car drivers will react immediately!
* If the car goes off the end of the road it just disappears from view
* There will always be some road between adjacent traffic lights

# Example

Run simulation for 10 time units

**Input**
* `road = "C...R............G......"`
* `n = 10`

**Result**

---

Good luck!

DM

Difficulty: introductory

Starter code:

def traffic_lights(road, n):
	

Solutions:
def traffic_lights(road, n):
    lightsIdx = [ (i, 6*(c!='G')) for i,c in enumerate(road) if c in 'RG' ]
    car, ref  = road.find('C'), road.replace('C','.')
    mut, out  = list(ref), [road]
    
    for turn in range(1,n+1):
    
        for i,delta in lightsIdx:                                  # Update all lights
            state = (delta+turn) % 11
            mut[i] = 'G' if state<5 else 'O' if state==5 else 'R'
        
        car += car+1>=len(road) or mut[car+1] in '.G'              # Move the car if possible (even if outside of the road)
        
        if car<len(road): old, mut[car] = mut[car], 'C'            # Update, archive, then restore the road state
        out.append(''.join(mut))
        if car<len(road): mut[car] = old
        
    return out


from itertools import cycle 

def traffic_lights(road, n):
    light1 = iter(cycle( 'RRRRRGGGGGO' ))
    light2 = iter(cycle( 'GGGGGORRRRR' ))
    
    traffic , car = [], -1
     
    for _ in range(n+1):
        temp, RL, GL = [], next(light1), next(light2)
        for i in range(len(road)):
            temp.append( { 'R':RL, 'G':GL }.get(road[i], '.') ) 
        if car<len(temp)-1 and  temp[car+1] in 'RO': car -=1
        car +=1 
        if car<len(temp): temp[car] = 'C'
        traffic.append(''.join(temp))
    return traffic

def traffic_lights(road, n):
    light_cycle = {"R": "RRRRRGGGGGO", "G": "GGGGGORRRRR"}
    lights = {pos: light_cycle[light] for pos, light in enumerate(road) if light in light_cycle}
    car, result = 0, [road]
    for state in range(1 , n + 1):
        if car+1 not in lights or lights[car+1][state%11] not in "OR":
            car += 1
        result.append("".join("C" if pos == car else lights[pos][state%11] if pos in lights else "." for pos in range(len(road))))
    return result   

def light_changes_iter(n, *args):
    '''
    n - no. iterations
    args is a pattern in a form of tuple
    stores the iterations where lights must be changed
    '''
    iteration = 0
    tup = () 
    while True:
        for x in args:
            iteration += x
            tup += (iteration,) #append tuple
            if max(tup) > n:
                return tup[:-1] #pop out last element, it is above last iteration

def shift_lights(road_state, init_state):
    '''
    current road_state
    initial_state - list with the indexes of the initial light state
    current_pos - current position of the car to be updated
    pos_index - position of the car
    '''
    temp = road_state.split(" ") #string to list
    
    #only updates the positions correspondent to the initial signal
    #change current_pos if the car is in the same position as a signal
    for index in init_state: 
        if temp[0][index] == "O":
            temp[0] = temp[0][:index] + "R" + temp[0][index+1:]

        elif temp[0][index] == "G":
            temp[0] = temp[0][:index] + "O" + temp[0][index+1:]

        elif temp[0][index] == "R":
            temp[0] = temp[0][:index] + "G" + temp[0][index+1:]

    return "".join(temp)
 
def traffic_lights(road_state, n):
    '''
    road_state is a list with the initial road state
    '''
    road = [] + [road_state] #store road progress in a list
    road_simulated = "." + road_state[1:] #simulates road without car
    
    #iterations where light changes if position starts with green, orange, red
    green = light_changes_iter(n, 5,1,5)
    orange = light_changes_iter(n, 1,5,5) 
    red = light_changes_iter(n, 5,5,1)

    #store the indexes of initial states of the lights to keep track 
    #how they should change across iterations
    init_green = [i for i,char in enumerate(road_simulated) if char == "G"]
    init_orange = [i for i,char in enumerate(road_simulated) if char == "O"]
    init_red = [i for i,char in enumerate(road_simulated) if char == "R"]
    
    #start variables
    pos_index = 0 #current position of the car

    for ite in range(1,n+1):
        #update lights according to iteration
        if ite in green:
            road_simulated = shift_lights(road_simulated, init_green)
        if ite in orange:
            road_simulated = shift_lights(road_simulated, init_orange)
        if ite in red:
            road_simulated = shift_lights(road_simulated, init_red)
        
        try:
            #check if car should stop
            if road_simulated[pos_index + 1] in ("O", "R"):
                road_state = road_simulated[:pos_index] + "C" + road_simulated[pos_index+1:]
                road.append(road_state)
                continue
            
            #move the car
            pos_index += 1
            road_state = road_simulated[:pos_index] + "C" + road_simulated[pos_index+1:]
            road.append(road_state)
    
        except IndexError: #last iteration, car goes out of road
            road.append(road_simulated)  
        
    return road


def traffic_lights(road, n):

    print(road)
    index_red_init = [i for i,j in enumerate(road) if j =='R']
    index_green_init = [i for i,j in enumerate(road) if j =='G']
    index_orange_init = [i for i,j in enumerate(road) if j =='O']
    print(index_green_init)
    #print(type(road))
    road_lst = [i for i in road]

    red_init = 'RRRRRGGGGGO'
    green_init = 'GGGGGORRRRR'
    orange_init = 'ORRRRRGGGGG'
    
    index_car = 0
    
    time = 0
    count = 0
    car_index = -1
    final = []
    while time <= n and car_index <= len(road) - 1:
        
        #if car_index == len(road) - 1:
            
        
        if count >= len(red_init):
            count = count - len(red_init)
        for i in index_red_init:
            road_lst[i] = red_init[count]
        for i in index_green_init:
            road_lst[i] = green_init[count]
        for i in index_orange_init:
            road_lst[i] = orange_init[count]
        
        #print(car_index + 1)
        
        if car_index != len(road) - 1:
        
            if road_lst[car_index + 1] == 'R':
                car_index = car_index
            elif road_lst[car_index + 1] == 'O':
                car_index = car_index
            else:
                car_index += 1
            road_lst[car_index] = 'C'
        elif road[-1] == 'R':
            road_lst[-1] = red_init[count]
        elif road[-1] == 'G':
            road_lst[-1] = green_init[count]
        elif road[-1] == 'O':
            road_lst[-1] = orange_init[count]
        else:
            road_lst[-1] = '.'
            
        

        if car_index - 1 in index_red_init:
            road_lst[car_index - 1] = red_init[count]
        elif car_index - 1  in index_green_init:
            road_lst[car_index - 1] = green_init[count]
        elif car_index - 1  in index_orange_init:
            road_lst[car_index - 1] = orange_init[count]
        elif car_index - 1 >= 0:
            road_lst[car_index - 1] = '.'
            
        result = ''.join(road_lst)

        final.append(result)
        count += 1
            
        time += 1
    
    return final

def traffic_lights(road, n):
    C, D, res = 0, {i:[c, 0] for i,c in enumerate(road) if c in "GOR"}, [road]
    def updateLights():
        for i, (c, k) in D.items():
            if c == 'G':
                if k == 4: D[i] = ('O', 0)
                else: D[i] = ('G', k+1)
            elif c == 'O': D[i] = ('R', 0)
            elif k == 4: D[i] = ('G', 0)
            else: D[i] = ('R', k+1)
    for _ in range(n):
        updateLights()
        if not (C+1) in D or D[C+1][0] == 'G': C += 1
        res.append(''.join('C' if i == C else D[i][0] if i in D else '.' for i in range(len(road))))
    return res

class TrafficUnit:

    def __init__(self, color):
        # '.': road
        # 'R'/'G'/'B': light
        self.color = color
        self.t = 0

    def can_pass(self):
        return self.color is '.' or self.color == 'G'

    def step(self):
        self.t = (self.t + 1) % 5
        if self.color == 'G':
            if self.t == 0:
                self.color = 'O'
        elif self.color == 'O':
            self.color = 'R'
            self.t = 0
        elif self.color == 'R':
            if self.t == 0:
                self.color = 'G'
        return self

    def __str__(self):
        return self.color


def traffic_lights(road, n):
    def f():
        car_pos = 0
        units = [TrafficUnit(c.replace('C', '.')) for c in road + '.']
        for i in range(n+1):
            xs = list(map(str, units))
            if car_pos < len(road):
                xs[car_pos] = 'C'
            yield ''.join(xs[:-1])
            units = [unit.step() for unit in units]
            if car_pos < len(road) and units[car_pos+1].can_pass():
                car_pos += 1
    return list(f())

def traffic_lights(road, n):
    k, car, res = 'GGGGGORRRRR', 0, []
    for i in range(n+1):
        lights = [k[(k.index(s) + i) % 11] if s in 'ROG' else '.' for s in road]
        if car < len(road) - 1:
            if i: car += lights[car+1] not in 'RO'
            lights[car] = 'C' 
        res.append(''.join(lights))
    return res


def traffic_lights(road, n):
    empty = '.'*len(road)
    r = [road]+[empty]*n
    l = 10*(5*'G'+'O'+5*'R')
    for i in range(len(road)):
        if road[i] in l:
            for j in range(n+1):
                r[j] = r[j][:i]+l[j+l.index(road[i])]+r[j][i+1:]
    for i in range(n):
        if 'C' in r[i][:-1]:
            c = r[i][:-1].index('C')
            if r[i+1][c+1] is 'R' or r[i+1][c+1] is 'O':
                r[i+1] = r[i+1][:c]+'C'+r[i+1][c+1:]
            else:
                r[i+1] = r[i+1][:c+1]+'C'+r[i+1][c+2:]
    return r


def traffic_lights(road,n):
    a,b,c = 'GGGGGORRRRR','ORRRRRGGGGG','RRRRRGGGGGO'
    r,p = [road],0
    for i in range(1,n+1):
        t = [a[i%11] if x=='G' else b[i%11] if x=='O' else c[i%11] if x=='R' else x for x in road]
        if p<len(road)-1:
            if t[p+1] not in 'RO':
                p += 1
                t[p] = 'C'
            elif t[p+1] in 'RO':
                t[p] = 'C'
        t[0] = 'C' if p==0 else '.'
        r.append(''.join(t))
    return r