broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    m = x['min_green']
    initial = min(x['max_initial'], max(m, -(-x['red_actuations'] * x['added_per_act_tenths'] // 10)))
    g0, gm = x['initial_gap_tenths'], x['min_gap_tenths']
    el = x['t'] - max(x['call'], 0)
    if el <= x['time_before_reduction']:
        gap = g0
    elif el >= x['time_to_reduce']:
        gap = gm
    else:
        done = el - x['time_before_reduction']
        gap = g0 - (g0 - gm) * done // x['time_to_reduce']
    return {'initial': initial, 'gap_tenths': gap}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'min_green': 10, 'added_per_act_tenths': 25, 'max_initial': 14, 'red_actuations': 20, 'initial_gap_tenths': 35, 'min_gap_tenths': 10, 'time_before_reduction': 3, 'time_to_reduce': 6, 'call': 3, 't': 27}, {'initial': 14, 'gap_tenths': 10}), ({'min_green': 6, 'added_per_act_tenths': 10, 'max_initial': 12, 'red_actuations': 1, 'initial_gap_tenths': 50, 'min_gap_tenths': 10, 'time_before_reduction': 8, 'time_to_reduce': 19, 'call': 4, 't': 2}, {'initial': 6, 'gap_tenths': 50}), ({'min_green': 9, 'added_per_act_tenths': 25, 'max_initial': 17, 'red_actuations': 9, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 7, 'time_to_reduce': 23, 'call': -4, 't': 60}, {'initial': 17, 'gap_tenths': 20}), ({'min_green': 10, 'added_per_act_tenths': 10, 'max_initial': 16, 'red_actuations': 20, 'initial_gap_tenths': 30, 'min_gap_tenths': 20, 'time_before_reduction': 9, 'time_to_reduce': 15, 'call': 14, 't': 29}, {'initial': 16, 'gap_tenths': 26}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31}), ({'min_green': 5, 'added_per_act_tenths': 20, 'max_initial': 27, 'red_actuations': 18, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 13, 'time_to_reduce': 24, 'call': 7, 't': 33}, {'initial': 27, 'gap_tenths': 34}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28})], [({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31}), ({'min_green': 8, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 4, 'initial_gap_tenths': 30, 'min_gap_tenths': 15, 'time_before_reduction': 7, 'time_to_reduce': 17, 'call': 0, 't': 20}, {'initial': 8, 'gap_tenths': 19}), ({'min_green': 8, 'added_per_act_tenths': 10, 'max_initial': 29, 'red_actuations': 6, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 12, 'time_to_reduce': 15, 'call': 5, 't': 24}, {'initial': 8, 'gap_tenths': 36}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28}), ({'min_green': 5, 'added_per_act_tenths': 20, 'max_initial': 14, 'red_actuations': 3, 'initial_gap_tenths': 40, 'min_gap_tenths': 10, 'time_before_reduction': 15, 'time_to_reduce': 10, 'call': 14, 't': 39}, {'initial': 6, 'gap_tenths': 10}), ({'min_green': 8, 'added_per_act_tenths': 10, 'max_initial': 12, 'red_actuations': 14, 'initial_gap_tenths': 40, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 11, 'call': 7, 't': 49}, {'initial': 12, 'gap_tenths': 15}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 16, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 20, 'time_before_reduction': 3, 'time_to_reduce': 25, 'call': 1, 't': 20}, {'initial': 14, 'gap_tenths': 26})], [({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28}), ({'min_green': 4, 'added_per_act_tenths': 20, 'max_initial': 10, 'red_actuations': 13, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 21, 'call': 5, 't': 13}, {'initial': 10, 'gap_tenths': 40}), ({'min_green': 10, 'added_per_act_tenths': 25, 'max_initial': 28, 'red_actuations': 18, 'initial_gap_tenths': 30, 'min_gap_tenths': 10, 'time_before_reduction': 3, 'time_to_reduce': 30, 'call': 14, 't': 33}, {'initial': 28, 'gap_tenths': 20}), ({'min_green': 9, 'added_per_act_tenths': 10, 'max_initial': 19, 'red_actuations': 0, 'initial_gap_tenths': 30, 'min_gap_tenths': 10, 'time_before_reduction': 7, 'time_to_reduce': 20, 'call': 2, 't': 38}, {'initial': 9, 'gap_tenths': 10}), ({'min_green': 7, 'added_per_act_tenths': 15, 'max_initial': 19, 'red_actuations': 9, 'initial_gap_tenths': 50, 'min_gap_tenths': 10, 'time_before_reduction': 5, 'time_to_reduce': 15, 'call': 9, 't': 26}, {'initial': 14, 'gap_tenths': 18}), ({'min_green': 5, 'added_per_act_tenths': 20, 'max_initial': 10, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 10, 'time_before_reduction': 12, 'time_to_reduce': 9, 'call': 12, 't': 31}, {'initial': 10, 'gap_tenths': 17})], [({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28}), ({'min_green': 6, 'added_per_act_tenths': 20, 'max_initial': 26, 'red_actuations': 2, 'initial_gap_tenths': 35, 'min_gap_tenths': 20, 'time_before_reduction': 3, 'time_to_reduce': 14, 'call': 12, 't': 28}, {'initial': 6, 'gap_tenths': 22}), ({'min_green': 8, 'added_per_act_tenths': 25, 'max_initial': 24, 'red_actuations': 0, 'initial_gap_tenths': 30, 'min_gap_tenths': 15, 'time_before_reduction': 14, 'time_to_reduce': 27, 'call': 1, 't': 34}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 7, 'added_per_act_tenths': 10, 'max_initial': 29, 'red_actuations': 1, 'initial_gap_tenths': 35, 'min_gap_tenths': 10, 'time_before_reduction': 1, 'time_to_reduce': 21, 'call': 14, 't': 30}, {'initial': 7, 'gap_tenths': 18}), ({'min_green': 8, 'added_per_act_tenths': 25, 'max_initial': 28, 'red_actuations': 14, 'initial_gap_tenths': 40, 'min_gap_tenths': 10, 'time_before_reduction': 15, 'time_to_reduce': 30, 'call': 10, 't': 56}, {'initial': 28, 'gap_tenths': 10}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 30, 'red_actuations': 12, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 11, 'time_to_reduce': 25, 'call': -2, 't': 12}, {'initial': 24, 'gap_tenths': 40}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31})], [({'min_green': 4, 'added_per_act_tenths': 25, 'max_initial': 20, 'red_actuations': 9, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 6, 'time_to_reduce': 23, 'call': 2, 't': 17}, {'initial': 20, 'gap_tenths': 33}), ({'min_green': 5, 'added_per_act_tenths': 25, 'max_initial': 13, 'red_actuations': 11, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 16, 'call': 6, 't': 27}, {'initial': 13, 'gap_tenths': 26}), ({'min_green': 4, 'added_per_act_tenths': 15, 'max_initial': 17, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 14, 'time_to_reduce': 8, 'call': 3, 't': 50}, {'initial': 11, 'gap_tenths': 20}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 16, 'red_actuations': 4, 'initial_gap_tenths': 50, 'min_gap_tenths': 15, 'time_before_reduction': 10, 'time_to_reduce': 22, 'call': 5, 't': 28}, {'initial': 10, 'gap_tenths': 30}), ({'min_green': 8, 'added_per_act_tenths': 25, 'max_initial': 23, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 10, 'time_before_reduction': 3, 'time_to_reduce': 30, 'call': 3, 't': 53}, {'initial': 8, 'gap_tenths': 10})]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    m = x['min_green']
    initial = min(x['max_initial'], max(m, -(-x['red_actuations'] * x['added_per_act_tenths'] // 10)))
    g0, gm = x['initial_gap_tenths'], x['min_gap_tenths']
    el = x['t'] - max(x['call'], 0)
    if el <= x['time_before_reduction']:
        gap = g0
    elif el >= max(x['time_before_reduction'], x['time_to_reduce']):
        gap = gm
    else:
        done = el - x['time_before_reduction']
        gap = g0 - (g0 - gm) * done // x['time_to_reduce']
    return {'initial': initial, 'gap_tenths': gap}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'min_green': 10, 'added_per_act_tenths': 25, 'max_initial': 14, 'red_actuations': 20, 'initial_gap_tenths': 35, 'min_gap_tenths': 10, 'time_before_reduction': 3, 'time_to_reduce': 6, 'call': 3, 't': 27}, {'initial': 14, 'gap_tenths': 10}), ({'min_green': 6, 'added_per_act_tenths': 10, 'max_initial': 12, 'red_actuations': 1, 'initial_gap_tenths': 50, 'min_gap_tenths': 10, 'time_before_reduction': 8, 'time_to_reduce': 19, 'call': 4, 't': 2}, {'initial': 6, 'gap_tenths': 50}), ({'min_green': 9, 'added_per_act_tenths': 25, 'max_initial': 17, 'red_actuations': 9, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 7, 'time_to_reduce': 23, 'call': -4, 't': 60}, {'initial': 17, 'gap_tenths': 20}), ({'min_green': 10, 'added_per_act_tenths': 10, 'max_initial': 16, 'red_actuations': 20, 'initial_gap_tenths': 30, 'min_gap_tenths': 20, 'time_before_reduction': 9, 'time_to_reduce': 15, 'call': 14, 't': 29}, {'initial': 16, 'gap_tenths': 26}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31}), ({'min_green': 5, 'added_per_act_tenths': 20, 'max_initial': 27, 'red_actuations': 18, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 13, 'time_to_reduce': 24, 'call': 7, 't': 33}, {'initial': 27, 'gap_tenths': 34}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28})], [({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31}), ({'min_green': 8, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 4, 'initial_gap_tenths': 30, 'min_gap_tenths': 15, 'time_before_reduction': 7, 'time_to_reduce': 17, 'call': 0, 't': 20}, {'initial': 8, 'gap_tenths': 19}), ({'min_green': 8, 'added_per_act_tenths': 10, 'max_initial': 29, 'red_actuations': 6, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 12, 'time_to_reduce': 15, 'call': 5, 't': 24}, {'initial': 8, 'gap_tenths': 36}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28}), ({'min_green': 5, 'added_per_act_tenths': 20, 'max_initial': 14, 'red_actuations': 3, 'initial_gap_tenths': 40, 'min_gap_tenths': 10, 'time_before_reduction': 15, 'time_to_reduce': 10, 'call': 14, 't': 39}, {'initial': 6, 'gap_tenths': 10}), ({'min_green': 8, 'added_per_act_tenths': 10, 'max_initial': 12, 'red_actuations': 14, 'initial_gap_tenths': 40, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 11, 'call': 7, 't': 49}, {'initial': 12, 'gap_tenths': 15}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 16, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 20, 'time_before_reduction': 3, 'time_to_reduce': 25, 'call': 1, 't': 20}, {'initial': 14, 'gap_tenths': 26})], [({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28}), ({'min_green': 4, 'added_per_act_tenths': 20, 'max_initial': 10, 'red_actuations': 13, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 21, 'call': 5, 't': 13}, {'initial': 10, 'gap_tenths': 40}), ({'min_green': 10, 'added_per_act_tenths': 25, 'max_initial': 28, 'red_actuations': 18, 'initial_gap_tenths': 30, 'min_gap_tenths': 10, 'time_before_reduction': 3, 'time_to_reduce': 30, 'call': 14, 't': 33}, {'initial': 28, 'gap_tenths': 20}), ({'min_green': 9, 'added_per_act_tenths': 10, 'max_initial': 19, 'red_actuations': 0, 'initial_gap_tenths': 30, 'min_gap_tenths': 10, 'time_before_reduction': 7, 'time_to_reduce': 20, 'call': 2, 't': 38}, {'initial': 9, 'gap_tenths': 10}), ({'min_green': 7, 'added_per_act_tenths': 15, 'max_initial': 19, 'red_actuations': 9, 'initial_gap_tenths': 50, 'min_gap_tenths': 10, 'time_before_reduction': 5, 'time_to_reduce': 15, 'call': 9, 't': 26}, {'initial': 14, 'gap_tenths': 18}), ({'min_green': 5, 'added_per_act_tenths': 20, 'max_initial': 10, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 10, 'time_before_reduction': 12, 'time_to_reduce': 9, 'call': 12, 't': 31}, {'initial': 10, 'gap_tenths': 17})], [({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28}), ({'min_green': 6, 'added_per_act_tenths': 20, 'max_initial': 26, 'red_actuations': 2, 'initial_gap_tenths': 35, 'min_gap_tenths': 20, 'time_before_reduction': 3, 'time_to_reduce': 14, 'call': 12, 't': 28}, {'initial': 6, 'gap_tenths': 22}), ({'min_green': 8, 'added_per_act_tenths': 25, 'max_initial': 24, 'red_actuations': 0, 'initial_gap_tenths': 30, 'min_gap_tenths': 15, 'time_before_reduction': 14, 'time_to_reduce': 27, 'call': 1, 't': 34}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 7, 'added_per_act_tenths': 10, 'max_initial': 29, 'red_actuations': 1, 'initial_gap_tenths': 35, 'min_gap_tenths': 10, 'time_before_reduction': 1, 'time_to_reduce': 21, 'call': 14, 't': 30}, {'initial': 7, 'gap_tenths': 18}), ({'min_green': 8, 'added_per_act_tenths': 25, 'max_initial': 28, 'red_actuations': 14, 'initial_gap_tenths': 40, 'min_gap_tenths': 10, 'time_before_reduction': 15, 'time_to_reduce': 30, 'call': 10, 't': 56}, {'initial': 28, 'gap_tenths': 10}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 30, 'red_actuations': 12, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 11, 'time_to_reduce': 25, 'call': -2, 't': 12}, {'initial': 24, 'gap_tenths': 40}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31})], [({'min_green': 4, 'added_per_act_tenths': 25, 'max_initial': 20, 'red_actuations': 9, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 6, 'time_to_reduce': 23, 'call': 2, 't': 17}, {'initial': 20, 'gap_tenths': 33}), ({'min_green': 5, 'added_per_act_tenths': 25, 'max_initial': 13, 'red_actuations': 11, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 16, 'call': 6, 't': 27}, {'initial': 13, 'gap_tenths': 26}), ({'min_green': 4, 'added_per_act_tenths': 15, 'max_initial': 17, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 14, 'time_to_reduce': 8, 'call': 3, 't': 50}, {'initial': 11, 'gap_tenths': 20}), ({'min_green': 5, 'added_per_act_tenths': 15, 'max_initial': 20, 'red_actuations': 7, 'initial_gap_tenths': 40, 'min_gap_tenths': 20, 'time_before_reduction': 10, 'time_to_reduce': 15, 'call': 3, 't': 20}, {'initial': 11, 'gap_tenths': 31}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 25, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 20, 'time_before_reduction': 8, 'time_to_reduce': 12, 'call': 0, 't': 40}, {'initial': 8, 'gap_tenths': 20}), ({'min_green': 8, 'added_per_act_tenths': 20, 'max_initial': 12, 'red_actuations': 9, 'initial_gap_tenths': 35, 'min_gap_tenths': 15, 'time_before_reduction': 5, 'time_to_reduce': 20, 'call': -4, 't': 12}, {'initial': 12, 'gap_tenths': 28}), ({'min_green': 6, 'added_per_act_tenths': 25, 'max_initial': 16, 'red_actuations': 4, 'initial_gap_tenths': 50, 'min_gap_tenths': 15, 'time_before_reduction': 10, 'time_to_reduce': 22, 'call': 5, 't': 28}, {'initial': 10, 'gap_tenths': 30}), ({'min_green': 8, 'added_per_act_tenths': 25, 'max_initial': 23, 'red_actuations': 3, 'initial_gap_tenths': 50, 'min_gap_tenths': 10, 'time_before_reduction': 3, 'time_to_reduce': 30, 'call': 3, 't': 53}, {'initial': 8, 'gap_tenths': 10})]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Volume-density added initial and gap reduction returns a wrong result when the minimum gap is reached after time_to_reduce alone.

Input {min_green, added_per_act_tenths, max_initial, red_actuations, initial_gap_tenths, min_gap_tenths, time_before_reduction, time_to_reduce, call, t}. Variable initial = min(max_initial, max(min_green, ceil(actuations*added/10))) seconds. Gap reduction is timed from the conflicting call (a call before green start counts from 0): until time_before_reduction elapses the allowed gap is the initial gap; during time_to_reduce it falls linearly with the reduction amount truncated to whole tenths; afterwards it is the minimum gap. Return {initial, gap_tenths}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if sum(s for _, s in sp) != C:
        return 'bad-splits'
    lc = (x['master'] + x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc + sp[0][1] - y - r) % C
    start = 0
    for ph, s in sp:
        ge = start + s - y - r
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', ge + y - lc]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 97, 'offset': 74, 'master': 66, 'splits': [[2, 28], [4, 37], [6, 32]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [2, 'green', 8]), ({'cycle': 109, 'offset': 101, 'master': 219, 'splits': [[2, 27], [4, 38], [6, 26], [8, 13]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 42, 'offset': 30, 'master': 306, 'splits': [[2, 15], [4, 32]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 105, 'offset': 36, 'master': 667, 'splits': [[2, 15], [4, 33], [6, 40], [8, 12]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 88, 'offset': 4, 'master': 126, 'splits': [[2, 27], [4, 40], [6, 21]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [4, 'green', 6]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 63, 'offset': 57, 'master': 778, 'splits': [[2, 15], [4, 31], [6, 22]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 62, 'offset': 20, 'master': 999, 'splits': [[2, 20], [4, 37]], 'yellow': 3, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 89, 'offset': 32, 'master': 82, 'splits': [[2, 39], [4, 21], [6, 29]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [4, 'green', 6]), ({'cycle': 75, 'offset': 42, 'master': 10, 'splits': [[2, 38], [4, 37]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [4, 'green', 27]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 136, 'offset': 108, 'master': 748, 'splits': [[2, 32], [4, 31], [6, 40], [8, 38]], 'yellow': 3, 'red': 2, 'ref': 'end'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 90, 'offset': 44, 'master': 143, 'splits': [[2, 29], [4, 40], [6, 16]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 76, 'offset': 22, 'master': 517, 'splits': [[2, 35], [4, 12], [6, 29]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'green', 2]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 73, 'offset': 66, 'master': 19, 'splits': [[2, 21], [4, 19], [6, 17], [8, 16]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [4, 'green', 9]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 71, 'offset': 31, 'master': 983, 'splits': [[2, 30], [4, 27], [6, 19]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 59, 'offset': 10, 'master': 266, 'splits': [[2, 22], [4, 17], [6, 15]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits')], [({'cycle': 96, 'offset': 85, 'master': 624, 'splits': [[2, 40], [4, 37], [6, 24]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 113, 'offset': 93, 'master': 56, 'splits': [[2, 40], [4, 28], [6, 15], [8, 30]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [6, 'green', 3]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 40, 'offset': 24, 'master': 26, 'splits': [[2, 17], [4, 23]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [2, 'green', 11]), ({'cycle': 57, 'offset': 53, 'master': 5, 'splits': [[2, 28], [4, 13], [6, 21]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 42, 'offset': 12, 'master': 106, 'splits': [[2, 25], [4, 22]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 70, 'offset': 10, 'master': 112, 'splits': [[2, 21], [4, 27], [6, 22]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [4, 'green', 11]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 52, 'offset': 23, 'master': 249, 'splits': [[2, 34], [4, 13]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 64, 'offset': 44, 'master': 37, 'splits': [[2, 16], [4, 29], [6, 19]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [6, 'green', 1]), ({'cycle': 87, 'offset': 64, 'master': 242, 'splits': [[2, 19], [4, 21], [6, 23], [8, 19]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 70, 'offset': 6, 'master': 678, 'splits': [[2, 24], [4, 16], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits')]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if sum(s for _, s in sp) != C:
        return 'bad-splits'
    lc = abs(x['master'] - x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc + sp[0][1] - y - r) % C
    start = 0
    for ph, s in sp:
        ge = start + s - y - r
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', ge + y - lc]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 97, 'offset': 74, 'master': 66, 'splits': [[2, 28], [4, 37], [6, 32]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [2, 'green', 8]), ({'cycle': 109, 'offset': 101, 'master': 219, 'splits': [[2, 27], [4, 38], [6, 26], [8, 13]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 42, 'offset': 30, 'master': 306, 'splits': [[2, 15], [4, 32]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 105, 'offset': 36, 'master': 667, 'splits': [[2, 15], [4, 33], [6, 40], [8, 12]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 88, 'offset': 4, 'master': 126, 'splits': [[2, 27], [4, 40], [6, 21]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [4, 'green', 6]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 63, 'offset': 57, 'master': 778, 'splits': [[2, 15], [4, 31], [6, 22]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 62, 'offset': 20, 'master': 999, 'splits': [[2, 20], [4, 37]], 'yellow': 3, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 89, 'offset': 32, 'master': 82, 'splits': [[2, 39], [4, 21], [6, 29]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [4, 'green', 6]), ({'cycle': 75, 'offset': 42, 'master': 10, 'splits': [[2, 38], [4, 37]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [4, 'green', 27]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 136, 'offset': 108, 'master': 748, 'splits': [[2, 32], [4, 31], [6, 40], [8, 38]], 'yellow': 3, 'red': 2, 'ref': 'end'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 90, 'offset': 44, 'master': 143, 'splits': [[2, 29], [4, 40], [6, 16]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 76, 'offset': 22, 'master': 517, 'splits': [[2, 35], [4, 12], [6, 29]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'green', 2]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 73, 'offset': 66, 'master': 19, 'splits': [[2, 21], [4, 19], [6, 17], [8, 16]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [4, 'green', 9]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 71, 'offset': 31, 'master': 983, 'splits': [[2, 30], [4, 27], [6, 19]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 59, 'offset': 10, 'master': 266, 'splits': [[2, 22], [4, 17], [6, 15]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits')], [({'cycle': 96, 'offset': 85, 'master': 624, 'splits': [[2, 40], [4, 37], [6, 24]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 113, 'offset': 93, 'master': 56, 'splits': [[2, 40], [4, 28], [6, 15], [8, 30]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [6, 'green', 3]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 40, 'offset': 24, 'master': 26, 'splits': [[2, 17], [4, 23]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [2, 'green', 11]), ({'cycle': 57, 'offset': 53, 'master': 5, 'splits': [[2, 28], [4, 13], [6, 21]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 42, 'offset': 12, 'master': 106, 'splits': [[2, 25], [4, 22]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 70, 'offset': 10, 'master': 112, 'splits': [[2, 21], [4, 27], [6, 22]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [4, 'green', 11]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 52, 'offset': 23, 'master': 249, 'splits': [[2, 34], [4, 13]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 64, 'offset': 44, 'master': 37, 'splits': [[2, 16], [4, 29], [6, 19]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [6, 'green', 1]), ({'cycle': 87, 'offset': 64, 'master': 242, 'splits': [[2, 19], [4, 21], [6, 23], [8, 19]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 70, 'offset': 6, 'master': 678, 'splits': [[2, 24], [4, 16], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits')]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Coordinated local cycle timer returns a wrong result when the offset is added to the master clock.

Input {cycle, offset, master, splits: [[phase, split s]] in sequence starting with the coordinated phase, yellow, red, ref}. Splits must sum to the cycle, else 'bad-splits'. Local time = (master - offset) mod cycle, where the offset marks the start of coordinated green (ref 'begin') or the end of coordinated green (ref 'end'). Each split is green then yellow then all-red. Return [phase, interval, seconds remaining].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if sum(s for _, s in sp) != C:
        return 'bad-splits'
    lc = (x['master'] - x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc - sp[0][1] + y + r) % C
    start = 0
    for ph, s in sp:
        ge = start + s - y - r
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', ge + y - lc]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 105, 'offset': 35, 'master': 4, 'splits': [[2, 37], [4, 29], [6, 39]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [6, 'green', 26]), ({'cycle': 116, 'offset': 95, 'master': 503, 'splits': [[2, 32], [4, 37], [6, 31], [8, 16]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [4, 'green', 5]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 46, 'offset': 4, 'master': 249, 'splits': [[2, 15], [4, 31]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [4, 'green', 27]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 74, 'offset': 17, 'master': 890, 'splits': [[2, 21], [4, 29], [6, 24]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'green', 15]), ({'cycle': 126, 'offset': 79, 'master': 132, 'splits': [[2, 32], [4, 37], [6, 40], [8, 17]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [6, 'green', 24])], [({'cycle': 84, 'offset': 40, 'master': 210, 'splits': [[2, 39], [4, 14], [6, 31]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 32]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 39, 'offset': 16, 'master': 927, 'splits': [[2, 16], [4, 23]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'yellow', 1]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 44, 'offset': 26, 'master': 566, 'splits': [[2, 32], [4, 12]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'yellow', 4]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 94, 'offset': 81, 'master': 161, 'splits': [[2, 32], [4, 26], [6, 36]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [2, 'green', 14]), ({'cycle': 56, 'offset': 16, 'master': 493, 'splits': [[2, 27], [4, 29]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [4, 'green', 21])], [({'cycle': 69, 'offset': 41, 'master': 89, 'splits': [[2, 30], [4, 39]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [4, 'green', 16]), ({'cycle': 56, 'offset': 17, 'master': 73, 'splits': [[2, 25], [4, 31]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [2, 'yellow', 4]), ({'cycle': 105, 'offset': 65, 'master': 94, 'splits': [[2, 32], [4, 20], [6, 33], [8, 15]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 43, 'offset': 9, 'master': 403, 'splits': [[2, 15], [4, 28]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'green', 3]), ({'cycle': 102, 'offset': 65, 'master': 146, 'splits': [[2, 29], [4, 16], [6, 27], [8, 30]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [2, 'green', 21]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 99, 'offset': 95, 'master': 689, 'splits': [[2, 39], [4, 32], [6, 28]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'green', 34]), ({'cycle': 69, 'offset': 37, 'master': 680, 'splits': [[2, 31], [4, 38]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'green', 16]), ({'cycle': 78, 'offset': 0, 'master': 597, 'splits': [[2, 27], [4, 16], [6, 35]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [6, 'green', 21]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 72, 'offset': 22, 'master': 392, 'splits': [[2, 23], [4, 30], [6, 19]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'green', 20]), ({'cycle': 72, 'offset': 34, 'master': 687, 'splits': [[2, 32], [4, 40]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'red', 1]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 70, 'offset': 26, 'master': 359, 'splits': [[2, 38], [4, 32]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [2, 'green', 17]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 112, 'offset': 45, 'master': 656, 'splits': [[2, 29], [4, 39], [6, 25], [8, 19]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [4, 'green', 11]), ({'cycle': 140, 'offset': 33, 'master': 792, 'splits': [[2, 35], [4, 37], [6, 35], [8, 33]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'green', 13]), ({'cycle': 59, 'offset': 32, 'master': 537, 'splits': [[2, 21], [4, 18], [6, 20]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [4, 'green', 1]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 93, 'offset': 2, 'master': 972, 'splits': [[2, 40], [4, 36], [6, 17]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'red', 1])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if sum(s for _, s in sp) != C:
        return 'bad-splits'
    lc = (x['master'] - x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc + sp[0][1]) % C
    start = 0
    for ph, s in sp:
        ge = start + s - y - r
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', ge + y - lc]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 105, 'offset': 35, 'master': 4, 'splits': [[2, 37], [4, 29], [6, 39]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [6, 'green', 26]), ({'cycle': 116, 'offset': 95, 'master': 503, 'splits': [[2, 32], [4, 37], [6, 31], [8, 16]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [4, 'green', 5]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 46, 'offset': 4, 'master': 249, 'splits': [[2, 15], [4, 31]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [4, 'green', 27]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 74, 'offset': 17, 'master': 890, 'splits': [[2, 21], [4, 29], [6, 24]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'green', 15]), ({'cycle': 126, 'offset': 79, 'master': 132, 'splits': [[2, 32], [4, 37], [6, 40], [8, 17]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [6, 'green', 24])], [({'cycle': 84, 'offset': 40, 'master': 210, 'splits': [[2, 39], [4, 14], [6, 31]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 32]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 39, 'offset': 16, 'master': 927, 'splits': [[2, 16], [4, 23]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'yellow', 1]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 44, 'offset': 26, 'master': 566, 'splits': [[2, 32], [4, 12]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'yellow', 4]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 94, 'offset': 81, 'master': 161, 'splits': [[2, 32], [4, 26], [6, 36]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [2, 'green', 14]), ({'cycle': 56, 'offset': 16, 'master': 493, 'splits': [[2, 27], [4, 29]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [4, 'green', 21])], [({'cycle': 69, 'offset': 41, 'master': 89, 'splits': [[2, 30], [4, 39]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [4, 'green', 16]), ({'cycle': 56, 'offset': 17, 'master': 73, 'splits': [[2, 25], [4, 31]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [2, 'yellow', 4]), ({'cycle': 105, 'offset': 65, 'master': 94, 'splits': [[2, 32], [4, 20], [6, 33], [8, 15]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 43, 'offset': 9, 'master': 403, 'splits': [[2, 15], [4, 28]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'green', 3]), ({'cycle': 102, 'offset': 65, 'master': 146, 'splits': [[2, 29], [4, 16], [6, 27], [8, 30]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [2, 'green', 21]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 99, 'offset': 95, 'master': 689, 'splits': [[2, 39], [4, 32], [6, 28]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'green', 34]), ({'cycle': 69, 'offset': 37, 'master': 680, 'splits': [[2, 31], [4, 38]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'green', 16]), ({'cycle': 78, 'offset': 0, 'master': 597, 'splits': [[2, 27], [4, 16], [6, 35]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [6, 'green', 21]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 72, 'offset': 22, 'master': 392, 'splits': [[2, 23], [4, 30], [6, 19]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'green', 20]), ({'cycle': 72, 'offset': 34, 'master': 687, 'splits': [[2, 32], [4, 40]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'red', 1]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 70, 'offset': 26, 'master': 359, 'splits': [[2, 38], [4, 32]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [2, 'green', 17]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 112, 'offset': 45, 'master': 656, 'splits': [[2, 29], [4, 39], [6, 25], [8, 19]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [4, 'green', 11]), ({'cycle': 140, 'offset': 33, 'master': 792, 'splits': [[2, 35], [4, 37], [6, 35], [8, 33]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'green', 13]), ({'cycle': 59, 'offset': 32, 'master': 537, 'splits': [[2, 21], [4, 18], [6, 20]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [4, 'green', 1]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 93, 'offset': 2, 'master': 972, 'splits': [[2, 40], [4, 36], [6, 17]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'red', 1])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Coordinated local cycle timer returns a wrong result when end-of-green offsets are shifted in the wrong direction.

Input {cycle, offset, master, splits: [[phase, split s]] in sequence starting with the coordinated phase, yellow, red, ref}. Splits must sum to the cycle, else 'bad-splits'. Local time = (master - offset) mod cycle, where the offset marks the start of coordinated green (ref 'begin') or the end of coordinated green (ref 'end'). Each split is green then yellow then all-red. Return [phase, interval, seconds remaining].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if sum(s for _, s in sp) != C:
        return 'bad-splits'
    lc = (x['master'] - x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc + sp[0][1] - y - r) % C
    start = 0
    for ph, s in sp:
        ge = start + s - y
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', ge + y - lc]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 102, 'offset': 93, 'master': 365, 'splits': [[2, 23], [4, 36], [6, 27], [8, 21]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 77, 'offset': 52, 'master': 478, 'splits': [[2, 16], [4, 35], [6, 31]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 69, 'offset': 26, 'master': 109, 'splits': [[2, 29], [4, 40]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [4, 'green', 26]), ({'cycle': 56, 'offset': 40, 'master': 328, 'splits': [[2, 20], [4, 18], [6, 13]], 'yellow': 3, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 101, 'offset': 45, 'master': 754, 'splits': [[2, 37], [4, 34], [6, 18], [8, 12]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 30]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits')], [({'cycle': 80, 'offset': 58, 'master': 397, 'splits': [[2, 13], [4, 12], [6, 28], [8, 32]], 'yellow': 3, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 90, 'offset': 36, 'master': 162, 'splits': [[2, 34], [4, 28], [6, 16], [8, 17]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 116, 'offset': 2, 'master': 729, 'splits': [[2, 32], [4, 38], [6, 29], [8, 17]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'green', 7]), ({'cycle': 45, 'offset': 12, 'master': 489, 'splits': [[2, 17], [4, 33]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 97, 'offset': 25, 'master': 957, 'splits': [[2, 37], [4, 38], [6, 22]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [6, 'green', 1]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10])], [({'cycle': 118, 'offset': 70, 'master': 343, 'splits': [[2, 39], [4, 20], [6, 26], [8, 28]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 81, 'offset': 45, 'master': 213, 'splits': [[2, 40], [4, 18], [6, 18]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 53, 'offset': 19, 'master': 297, 'splits': [[2, 23], [4, 30]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [4, 'green', 17]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 82, 'offset': 1, 'master': 853, 'splits': [[2, 29], [4, 36], [6, 22]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 91, 'offset': 88, 'master': 494, 'splits': [[2, 35], [4, 34], [6, 22]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'green', 14]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 58, 'offset': 8, 'master': 318, 'splits': [[2, 32], [4, 26]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'green', 7]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 26, 'offset': 5, 'master': 373, 'splits': [[2, 19], [4, 12]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 58, 'offset': 47, 'master': 814, 'splits': [[2, 40], [4, 13]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 119, 'offset': 49, 'master': 964, 'splits': [[2, 40], [4, 38], [6, 28], [8, 13]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [8, 'red', 2]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 113, 'offset': 43, 'master': 818, 'splits': [[2, 31], [4, 27], [6, 20], [8, 40]], 'yellow': 3, 'red': 2, 'ref': 'end'}, 'bad-splits')], [({'cycle': 63, 'offset': 45, 'master': 684, 'splits': [[2, 15], [4, 21], [6, 32]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 85, 'offset': 19, 'master': 704, 'splits': [[2, 30], [4, 29], [6, 26]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 24]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 103, 'offset': 26, 'master': 254, 'splits': [[2, 35], [4, 31], [6, 37]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [4, 'green', 9]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 96, 'offset': 11, 'master': 271, 'splits': [[2, 23], [4, 18], [6, 24], [8, 36]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 49, 'offset': 34, 'master': 885, 'splits': [[2, 17], [4, 37]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits')]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if sum(s for _, s in sp) != C:
        return 'bad-splits'
    lc = (x['master'] - x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc + sp[0][1] - y - r) % C
    start = 0
    for ph, s in sp:
        ge = start + s - max(y, r)
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', ge + y - lc]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 102, 'offset': 93, 'master': 365, 'splits': [[2, 23], [4, 36], [6, 27], [8, 21]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 77, 'offset': 52, 'master': 478, 'splits': [[2, 16], [4, 35], [6, 31]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 69, 'offset': 26, 'master': 109, 'splits': [[2, 29], [4, 40]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [4, 'green', 26]), ({'cycle': 56, 'offset': 40, 'master': 328, 'splits': [[2, 20], [4, 18], [6, 13]], 'yellow': 3, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 101, 'offset': 45, 'master': 754, 'splits': [[2, 37], [4, 34], [6, 18], [8, 12]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 30]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits')], [({'cycle': 80, 'offset': 58, 'master': 397, 'splits': [[2, 13], [4, 12], [6, 28], [8, 32]], 'yellow': 3, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 90, 'offset': 36, 'master': 162, 'splits': [[2, 34], [4, 28], [6, 16], [8, 17]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 116, 'offset': 2, 'master': 729, 'splits': [[2, 32], [4, 38], [6, 29], [8, 17]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'green', 7]), ({'cycle': 45, 'offset': 12, 'master': 489, 'splits': [[2, 17], [4, 33]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 97, 'offset': 25, 'master': 957, 'splits': [[2, 37], [4, 38], [6, 22]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [6, 'green', 1]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10])], [({'cycle': 118, 'offset': 70, 'master': 343, 'splits': [[2, 39], [4, 20], [6, 26], [8, 28]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 81, 'offset': 45, 'master': 213, 'splits': [[2, 40], [4, 18], [6, 18]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 53, 'offset': 19, 'master': 297, 'splits': [[2, 23], [4, 30]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [4, 'green', 17]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 82, 'offset': 1, 'master': 853, 'splits': [[2, 29], [4, 36], [6, 22]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 91, 'offset': 88, 'master': 494, 'splits': [[2, 35], [4, 34], [6, 22]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'green', 14]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 58, 'offset': 8, 'master': 318, 'splits': [[2, 32], [4, 26]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'green', 7]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 26, 'offset': 5, 'master': 373, 'splits': [[2, 19], [4, 12]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 58, 'offset': 47, 'master': 814, 'splits': [[2, 40], [4, 13]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 119, 'offset': 49, 'master': 964, 'splits': [[2, 40], [4, 38], [6, 28], [8, 13]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [8, 'red', 2]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 113, 'offset': 43, 'master': 818, 'splits': [[2, 31], [4, 27], [6, 20], [8, 40]], 'yellow': 3, 'red': 2, 'ref': 'end'}, 'bad-splits')], [({'cycle': 63, 'offset': 45, 'master': 684, 'splits': [[2, 15], [4, 21], [6, 32]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 85, 'offset': 19, 'master': 704, 'splits': [[2, 30], [4, 29], [6, 26]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 24]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 103, 'offset': 26, 'master': 254, 'splits': [[2, 35], [4, 31], [6, 37]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [4, 'green', 9]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 96, 'offset': 11, 'master': 271, 'splits': [[2, 23], [4, 18], [6, 24], [8, 36]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 49, 'offset': 34, 'master': 885, 'splits': [[2, 17], [4, 37]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits')]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Coordinated local cycle timer returns a wrong result when only the yellow is subtracted from the split to find green end.

Input {cycle, offset, master, splits: [[phase, split s]] in sequence starting with the coordinated phase, yellow, red, ref}. Splits must sum to the cycle, else 'bad-splits'. Local time = (master - offset) mod cycle, where the offset marks the start of coordinated green (ref 'begin') or the end of coordinated green (ref 'end'). Each split is green then yellow then all-red. Return [phase, interval, seconds remaining].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if sum(s for _, s in sp) > C:
        return 'bad-splits'
    lc = (x['master'] - x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc + sp[0][1] - y - r) % C
    start = 0
    for ph, s in sp:
        ge = start + s - y - r
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', ge + y - lc]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 92, 'offset': 61, 'master': 911, 'splits': [[2, 16], [4, 40], [6, 36]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 18]), ({'cycle': 110, 'offset': 102, 'master': 693, 'splits': [[2, 36], [4, 32], [6, 37]], 'yellow': 3, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 125, 'offset': 116, 'master': 414, 'splits': [[2, 28], [4, 36], [6, 34], [8, 22]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 69, 'offset': 24, 'master': 562, 'splits': [[2, 25], [4, 26], [6, 13]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 117, 'offset': 57, 'master': 934, 'splits': [[2, 29], [4, 30], [6, 27], [8, 36]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 93, 'offset': 12, 'master': 316, 'splits': [[2, 40], [4, 30], [6, 13], [8, 15]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 97, 'offset': 24, 'master': 364, 'splits': [[2, 13], [4, 26], [6, 16], [8, 37]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 96, 'offset': 7, 'master': 143, 'splits': [[2, 26], [4, 33], [6, 32]], 'yellow': 3, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 102, 'offset': 99, 'master': 769, 'splits': [[2, 32], [4, 35], [6, 16], [8, 14]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 72, 'offset': 54, 'master': 138, 'splits': [[2, 13], [4, 34], [6, 25]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [2, 'red', 1])], [({'cycle': 88, 'offset': 68, 'master': 958, 'splits': [[2, 30], [4, 14], [6, 39]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 125, 'offset': 19, 'master': 173, 'splits': [[2, 24], [4, 35], [6, 32], [8, 29]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 77, 'offset': 17, 'master': 15, 'splits': [[2, 12], [4, 17], [6, 30], [8, 18]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [8, 'red', 2]), ({'cycle': 73, 'offset': 16, 'master': 221, 'splits': [[2, 22], [4, 12], [6, 34]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 45, 'offset': 36, 'master': 84, 'splits': [[2, 26], [4, 19]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [2, 'red', 2]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 114, 'offset': 64, 'master': 776, 'splits': [[2, 27], [4, 31], [6, 21], [8, 30]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 64, 'offset': 7, 'master': 813, 'splits': [[2, 18], [4, 26], [6, 20]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [4, 'yellow', 4]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 98, 'offset': 4, 'master': 47, 'splits': [[2, 39], [4, 12], [6, 31], [8, 16]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'yellow', 3]), ({'cycle': 72, 'offset': 25, 'master': 319, 'splits': [[2, 37], [4, 30]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 108, 'offset': 82, 'master': 957, 'splits': [[2, 21], [4, 30], [6, 34], [8, 18]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 96, 'offset': 76, 'master': 103, 'splits': [[2, 16], [4, 32], [6, 14], [8, 29]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 87, 'offset': 58, 'master': 226, 'splits': [[2, 19], [4, 16], [6, 19], [8, 28]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 125, 'offset': 21, 'master': 401, 'splits': [[2, 14], [4, 40], [6, 32], [8, 34]], 'yellow': 3, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 51, 'offset': 43, 'master': 478, 'splits': [[2, 38], [4, 18]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 79, 'offset': 42, 'master': 241, 'splits': [[2, 27], [4, 37], [6, 15]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [4, 'red', 2])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if max(s for _, s in sp) > C:
        return 'bad-splits'
    lc = (x['master'] - x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc + sp[0][1] - y - r) % C
    start = 0
    for ph, s in sp:
        ge = start + s - y - r
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', ge + y - lc]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 92, 'offset': 61, 'master': 911, 'splits': [[2, 16], [4, 40], [6, 36]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 18]), ({'cycle': 110, 'offset': 102, 'master': 693, 'splits': [[2, 36], [4, 32], [6, 37]], 'yellow': 3, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 125, 'offset': 116, 'master': 414, 'splits': [[2, 28], [4, 36], [6, 34], [8, 22]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 69, 'offset': 24, 'master': 562, 'splits': [[2, 25], [4, 26], [6, 13]], 'yellow': 4, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 117, 'offset': 57, 'master': 934, 'splits': [[2, 29], [4, 30], [6, 27], [8, 36]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 93, 'offset': 12, 'master': 316, 'splits': [[2, 40], [4, 30], [6, 13], [8, 15]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 97, 'offset': 24, 'master': 364, 'splits': [[2, 13], [4, 26], [6, 16], [8, 37]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 96, 'offset': 7, 'master': 143, 'splits': [[2, 26], [4, 33], [6, 32]], 'yellow': 3, 'red': 1, 'ref': 'end'}, 'bad-splits'), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 102, 'offset': 99, 'master': 769, 'splits': [[2, 32], [4, 35], [6, 16], [8, 14]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 72, 'offset': 54, 'master': 138, 'splits': [[2, 13], [4, 34], [6, 25]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [2, 'red', 1])], [({'cycle': 88, 'offset': 68, 'master': 958, 'splits': [[2, 30], [4, 14], [6, 39]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 125, 'offset': 19, 'master': 173, 'splits': [[2, 24], [4, 35], [6, 32], [8, 29]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 77, 'offset': 17, 'master': 15, 'splits': [[2, 12], [4, 17], [6, 30], [8, 18]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [8, 'red', 2]), ({'cycle': 73, 'offset': 16, 'master': 221, 'splits': [[2, 22], [4, 12], [6, 34]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 45, 'offset': 36, 'master': 84, 'splits': [[2, 26], [4, 19]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [2, 'red', 2]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 114, 'offset': 64, 'master': 776, 'splits': [[2, 27], [4, 31], [6, 21], [8, 30]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 64, 'offset': 7, 'master': 813, 'splits': [[2, 18], [4, 26], [6, 20]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [4, 'yellow', 4]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 98, 'offset': 4, 'master': 47, 'splits': [[2, 39], [4, 12], [6, 31], [8, 16]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'yellow', 3]), ({'cycle': 72, 'offset': 25, 'master': 319, 'splits': [[2, 37], [4, 30]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 108, 'offset': 82, 'master': 957, 'splits': [[2, 21], [4, 30], [6, 34], [8, 18]], 'yellow': 4, 'red': 2, 'ref': 'end'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 96, 'offset': 76, 'master': 103, 'splits': [[2, 16], [4, 32], [6, 14], [8, 29]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 87, 'offset': 58, 'master': 226, 'splits': [[2, 19], [4, 16], [6, 19], [8, 28]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 125, 'offset': 21, 'master': 401, 'splits': [[2, 14], [4, 40], [6, 32], [8, 34]], 'yellow': 3, 'red': 2, 'ref': 'end'}, 'bad-splits'), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 51, 'offset': 43, 'master': 478, 'splits': [[2, 38], [4, 18]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 79, 'offset': 42, 'master': 241, 'splits': [[2, 27], [4, 37], [6, 15]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [4, 'red', 2])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Coordinated local cycle timer returns a wrong result when splits shorter than the cycle are accepted.

Input {cycle, offset, master, splits: [[phase, split s]] in sequence starting with the coordinated phase, yellow, red, ref}. Splits must sum to the cycle, else 'bad-splits'. Local time = (master - offset) mod cycle, where the offset marks the start of coordinated green (ref 'begin') or the end of coordinated green (ref 'end'). Each split is green then yellow then all-red. Return [phase, interval, seconds remaining].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if sum(s for _, s in sp) != C:
        return 'bad-splits'
    lc = (x['master'] - x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc + sp[0][1] - y - r) % C
    start = 0
    for ph, s in sp:
        ge = start + s - y - r
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', y]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 42, 'offset': 22, 'master': 276, 'splits': [[2, 30], [4, 12]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [2, 'yellow', 2]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 67, 'offset': 15, 'master': 313, 'splits': [[2, 40], [4, 27]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [4, 'yellow', 1]), ({'cycle': 90, 'offset': 55, 'master': 1000, 'splits': [[2, 18], [4, 18], [6, 24], [8, 30]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [6, 'yellow', 1]), ({'cycle': 118, 'offset': 26, 'master': 74, 'splits': [[2, 40], [4, 22], [6, 21], [8, 35]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [4, 'green', 9]), ({'cycle': 30, 'offset': 8, 'master': 32, 'splits': [[2, 14], [4, 16]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [4, 'green', 1]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 88, 'offset': 76, 'master': 606, 'splits': [[2, 19], [4, 33], [6, 23], [8, 13]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'yellow', 2]), ({'cycle': 52, 'offset': 51, 'master': 207, 'splits': [[2, 22], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [2, 'yellow', 3]), ({'cycle': 64, 'offset': 4, 'master': 173, 'splits': [[2, 28], [4, 16], [6, 20]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [4, 'yellow', 2]), ({'cycle': 98, 'offset': 74, 'master': 280, 'splits': [[2, 30], [4, 21], [6, 14], [8, 33]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 15]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 42, 'offset': 32, 'master': 833, 'splits': [[2, 27], [4, 15]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'yellow', 1])], [({'cycle': 57, 'offset': 37, 'master': 74, 'splits': [[2, 22], [4, 16], [6, 19]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'yellow', 1]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 54, 'offset': 4, 'master': 576, 'splits': [[2, 35], [4, 19]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'yellow', 1]), ({'cycle': 76, 'offset': 48, 'master': 580, 'splits': [[2, 36], [4, 40]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'yellow', 4]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 64, 'offset': 4, 'master': 283, 'splits': [[2, 25], [4, 39]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'yellow', 1]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 86, 'offset': 58, 'master': 977, 'splits': [[2, 31], [4, 19], [6, 36]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [2, 'green', 27])], [({'cycle': 51, 'offset': 44, 'master': 5, 'splits': [[2, 16], [4, 35]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [2, 'yellow', 2]), ({'cycle': 116, 'offset': 89, 'master': 203, 'splits': [[2, 19], [4, 29], [6, 36], [8, 32]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [8, 'yellow', 1]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 88, 'offset': 39, 'master': 770, 'splits': [[2, 29], [4, 25], [6, 34]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [2, 'yellow', 1]), ({'cycle': 37, 'offset': 13, 'master': 804, 'splits': [[2, 19], [4, 18]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'yellow', 3]), ({'cycle': 86, 'offset': 61, 'master': 865, 'splits': [[2, 31], [4, 35], [6, 20]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'green', 5]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 47, 'offset': 23, 'master': 37, 'splits': [[2, 25], [4, 22]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 6]), ({'cycle': 86, 'offset': 78, 'master': 997, 'splits': [[2, 29], [4, 32], [6, 25]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'yellow', 1]), ({'cycle': 78, 'offset': 64, 'master': 139, 'splits': [[2, 14], [4, 15], [6, 36], [8, 13]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [8, 'yellow', 1]), ({'cycle': 82, 'offset': 44, 'master': 456, 'splits': [[2, 32], [4, 23], [6, 27]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'yellow', 2]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 69, 'offset': 12, 'master': 586, 'splits': [[2, 18], [4, 33], [6, 23]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits')]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    sp = x['splits']
    y, r = x['yellow'], x['red']
    if sum(s for _, s in sp) != C:
        return 'bad-splits'
    lc = (x['master'] - x['offset']) % C
    if x['ref'] == 'end':
        lc = (lc + sp[0][1] - y - r) % C
    start = 0
    for ph, s in sp:
        ge = start + s - y - r
        if lc < ge:
            return [ph, 'green', ge - lc]
        if lc < ge + y:
            return [ph, 'yellow', ge + y - lc - 1]
        if lc < start + s:
            return [ph, 'red', start + s - lc]
        start += s
    return ['free', 'dark', 0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 42, 'offset': 22, 'master': 276, 'splits': [[2, 30], [4, 12]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [2, 'yellow', 2]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 67, 'offset': 15, 'master': 313, 'splits': [[2, 40], [4, 27]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [4, 'yellow', 1]), ({'cycle': 90, 'offset': 55, 'master': 1000, 'splits': [[2, 18], [4, 18], [6, 24], [8, 30]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [6, 'yellow', 1]), ({'cycle': 118, 'offset': 26, 'master': 74, 'splits': [[2, 40], [4, 22], [6, 21], [8, 35]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [4, 'green', 9]), ({'cycle': 30, 'offset': 8, 'master': 32, 'splits': [[2, 14], [4, 16]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [4, 'green', 1]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25])], [({'cycle': 88, 'offset': 76, 'master': 606, 'splits': [[2, 19], [4, 33], [6, 23], [8, 13]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'yellow', 2]), ({'cycle': 52, 'offset': 51, 'master': 207, 'splits': [[2, 22], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [2, 'yellow', 3]), ({'cycle': 64, 'offset': 4, 'master': 173, 'splits': [[2, 28], [4, 16], [6, 20]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [4, 'yellow', 2]), ({'cycle': 98, 'offset': 74, 'master': 280, 'splits': [[2, 30], [4, 21], [6, 14], [8, 33]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 15]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 42, 'offset': 32, 'master': 833, 'splits': [[2, 27], [4, 15]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'yellow', 1])], [({'cycle': 57, 'offset': 37, 'master': 74, 'splits': [[2, 22], [4, 16], [6, 19]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'yellow', 1]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 54, 'offset': 4, 'master': 576, 'splits': [[2, 35], [4, 19]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'yellow', 1]), ({'cycle': 76, 'offset': 48, 'master': 580, 'splits': [[2, 36], [4, 40]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'yellow', 4]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 64, 'offset': 4, 'master': 283, 'splits': [[2, 25], [4, 39]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [2, 'yellow', 1]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 86, 'offset': 58, 'master': 977, 'splits': [[2, 31], [4, 19], [6, 36]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [2, 'green', 27])], [({'cycle': 51, 'offset': 44, 'master': 5, 'splits': [[2, 16], [4, 35]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [2, 'yellow', 2]), ({'cycle': 116, 'offset': 89, 'master': 203, 'splits': [[2, 19], [4, 29], [6, 36], [8, 32]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, [8, 'yellow', 1]), ({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 88, 'offset': 39, 'master': 770, 'splits': [[2, 29], [4, 25], [6, 34]], 'yellow': 3, 'red': 1, 'ref': 'begin'}, [2, 'yellow', 1]), ({'cycle': 37, 'offset': 13, 'master': 804, 'splits': [[2, 19], [4, 18]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'yellow', 3]), ({'cycle': 86, 'offset': 61, 'master': 865, 'splits': [[2, 31], [4, 35], [6, 20]], 'yellow': 3, 'red': 2, 'ref': 'end'}, [4, 'green', 5]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits')], [({'cycle': 80, 'offset': 70, 'master': 10, 'splits': [[2, 50], [4, 30]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 25]), ({'cycle': 47, 'offset': 23, 'master': 37, 'splits': [[2, 25], [4, 22]], 'yellow': 3, 'red': 2, 'ref': 'begin'}, [2, 'green', 6]), ({'cycle': 86, 'offset': 78, 'master': 997, 'splits': [[2, 29], [4, 32], [6, 25]], 'yellow': 3, 'red': 1, 'ref': 'end'}, [6, 'yellow', 1]), ({'cycle': 78, 'offset': 64, 'master': 139, 'splits': [[2, 14], [4, 15], [6, 36], [8, 13]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, [8, 'yellow', 1]), ({'cycle': 82, 'offset': 44, 'master': 456, 'splits': [[2, 32], [4, 23], [6, 27]], 'yellow': 4, 'red': 2, 'ref': 'end'}, [2, 'yellow', 2]), ({'cycle': 90, 'offset': 30, 'master': 45, 'splits': [[2, 40], [4, 25], [6, 25]], 'yellow': 4, 'red': 1, 'ref': 'end'}, [4, 'green', 10]), ({'cycle': 100, 'offset': 5, 'master': 3, 'splits': [[2, 50], [4, 30], [8, 25]], 'yellow': 4, 'red': 2, 'ref': 'begin'}, 'bad-splits'), ({'cycle': 69, 'offset': 12, 'master': 586, 'splits': [[2, 18], [4, 33], [6, 23]], 'yellow': 4, 'red': 1, 'ref': 'begin'}, 'bad-splits')]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Coordinated local cycle timer returns a wrong result when the full yellow is reported regardless of elapsed yellow.

Input {cycle, offset, master, splits: [[phase, split s]] in sequence starting with the coordinated phase, yellow, red, ref}. Splits must sum to the cycle, else 'bad-splits'. Local time = (master - offset) mod cycle, where the offset marks the start of coordinated green (ref 'begin') or the end of coordinated green (ref 'end'). Each split is green then yellow then all-red. Return [phase, interval, seconds remaining].

split: open-access