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

N = 1
observations = []
def solve(x):
    par = set(x['parents'])
    nd = set(x['not_during'])
    cur = {ph: iv for ph, iv in x['state']}
    if any(cur.get(p) == 'G' for p in nd):
        return 'R'
    if any(cur.get(p) == 'G' for p in par):
        return 'G'
    terminating = [p for p in sorted(par) if cur.get(p) in ('Y', 'RC')]
    if terminating:
        if any(p in terminating for p in x['next']):
            return 'G'
        if any(cur[p] == 'Y' for p in terminating):
            return 'Y'
        return 'R'
    return 'R'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'parents': [3, 4, 7], 'not_during': [5, 6], 'state': [[6, 'R'], [3, 'R'], [7, 'Y']], 'next': [1, 6]}, 'Y'), ({'parents': [4, 5, 8], 'not_during': [], 'state': [[4, 'Y'], [6, 'R']], 'next': [7, 8]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4], 'not_during': [2], 'state': [[8, 'Y'], [4, 'RC']], 'next': [3, 4]}, 'G'), ({'parents': [2, 6, 7], 'not_during': [], 'state': [[7, 'G'], [1, 'RC'], [3, 'G']], 'next': []}, 'G'), ({'parents': [3, 4, 7], 'not_during': [6], 'state': [[4, 'Y'], [7, 'R']], 'next': [1, 4]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y')], [({'parents': [6, 8], 'not_during': [], 'state': [[6, 'Y'], [1, 'RC'], [2, 'Y']], 'next': [4, 6]}, 'G'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 6, 8], 'not_during': [1], 'state': [[6, 'Y']], 'next': [3, 6]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [1, 2, 5], 'not_during': [7], 'state': [[3, 'Y'], [1, 'RC']], 'next': [2, 8]}, 'G'), ({'parents': [4], 'not_during': [1, 8], 'state': [[4, 'Y'], [1, 'RC']], 'next': []}, 'Y'), ({'parents': [5, 6, 8], 'not_during': [], 'state': [[5, 'Y'], [3, 'G'], [4, 'Y']], 'next': [8]}, 'G')], [({'parents': [2, 4, 8], 'not_during': [1], 'state': [[1, 'Y'], [8, 'R'], [4, 'Y']], 'next': [3, 8]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [2, 5], 'not_during': [], 'state': [[7, 'Y'], [5, 'R'], [1, 'R']], 'next': [6]}, 'R'), ({'parents': [3], 'not_during': [], 'state': [[1, 'G']], 'next': []}, 'R'), ({'parents': [5, 7], 'not_during': [3], 'state': [[6, 'Y'], [7, 'Y'], [2, 'G']], 'next': [5]}, 'G'), ({'parents': [5], 'not_during': [7], 'state': [[3, 'G'], [7, 'G'], [8, 'R']], 'next': [8]}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y')], [({'parents': [3, 8], 'not_during': [2, 7], 'state': [[8, 'RC']], 'next': [8]}, 'G'), ({'parents': [3], 'not_during': [6], 'state': [[7, 'G'], [5, 'RC'], [6, 'R']], 'next': []}, 'R'), ({'parents': [1, 7], 'not_during': [2], 'state': [[7, 'Y'], [2, 'R']], 'next': [4, 7]}, 'G'), ({'parents': [3, 6, 7], 'not_during': [], 'state': [[2, 'Y'], [3, 'Y'], [1, 'G']], 'next': [2, 6]}, 'G'), ({'parents': [2, 6, 7], 'not_during': [], 'state': [[7, 'Y'], [5, 'R'], [4, 'Y']], 'next': [2, 8]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y')], [({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [6, 7], 'not_during': [2, 4], 'state': [[7, 'Y'], [2, 'G'], [1, 'R']], 'next': [3]}, 'R'), ({'parents': [5, 7], 'not_during': [], 'state': [[6, 'R'], [8, 'Y']], 'next': [2]}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [6, 8], 'not_during': [3], 'state': [[8, 'RC']], 'next': [3, 6]}, 'G'), ({'parents': [1, 4, 8], 'not_during': [3], 'state': [[1, 'Y']], 'next': [3, 8]}, 'G'), ({'parents': [4, 5, 7], 'not_during': [], 'state': [[3, 'G'], [4, 'Y'], [2, 'R']], 'next': [5, 7]}, 'G')]]
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):
    par = set(x['parents'])
    nd = set(x['not_during'])
    cur = {ph: iv for ph, iv in x['state']}
    if any(cur.get(p) == 'G' for p in nd):
        return 'R'
    if any(cur.get(p) == 'G' for p in par):
        return 'G'
    terminating = [p for p in sorted(par) if cur.get(p) in ('Y', 'RC')]
    if terminating:
        if x['next'] and x['next'][0] in par:
            return 'G'
        if any(cur[p] == 'Y' for p in terminating):
            return 'Y'
        return 'R'
    return 'R'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'parents': [3, 4, 7], 'not_during': [5, 6], 'state': [[6, 'R'], [3, 'R'], [7, 'Y']], 'next': [1, 6]}, 'Y'), ({'parents': [4, 5, 8], 'not_during': [], 'state': [[4, 'Y'], [6, 'R']], 'next': [7, 8]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4], 'not_during': [2], 'state': [[8, 'Y'], [4, 'RC']], 'next': [3, 4]}, 'G'), ({'parents': [2, 6, 7], 'not_during': [], 'state': [[7, 'G'], [1, 'RC'], [3, 'G']], 'next': []}, 'G'), ({'parents': [3, 4, 7], 'not_during': [6], 'state': [[4, 'Y'], [7, 'R']], 'next': [1, 4]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y')], [({'parents': [6, 8], 'not_during': [], 'state': [[6, 'Y'], [1, 'RC'], [2, 'Y']], 'next': [4, 6]}, 'G'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 6, 8], 'not_during': [1], 'state': [[6, 'Y']], 'next': [3, 6]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [1, 2, 5], 'not_during': [7], 'state': [[3, 'Y'], [1, 'RC']], 'next': [2, 8]}, 'G'), ({'parents': [4], 'not_during': [1, 8], 'state': [[4, 'Y'], [1, 'RC']], 'next': []}, 'Y'), ({'parents': [5, 6, 8], 'not_during': [], 'state': [[5, 'Y'], [3, 'G'], [4, 'Y']], 'next': [8]}, 'G')], [({'parents': [2, 4, 8], 'not_during': [1], 'state': [[1, 'Y'], [8, 'R'], [4, 'Y']], 'next': [3, 8]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [2, 5], 'not_during': [], 'state': [[7, 'Y'], [5, 'R'], [1, 'R']], 'next': [6]}, 'R'), ({'parents': [3], 'not_during': [], 'state': [[1, 'G']], 'next': []}, 'R'), ({'parents': [5, 7], 'not_during': [3], 'state': [[6, 'Y'], [7, 'Y'], [2, 'G']], 'next': [5]}, 'G'), ({'parents': [5], 'not_during': [7], 'state': [[3, 'G'], [7, 'G'], [8, 'R']], 'next': [8]}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y')], [({'parents': [3, 8], 'not_during': [2, 7], 'state': [[8, 'RC']], 'next': [8]}, 'G'), ({'parents': [3], 'not_during': [6], 'state': [[7, 'G'], [5, 'RC'], [6, 'R']], 'next': []}, 'R'), ({'parents': [1, 7], 'not_during': [2], 'state': [[7, 'Y'], [2, 'R']], 'next': [4, 7]}, 'G'), ({'parents': [3, 6, 7], 'not_during': [], 'state': [[2, 'Y'], [3, 'Y'], [1, 'G']], 'next': [2, 6]}, 'G'), ({'parents': [2, 6, 7], 'not_during': [], 'state': [[7, 'Y'], [5, 'R'], [4, 'Y']], 'next': [2, 8]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y')], [({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [6, 7], 'not_during': [2, 4], 'state': [[7, 'Y'], [2, 'G'], [1, 'R']], 'next': [3]}, 'R'), ({'parents': [5, 7], 'not_during': [], 'state': [[6, 'R'], [8, 'Y']], 'next': [2]}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [6, 8], 'not_during': [3], 'state': [[8, 'RC']], 'next': [3, 6]}, 'G'), ({'parents': [1, 4, 8], 'not_during': [3], 'state': [[1, 'Y']], 'next': [3, 8]}, 'G'), ({'parents': [4, 5, 7], 'not_during': [], 'state': [[3, 'G'], [4, 'Y'], [2, 'R']], 'next': [5, 7]}, 'G')]]
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:
Overlap phase indication returns a wrong result when the overlap continues only when the same parent is re-served.

Input {parents, not_during, state: [[phase, G|Y|RC|R]] for timing phases, next: phases to be served next}. The overlap is red while any not_during phase is green. Otherwise it is green while any parent is green. If a parent is terminating (Y or RC) the overlap stays green when any next phase is a parent; otherwise it is yellow if any terminating parent is in yellow, else red. Otherwise red.

split: open-access


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

N = 1
observations = []
def solve(x):
    par = set(x['parents'])
    nd = set(x['not_during'])
    cur = {ph: iv for ph, iv in x['state']}
    if any(cur.get(p) == 'G' for p in nd):
        return 'R'
    if any(cur.get(p) == 'G' for p in par):
        return 'G'
    terminating = [p for p in sorted(par) if cur.get(p) == 'Y']
    if terminating:
        if any(p in par for p in x['next']):
            return 'G'
        if any(cur[p] == 'Y' for p in terminating):
            return 'Y'
        return 'R'
    return 'R'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'parents': [3, 4, 8], 'not_during': [2, 6], 'state': [[4, 'R'], [5, 'RC']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [1, 2, 4], 'not_during': [], 'state': [[8, 'G'], [4, 'RC']], 'next': [2, 7]}, 'G'), ({'parents': [4, 7], 'not_during': [2, 3], 'state': [[7, 'R'], [2, 'G']], 'next': [3, 8]}, 'R'), ({'parents': [3, 4, 5], 'not_during': [2, 7], 'state': [[8, 'RC'], [3, 'RC'], [6, 'RC']], 'next': [5]}, 'G'), ({'parents': [5, 6], 'not_during': [7], 'state': [[3, 'G'], [6, 'R']], 'next': [4, 6]}, 'R')], [({'parents': [1, 4], 'not_during': [8], 'state': [[3, 'Y'], [5, 'G']], 'next': []}, 'R'), ({'parents': [3, 4, 8], 'not_during': [5], 'state': [[1, 'G'], [4, 'RC']], 'next': [4]}, 'G'), ({'parents': [1, 5], 'not_during': [], 'state': [[6, 'G'], [8, 'Y']], 'next': []}, 'R'), ({'parents': [4, 5, 7], 'not_during': [3], 'state': [[5, 'RC'], [1, 'Y']], 'next': [5]}, 'G'), ({'parents': [5, 7], 'not_during': [4, 6], 'state': [[3, 'Y'], [5, 'RC']], 'next': [3, 8]}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y')], [({'parents': [2, 4], 'not_during': [3, 5], 'state': [[6, 'G'], [5, 'G']], 'next': [1, 5]}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [2], 'not_during': [], 'state': [[6, 'Y'], [7, 'G'], [8, 'G']], 'next': []}, 'R'), ({'parents': [3], 'not_during': [], 'state': [[4, 'RC']], 'next': [7]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 3, 4], 'not_during': [], 'state': [[6, 'R'], [4, 'RC'], [5, 'Y']], 'next': [2, 6]}, 'G'), ({'parents': [6, 7], 'not_during': [2], 'state': [[4, 'G'], [1, 'Y'], [7, 'RC']], 'next': [4, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G')], [({'parents': [4], 'not_during': [3], 'state': [[7, 'R'], [5, 'R'], [4, 'RC']], 'next': [4, 8]}, 'G'), ({'parents': [8], 'not_during': [1, 7], 'state': [[3, 'RC'], [2, 'R']], 'next': []}, 'R'), ({'parents': [2, 6, 8], 'not_during': [3, 5], 'state': [[1, 'R'], [3, 'Y']], 'next': [6, 8]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 4], 'not_during': [], 'state': [[1, 'RC']], 'next': [4, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [1, 3, 5], 'not_during': [4, 6], 'state': [[3, 'R']], 'next': [4, 5]}, 'R')], [({'parents': [1, 2, 6], 'not_during': [3], 'state': [[6, 'RC'], [3, 'RC'], [5, 'G']], 'next': [2, 6]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [5], 'not_during': [], 'state': [[8, 'G']], 'next': [3, 8]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [5], 'not_during': [2], 'state': [[4, 'RC'], [2, 'R'], [6, 'G']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 4], 'not_during': [5], 'state': [[1, 'RC'], [4, 'RC'], [2, 'RC']], 'next': [4, 7]}, 'G'), ({'parents': [5, 7, 8], 'not_during': [2, 3], 'state': [[7, 'RC'], [6, 'G'], [8, 'RC']], 'next': []}, 'R')]]
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):
    par = set(x['parents'])
    nd = set(x['not_during'])
    cur = {ph: iv for ph, iv in x['state']}
    if any(cur.get(p) == 'G' for p in nd):
        return 'R'
    if any(cur.get(p) == 'G' for p in par):
        return 'G'
    terminating = [p for p in sorted(par) if cur.get(p) in ('Y', 'R')]
    if terminating:
        if any(p in par for p in x['next']):
            return 'G'
        if any(cur[p] == 'Y' for p in terminating):
            return 'Y'
        return 'R'
    return 'R'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'parents': [3, 4, 8], 'not_during': [2, 6], 'state': [[4, 'R'], [5, 'RC']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [1, 2, 4], 'not_during': [], 'state': [[8, 'G'], [4, 'RC']], 'next': [2, 7]}, 'G'), ({'parents': [4, 7], 'not_during': [2, 3], 'state': [[7, 'R'], [2, 'G']], 'next': [3, 8]}, 'R'), ({'parents': [3, 4, 5], 'not_during': [2, 7], 'state': [[8, 'RC'], [3, 'RC'], [6, 'RC']], 'next': [5]}, 'G'), ({'parents': [5, 6], 'not_during': [7], 'state': [[3, 'G'], [6, 'R']], 'next': [4, 6]}, 'R')], [({'parents': [1, 4], 'not_during': [8], 'state': [[3, 'Y'], [5, 'G']], 'next': []}, 'R'), ({'parents': [3, 4, 8], 'not_during': [5], 'state': [[1, 'G'], [4, 'RC']], 'next': [4]}, 'G'), ({'parents': [1, 5], 'not_during': [], 'state': [[6, 'G'], [8, 'Y']], 'next': []}, 'R'), ({'parents': [4, 5, 7], 'not_during': [3], 'state': [[5, 'RC'], [1, 'Y']], 'next': [5]}, 'G'), ({'parents': [5, 7], 'not_during': [4, 6], 'state': [[3, 'Y'], [5, 'RC']], 'next': [3, 8]}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y')], [({'parents': [2, 4], 'not_during': [3, 5], 'state': [[6, 'G'], [5, 'G']], 'next': [1, 5]}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [2], 'not_during': [], 'state': [[6, 'Y'], [7, 'G'], [8, 'G']], 'next': []}, 'R'), ({'parents': [3], 'not_during': [], 'state': [[4, 'RC']], 'next': [7]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 3, 4], 'not_during': [], 'state': [[6, 'R'], [4, 'RC'], [5, 'Y']], 'next': [2, 6]}, 'G'), ({'parents': [6, 7], 'not_during': [2], 'state': [[4, 'G'], [1, 'Y'], [7, 'RC']], 'next': [4, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G')], [({'parents': [4], 'not_during': [3], 'state': [[7, 'R'], [5, 'R'], [4, 'RC']], 'next': [4, 8]}, 'G'), ({'parents': [8], 'not_during': [1, 7], 'state': [[3, 'RC'], [2, 'R']], 'next': []}, 'R'), ({'parents': [2, 6, 8], 'not_during': [3, 5], 'state': [[1, 'R'], [3, 'Y']], 'next': [6, 8]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 4], 'not_during': [], 'state': [[1, 'RC']], 'next': [4, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [1, 3, 5], 'not_during': [4, 6], 'state': [[3, 'R']], 'next': [4, 5]}, 'R')], [({'parents': [1, 2, 6], 'not_during': [3], 'state': [[6, 'RC'], [3, 'RC'], [5, 'G']], 'next': [2, 6]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [5], 'not_during': [], 'state': [[8, 'G']], 'next': [3, 8]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [5], 'not_during': [2], 'state': [[4, 'RC'], [2, 'R'], [6, 'G']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 4], 'not_during': [5], 'state': [[1, 'RC'], [4, 'RC'], [2, 'RC']], 'next': [4, 7]}, 'G'), ({'parents': [5, 7, 8], 'not_during': [2, 3], 'state': [[7, 'RC'], [6, 'G'], [8, 'RC']], 'next': []}, 'R')]]
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:
Overlap phase indication returns a wrong result when parents in red clearance are not treated as terminating.

Input {parents, not_during, state: [[phase, G|Y|RC|R]] for timing phases, next: phases to be served next}. The overlap is red while any not_during phase is green. Otherwise it is green while any parent is green. If a parent is terminating (Y or RC) the overlap stays green when any next phase is a parent; otherwise it is yellow if any terminating parent is in yellow, else red. Otherwise red.

split: open-access


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

N = 1
observations = []
def solve(x):
    par = set(x['parents'])
    nd = set(x['not_during'])
    cur = {ph: iv for ph, iv in x['state']}
    if any(cur.get(p) == 'G' for p in nd):
        return 'R'
    if any(cur.get(p) == 'G' for p in par):
        return 'G'
    terminating = [p for p in sorted(par) if cur.get(p) in ('Y', 'RC')]
    if terminating:
        if any(p in par for p in x['next']):
            return 'G'
        if any(iv == 'Y' for iv in cur.values()):
            return 'Y'
        return 'R'
    return 'R'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'parents': [1, 6, 8], 'not_during': [], 'state': [[7, 'Y'], [1, 'RC'], [4, 'G']], 'next': []}, 'R'), ({'parents': [5], 'not_during': [], 'state': [[5, 'RC']], 'next': [7]}, 'R'), ({'parents': [1, 2, 3], 'not_during': [], 'state': [[4, 'Y'], [2, 'RC'], [1, 'RC']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 7], 'not_during': [2], 'state': [[7, 'R']], 'next': []}, 'R'), ({'parents': [2, 6], 'not_during': [], 'state': [[1, 'G'], [2, 'RC'], [8, 'Y']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G')], [({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 2, 6], 'not_during': [5, 8], 'state': [[5, 'Y'], [6, 'RC']], 'next': [5]}, 'R'), ({'parents': [3, 4], 'not_during': [], 'state': [[7, 'RC']], 'next': [1, 8]}, 'R'), ({'parents': [3], 'not_during': [5, 7], 'state': [[2, 'G'], [8, 'G'], [3, 'G']], 'next': [4, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [3, 4, 8], 'not_during': [1], 'state': [[7, 'G'], [6, 'Y'], [4, 'RC']], 'next': [6, 7]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 8], 'not_during': [5, 6], 'state': [[2, 'RC'], [3, 'R'], [8, 'Y']], 'next': []}, 'Y')], [({'parents': [6, 7], 'not_during': [4], 'state': [[7, 'RC'], [4, 'Y'], [3, 'G']], 'next': [5, 8]}, 'R'), ({'parents': [6], 'not_during': [1, 5], 'state': [[6, 'RC'], [3, 'Y']], 'next': [3, 4]}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 8], 'not_during': [2], 'state': [[7, 'R'], [8, 'G']], 'next': []}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [1, 2, 4], 'not_during': [6], 'state': [[6, 'Y'], [2, 'RC']], 'next': [3]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 7], 'not_during': [8], 'state': [[8, 'R'], [3, 'Y']], 'next': []}, 'R')], [({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [2], 'not_during': [], 'state': [[3, 'Y'], [1, 'G'], [2, 'RC']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 2], 'not_during': [4], 'state': [[7, 'Y'], [1, 'RC'], [2, 'Y']], 'next': []}, 'Y'), ({'parents': [1, 5], 'not_during': [3], 'state': [[7, 'R'], [4, 'Y'], [5, 'RC']], 'next': []}, 'R'), ({'parents': [4], 'not_during': [3, 8], 'state': [[4, 'RC'], [3, 'Y'], [5, 'Y']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [1, 6], 'not_during': [5, 7], 'state': [[5, 'G'], [4, 'Y'], [8, 'R']], 'next': []}, 'R')], [({'parents': [3, 5], 'not_during': [], 'state': [[8, 'G'], [2, 'G'], [7, 'RC']], 'next': [2, 7]}, 'R'), ({'parents': [6, 8], 'not_during': [], 'state': [[2, 'Y'], [4, 'Y'], [6, 'RC']], 'next': []}, 'R'), ({'parents': [1, 2, 7], 'not_during': [4, 6], 'state': [[7, 'RC'], [6, 'R'], [8, 'Y']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 4, 6], 'not_during': [2], 'state': [[5, 'R'], [1, 'RC'], [3, 'Y']], 'next': []}, 'R'), ({'parents': [1, 2], 'not_during': [], 'state': [[2, 'RC']], 'next': [7]}, 'R')]]
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):
    par = set(x['parents'])
    nd = set(x['not_during'])
    cur = {ph: iv for ph, iv in x['state']}
    if any(cur.get(p) == 'G' for p in nd):
        return 'R'
    if any(cur.get(p) == 'G' for p in par):
        return 'G'
    terminating = [p for p in sorted(par) if cur.get(p) in ('Y', 'RC')]
    if terminating:
        if any(p in par for p in x['next']):
            return 'G'
        if cur[terminating[0]] == 'Y':
            return 'Y'
        return 'R'
    return 'R'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'parents': [1, 6, 8], 'not_during': [], 'state': [[7, 'Y'], [1, 'RC'], [4, 'G']], 'next': []}, 'R'), ({'parents': [5], 'not_during': [], 'state': [[5, 'RC']], 'next': [7]}, 'R'), ({'parents': [1, 2, 3], 'not_during': [], 'state': [[4, 'Y'], [2, 'RC'], [1, 'RC']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 7], 'not_during': [2], 'state': [[7, 'R']], 'next': []}, 'R'), ({'parents': [2, 6], 'not_during': [], 'state': [[1, 'G'], [2, 'RC'], [8, 'Y']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G')], [({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 2, 6], 'not_during': [5, 8], 'state': [[5, 'Y'], [6, 'RC']], 'next': [5]}, 'R'), ({'parents': [3, 4], 'not_during': [], 'state': [[7, 'RC']], 'next': [1, 8]}, 'R'), ({'parents': [3], 'not_during': [5, 7], 'state': [[2, 'G'], [8, 'G'], [3, 'G']], 'next': [4, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [3, 4, 8], 'not_during': [1], 'state': [[7, 'G'], [6, 'Y'], [4, 'RC']], 'next': [6, 7]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 8], 'not_during': [5, 6], 'state': [[2, 'RC'], [3, 'R'], [8, 'Y']], 'next': []}, 'Y')], [({'parents': [6, 7], 'not_during': [4], 'state': [[7, 'RC'], [4, 'Y'], [3, 'G']], 'next': [5, 8]}, 'R'), ({'parents': [6], 'not_during': [1, 5], 'state': [[6, 'RC'], [3, 'Y']], 'next': [3, 4]}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [4, 8], 'not_during': [2], 'state': [[7, 'R'], [8, 'G']], 'next': []}, 'G'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [1, 2, 4], 'not_during': [6], 'state': [[6, 'Y'], [2, 'RC']], 'next': [3]}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 7], 'not_during': [8], 'state': [[8, 'R'], [3, 'Y']], 'next': []}, 'R')], [({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [2], 'not_during': [], 'state': [[3, 'Y'], [1, 'G'], [2, 'RC']], 'next': []}, 'R'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 2], 'not_during': [4], 'state': [[7, 'Y'], [1, 'RC'], [2, 'Y']], 'next': []}, 'Y'), ({'parents': [1, 5], 'not_during': [3], 'state': [[7, 'R'], [4, 'Y'], [5, 'RC']], 'next': []}, 'R'), ({'parents': [4], 'not_during': [3, 8], 'state': [[4, 'RC'], [3, 'Y'], [5, 'Y']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [1, 6], 'not_during': [5, 7], 'state': [[5, 'G'], [4, 'Y'], [8, 'R']], 'next': []}, 'R')], [({'parents': [3, 5], 'not_during': [], 'state': [[8, 'G'], [2, 'G'], [7, 'RC']], 'next': [2, 7]}, 'R'), ({'parents': [6, 8], 'not_during': [], 'state': [[2, 'Y'], [4, 'Y'], [6, 'RC']], 'next': []}, 'R'), ({'parents': [1, 2, 7], 'not_during': [4, 6], 'state': [[7, 'RC'], [6, 'R'], [8, 'Y']], 'next': []}, 'R'), ({'parents': [4, 5], 'not_during': [], 'state': [[4, 'RC'], [5, 'Y']], 'next': [1]}, 'Y'), ({'parents': [2, 3], 'not_during': [], 'state': [[2, 'RC'], [6, 'RC']], 'next': [3, 7]}, 'G'), ({'parents': [2, 3], 'not_during': [5], 'state': [[3, 'G'], [5, 'G']], 'next': []}, 'R'), ({'parents': [1, 4, 6], 'not_during': [2], 'state': [[5, 'R'], [1, 'RC'], [3, 'Y']], 'next': []}, 'R'), ({'parents': [1, 2], 'not_during': [], 'state': [[2, 'RC']], 'next': [7]}, 'R')]]
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:
Overlap phase indication returns a wrong result when overlap yellow follows any yellow phase at the intersection.

Input {parents, not_during, state: [[phase, G|Y|RC|R]] for timing phases, next: phases to be served next}. The overlap is red while any not_during phase is green. Otherwise it is green while any parent is green. If a parent is terminating (Y or RC) the overlap stays green when any next phase is a parent; otherwise it is yellow if any terminating parent is in yellow, else red. Otherwise red.

split: open-access


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

N = 1
observations = []
def solve(x):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur - x['grace'], 1440)
        fee = days * x['daily_max'] + min(x['daily_max'], -(-rem // 60) * x['hourly'])
    if x['lost_ticket']:
        fee = max(fee, x['lost_fee'])
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1632, 'exit': 3252, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 2400), ({'entry': 2554, 'exit': 4295, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 1901, 'exit': 2083, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 800), ({'entry': 2535, 'exit': 2780, 'grace': 10, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 1000), ({'entry': 2829, 'exit': 3340, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0)], [({'entry': 1167, 'exit': 1504, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 1800), ({'entry': 2822, 'exit': 3008, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 800), ({'entry': 1104, 'exit': 1533, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1858, 'exit': 1884, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 450), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2627, 'exit': 2930, 'grace': 20, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 2400)], [({'entry': 1596, 'exit': 1839, 'grace': 10, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000), ({'entry': 1635, 'exit': 1861, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1200), ({'entry': 804, 'exit': 2244, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1006, 'exit': 1076, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 900), ({'entry': 2160, 'exit': 6481, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7400)], [({'entry': 2742, 'exit': 4255, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2900), ({'entry': 414, 'exit': 2095, 'grace': 20, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 271, 'exit': 685, 'grace': 15, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1400), ({'entry': 2163, 'exit': 2233, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 1405, 'exit': 1831, 'grace': 10, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 1600), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 2752, 'exit': 3173, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1055, 'exit': 1487, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 1600), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2422, 'exit': 2542, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 2869, 'exit': 3243, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 1400), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 857, 'exit': 1248, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1500)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur - x['grace'], 1440) if dur < 1440 else divmod(dur, 1440)
        fee = days * x['daily_max'] + min(x['daily_max'], -(-rem // 60) * x['hourly'])
    if x['lost_ticket']:
        fee = max(fee, x['lost_fee'])
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1632, 'exit': 3252, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 2400), ({'entry': 2554, 'exit': 4295, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 1901, 'exit': 2083, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 800), ({'entry': 2535, 'exit': 2780, 'grace': 10, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 1000), ({'entry': 2829, 'exit': 3340, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0)], [({'entry': 1167, 'exit': 1504, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 1800), ({'entry': 2822, 'exit': 3008, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 800), ({'entry': 1104, 'exit': 1533, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1858, 'exit': 1884, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 450), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2627, 'exit': 2930, 'grace': 20, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 2400)], [({'entry': 1596, 'exit': 1839, 'grace': 10, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000), ({'entry': 1635, 'exit': 1861, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1200), ({'entry': 804, 'exit': 2244, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1006, 'exit': 1076, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 900), ({'entry': 2160, 'exit': 6481, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7400)], [({'entry': 2742, 'exit': 4255, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2900), ({'entry': 414, 'exit': 2095, 'grace': 20, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 271, 'exit': 685, 'grace': 15, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1400), ({'entry': 2163, 'exit': 2233, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 1405, 'exit': 1831, 'grace': 10, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 1600), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 2752, 'exit': 3173, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1055, 'exit': 1487, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 1600), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2422, 'exit': 2542, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 2869, 'exit': 3243, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 1400), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 857, 'exit': 1248, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1500)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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:
Garage hourly fee with grace and daily maximum returns a wrong result when the grace period is deducted from every stay.

Input {entry, exit (absolute minutes), grace, hourly, daily_max, lost_ticket, lost_fee}; cents. Exit before entry is 'invalid'. A stay no longer than grace is free (grace is not deducted from longer stays). Otherwise each full 1440-minute block costs daily_max and the remainder costs hourly per started hour, capped at daily_max. A lost ticket pays the greater of the computed fee and lost_fee.

split: open-access


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

N = 1
observations = []
def solve(x):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur, 1440)
        fee = days * x['daily_max'] + min(x['daily_max'], (rem // 60) * x['hourly'])
    if x['lost_ticket']:
        fee = max(fee, x['lost_fee'])
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 2558, 'exit': 3256, 'grace': 10, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000), ({'entry': 2210, 'exit': 2538, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 319, 'exit': 350, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 300), ({'entry': 1650, 'exit': 2045, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2110, 'exit': 2118, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 0)], [({'entry': 396, 'exit': 561, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 900), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 625, 'exit': 633, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 889, 'exit': 910, 'grace': 0, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 450), ({'entry': 2241, 'exit': 6561, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 436, 'exit': 417, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0)], [({'entry': 561, 'exit': 4971, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4900), ({'entry': 353, 'exit': 551, 'grace': 20, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1800), ({'entry': 1031, 'exit': 1034, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1182, 'exit': 5502, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 963, 'exit': 1120, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 810, 'exit': 1530, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 866, 'exit': 1216, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 2379, 'exit': 2409, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 256, 'exit': 551, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1000), ({'entry': 33, 'exit': 4353, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 6000)], [({'entry': 2094, 'exit': 2098, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 450), ({'entry': 567, 'exit': 1020, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 2252, 'exit': 2411, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 1169, 'exit': 1186, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2558, 'exit': 2796, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur, 1440)
        fee = days * x['daily_max'] + min(x['daily_max'], (rem // 60 + 1) * x['hourly'])
    if x['lost_ticket']:
        fee = max(fee, x['lost_fee'])
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 2558, 'exit': 3256, 'grace': 10, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000), ({'entry': 2210, 'exit': 2538, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 319, 'exit': 350, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 300), ({'entry': 1650, 'exit': 2045, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2110, 'exit': 2118, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 0)], [({'entry': 396, 'exit': 561, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 900), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 625, 'exit': 633, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 889, 'exit': 910, 'grace': 0, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 450), ({'entry': 2241, 'exit': 6561, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 436, 'exit': 417, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0)], [({'entry': 561, 'exit': 4971, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4900), ({'entry': 353, 'exit': 551, 'grace': 20, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1800), ({'entry': 1031, 'exit': 1034, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1182, 'exit': 5502, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 963, 'exit': 1120, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 810, 'exit': 1530, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 866, 'exit': 1216, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 2379, 'exit': 2409, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 256, 'exit': 551, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1000), ({'entry': 33, 'exit': 4353, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 6000)], [({'entry': 2094, 'exit': 2098, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 450), ({'entry': 567, 'exit': 1020, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 2252, 'exit': 2411, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 1169, 'exit': 1186, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2558, 'exit': 2796, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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:
Garage hourly fee with grace and daily maximum returns a wrong result when partial hours are not charged.

Input {entry, exit (absolute minutes), grace, hourly, daily_max, lost_ticket, lost_fee}; cents. Exit before entry is 'invalid'. A stay no longer than grace is free (grace is not deducted from longer stays). Otherwise each full 1440-minute block costs daily_max and the remainder costs hourly per started hour, capped at daily_max. A lost ticket pays the greater of the computed fee and lost_fee.

split: open-access


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

N = 1
observations = []
def solve(x):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur, 1440)
        fee = days * x['daily_max'] + -(-rem // 60) * x['hourly']
    if x['lost_ticket']:
        fee = max(fee, x['lost_fee'])
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 1945, 'exit': 6562, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 5500), ({'entry': 567, 'exit': 963, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 1362, 'exit': 5675, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 731, 'exit': 2171, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1335, 'exit': 1738, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000)], [({'entry': 132, 'exit': 552, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 465, 'exit': 1605, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 53, 'exit': 593, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1903, 'exit': 4783, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 4000), ({'entry': 2049, 'exit': 2559, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 2400), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 2226, 'exit': 4482, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 918, 'exit': 3798, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 4800), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1152, 'exit': 1160, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2128, 'exit': 3328, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 1705, 'exit': 3954, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800)], [({'entry': 2136, 'exit': 3576, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 359, 'exit': 377, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 358, 'exit': 898, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1365, 'exit': 3758, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 411, 'exit': 4074, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350)], [({'entry': 2534, 'exit': 2857, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 163, 'exit': 3043, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 2508, 'exit': 6945, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 7800), ({'entry': 950, 'exit': 1518, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2204, 'exit': 4608, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 4000), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur, 1440)
        fee = days * x['daily_max'] + min(x['daily_max'], -(-dur // 60) * x['hourly'])
    if x['lost_ticket']:
        fee = max(fee, x['lost_fee'])
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 1945, 'exit': 6562, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 5500), ({'entry': 567, 'exit': 963, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 1362, 'exit': 5675, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 731, 'exit': 2171, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1335, 'exit': 1738, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000)], [({'entry': 132, 'exit': 552, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 465, 'exit': 1605, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 53, 'exit': 593, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1903, 'exit': 4783, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 4000), ({'entry': 2049, 'exit': 2559, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 2400), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 2226, 'exit': 4482, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 918, 'exit': 3798, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 4800), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1152, 'exit': 1160, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2128, 'exit': 3328, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 1705, 'exit': 3954, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800)], [({'entry': 2136, 'exit': 3576, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 359, 'exit': 377, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 358, 'exit': 898, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1365, 'exit': 3758, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 411, 'exit': 4074, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350)], [({'entry': 2534, 'exit': 2857, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 163, 'exit': 3043, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 2508, 'exit': 6945, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 7800), ({'entry': 950, 'exit': 1518, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2204, 'exit': 4608, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 4000), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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:
Garage hourly fee with grace and daily maximum returns a wrong result when the remainder of a multi-day stay is not capped.

Input {entry, exit (absolute minutes), grace, hourly, daily_max, lost_ticket, lost_fee}; cents. Exit before entry is 'invalid'. A stay no longer than grace is free (grace is not deducted from longer stays). Otherwise each full 1440-minute block costs daily_max and the remainder costs hourly per started hour, capped at daily_max. A lost ticket pays the greater of the computed fee and lost_fee.

split: open-access


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

N = 1
observations = []
def solve(x):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur, 1440)
        fee = days * 24 * x['hourly'] + min(x['daily_max'], -(-rem // 60) * x['hourly'])
    if x['lost_ticket']:
        fee = max(fee, x['lost_fee'])
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 2887, 'exit': 5767, 'grace': 10, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 3000), ({'entry': 1112, 'exit': 1101, 'grace': 0, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 558, 'exit': 4878, 'grace': 10, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 6000), ({'entry': 2883, 'exit': 2887, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1964, 'exit': 3429, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2700)], [({'entry': 633, 'exit': 4953, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 2832, 'exit': 4032, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 491, 'exit': 518, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 300), ({'entry': 2071, 'exit': 3511, 'grace': 15, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 1163, 'exit': 5200, 'grace': 0, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 7200)], [({'entry': 333, 'exit': 633, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2127, 'exit': 2128, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 140, 'exit': 1640, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2300), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 703, 'exit': 3465, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 4800), ({'entry': 2181, 'exit': 6501, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000)], [({'entry': 1596, 'exit': 5916, 'grace': 10, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 6000), ({'entry': 162, 'exit': 942, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2284, 'exit': 5992, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 7200), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1031, 'exit': 2171, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 2400), ({'entry': 371, 'exit': 905, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400)], [({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 2834, 'exit': 2808, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 'invalid'), ({'entry': 228, 'exit': 211, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 728, 'exit': 3608, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 4800), ({'entry': 2865, 'exit': 2837, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1658, 'exit': 4538, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 4000), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur, 1440)
        fee = max(0, days - 1) * x['daily_max'] + min(x['daily_max'], -(-rem // 60) * x['hourly'])
    if x['lost_ticket']:
        fee = max(fee, x['lost_fee'])
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 2887, 'exit': 5767, 'grace': 10, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 3000), ({'entry': 1112, 'exit': 1101, 'grace': 0, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 558, 'exit': 4878, 'grace': 10, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 6000), ({'entry': 2883, 'exit': 2887, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1964, 'exit': 3429, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2700)], [({'entry': 633, 'exit': 4953, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 2832, 'exit': 4032, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 491, 'exit': 518, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 300), ({'entry': 2071, 'exit': 3511, 'grace': 15, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 1163, 'exit': 5200, 'grace': 0, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 7200)], [({'entry': 333, 'exit': 633, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2127, 'exit': 2128, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 140, 'exit': 1640, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2300), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 703, 'exit': 3465, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 4800), ({'entry': 2181, 'exit': 6501, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000)], [({'entry': 1596, 'exit': 5916, 'grace': 10, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 6000), ({'entry': 162, 'exit': 942, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2284, 'exit': 5992, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 7200), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1031, 'exit': 2171, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 2400), ({'entry': 371, 'exit': 905, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400)], [({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 2834, 'exit': 2808, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 'invalid'), ({'entry': 228, 'exit': 211, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 728, 'exit': 3608, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 4800), ({'entry': 2865, 'exit': 2837, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1658, 'exit': 4538, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 4000), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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:
Garage hourly fee with grace and daily maximum returns a wrong result when full day blocks are billed at 24 hourly charges.

Input {entry, exit (absolute minutes), grace, hourly, daily_max, lost_ticket, lost_fee}; cents. Exit before entry is 'invalid'. A stay no longer than grace is free (grace is not deducted from longer stays). Otherwise each full 1440-minute block costs daily_max and the remainder costs hourly per started hour, capped at daily_max. A lost ticket pays the greater of the computed fee and lost_fee.

split: open-access


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

N = 1
observations = []
def solve(x):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur, 1440)
        fee = days * x['daily_max'] + min(x['daily_max'], -(-rem // 60) * x['hourly'])
    if x['lost_ticket']:
        fee = x['lost_fee']
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 1082, 'exit': 5693, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 6000), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 184, 'exit': 280, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 2107, 'exit': 2568, 'grace': 10, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2424, 'exit': 6728, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 3000}, 4500), ({'entry': 2475, 'exit': 5355, 'grace': 20, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 124, 'exit': 143, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 318, 'exit': 5189, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 9600), ({'entry': 927, 'exit': 1380, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 69, 'exit': 4389, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 3000}, 4500), ({'entry': 648, 'exit': 2644, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 4800), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)], [({'entry': 2135, 'exit': 5612, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 7200), ({'entry': 166, 'exit': 2354, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1120, 'exit': 1138, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 429, 'exit': 683, 'grace': 20, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 4, 'exit': 2884, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 4800)], [({'entry': 2108, 'exit': 4988, 'grace': 20, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 4000), ({'entry': 1675, 'exit': 6410, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 6000), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2388, 'exit': 2625, 'grace': 15, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 903, 'exit': 4042, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 3000}, 4000), ({'entry': 1659, 'exit': 2168, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)], [({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 445, 'exit': 3325, 'grace': 0, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 4800), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1568, 'exit': 2228, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 2826, 'exit': 7146, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 7200), ({'entry': 2274, 'exit': 5519, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 4500), ({'entry': 1853, 'exit': 1872, 'grace': 10, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 3000)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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):
    if x['exit'] < x['entry']:
        return 'invalid'
    dur = x['exit'] - x['entry']
    if dur <= x['grace']:
        fee = 0
    else:
        days, rem = divmod(dur, 1440)
        fee = days * x['daily_max'] + min(x['daily_max'], -(-rem // 60) * x['hourly'])
    if x['lost_ticket']:
        fee = fee + x['lost_fee']
    return fee
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 1082, 'exit': 5693, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 6000), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 184, 'exit': 280, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 2107, 'exit': 2568, 'grace': 10, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2424, 'exit': 6728, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 3000}, 4500), ({'entry': 2475, 'exit': 5355, 'grace': 20, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 124, 'exit': 143, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 318, 'exit': 5189, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 9600), ({'entry': 927, 'exit': 1380, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 69, 'exit': 4389, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 3000}, 4500), ({'entry': 648, 'exit': 2644, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 4800), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)], [({'entry': 2135, 'exit': 5612, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 7200), ({'entry': 166, 'exit': 2354, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1120, 'exit': 1138, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 429, 'exit': 683, 'grace': 20, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 4, 'exit': 2884, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 4800)], [({'entry': 2108, 'exit': 4988, 'grace': 20, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 4000), ({'entry': 1675, 'exit': 6410, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 6000), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2388, 'exit': 2625, 'grace': 15, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 903, 'exit': 4042, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 3000}, 4000), ({'entry': 1659, 'exit': 2168, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)], [({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 445, 'exit': 3325, 'grace': 0, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 4800), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1568, 'exit': 2228, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 2826, 'exit': 7146, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 7200), ({'entry': 2274, 'exit': 5519, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 4500), ({'entry': 1853, 'exit': 1872, 'grace': 10, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 3000}, 3000)]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('fee 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:
Garage hourly fee with grace and daily maximum returns a wrong result when the lost ticket fee replaces a larger computed fee.

Input {entry, exit (absolute minutes), grace, hourly, daily_max, lost_ticket, lost_fee}; cents. Exit before entry is 'invalid'. A stay no longer than grace is free (grace is not deducted from longer stays). Otherwise each full 1440-minute block costs daily_max and the remainder costs hourly per started hour, capped at daily_max. A lost ticket pays the greater of the computed fee and lost_fee.

split: open-access