**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: EASY

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:
			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'
		if car < len(road):
			(old, mut[car]) = (mut[car], 'C')
		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):
	iteration = 0
	tup = ()
	while True:
		for x in args:
			iteration += x
			tup += (iteration,)
			if max(tup) > n:
				return tup[:-1]

def shift_lights(road_state, init_state):
	temp = road_state.split(' ')
	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 = [] + [road_state]
	road_simulated = '.' + road_state[1:]
	green = light_changes_iter(n, 5, 1, 5)
	orange = light_changes_iter(n, 1, 5, 5)
	red = light_changes_iter(n, 5, 5, 1)
	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']
	pos_index = 0
	for ite in range(1, n + 1):
		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:
			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
			pos_index += 1
			road_state = road_simulated[:pos_index] + 'C' + road_simulated[pos_index + 1:]
			road.append(road_state)
		except IndexError:
			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)
	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 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]
		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):
		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