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

N = 1
observations = []
def solve(x):
    T = x['release_s']
    state = 'free'
    until = None
    approach = False
    out = []
    for t, kind in x['events']:
        if state == 'locked' and t >= until:
            state = 'free'
        if kind == 'approach_occ':
            approach = True
        elif kind == 'approach_clear':
            pass
        elif kind == 'set' and state == 'free':
            state = 'set'
        elif kind == 'cancel' and state == 'set':
            if approach:
                state = 'locked'
                until = t + T
            else:
                state = 'free'
        elif kind == 'pass_signal':
            approach = False
            if state == 'set':
                state = 'in-use'
        elif kind == 'train_clear' and state == 'in-use':
            state = 'free'
        elif kind == 'query':
            out.append('locked-until:%d' % until if state == 'locked' else state)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('control 1', {'release_s': 120, 'events': [[120, 'query'], [125, 'set'], [185, 'set'], [215, 'pass_signal'], [275, 'query'], [475, 'query']]}, ['free', 'in-use', 'in-use']), ('control 4', {'release_s': 60, 'events': [[30, 'query'], [60, 'query'], [120, 'query'], [180, 'cancel'], [240, 'query'], [245, 'approach_occ'], [445, 'query']]}, ['free', 'free', 'free', 'free', 'free']), ('control 7', {'release_s': 120, 'events': [[0, 'cancel'], [0, 'query'], [0, 'approach_occ'], [1, 'set'], [11, 'approach_clear'], [41, 'query'], [42, 'approach_occ'], [242, 'query']]}, ['free', 'set', 'set'])], [('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('sampled regression 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 12', {'release_s': 120, 'events': [[1, 'query'], [121, 'approach_clear'], [241, 'set'], [271, 'set'], [391, 'approach_occ'], [451, 'query']]}, ['free', 'set']), ('control 15', {'release_s': 60, 'events': [[5, 'set'], [6, 'query'], [6, 'cancel'], [36, 'set'], [46, 'query'], [106, 'approach_clear'], [226, 'query'], [227, 'query'], [237, 'query'], [267, 'set'], [327, 'set'], [327, 'query']]}, ['set', 'set', 'set', 'set', 'set', 'set']), ('sampled regression 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set'])], [('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('sampled regression 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('control 23', {'release_s': 60, 'events': [[10, 'cancel'], [15, 'set'], [25, 'approach_occ'], [26, 'set'], [36, 'cancel'], [156, 'query']]}, ['free']), ('control 26', {'release_s': 60, 'events': [[1, 'approach_occ'], [6, 'set'], [66, 'set'], [66, 'cancel'], [96, 'query'], [106, 'approach_clear'], [136, 'query'], [141, 'approach_clear'], [151, 'approach_occ'], [211, 'train_clear'], [271, 'query']]}, ['locked-until:126', 'free', 'free']), ('control 29', {'release_s': 60, 'events': [[0, 'set'], [0, 'set'], [30, 'train_clear'], [40, 'set'], [40, 'query'], [100, 'cancel'], [110, 'approach_occ'], [170, 'query']]}, ['set', 'free'])], [('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('control 34', {'release_s': 120, 'events': [[120, 'set'], [121, 'set'], [121, 'cancel'], [241, 'approach_occ'], [361, 'pass_signal'], [371, 'cancel'], [491, 'approach_occ'], [611, 'query']]}, ['free']), ('control 37', {'release_s': 60, 'events': [[60, 'query'], [61, 'train_clear'], [71, 'set'], [131, 'train_clear'], [131, 'pass_signal'], [136, 'approach_occ'], [196, 'set'], [197, 'cancel'], [202, 'set'], [262, 'train_clear'], [382, 'query'], [382, 'query']]}, ['free', 'free', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425'])], [('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('sampled regression 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('control 48', {'release_s': 60, 'events': [[120, 'set'], [121, 'train_clear'], [122, 'set'], [242, 'query'], [242, 'query'], [252, 'pass_signal'], [257, 'approach_occ'], [257, 'query']]}, ['set', 'set', 'in-use']), ('control 51', {'release_s': 60, 'events': [[120, 'pass_signal'], [120, 'cancel'], [125, 'approach_clear'], [126, 'cancel'], [136, 'cancel'], [256, 'approach_clear'], [316, 'pass_signal'], [376, 'query'], [377, 'query'], [387, 'cancel'], [387, 'query']]}, ['free', 'free', 'free'])]]
for label, args, expected in fixtures[N-1]:
    check(label, 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):
    T = x['release_s']
    state = 'free'
    until = None
    approach = False
    out = []
    for t, kind in x['events']:
        if state == 'locked' and t >= until:
            state = 'free'
        if kind == 'approach_occ':
            approach = True
        elif kind == 'approach_clear' and state != 'set':
            approach = False
        elif kind == 'set' and state == 'free':
            state = 'set'
        elif kind == 'cancel' and state == 'set':
            if approach:
                state = 'locked'
                until = t + T
            else:
                state = 'free'
        elif kind == 'pass_signal':
            approach = False
            if state == 'set':
                state = 'in-use'
        elif kind == 'train_clear' and state == 'in-use':
            state = 'free'
        elif kind == 'query':
            out.append('locked-until:%d' % until if state == 'locked' else state)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('control 1', {'release_s': 120, 'events': [[120, 'query'], [125, 'set'], [185, 'set'], [215, 'pass_signal'], [275, 'query'], [475, 'query']]}, ['free', 'in-use', 'in-use']), ('control 4', {'release_s': 60, 'events': [[30, 'query'], [60, 'query'], [120, 'query'], [180, 'cancel'], [240, 'query'], [245, 'approach_occ'], [445, 'query']]}, ['free', 'free', 'free', 'free', 'free']), ('control 7', {'release_s': 120, 'events': [[0, 'cancel'], [0, 'query'], [0, 'approach_occ'], [1, 'set'], [11, 'approach_clear'], [41, 'query'], [42, 'approach_occ'], [242, 'query']]}, ['free', 'set', 'set'])], [('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('sampled regression 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 12', {'release_s': 120, 'events': [[1, 'query'], [121, 'approach_clear'], [241, 'set'], [271, 'set'], [391, 'approach_occ'], [451, 'query']]}, ['free', 'set']), ('control 15', {'release_s': 60, 'events': [[5, 'set'], [6, 'query'], [6, 'cancel'], [36, 'set'], [46, 'query'], [106, 'approach_clear'], [226, 'query'], [227, 'query'], [237, 'query'], [267, 'set'], [327, 'set'], [327, 'query']]}, ['set', 'set', 'set', 'set', 'set', 'set']), ('sampled regression 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set'])], [('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('sampled regression 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('control 23', {'release_s': 60, 'events': [[10, 'cancel'], [15, 'set'], [25, 'approach_occ'], [26, 'set'], [36, 'cancel'], [156, 'query']]}, ['free']), ('control 26', {'release_s': 60, 'events': [[1, 'approach_occ'], [6, 'set'], [66, 'set'], [66, 'cancel'], [96, 'query'], [106, 'approach_clear'], [136, 'query'], [141, 'approach_clear'], [151, 'approach_occ'], [211, 'train_clear'], [271, 'query']]}, ['locked-until:126', 'free', 'free']), ('control 29', {'release_s': 60, 'events': [[0, 'set'], [0, 'set'], [30, 'train_clear'], [40, 'set'], [40, 'query'], [100, 'cancel'], [110, 'approach_occ'], [170, 'query']]}, ['set', 'free'])], [('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('control 34', {'release_s': 120, 'events': [[120, 'set'], [121, 'set'], [121, 'cancel'], [241, 'approach_occ'], [361, 'pass_signal'], [371, 'cancel'], [491, 'approach_occ'], [611, 'query']]}, ['free']), ('control 37', {'release_s': 60, 'events': [[60, 'query'], [61, 'train_clear'], [71, 'set'], [131, 'train_clear'], [131, 'pass_signal'], [136, 'approach_occ'], [196, 'set'], [197, 'cancel'], [202, 'set'], [262, 'train_clear'], [382, 'query'], [382, 'query']]}, ['free', 'free', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425'])], [('regression: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('sampled regression 62', {'release_s': 120, 'events': [[1, 'pass_signal'], [6, 'cancel'], [126, 'approach_clear'], [131, 'set'], [141, 'approach_clear'], [171, 'train_clear'], [172, 'approach_occ'], [172, 'approach_clear'], [202, 'approach_clear'], [207, 'train_clear'], [217, 'cancel'], [247, 'train_clear'], [307, 'query']]}, ['free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('sampled regression 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('control 48', {'release_s': 60, 'events': [[120, 'set'], [121, 'train_clear'], [122, 'set'], [242, 'query'], [242, 'query'], [252, 'pass_signal'], [257, 'approach_occ'], [257, 'query']]}, ['set', 'set', 'in-use']), ('control 51', {'release_s': 60, 'events': [[120, 'pass_signal'], [120, 'cancel'], [125, 'approach_clear'], [126, 'cancel'], [136, 'cancel'], [256, 'approach_clear'], [316, 'pass_signal'], [376, 'query'], [377, 'query'], [387, 'cancel'], [387, 'query']]}, ['free', 'free', 'free'])]]
for label, args, expected in fixtures[N-1]:
    check(label, 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:
A route is approach-locked although the approaching train has already left.

A route can be set only when free. pass_signal moves a set route to in-use; train_clear frees an in-use route. Cancelling a set route frees it at once unless a train is in the approach section, in which case it is approach-locked until cancel time + release_s (released when an event time reaches the deadline). approach_occ/approach_clear track the approach section. query appends set, free, in-use or locked-until:<t>.

split: open-access


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

N = 1
observations = []
def solve(x):
    T = x['release_s']
    state = 'free'
    until = None
    approach = False
    out = []
    for t, kind in x['events']:
        if state == 'locked' and t >= until:
            state = 'free'
        if kind == 'approach_occ':
            approach = True
        elif kind == 'approach_clear':
            approach = False
        elif kind == 'set' and state == 'free':
            state = 'set'
        elif kind == 'cancel' and state == 'set':
            if approach:
                state = 'locked'
                until = t + T if until is None else until
            else:
                state = 'free'
        elif kind == 'pass_signal':
            approach = False
            if state == 'set':
                state = 'in-use'
        elif kind == 'train_clear' and state == 'in-use':
            state = 'free'
        elif kind == 'query':
            out.append('locked-until:%d' % until if state == 'locked' else state)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 1', {'release_s': 120, 'events': [[120, 'query'], [125, 'set'], [185, 'set'], [215, 'pass_signal'], [275, 'query'], [475, 'query']]}, ['free', 'in-use', 'in-use']), ('control 4', {'release_s': 60, 'events': [[30, 'query'], [60, 'query'], [120, 'query'], [180, 'cancel'], [240, 'query'], [245, 'approach_occ'], [445, 'query']]}, ['free', 'free', 'free', 'free', 'free']), ('control 7', {'release_s': 120, 'events': [[0, 'cancel'], [0, 'query'], [0, 'approach_occ'], [1, 'set'], [11, 'approach_clear'], [41, 'query'], [42, 'approach_occ'], [242, 'query']]}, ['free', 'set', 'set'])], [('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('control 12', {'release_s': 120, 'events': [[1, 'query'], [121, 'approach_clear'], [241, 'set'], [271, 'set'], [391, 'approach_occ'], [451, 'query']]}, ['free', 'set']), ('control 15', {'release_s': 60, 'events': [[5, 'set'], [6, 'query'], [6, 'cancel'], [36, 'set'], [46, 'query'], [106, 'approach_clear'], [226, 'query'], [227, 'query'], [237, 'query'], [267, 'set'], [327, 'set'], [327, 'query']]}, ['set', 'set', 'set', 'set', 'set', 'set']), ('control 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set'])], [('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('control 23', {'release_s': 60, 'events': [[10, 'cancel'], [15, 'set'], [25, 'approach_occ'], [26, 'set'], [36, 'cancel'], [156, 'query']]}, ['free']), ('control 26', {'release_s': 60, 'events': [[1, 'approach_occ'], [6, 'set'], [66, 'set'], [66, 'cancel'], [96, 'query'], [106, 'approach_clear'], [136, 'query'], [141, 'approach_clear'], [151, 'approach_occ'], [211, 'train_clear'], [271, 'query']]}, ['locked-until:126', 'free', 'free']), ('control 29', {'release_s': 60, 'events': [[0, 'set'], [0, 'set'], [30, 'train_clear'], [40, 'set'], [40, 'query'], [100, 'cancel'], [110, 'approach_occ'], [170, 'query']]}, ['set', 'free'])], [('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('control 34', {'release_s': 120, 'events': [[120, 'set'], [121, 'set'], [121, 'cancel'], [241, 'approach_occ'], [361, 'pass_signal'], [371, 'cancel'], [491, 'approach_occ'], [611, 'query']]}, ['free']), ('control 37', {'release_s': 60, 'events': [[60, 'query'], [61, 'train_clear'], [71, 'set'], [131, 'train_clear'], [131, 'pass_signal'], [136, 'approach_occ'], [196, 'set'], [197, 'cancel'], [202, 'set'], [262, 'train_clear'], [382, 'query'], [382, 'query']]}, ['free', 'free', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425'])], [('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('control 48', {'release_s': 60, 'events': [[120, 'set'], [121, 'train_clear'], [122, 'set'], [242, 'query'], [242, 'query'], [252, 'pass_signal'], [257, 'approach_occ'], [257, 'query']]}, ['set', 'set', 'in-use']), ('control 51', {'release_s': 60, 'events': [[120, 'pass_signal'], [120, 'cancel'], [125, 'approach_clear'], [126, 'cancel'], [136, 'cancel'], [256, 'approach_clear'], [316, 'pass_signal'], [376, 'query'], [377, 'query'], [387, 'cancel'], [387, 'query']]}, ['free', 'free', 'free'])]]
for label, args, expected in fixtures[N-1]:
    check(label, 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):
    T = x['release_s']
    state = 'free'
    until = None
    approach = False
    out = []
    for t, kind in x['events']:
        if state == 'locked' and t >= until:
            state = 'free'
        if kind == 'approach_occ':
            approach = True
        elif kind == 'approach_clear':
            approach = False
        elif kind == 'set' and state == 'free':
            state = 'set'
        elif kind == 'cancel' and state == 'set':
            if approach:
                state = 'locked'
                until = (until or t) + T
            else:
                state = 'free'
        elif kind == 'pass_signal':
            approach = False
            if state == 'set':
                state = 'in-use'
        elif kind == 'train_clear' and state == 'in-use':
            state = 'free'
        elif kind == 'query':
            out.append('locked-until:%d' % until if state == 'locked' else state)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 1', {'release_s': 120, 'events': [[120, 'query'], [125, 'set'], [185, 'set'], [215, 'pass_signal'], [275, 'query'], [475, 'query']]}, ['free', 'in-use', 'in-use']), ('control 4', {'release_s': 60, 'events': [[30, 'query'], [60, 'query'], [120, 'query'], [180, 'cancel'], [240, 'query'], [245, 'approach_occ'], [445, 'query']]}, ['free', 'free', 'free', 'free', 'free']), ('control 7', {'release_s': 120, 'events': [[0, 'cancel'], [0, 'query'], [0, 'approach_occ'], [1, 'set'], [11, 'approach_clear'], [41, 'query'], [42, 'approach_occ'], [242, 'query']]}, ['free', 'set', 'set'])], [('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('control 12', {'release_s': 120, 'events': [[1, 'query'], [121, 'approach_clear'], [241, 'set'], [271, 'set'], [391, 'approach_occ'], [451, 'query']]}, ['free', 'set']), ('control 15', {'release_s': 60, 'events': [[5, 'set'], [6, 'query'], [6, 'cancel'], [36, 'set'], [46, 'query'], [106, 'approach_clear'], [226, 'query'], [227, 'query'], [237, 'query'], [267, 'set'], [327, 'set'], [327, 'query']]}, ['set', 'set', 'set', 'set', 'set', 'set']), ('control 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set'])], [('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('control 23', {'release_s': 60, 'events': [[10, 'cancel'], [15, 'set'], [25, 'approach_occ'], [26, 'set'], [36, 'cancel'], [156, 'query']]}, ['free']), ('control 26', {'release_s': 60, 'events': [[1, 'approach_occ'], [6, 'set'], [66, 'set'], [66, 'cancel'], [96, 'query'], [106, 'approach_clear'], [136, 'query'], [141, 'approach_clear'], [151, 'approach_occ'], [211, 'train_clear'], [271, 'query']]}, ['locked-until:126', 'free', 'free']), ('control 29', {'release_s': 60, 'events': [[0, 'set'], [0, 'set'], [30, 'train_clear'], [40, 'set'], [40, 'query'], [100, 'cancel'], [110, 'approach_occ'], [170, 'query']]}, ['set', 'free'])], [('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('control 34', {'release_s': 120, 'events': [[120, 'set'], [121, 'set'], [121, 'cancel'], [241, 'approach_occ'], [361, 'pass_signal'], [371, 'cancel'], [491, 'approach_occ'], [611, 'query']]}, ['free']), ('control 37', {'release_s': 60, 'events': [[60, 'query'], [61, 'train_clear'], [71, 'set'], [131, 'train_clear'], [131, 'pass_signal'], [136, 'approach_occ'], [196, 'set'], [197, 'cancel'], [202, 'set'], [262, 'train_clear'], [382, 'query'], [382, 'query']]}, ['free', 'free', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425'])], [('regression: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('control 48', {'release_s': 60, 'events': [[120, 'set'], [121, 'train_clear'], [122, 'set'], [242, 'query'], [242, 'query'], [252, 'pass_signal'], [257, 'approach_occ'], [257, 'query']]}, ['set', 'set', 'in-use']), ('control 51', {'release_s': 60, 'events': [[120, 'pass_signal'], [120, 'cancel'], [125, 'approach_clear'], [126, 'cancel'], [136, 'cancel'], [256, 'approach_clear'], [316, 'pass_signal'], [376, 'query'], [377, 'query'], [387, 'cancel'], [387, 'query']]}, ['free', 'free', 'free'])]]
for label, args, expected in fixtures[N-1]:
    check(label, 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:
A second approach lock reports the deadline of an earlier lock.

A route can be set only when free. pass_signal moves a set route to in-use; train_clear frees an in-use route. Cancelling a set route frees it at once unless a train is in the approach section, in which case it is approach-locked until cancel time + release_s (released when an event time reaches the deadline). approach_occ/approach_clear track the approach section. query appends set, free, in-use or locked-until:<t>.

split: open-access


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

N = 1
observations = []
def solve(x):
    T = x['release_s']
    state = 'free'
    until = None
    approach = False
    out = []
    for t, kind in x['events']:
        if state == 'locked' and t >= until:
            state = 'free'
        if kind == 'approach_occ':
            approach = True
        elif kind == 'approach_clear':
            approach = False
        elif kind == 'set' and state == 'free':
            state = 'set'
        elif kind == 'cancel' and state in ('set', 'in-use'):
            if approach:
                state = 'locked'
                until = t + T
            else:
                state = 'free'
        elif kind == 'pass_signal':
            approach = False
            if state == 'set':
                state = 'in-use'
        elif kind == 'train_clear' and state == 'in-use':
            state = 'free'
        elif kind == 'query':
            out.append('locked-until:%d' % until if state == 'locked' else state)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('sampled regression 28', {'release_s': 60, 'events': [[120, 'cancel'], [130, 'approach_clear'], [190, 'approach_clear'], [250, 'approach_clear'], [251, 'train_clear'], [256, 'query'], [286, 'query'], [287, 'approach_clear'], [407, 'set'], [527, 'pass_signal'], [587, 'cancel'], [597, 'approach_occ'], [797, 'query']]}, ['free', 'free', 'in-use']), ('control 8', {'release_s': 120, 'events': [[120, 'approach_occ'], [125, 'approach_occ'], [130, 'set'], [190, 'cancel'], [190, 'query'], [200, 'train_clear'], [260, 'cancel'], [261, 'approach_clear'], [261, 'pass_signal'], [321, 'query']]}, ['locked-until:310', 'free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('control 1', {'release_s': 120, 'events': [[120, 'query'], [125, 'set'], [185, 'set'], [215, 'pass_signal'], [275, 'query'], [475, 'query']]}, ['free', 'in-use', 'in-use']), ('control 4', {'release_s': 60, 'events': [[30, 'query'], [60, 'query'], [120, 'query'], [180, 'cancel'], [240, 'query'], [245, 'approach_occ'], [445, 'query']]}, ['free', 'free', 'free', 'free', 'free']), ('control 7', {'release_s': 120, 'events': [[0, 'cancel'], [0, 'query'], [0, 'approach_occ'], [1, 'set'], [11, 'approach_clear'], [41, 'query'], [42, 'approach_occ'], [242, 'query']]}, ['free', 'set', 'set'])], [('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('control 12', {'release_s': 120, 'events': [[1, 'query'], [121, 'approach_clear'], [241, 'set'], [271, 'set'], [391, 'approach_occ'], [451, 'query']]}, ['free', 'set']), ('control 15', {'release_s': 60, 'events': [[5, 'set'], [6, 'query'], [6, 'cancel'], [36, 'set'], [46, 'query'], [106, 'approach_clear'], [226, 'query'], [227, 'query'], [237, 'query'], [267, 'set'], [327, 'set'], [327, 'query']]}, ['set', 'set', 'set', 'set', 'set', 'set']), ('control 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set'])], [('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('sampled regression 16', {'release_s': 60, 'events': [[120, 'approach_occ'], [180, 'query'], [185, 'query'], [305, 'set'], [306, 'pass_signal'], [306, 'cancel'], [307, 'query'], [317, 'cancel'], [318, 'train_clear'], [438, 'query']]}, ['free', 'free', 'in-use', 'free']), ('sampled regression 56', {'release_s': 60, 'events': [[5, 'approach_clear'], [15, 'query'], [75, 'set'], [75, 'query'], [105, 'query'], [106, 'query'], [136, 'pass_signal'], [196, 'approach_clear'], [206, 'cancel'], [216, 'set'], [336, 'query']]}, ['free', 'set', 'set', 'set', 'in-use']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('control 23', {'release_s': 60, 'events': [[10, 'cancel'], [15, 'set'], [25, 'approach_occ'], [26, 'set'], [36, 'cancel'], [156, 'query']]}, ['free']), ('control 26', {'release_s': 60, 'events': [[1, 'approach_occ'], [6, 'set'], [66, 'set'], [66, 'cancel'], [96, 'query'], [106, 'approach_clear'], [136, 'query'], [141, 'approach_clear'], [151, 'approach_occ'], [211, 'train_clear'], [271, 'query']]}, ['locked-until:126', 'free', 'free']), ('control 29', {'release_s': 60, 'events': [[0, 'set'], [0, 'set'], [30, 'train_clear'], [40, 'set'], [40, 'query'], [100, 'cancel'], [110, 'approach_occ'], [170, 'query']]}, ['set', 'free'])], [('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('sampled regression 56', {'release_s': 60, 'events': [[5, 'approach_clear'], [15, 'query'], [75, 'set'], [75, 'query'], [105, 'query'], [106, 'query'], [136, 'pass_signal'], [196, 'approach_clear'], [206, 'cancel'], [216, 'set'], [336, 'query']]}, ['free', 'set', 'set', 'set', 'in-use']), ('sampled regression 28', {'release_s': 60, 'events': [[120, 'cancel'], [130, 'approach_clear'], [190, 'approach_clear'], [250, 'approach_clear'], [251, 'train_clear'], [256, 'query'], [286, 'query'], [287, 'approach_clear'], [407, 'set'], [527, 'pass_signal'], [587, 'cancel'], [597, 'approach_occ'], [797, 'query']]}, ['free', 'free', 'in-use']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('control 34', {'release_s': 120, 'events': [[120, 'set'], [121, 'set'], [121, 'cancel'], [241, 'approach_occ'], [361, 'pass_signal'], [371, 'cancel'], [491, 'approach_occ'], [611, 'query']]}, ['free']), ('control 37', {'release_s': 60, 'events': [[60, 'query'], [61, 'train_clear'], [71, 'set'], [131, 'train_clear'], [131, 'pass_signal'], [136, 'approach_occ'], [196, 'set'], [197, 'cancel'], [202, 'set'], [262, 'train_clear'], [382, 'query'], [382, 'query']]}, ['free', 'free', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425'])], [('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('sampled regression 9', {'release_s': 120, 'events': [[10, 'query'], [15, 'set'], [15, 'pass_signal'], [20, 'approach_occ'], [140, 'query'], [260, 'cancel'], [320, 'query'], [321, 'set'], [351, 'approach_clear'], [471, 'cancel'], [471, 'query']]}, ['free', 'in-use', 'in-use', 'in-use']), ('sampled regression 16', {'release_s': 60, 'events': [[120, 'approach_occ'], [180, 'query'], [185, 'query'], [305, 'set'], [306, 'pass_signal'], [306, 'cancel'], [307, 'query'], [317, 'cancel'], [318, 'train_clear'], [438, 'query']]}, ['free', 'free', 'in-use', 'free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('control 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('control 48', {'release_s': 60, 'events': [[120, 'set'], [121, 'train_clear'], [122, 'set'], [242, 'query'], [242, 'query'], [252, 'pass_signal'], [257, 'approach_occ'], [257, 'query']]}, ['set', 'set', 'in-use']), ('control 51', {'release_s': 60, 'events': [[120, 'pass_signal'], [120, 'cancel'], [125, 'approach_clear'], [126, 'cancel'], [136, 'cancel'], [256, 'approach_clear'], [316, 'pass_signal'], [376, 'query'], [377, 'query'], [387, 'cancel'], [387, 'query']]}, ['free', 'free', 'free'])]]
for label, args, expected in fixtures[N-1]:
    check(label, 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):
    T = x['release_s']
    state = 'free'
    until = None
    approach = False
    out = []
    for t, kind in x['events']:
        if state == 'locked' and t >= until:
            state = 'free'
        if kind == 'approach_occ':
            approach = True
        elif kind == 'approach_clear':
            approach = False
        elif kind == 'set' and state == 'free':
            state = 'set'
        elif kind == 'cancel' and state != 'free':
            if approach:
                state = 'locked'
                until = t + T
            else:
                state = 'free'
        elif kind == 'pass_signal':
            approach = False
            if state == 'set':
                state = 'in-use'
        elif kind == 'train_clear' and state == 'in-use':
            state = 'free'
        elif kind == 'query':
            out.append('locked-until:%d' % until if state == 'locked' else state)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('sampled regression 28', {'release_s': 60, 'events': [[120, 'cancel'], [130, 'approach_clear'], [190, 'approach_clear'], [250, 'approach_clear'], [251, 'train_clear'], [256, 'query'], [286, 'query'], [287, 'approach_clear'], [407, 'set'], [527, 'pass_signal'], [587, 'cancel'], [597, 'approach_occ'], [797, 'query']]}, ['free', 'free', 'in-use']), ('control 8', {'release_s': 120, 'events': [[120, 'approach_occ'], [125, 'approach_occ'], [130, 'set'], [190, 'cancel'], [190, 'query'], [200, 'train_clear'], [260, 'cancel'], [261, 'approach_clear'], [261, 'pass_signal'], [321, 'query']]}, ['locked-until:310', 'free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('control 1', {'release_s': 120, 'events': [[120, 'query'], [125, 'set'], [185, 'set'], [215, 'pass_signal'], [275, 'query'], [475, 'query']]}, ['free', 'in-use', 'in-use']), ('control 4', {'release_s': 60, 'events': [[30, 'query'], [60, 'query'], [120, 'query'], [180, 'cancel'], [240, 'query'], [245, 'approach_occ'], [445, 'query']]}, ['free', 'free', 'free', 'free', 'free']), ('control 7', {'release_s': 120, 'events': [[0, 'cancel'], [0, 'query'], [0, 'approach_occ'], [1, 'set'], [11, 'approach_clear'], [41, 'query'], [42, 'approach_occ'], [242, 'query']]}, ['free', 'set', 'set'])], [('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('control 12', {'release_s': 120, 'events': [[1, 'query'], [121, 'approach_clear'], [241, 'set'], [271, 'set'], [391, 'approach_occ'], [451, 'query']]}, ['free', 'set']), ('control 15', {'release_s': 60, 'events': [[5, 'set'], [6, 'query'], [6, 'cancel'], [36, 'set'], [46, 'query'], [106, 'approach_clear'], [226, 'query'], [227, 'query'], [237, 'query'], [267, 'set'], [327, 'set'], [327, 'query']]}, ['set', 'set', 'set', 'set', 'set', 'set']), ('control 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set'])], [('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('sampled regression 16', {'release_s': 60, 'events': [[120, 'approach_occ'], [180, 'query'], [185, 'query'], [305, 'set'], [306, 'pass_signal'], [306, 'cancel'], [307, 'query'], [317, 'cancel'], [318, 'train_clear'], [438, 'query']]}, ['free', 'free', 'in-use', 'free']), ('sampled regression 56', {'release_s': 60, 'events': [[5, 'approach_clear'], [15, 'query'], [75, 'set'], [75, 'query'], [105, 'query'], [106, 'query'], [136, 'pass_signal'], [196, 'approach_clear'], [206, 'cancel'], [216, 'set'], [336, 'query']]}, ['free', 'set', 'set', 'set', 'in-use']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('control 23', {'release_s': 60, 'events': [[10, 'cancel'], [15, 'set'], [25, 'approach_occ'], [26, 'set'], [36, 'cancel'], [156, 'query']]}, ['free']), ('control 26', {'release_s': 60, 'events': [[1, 'approach_occ'], [6, 'set'], [66, 'set'], [66, 'cancel'], [96, 'query'], [106, 'approach_clear'], [136, 'query'], [141, 'approach_clear'], [151, 'approach_occ'], [211, 'train_clear'], [271, 'query']]}, ['locked-until:126', 'free', 'free']), ('control 29', {'release_s': 60, 'events': [[0, 'set'], [0, 'set'], [30, 'train_clear'], [40, 'set'], [40, 'query'], [100, 'cancel'], [110, 'approach_occ'], [170, 'query']]}, ['set', 'free'])], [('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('sampled regression 56', {'release_s': 60, 'events': [[5, 'approach_clear'], [15, 'query'], [75, 'set'], [75, 'query'], [105, 'query'], [106, 'query'], [136, 'pass_signal'], [196, 'approach_clear'], [206, 'cancel'], [216, 'set'], [336, 'query']]}, ['free', 'set', 'set', 'set', 'in-use']), ('sampled regression 28', {'release_s': 60, 'events': [[120, 'cancel'], [130, 'approach_clear'], [190, 'approach_clear'], [250, 'approach_clear'], [251, 'train_clear'], [256, 'query'], [286, 'query'], [287, 'approach_clear'], [407, 'set'], [527, 'pass_signal'], [587, 'cancel'], [597, 'approach_occ'], [797, 'query']]}, ['free', 'free', 'in-use']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('control 34', {'release_s': 120, 'events': [[120, 'set'], [121, 'set'], [121, 'cancel'], [241, 'approach_occ'], [361, 'pass_signal'], [371, 'cancel'], [491, 'approach_occ'], [611, 'query']]}, ['free']), ('control 37', {'release_s': 60, 'events': [[60, 'query'], [61, 'train_clear'], [71, 'set'], [131, 'train_clear'], [131, 'pass_signal'], [136, 'approach_occ'], [196, 'set'], [197, 'cancel'], [202, 'set'], [262, 'train_clear'], [382, 'query'], [382, 'query']]}, ['free', 'free', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425'])], [('regression: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('sampled regression 9', {'release_s': 120, 'events': [[10, 'query'], [15, 'set'], [15, 'pass_signal'], [20, 'approach_occ'], [140, 'query'], [260, 'cancel'], [320, 'query'], [321, 'set'], [351, 'approach_clear'], [471, 'cancel'], [471, 'query']]}, ['free', 'in-use', 'in-use', 'in-use']), ('sampled regression 16', {'release_s': 60, 'events': [[120, 'approach_occ'], [180, 'query'], [185, 'query'], [305, 'set'], [306, 'pass_signal'], [306, 'cancel'], [307, 'query'], [317, 'cancel'], [318, 'train_clear'], [438, 'query']]}, ['free', 'free', 'in-use', 'free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('control 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('control 48', {'release_s': 60, 'events': [[120, 'set'], [121, 'train_clear'], [122, 'set'], [242, 'query'], [242, 'query'], [252, 'pass_signal'], [257, 'approach_occ'], [257, 'query']]}, ['set', 'set', 'in-use']), ('control 51', {'release_s': 60, 'events': [[120, 'pass_signal'], [120, 'cancel'], [125, 'approach_clear'], [126, 'cancel'], [136, 'cancel'], [256, 'approach_clear'], [316, 'pass_signal'], [376, 'query'], [377, 'query'], [387, 'cancel'], [387, 'query']]}, ['free', 'free', 'free'])]]
for label, args, expected in fixtures[N-1]:
    check(label, 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:
Cancelling frees a route that a train is still using.

A route can be set only when free. pass_signal moves a set route to in-use; train_clear frees an in-use route. Cancelling a set route frees it at once unless a train is in the approach section, in which case it is approach-locked until cancel time + release_s (released when an event time reaches the deadline). approach_occ/approach_clear track the approach section. query appends set, free, in-use or locked-until:<t>.

split: open-access


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

N = 1
observations = []
def solve(x):
    T = x['release_s']
    state = 'free'
    until = None
    approach = False
    out = []
    for t, kind in x['events']:
        if state == 'locked' and t >= until:
            state = 'free'
        if kind == 'approach_occ':
            approach = True
        elif kind == 'approach_clear':
            approach = False
        elif kind == 'set' and state != 'in-use':
            state = 'set'
        elif kind == 'cancel' and state == 'set':
            if approach:
                state = 'locked'
                until = t + T
            else:
                state = 'free'
        elif kind == 'pass_signal':
            approach = False
            if state == 'set':
                state = 'in-use'
        elif kind == 'train_clear' and state == 'in-use':
            state = 'free'
        elif kind == 'query':
            out.append('locked-until:%d' % until if state == 'locked' else state)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('sampled regression 35', {'release_s': 120, 'events': [[10, 'approach_occ'], [130, 'set'], [190, 'approach_occ'], [200, 'cancel'], [205, 'train_clear'], [210, 'query'], [240, 'approach_clear'], [240, 'pass_signal'], [241, 'set'], [241, 'query'], [361, 'query']]}, ['locked-until:320', 'locked-until:320', 'free']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('control 1', {'release_s': 120, 'events': [[120, 'query'], [125, 'set'], [185, 'set'], [215, 'pass_signal'], [275, 'query'], [475, 'query']]}, ['free', 'in-use', 'in-use']), ('control 4', {'release_s': 60, 'events': [[30, 'query'], [60, 'query'], [120, 'query'], [180, 'cancel'], [240, 'query'], [245, 'approach_occ'], [445, 'query']]}, ['free', 'free', 'free', 'free', 'free']), ('control 7', {'release_s': 120, 'events': [[0, 'cancel'], [0, 'query'], [0, 'approach_occ'], [1, 'set'], [11, 'approach_clear'], [41, 'query'], [42, 'approach_occ'], [242, 'query']]}, ['free', 'set', 'set'])], [('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('control 19', {'release_s': 60, 'events': [[1, 'cancel'], [11, 'cancel'], [131, 'approach_clear'], [161, 'cancel'], [221, 'cancel'], [222, 'approach_occ'], [222, 'query'], [342, 'set'], [342, 'train_clear'], [342, 'query']]}, ['free', 'set']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 12', {'release_s': 120, 'events': [[1, 'query'], [121, 'approach_clear'], [241, 'set'], [271, 'set'], [391, 'approach_occ'], [451, 'query']]}, ['free', 'set']), ('control 15', {'release_s': 60, 'events': [[5, 'set'], [6, 'query'], [6, 'cancel'], [36, 'set'], [46, 'query'], [106, 'approach_clear'], [226, 'query'], [227, 'query'], [237, 'query'], [267, 'set'], [327, 'set'], [327, 'query']]}, ['set', 'set', 'set', 'set', 'set', 'set']), ('control 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set'])], [('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('sampled regression 35', {'release_s': 120, 'events': [[10, 'approach_occ'], [130, 'set'], [190, 'approach_occ'], [200, 'cancel'], [205, 'train_clear'], [210, 'query'], [240, 'approach_clear'], [240, 'pass_signal'], [241, 'set'], [241, 'query'], [361, 'query']]}, ['locked-until:320', 'locked-until:320', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 23', {'release_s': 60, 'events': [[10, 'cancel'], [15, 'set'], [25, 'approach_occ'], [26, 'set'], [36, 'cancel'], [156, 'query']]}, ['free']), ('control 26', {'release_s': 60, 'events': [[1, 'approach_occ'], [6, 'set'], [66, 'set'], [66, 'cancel'], [96, 'query'], [106, 'approach_clear'], [136, 'query'], [141, 'approach_clear'], [151, 'approach_occ'], [211, 'train_clear'], [271, 'query']]}, ['locked-until:126', 'free', 'free']), ('control 29', {'release_s': 60, 'events': [[0, 'set'], [0, 'set'], [30, 'train_clear'], [40, 'set'], [40, 'query'], [100, 'cancel'], [110, 'approach_occ'], [170, 'query']]}, ['set', 'free'])], [('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('control 34', {'release_s': 120, 'events': [[120, 'set'], [121, 'set'], [121, 'cancel'], [241, 'approach_occ'], [361, 'pass_signal'], [371, 'cancel'], [491, 'approach_occ'], [611, 'query']]}, ['free']), ('control 37', {'release_s': 60, 'events': [[60, 'query'], [61, 'train_clear'], [71, 'set'], [131, 'train_clear'], [131, 'pass_signal'], [136, 'approach_occ'], [196, 'set'], [197, 'cancel'], [202, 'set'], [262, 'train_clear'], [382, 'query'], [382, 'query']]}, ['free', 'free', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425'])], [('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('sampled regression 35', {'release_s': 120, 'events': [[10, 'approach_occ'], [130, 'set'], [190, 'approach_occ'], [200, 'cancel'], [205, 'train_clear'], [210, 'query'], [240, 'approach_clear'], [240, 'pass_signal'], [241, 'set'], [241, 'query'], [361, 'query']]}, ['locked-until:320', 'locked-until:320', 'free']), ('control 19', {'release_s': 60, 'events': [[1, 'cancel'], [11, 'cancel'], [131, 'approach_clear'], [161, 'cancel'], [221, 'cancel'], [222, 'approach_occ'], [222, 'query'], [342, 'set'], [342, 'train_clear'], [342, 'query']]}, ['free', 'set']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('control 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('control 48', {'release_s': 60, 'events': [[120, 'set'], [121, 'train_clear'], [122, 'set'], [242, 'query'], [242, 'query'], [252, 'pass_signal'], [257, 'approach_occ'], [257, 'query']]}, ['set', 'set', 'in-use']), ('control 51', {'release_s': 60, 'events': [[120, 'pass_signal'], [120, 'cancel'], [125, 'approach_clear'], [126, 'cancel'], [136, 'cancel'], [256, 'approach_clear'], [316, 'pass_signal'], [376, 'query'], [377, 'query'], [387, 'cancel'], [387, 'query']]}, ['free', 'free', 'free'])]]
for label, args, expected in fixtures[N-1]:
    check(label, 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):
    T = x['release_s']
    state = 'free'
    until = None
    approach = False
    out = []
    for t, kind in x['events']:
        if state == 'locked' and t >= until:
            state = 'free'
        if kind == 'approach_occ':
            approach = True
        elif kind == 'approach_clear':
            approach = False
        elif kind == 'set' and state == 'free' and not approach:
            state = 'set'
        elif kind == 'cancel' and state == 'set':
            if approach:
                state = 'locked'
                until = t + T
            else:
                state = 'free'
        elif kind == 'pass_signal':
            approach = False
            if state == 'set':
                state = 'in-use'
        elif kind == 'train_clear' and state == 'in-use':
            state = 'free'
        elif kind == 'query':
            out.append('locked-until:%d' % until if state == 'locked' else state)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('sampled regression 35', {'release_s': 120, 'events': [[10, 'approach_occ'], [130, 'set'], [190, 'approach_occ'], [200, 'cancel'], [205, 'train_clear'], [210, 'query'], [240, 'approach_clear'], [240, 'pass_signal'], [241, 'set'], [241, 'query'], [361, 'query']]}, ['locked-until:320', 'locked-until:320', 'free']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('control 1', {'release_s': 120, 'events': [[120, 'query'], [125, 'set'], [185, 'set'], [215, 'pass_signal'], [275, 'query'], [475, 'query']]}, ['free', 'in-use', 'in-use']), ('control 4', {'release_s': 60, 'events': [[30, 'query'], [60, 'query'], [120, 'query'], [180, 'cancel'], [240, 'query'], [245, 'approach_occ'], [445, 'query']]}, ['free', 'free', 'free', 'free', 'free']), ('control 7', {'release_s': 120, 'events': [[0, 'cancel'], [0, 'query'], [0, 'approach_occ'], [1, 'set'], [11, 'approach_clear'], [41, 'query'], [42, 'approach_occ'], [242, 'query']]}, ['free', 'set', 'set'])], [('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('control 19', {'release_s': 60, 'events': [[1, 'cancel'], [11, 'cancel'], [131, 'approach_clear'], [161, 'cancel'], [221, 'cancel'], [222, 'approach_occ'], [222, 'query'], [342, 'set'], [342, 'train_clear'], [342, 'query']]}, ['free', 'set']), ('boundary: train backs out of the approach', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'approach_clear'], [2, 'set'], [3, 'cancel'], [4, 'query']]}, ['free']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 12', {'release_s': 120, 'events': [[1, 'query'], [121, 'approach_clear'], [241, 'set'], [271, 'set'], [391, 'approach_occ'], [451, 'query']]}, ['free', 'set']), ('control 15', {'release_s': 60, 'events': [[5, 'set'], [6, 'query'], [6, 'cancel'], [36, 'set'], [46, 'query'], [106, 'approach_clear'], [226, 'query'], [227, 'query'], [237, 'query'], [267, 'set'], [327, 'set'], [327, 'query']]}, ['set', 'set', 'set', 'set', 'set', 'set']), ('control 18', {'release_s': 60, 'events': [[5, 'approach_occ'], [10, 'approach_clear'], [70, 'approach_clear'], [190, 'query'], [195, 'set'], [195, 'cancel'], [195, 'cancel'], [200, 'query'], [260, 'set'], [265, 'set'], [325, 'query']]}, ['free', 'free', 'set'])], [('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: set with a train approaching', {'release_s': 60, 'events': [[0, 'approach_occ'], [1, 'set'], [2, 'query']]}, ['set']), ('sampled regression 35', {'release_s': 120, 'events': [[10, 'approach_occ'], [130, 'set'], [190, 'approach_occ'], [200, 'cancel'], [205, 'train_clear'], [210, 'query'], [240, 'approach_clear'], [240, 'pass_signal'], [241, 'set'], [241, 'query'], [361, 'query']]}, ['locked-until:320', 'locked-until:320', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425']), ('boundary: cancel under a train', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'pass_signal'], [3, 'cancel'], [4, 'query'], [5, 'train_clear'], [6, 'query']]}, ['in-use', 'free']), ('control 23', {'release_s': 60, 'events': [[10, 'cancel'], [15, 'set'], [25, 'approach_occ'], [26, 'set'], [36, 'cancel'], [156, 'query']]}, ['free']), ('control 26', {'release_s': 60, 'events': [[1, 'approach_occ'], [6, 'set'], [66, 'set'], [66, 'cancel'], [96, 'query'], [106, 'approach_clear'], [136, 'query'], [141, 'approach_clear'], [151, 'approach_occ'], [211, 'train_clear'], [271, 'query']]}, ['locked-until:126', 'free', 'free']), ('control 29', {'release_s': 60, 'events': [[0, 'set'], [0, 'set'], [30, 'train_clear'], [40, 'set'], [40, 'query'], [100, 'cancel'], [110, 'approach_occ'], [170, 'query']]}, ['set', 'free'])], [('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: re-set at exactly the release time', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [62, 'set'], [63, 'query']]}, ['set']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('boundary: cancel with empty approach', {'release_s': 60, 'events': [[0, 'set'], [1, 'cancel'], [2, 'query']]}, ['free']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('control 34', {'release_s': 120, 'events': [[120, 'set'], [121, 'set'], [121, 'cancel'], [241, 'approach_occ'], [361, 'pass_signal'], [371, 'cancel'], [491, 'approach_occ'], [611, 'query']]}, ['free']), ('control 37', {'release_s': 60, 'events': [[60, 'query'], [61, 'train_clear'], [71, 'set'], [131, 'train_clear'], [131, 'pass_signal'], [136, 'approach_occ'], [196, 'set'], [197, 'cancel'], [202, 'set'], [262, 'train_clear'], [382, 'query'], [382, 'query']]}, ['free', 'free', 'free']), ('control 40', {'release_s': 120, 'events': [[0, 'query'], [30, 'cancel'], [90, 'approach_occ'], [100, 'set'], [130, 'query'], [135, 'approach_clear'], [255, 'train_clear'], [260, 'query'], [265, 'approach_occ'], [270, 'set'], [275, 'train_clear'], [305, 'cancel'], [365, 'query']]}, ['free', 'set', 'set', 'locked-until:425'])], [('regression: set attempted while locked', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [30, 'set'], [31, 'query']]}, ['locked-until:62']), ('boundary: second lock after an earlier one', {'release_s': 60, 'events': [[0, 'set'], [1, 'approach_occ'], [2, 'cancel'], [70, 'set'], [80, 'cancel'], [81, 'query']]}, ['locked-until:140']), ('sampled regression 35', {'release_s': 120, 'events': [[10, 'approach_occ'], [130, 'set'], [190, 'approach_occ'], [200, 'cancel'], [205, 'train_clear'], [210, 'query'], [240, 'approach_clear'], [240, 'pass_signal'], [241, 'set'], [241, 'query'], [361, 'query']]}, ['locked-until:320', 'locked-until:320', 'free']), ('control 19', {'release_s': 60, 'events': [[1, 'cancel'], [11, 'cancel'], [131, 'approach_clear'], [161, 'cancel'], [221, 'cancel'], [222, 'approach_occ'], [222, 'query'], [342, 'set'], [342, 'train_clear'], [342, 'query']]}, ['free', 'set']), ('boundary: query at exactly the release time', {'release_s': 120, 'events': [[0, 'set'], [5, 'approach_occ'], [10, 'cancel'], [130, 'query']]}, ['free']), ('control 45', {'release_s': 120, 'events': [[0, 'set'], [0, 'cancel'], [0, 'train_clear'], [0, 'approach_occ'], [1, 'approach_clear'], [6, 'approach_clear'], [126, 'query'], [136, 'set'], [141, 'train_clear'], [151, 'cancel'], [152, 'approach_clear'], [152, 'pass_signal'], [212, 'query']]}, ['free', 'free']), ('control 48', {'release_s': 60, 'events': [[120, 'set'], [121, 'train_clear'], [122, 'set'], [242, 'query'], [242, 'query'], [252, 'pass_signal'], [257, 'approach_occ'], [257, 'query']]}, ['set', 'set', 'in-use']), ('control 51', {'release_s': 60, 'events': [[120, 'pass_signal'], [120, 'cancel'], [125, 'approach_clear'], [126, 'cancel'], [136, 'cancel'], [256, 'approach_clear'], [316, 'pass_signal'], [376, 'query'], [377, 'query'], [387, 'cancel'], [387, 'query']]}, ['free', 'free', 'free'])]]
for label, args, expected in fixtures[N-1]:
    check(label, 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:
Setting a route clears an active approach lock early, or a route cannot be set for an approaching train.

A route can be set only when free. pass_signal moves a set route to in-use; train_clear frees an in-use route. Cancelling a set route frees it at once unless a train is in the approach section, in which case it is approach-locked until cancel time + release_s (released when an event time reaches the deadline). approach_occ/approach_clear track the approach section. query appends set, free, in-use or locked-until:<t>.

split: open-access