{
  "id": "P097",
  "slug": "traffic-lights",
  "key": "P097-traffic-lights",
  "title": "Traffic lights",
  "summary": "A junction of two roads with a walk button, run second by second; and an audit that checks every second of a log against six rules and reports every violation - on the run itself, the run with a fault put in, or a log typed in.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P097 - Traffic lights\n\nA junction of two roads, north-south (NS) and east-west (EW), with a walk\nbutton, run second by second. Then an audit that checks every second of\na log against six rules and reports every violation, not just the first.\nIt audits the run itself, the run with a fault put in, or a log typed in.\nThe program starts with 120 seconds and the button pressed at seconds 5\nand 70.\n\n- `main.eml` - the menu, the run table, the audit report, presses and\n  timings\n- `lights.eml` - the controller, the audit, the faults, and reading a\n  typed log\n\nHow each part works:\n\n- The controller, as in the corpus case `traffic-light-simulator`: each\n  phase is held for its time, and an index moves on by hand: NS green, NS\n  yellow, all red, EW green, EW yellow, all red. A press of the button\n  is kept until the next all red ends. Then come walk, flashing, and the\n  next green. A press during a walk is already answered.\n- A log is one entry a second: NS, EW and the walk signal.\n- The audit, as in the corpus case `state-machine-trace-audit`: every\n  second is checked against every rule, and every violation is listed.\n  The rules:\n  1. a light goes green, yellow, red, green, with no other change;\n  2. never both roads not red;\n  3. walk or flashing only while both roads are red;\n  4. the walk signal goes don't walk, walk, flashing, don't walk;\n  5. a yellow lasts at least the yellow time;\n  6. a road turns green only after the other has been red for the all\n     red time.\n\n  A yellow already showing at second 0, or still showing at the end, is\n  not timed. The report ends with clean seconds plus seconds with a\n  violation, which add up to the seconds checked, and the count for each\n  rule.\n- The faults:\n  - stuck: NS stays green for the first 2 seconds of EW green;\n  - no-yellow: NS's first yellow shows green instead;\n  - short-yellow: NS's first yellow lasts 1 second;\n  - early-walk: the first walk starts a second before the all red.\n\n  Each is put in only where it will show before the log ends.\n\nWhat is checked: menu choices 1 to 5; a log name; 2 to 60 typed entries\nof three letters (G, Y or R twice, then D, W or F); up to 10 presses, each\nwithin the run, or none; green 5 to 60, yellow 3 to 6, all red 1 to 5,\nwalk 4 to 20 and flashing 3 to 20 seconds, and a run of 30 to 300\nseconds. An empty answer cancels.\n\nSessions: `sessions/basic.in` gives:\n- the run, with waits of 20 and 17 seconds; its audit, which is clean;\n- each fault and the violations it causes: 3, 1, 1 and 1;\n- a typed log with 8 violations in 5 of its 8 seconds;\n- presses at 30, 52 and 115: a wait, a press that is already walking,\n  and one with no walk before the run ends;\n- shorter timings and a 60-second run, which drops the press at 115; its\n  run and clean audit.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x; the log lizard; a cancel;\n- typed logs with one entry, a bad letter, and four letters;\n- presses abc, 120, eleven of them; a cancel; none, then a run with no\n  presses and an early-walk with no walk;\n- timings out of range for green, yellow, all red and walk; then\n  cancels.\n\nBuilt on the verified corpus cases `traffic-light-simulator` (phases held\nfor set times, the index moved on by hand) and\n`state-machine-trace-audit` (every event judged, not just the first bad\none, and the totals that tie the verdicts together).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P097 traffic lights: a junction with a walk button, run second by second,\n# and an audit that checks every second of a log against every rule -\n# the run itself, the run with a fault put in, or a log typed in.\nimport lights\n\ndef plain(s):\n    0 => i\n    len(s) => j\n    while i < j and s[i] == \" \":\n        i + 1 => i\n    while j > i and s[j - 1] == \" \":\n        j - 1 => j\n    return s[i:j]\n\ndef number(s, most):\n    if len(s) == 0 or len(s) > most:\n        return -1\n    0 => n\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n * 10 + int(c) => n\n    return n\n\ndef pad(s, n):\n    while len(s) < n:\n        s + \" \" => s\n    return s\n\ndef lpad(s, n):\n    while len(s) < n:\n        \" \" + s => s\n    return s\n\ndef seconds(n):\n    if n == 1:\n        return \"1 second\"\n    return str(n) + \" seconds\"\n\ndef ask(prompt, low, high):\n    while True:\n        plain(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \")) => a\n        if a == \"\":\n            return -1\n        number(a, 6) => n\n        if n >= low and n <= high:\n            return n\n        (\"Type a whole number from \" + str(low) + \" to \" + str(high) + \".\") ^0\n\ndef show_run(cfg, presses):\n    lights.run(cfg, presses) => log\n    (\"North-south (NS) and east-west (EW), \" + seconds(cfg[5]) + \": green \" + str(cfg[0]) + \", yellow \" + str(cfg[1]) + \", all red \" + str(cfg[2]) + \", walk \" + str(cfg[3]) + \", flashing \" + str(cfg[4]) + \".\") ^0\n    \"  seconds NS      EW      walk\" ^0\n    for g in lights.runs(log):\n        \"     \" => span\n        if g[1] > g[0]:\n            \"-\" + pad(str(g[1]), 4) => span\n        (\"  \" + lpad(str(g[0]), 3) + span + pad(lights.name(g[2][0]), 8) + pad(lights.name(g[2][1]), 8) + lights.name(g[2][2])) ^0\n    if len(presses) == 0:\n        \"Nobody pressed the walk button.\" ^0\n    for w in lights.waits(log, presses):\n        if w[1] == -1:\n            (\"Button at second \" + str(w[0]) + \": no walk before the run ends.\") ^0\n        elif w[1] == w[0]:\n            (\"Button at second \" + str(w[0]) + \": already walking.\") ^0\n        else:\n            (\"Button at second \" + str(w[0]) + \": walk at second \" + str(w[1]) + \", after \" + seconds(w[1] - w[0]) + \".\") ^0\n    \"The button is answered when the next all red ends: both roads have stopped, then walk, flashing, and the next green.\" ^0\n\ndef report(log, cfg):\n    lights.audit(log, cfg[1], cfg[2]) => found\n    \"Every second against every rule:\" ^0\n    \"  1  a light goes green, yellow, red, green - no other change\" ^0\n    \"  2  never both roads not red\" ^0\n    \"  3  walk or flashing only while both roads are red\" ^0\n    \"  4  the walk signal goes don't walk, walk, flashing, don't walk\" ^0\n    (\"  5  a yellow lasts at least \" + seconds(cfg[1])) ^0\n    (\"  6  a road turns green only after the other has been red for \" + seconds(cfg[2])) ^0\n    if len(found) == 0:\n        \"No violations.\" ^0\n    else:\n        \"Every violation, not just the first:\" ^0\n    {} => bad\n    [0, 0, 0, 0, 0, 0, 0] => by_rule\n    for f in found:\n        (\"  second \" + lpad(str(f[0]), 3) + \", rule \" + str(f[1]) + \": \" + f[2]) ^0\n        True => bad[f[0]]\n        by_rule[f[1]] + 1 => by_rule[f[1]]\n    len(bad) => n\n    (str(len(log)) + \" seconds checked: \" + str(len(log) - n) + \" clean + \" + str(n) + \" with a violation.\") ^0\n    if len(found) > 0:\n        \"\" => line\n        for r in [1:6]:\n            if by_rule[r] > 0:\n                if line != \"\":\n                    line + \", \" => line\n                line + \"rule \" + str(r) + \": \" + str(by_rule[r]) => line\n        (str(len(found)) + \" in all - \" + line + \".\") ^0\n\ndef audit_menu(cfg, presses):\n    lights.run(cfg, presses) => log\n    \"Audit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\" ^0\n    plain(input(\"log (run, stuck, no-yellow, short-yellow, early-walk or own)> \")) => s\n    if s == \"\":\n        \"Cancelled.\" ^0\n        return\n    if s == \"own\":\n        \"One entry a second, three letters each: NS and EW (G, Y or R), then the walk signal (D don't walk, W walk, F flashing). For example: GRD YRD RRD RGD.\" ^0\n        lights.parse(plain(input(\"log (2 to 60 entries)> \"))) => log\n        if len(log) == 0:\n            \"Type 2 to 60 entries like GRD, separated by spaces.\" ^0\n            return\n    elif s == \"stuck\" or s == \"no-yellow\" or s == \"short-yellow\" or s == \"early-walk\":\n        lights.inject(log, s, cfg) => faulty\n        if len(faulty) == 0:\n            if s == \"stuck\":\n                \"EW never turns green with 2 seconds to spare in this run.\" ^0\n            elif s == \"early-walk\":\n                \"Nobody walks in this run; press the button first.\" ^0\n            else:\n                \"NS never finishes a yellow in this run.\" ^0\n            return\n        faulty => log\n        if s == \"stuck\":\n            \"Fault: NS stays green for the first 2 seconds of EW green, like a stuck relay.\" ^0\n        elif s == \"no-yellow\":\n            \"Fault: NS's first yellow shows green instead.\" ^0\n        elif s == \"short-yellow\":\n            \"Fault: NS's first yellow lasts 1 second, with red after.\" ^0\n        else:\n            \"Fault: the first walk starts a second before the all red, while a road is still yellow.\" ^0\n    elif s != \"run\":\n        \"Type run, stuck, no-yellow, short-yellow, early-walk or own.\" ^0\n        return\n    report(log, cfg)\n\ndef set_presses(cfg, presses):\n    (\"Seconds the walk button is pressed, 0 to \" + str(cfg[5] - 1) + \", up to 10 of them; or none.\") ^0\n    plain(input(\"presses> \")) => t\n    if t == \"\":\n        \"Cancelled.\" ^0\n        return presses\n    if t == \"none\":\n        \"No presses.\" ^0\n        return []\n    {} => seen\n    [] => out\n    \"\" => w\n    True => ok\n    for c in t + \" \":\n        if c == \" \":\n            if w != \"\":\n                number(w, 3) => v\n                if v < 0 or v >= cfg[5]:\n                    False => ok\n                elif not (v in seen):\n                    True => seen[v]\n                    out + [v] => out\n            \"\" => w\n        else:\n            w + c => w\n    if not ok or len(out) > 10:\n        (\"Type up to 10 seconds from 0 to \" + str(cfg[5] - 1) + \", separated by spaces, or none.\") ^0\n        return presses\n    # in order\n    for i in [1:len(out) - 1]:\n        i => j\n        while j > 0 and out[j - 1] > out[j]:\n            out[j] => x\n            out[j - 1] => out[j]\n            x => out[j - 1]\n            j - 1 => j\n    \"\" => line\n    for v in out:\n        if line != \"\":\n            line + \", \" => line\n        line + str(v) => line\n    (\"Presses at \" + line + \".\") ^0\n    return out\n\ndef timings(cfg):\n    ask(\"green\", 5, 60) => g\n    if g == -1:\n        \"Cancelled.\" ^0\n        return cfg\n    ask(\"yellow\", 3, 6) => y\n    if y == -1:\n        \"Cancelled.\" ^0\n        return cfg\n    ask(\"all red\", 1, 5) => a\n    if a == -1:\n        \"Cancelled.\" ^0\n        return cfg\n    ask(\"walk\", 4, 20) => w\n    if w == -1:\n        \"Cancelled.\" ^0\n        return cfg\n    ask(\"flashing\", 3, 20) => f\n    if f == -1:\n        \"Cancelled.\" ^0\n        return cfg\n    ask(\"seconds to run\", 30, 300) => n\n    if n == -1:\n        \"Cancelled.\" ^0\n        return cfg\n    (\"Green \" + str(g) + \", yellow \" + str(y) + \", all red \" + str(a) + \", walk \" + str(w) + \", flashing \" + str(f) + \"; \" + seconds(n) + \".\") ^0\n    return [g, y, a, w, f, n]\n\n[20, 3, 2, 7, 5, 120] => cfg\n[5, 70] => presses\n\n\"== Traffic lights ==\" ^0\n\"A junction with a walk button, second by second - and an audit that checks every second of a log against every rule.\" ^0\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) run  2) audit  3) walk button  4) timings  5) quit\" ^0\n    plain(input(\"choice> \")) => choice\n    if choice == \"1\":\n        show_run(cfg, presses)\n    elif choice == \"2\":\n        audit_menu(cfg, presses)\n    elif choice == \"3\":\n        set_presses(cfg, presses) => presses\n    elif choice == \"4\":\n        timings(cfg) => new\n        if new[5] != cfg[5]:\n            [] => kept\n            for v in presses:\n                if v < new[5]:\n                    kept + [v] => kept\n            if len(kept) < len(presses):\n                \"\" => line\n                for v in presses:\n                    if v >= new[5]:\n                        if line != \"\":\n                            line + \", \" => line\n                        line + str(v) => line\n                (\"The run now ends at second \" + str(new[5] - 1) + \"; dropped: \" + line + \".\") ^0\n            kept => presses\n        new => cfg\n    elif choice == \"5\":\n        False => running\n    else:\n        \"Pick a number from 1 to 5.\" ^0\n\"Bye.\" ^0\n",
      "python": "import lights\n\ndef plain(s):\n    i = 0\n    j = len(s)\n    while i < j and s[i] == \" \":\n        i = i + 1\n    while j > i and s[j - 1] == \" \":\n        j = j - 1\n    return s[i:j]\n\ndef number(s, most):\n    if len(s) == 0 or len(s) > most:\n        return -1\n    n = 0\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n = n * 10 + int(c)\n    return n\n\ndef pad(s, n):\n    while len(s) < n:\n        s = s + \" \"\n    return s\n\ndef lpad(s, n):\n    while len(s) < n:\n        s = \" \" + s\n    return s\n\ndef seconds(n):\n    if n == 1:\n        return \"1 second\"\n    return str(n) + \" seconds\"\n\ndef ask(prompt, low, high):\n    while True:\n        a = plain(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \"))\n        if a == \"\":\n            return -1\n        n = number(a, 6)\n        if n >= low and n <= high:\n            return n\n        print(\"Type a whole number from \" + str(low) + \" to \" + str(high) + \".\")\n\ndef show_run(cfg, presses):\n    log = lights.run(cfg, presses)\n    print(\"North-south (NS) and east-west (EW), \" + seconds(cfg[5]) + \": green \" + str(cfg[0]) + \", yellow \" + str(cfg[1]) + \", all red \" + str(cfg[2]) + \", walk \" + str(cfg[3]) + \", flashing \" + str(cfg[4]) + \".\")\n    print(\"  seconds NS      EW      walk\")\n    for g in lights.runs(log):\n        span = \"     \"\n        if g[1] > g[0]:\n            span = \"-\" + pad(str(g[1]), 4)\n        print(\"  \" + lpad(str(g[0]), 3) + span + pad(lights.name(g[2][0]), 8) + pad(lights.name(g[2][1]), 8) + lights.name(g[2][2]))\n    if len(presses) == 0:\n        print(\"Nobody pressed the walk button.\")\n    for w in lights.waits(log, presses):\n        if w[1] == -1:\n            print(\"Button at second \" + str(w[0]) + \": no walk before the run ends.\")\n        elif w[1] == w[0]:\n            print(\"Button at second \" + str(w[0]) + \": already walking.\")\n        else:\n            print(\"Button at second \" + str(w[0]) + \": walk at second \" + str(w[1]) + \", after \" + seconds(w[1] - w[0]) + \".\")\n    print(\"The button is answered when the next all red ends: both roads have stopped, then walk, flashing, and the next green.\")\n\ndef report(log, cfg):\n    found = lights.audit(log, cfg[1], cfg[2])\n    print(\"Every second against every rule:\")\n    print(\"  1  a light goes green, yellow, red, green - no other change\")\n    print(\"  2  never both roads not red\")\n    print(\"  3  walk or flashing only while both roads are red\")\n    print(\"  4  the walk signal goes don't walk, walk, flashing, don't walk\")\n    print(\"  5  a yellow lasts at least \" + seconds(cfg[1]))\n    print(\"  6  a road turns green only after the other has been red for \" + seconds(cfg[2]))\n    if len(found) == 0:\n        print(\"No violations.\")\n    else:\n        print(\"Every violation, not just the first:\")\n    bad = {}\n    by_rule = [0, 0, 0, 0, 0, 0, 0]\n    for f in found:\n        print(\"  second \" + lpad(str(f[0]), 3) + \", rule \" + str(f[1]) + \": \" + f[2])\n        bad[f[0]] = True\n        by_rule[f[1]] = by_rule[f[1]] + 1\n    n = len(bad)\n    print(str(len(log)) + \" seconds checked: \" + str(len(log) - n) + \" clean + \" + str(n) + \" with a violation.\")\n    if len(found) > 0:\n        line = \"\"\n        for r in range(1, 7):\n            if by_rule[r] > 0:\n                if line != \"\":\n                    line = line + \", \"\n                line = line + \"rule \" + str(r) + \": \" + str(by_rule[r])\n        print(str(len(found)) + \" in all - \" + line + \".\")\n\ndef audit_menu(cfg, presses):\n    log = lights.run(cfg, presses)\n    print(\"Audit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\")\n    s = plain(input(\"log (run, stuck, no-yellow, short-yellow, early-walk or own)> \"))\n    if s == \"\":\n        print(\"Cancelled.\")\n        return\n    if s == \"own\":\n        print(\"One entry a second, three letters each: NS and EW (G, Y or R), then the walk signal (D don't walk, W walk, F flashing). For example: GRD YRD RRD RGD.\")\n        log = lights.parse(plain(input(\"log (2 to 60 entries)> \")))\n        if len(log) == 0:\n            print(\"Type 2 to 60 entries like GRD, separated by spaces.\")\n            return\n    elif s == \"stuck\" or s == \"no-yellow\" or s == \"short-yellow\" or s == \"early-walk\":\n        faulty = lights.inject(log, s, cfg)\n        if len(faulty) == 0:\n            if s == \"stuck\":\n                print(\"EW never turns green with 2 seconds to spare in this run.\")\n            elif s == \"early-walk\":\n                print(\"Nobody walks in this run; press the button first.\")\n            else:\n                print(\"NS never finishes a yellow in this run.\")\n            return\n        log = faulty\n        if s == \"stuck\":\n            print(\"Fault: NS stays green for the first 2 seconds of EW green, like a stuck relay.\")\n        elif s == \"no-yellow\":\n            print(\"Fault: NS's first yellow shows green instead.\")\n        elif s == \"short-yellow\":\n            print(\"Fault: NS's first yellow lasts 1 second, with red after.\")\n        else:\n            print(\"Fault: the first walk starts a second before the all red, while a road is still yellow.\")\n    elif s != \"run\":\n        print(\"Type run, stuck, no-yellow, short-yellow, early-walk or own.\")\n        return\n    report(log, cfg)\n\ndef set_presses(cfg, presses):\n    print(\"Seconds the walk button is pressed, 0 to \" + str(cfg[5] - 1) + \", up to 10 of them; or none.\")\n    t = plain(input(\"presses> \"))\n    if t == \"\":\n        print(\"Cancelled.\")\n        return presses\n    if t == \"none\":\n        print(\"No presses.\")\n        return []\n    seen = {}\n    out = []\n    w = \"\"\n    ok = True\n    for c in t + \" \":\n        if c == \" \":\n            if w != \"\":\n                v = number(w, 3)\n                if v < 0 or v >= cfg[5]:\n                    ok = False\n                elif not v in seen:\n                    seen[v] = True\n                    out = out + [v]\n            w = \"\"\n        else:\n            w = w + c\n    if not ok or len(out) > 10:\n        print(\"Type up to 10 seconds from 0 to \" + str(cfg[5] - 1) + \", separated by spaces, or none.\")\n        return presses\n    for i in range(1, len(out)):\n        j = i\n        while j > 0 and out[j - 1] > out[j]:\n            x = out[j]\n            out[j] = out[j - 1]\n            out[j - 1] = x\n            j = j - 1\n    line = \"\"\n    for v in out:\n        if line != \"\":\n            line = line + \", \"\n        line = line + str(v)\n    print(\"Presses at \" + line + \".\")\n    return out\n\ndef timings(cfg):\n    g = ask(\"green\", 5, 60)\n    if g == -1:\n        print(\"Cancelled.\")\n        return cfg\n    y = ask(\"yellow\", 3, 6)\n    if y == -1:\n        print(\"Cancelled.\")\n        return cfg\n    a = ask(\"all red\", 1, 5)\n    if a == -1:\n        print(\"Cancelled.\")\n        return cfg\n    w = ask(\"walk\", 4, 20)\n    if w == -1:\n        print(\"Cancelled.\")\n        return cfg\n    f = ask(\"flashing\", 3, 20)\n    if f == -1:\n        print(\"Cancelled.\")\n        return cfg\n    n = ask(\"seconds to run\", 30, 300)\n    if n == -1:\n        print(\"Cancelled.\")\n        return cfg\n    print(\"Green \" + str(g) + \", yellow \" + str(y) + \", all red \" + str(a) + \", walk \" + str(w) + \", flashing \" + str(f) + \"; \" + seconds(n) + \".\")\n    return [g, y, a, w, f, n]\n\ncfg = [20, 3, 2, 7, 5, 120]\npresses = [5, 70]\nprint(\"== Traffic lights ==\")\nprint(\"A junction with a walk button, second by second - and an audit that checks every second of a log against every rule.\")\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) run  2) audit  3) walk button  4) timings  5) quit\")\n    choice = plain(input(\"choice> \"))\n    if choice == \"1\":\n        show_run(cfg, presses)\n    elif choice == \"2\":\n        audit_menu(cfg, presses)\n    elif choice == \"3\":\n        presses = set_presses(cfg, presses)\n    elif choice == \"4\":\n        new = timings(cfg)\n        if new[5] != cfg[5]:\n            kept = []\n            for v in presses:\n                if v < new[5]:\n                    kept = kept + [v]\n            if len(kept) < len(presses):\n                line = \"\"\n                for v in presses:\n                    if v >= new[5]:\n                        if line != \"\":\n                            line = line + \", \"\n                        line = line + str(v)\n                print(\"The run now ends at second \" + str(new[5] - 1) + \"; dropped: \" + line + \".\")\n            presses = kept\n        cfg = new\n    elif choice == \"5\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 5.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "lights.eml",
      "eml": "# P097 traffic lights - a junction of two roads, north-south (NS) and\n# east-west (EW), with a walk button, run second by second as in the corpus\n# case traffic-light-simulator (phases held for set times, an index moved\n# on by hand). Then an audit of the log, as in the corpus case\n# state-machine-trace-audit: every second against every rule, reporting\n# every violation, not just the first.\n#\n# A log is one entry per second: [NS, EW, walk], the lights \"G\", \"Y\" or \"R\",\n# the walk signal \"D\" (don't walk), \"W\" (walk) or \"F\" (flashing).\n\ndef name(c):\n    {\"G\": \"green\", \"Y\": \"yellow\", \"R\": \"red\", \"D\": \"don't walk\", \"W\": \"walk\", \"F\": \"flashing\"} => names\n    return names[c]\n\ndef run(cfg, presses):\n    # cfg: [green, yellow, all red, walk, flashing, seconds to run]. The\n    # cars go NS green, NS yellow, all red, EW green, EW yellow, all red. A\n    # press of the button (not during a walk) is kept until the next all\n    # red ends; then walk, flashing, and on to the next green.\n    [[\"G\", \"R\", cfg[0]], [\"Y\", \"R\", cfg[1]], [\"R\", \"R\", cfg[2]], [\"R\", \"G\", cfg[0]], [\"R\", \"Y\", cfg[1]], [\"R\", \"R\", cfg[2]]] => phases\n    {} => pressed\n    for t in presses:\n        True => pressed[t]\n    [] => log\n    0 => p\n    \"D\" => walk\n    0 => elapsed\n    False => pending\n    for t in [0:cfg[5] - 1]:\n        if t in pressed and walk != \"W\":\n            True => pending\n        if walk == \"D\":\n            log + [[phases[p][0], phases[p][1], \"D\"]] => log\n        else:\n            log + [[\"R\", \"R\", walk]] => log\n        elapsed + 1 => elapsed\n        if walk == \"W\":\n            if elapsed == cfg[3]:\n                \"F\" => walk\n                0 => elapsed\n        elif walk == \"F\":\n            if elapsed == cfg[4]:\n                \"D\" => walk\n                0 => elapsed\n                (p + 1) % 6 => p\n        elif elapsed == phases[p][2]:\n            0 => elapsed\n            if (p == 2 or p == 5) and pending:\n                \"W\" => walk\n                False => pending\n            else:\n                (p + 1) % 6 => p\n    return log\n\ndef same(a, b):\n    return a[0] == b[0] and a[1] == b[1] and a[2] == b[2]\n\ndef runs(log):\n    # Seconds in a row with the same lights: [first, last, entry].\n    [] => out\n    0 => first\n    for t in [1:len(log)]:\n        if t == len(log) or not same(log[t], log[first]):\n            out + [[first, t - 1, log[first]]] => out\n            t => first\n    return out\n\ndef waits(log, presses):\n    # For each press, the second the walk shows (the press itself if it is\n    # already walking), or -1 if no walk comes before the log ends.\n    [] => out\n    for t in presses:\n        -1 => at\n        t => s\n        while at == -1 and s < len(log):\n            if log[s][2] == \"W\":\n                s => at\n            s + 1 => s\n        out + [[t, at]] => out\n    return out\n\ndef copy(log):\n    [] => out\n    for e in log:\n        out + [[e[0], e[1], e[2]]] => out\n    return out\n\ndef inject(log, fault, cfg):\n    # A copy of the log with one fault put in, or [] if the log has no place\n    # where the fault would show before it ends.\n    copy(log) => out\n    if fault == \"stuck\":\n        # NS stays green for the first 2 seconds of EW green\n        for t in [1:len(log) - 3]:\n            if log[t][1] == \"G\" and log[t - 1][1] == \"R\":\n                \"G\" => out[t][0]\n                \"G\" => out[t + 1][0]\n                return out\n        return []\n    if fault == \"no-yellow\" or fault == \"short-yellow\":\n        # NS's first yellow: shown green, or cut to 1 second with red after\n        -1 => first\n        for t in [0:len(log) - 1]:\n            if first == -1 and log[t][0] == \"Y\":\n                t => first\n        if first == -1:\n            return []\n        first => t\n        while t < len(log) and log[t][0] == \"Y\":\n            t + 1 => t\n        if t == len(log):\n            return []\n        first => t\n        while t < len(log) and log[t][0] == \"Y\":\n            if fault == \"no-yellow\":\n                \"G\" => out[t][0]\n            elif t > first:\n                \"R\" => out[t][0]\n            t + 1 => t\n        return out\n    if fault == \"early-walk\":\n        # the first walk starts a second before the all red\n        for t in [1:len(log) - 1]:\n            if log[t][2] == \"W\" and log[t - 1][2] == \"D\":\n                if t - cfg[2] - 1 < 0:\n                    return []\n                for k in [t - cfg[2] - 1:t - 1]:\n                    \"W\" => out[k][2]\n                return out\n        return []\n    return []\n\ndef audit(log, yellow, allred):\n    # Every second against every rule; returns [second, rule, what] for each\n    # violation, in order. 1 a light goes green, yellow, red, green only;\n    # 2 never both roads not red; 3 walk or flashing only while both roads\n    # are red; 4 the walk signal goes don't walk, walk, flashing, don't\n    # walk; 5 a yellow lasts at least `yellow` seconds; 6 a road turns\n    # green only after the other has been red for `allred` seconds. A\n    # yellow already showing at second 0, or one still showing at the end,\n    # is not timed; nor is a green before second `allred`.\n    {\"G\": \"Y\", \"Y\": \"R\", \"R\": \"G\"} => after\n    {\"D\": \"W\", \"W\": \"F\", \"F\": \"D\"} => walk_after\n    [\"NS\", \"EW\"] => road\n    [] => found\n    [-1, -1] => ystart\n    for t in [0:len(log) - 1]:\n        log[t] => s\n        if t > 0:\n            log[t - 1] => q\n            for r in [0:1]:\n                if s[r] != q[r] and s[r] != after[q[r]]:\n                    found + [[t, 1, road[r] + \" went \" + name(q[r]) + \" to \" + name(s[r])]] => found\n        if s[0] != \"R\" and s[1] != \"R\":\n            found + [[t, 2, \"NS \" + name(s[0]) + \" and EW \" + name(s[1]) + \" at once\"]] => found\n        if s[2] != \"D\":\n            for r in [0:1]:\n                if s[r] != \"R\" and (r == 0 or s[0] == \"R\"):\n                    found + [[t, 3, name(s[2]) + \" showing while \" + road[r] + \" is \" + name(s[r])]] => found\n        if t > 0:\n            if s[2] != q[2] and s[2] != walk_after[q[2]]:\n                found + [[t, 4, \"walk signal went \" + name(q[2]) + \" to \" + name(s[2])]] => found\n            for r in [0:1]:\n                if q[r] == \"Y\" and s[r] != \"Y\" and ystart[r] > 0 and t - ystart[r] < yellow:\n                    found + [[t, 5, road[r] + \" yellow lasted only \" + str(t - ystart[r]) + \" s\"]] => found\n            for r in [0:1]:\n                if q[r] == \"R\" and s[r] == \"G\" and t - allred >= 0:\n                    1 - r => o\n                    t - 1 => k\n                    while k >= t - allred and log[k][o] == \"R\":\n                        k - 1 => k\n                    if k >= t - allred:\n                        found + [[t, 6, road[r] + \" turned green after only \" + str(t - 1 - k) + \" s of \" + road[o] + \" red\"]] => found\n        for r in [0:1]:\n            if s[r] == \"Y\" and (t == 0 or log[t - 1][r] != \"Y\"):\n                t => ystart[r]\n    return found\n\ndef parse(text):\n    # \"GRD YRD RRD\": one entry a second, NS and EW (G, Y, R), then the walk\n    # signal (D, W, F); 2 to 60 of them, or [] if anything is wrong.\n    [] => out\n    \"\" => w\n    for c in text + \" \":\n        if c == \" \":\n            if w != \"\":\n                if len(w) != 3 or not (w[0] in {\"G\": 1, \"Y\": 1, \"R\": 1}) or not (w[1] in {\"G\": 1, \"Y\": 1, \"R\": 1}) or not (w[2] in {\"D\": 1, \"W\": 1, \"F\": 1}):\n                    return []\n                out + [[w[0], w[1], w[2]]] => out\n            \"\" => w\n        else:\n            w + c => w\n    if len(out) < 2 or len(out) > 60:\n        return []\n    return out\n",
      "python": "def name(c):\n    names = {\"G\": \"green\", \"Y\": \"yellow\", \"R\": \"red\", \"D\": \"don't walk\", \"W\": \"walk\", \"F\": \"flashing\"}\n    return names[c]\n\ndef run(cfg, presses):\n    phases = [[\"G\", \"R\", cfg[0]], [\"Y\", \"R\", cfg[1]], [\"R\", \"R\", cfg[2]], [\"R\", \"G\", cfg[0]], [\"R\", \"Y\", cfg[1]], [\"R\", \"R\", cfg[2]]]\n    pressed = {}\n    for t in presses:\n        pressed[t] = True\n    log = []\n    p = 0\n    walk = \"D\"\n    elapsed = 0\n    pending = False\n    for t in range(0, cfg[5]):\n        if t in pressed and walk != \"W\":\n            pending = True\n        if walk == \"D\":\n            log = log + [[phases[p][0], phases[p][1], \"D\"]]\n        else:\n            log = log + [[\"R\", \"R\", walk]]\n        elapsed = elapsed + 1\n        if walk == \"W\":\n            if elapsed == cfg[3]:\n                walk = \"F\"\n                elapsed = 0\n        elif walk == \"F\":\n            if elapsed == cfg[4]:\n                walk = \"D\"\n                elapsed = 0\n                p = (p + 1) % 6\n        elif elapsed == phases[p][2]:\n            elapsed = 0\n            if (p == 2 or p == 5) and pending:\n                walk = \"W\"\n                pending = False\n            else:\n                p = (p + 1) % 6\n    return log\n\ndef same(a, b):\n    return a[0] == b[0] and a[1] == b[1] and a[2] == b[2]\n\ndef runs(log):\n    out = []\n    first = 0\n    for t in range(1, len(log)+1):\n        if t == len(log) or not same(log[t], log[first]):\n            out = out + [[first, t - 1, log[first]]]\n            first = t\n    return out\n\ndef waits(log, presses):\n    out = []\n    for t in presses:\n        at = -1\n        s = t\n        while at == -1 and s < len(log):\n            if log[s][2] == \"W\":\n                at = s\n            s = s + 1\n        out = out + [[t, at]]\n    return out\n\ndef copy(log):\n    out = []\n    for e in log:\n        out = out + [[e[0], e[1], e[2]]]\n    return out\n\ndef inject(log, fault, cfg):\n    out = copy(log)\n    if fault == \"stuck\":\n        for t in range(1, len(log) - 3+1):\n            if log[t][1] == \"G\" and log[t - 1][1] == \"R\":\n                out[t][0] = \"G\"\n                out[t + 1][0] = \"G\"\n                return out\n        return []\n    if fault == \"no-yellow\" or fault == \"short-yellow\":\n        first = -1\n        for t in range(0, len(log)):\n            if first == -1 and log[t][0] == \"Y\":\n                first = t\n        if first == -1:\n            return []\n        t = first\n        while t < len(log) and log[t][0] == \"Y\":\n            t = t + 1\n        if t == len(log):\n            return []\n        t = first\n        while t < len(log) and log[t][0] == \"Y\":\n            if fault == \"no-yellow\":\n                out[t][0] = \"G\"\n            elif t > first:\n                out[t][0] = \"R\"\n            t = t + 1\n        return out\n    if fault == \"early-walk\":\n        for t in range(1, len(log)):\n            if log[t][2] == \"W\" and log[t - 1][2] == \"D\":\n                if t - cfg[2] - 1 < 0:\n                    return []\n                for k in range(t - cfg[2] - 1, t):\n                    out[k][2] = \"W\"\n                return out\n        return []\n    return []\n\ndef audit(log, yellow, allred):\n    after = {\"G\": \"Y\", \"Y\": \"R\", \"R\": \"G\"}\n    walk_after = {\"D\": \"W\", \"W\": \"F\", \"F\": \"D\"}\n    road = [\"NS\", \"EW\"]\n    found = []\n    ystart = [-1, -1]\n    for t in range(0, len(log)):\n        s = log[t]\n        if t > 0:\n            q = log[t - 1]\n            for r in range(0, 2):\n                if s[r] != q[r] and s[r] != after[q[r]]:\n                    found = found + [[t, 1, road[r] + \" went \" + name(q[r]) + \" to \" + name(s[r])]]\n        if s[0] != \"R\" and s[1] != \"R\":\n            found = found + [[t, 2, \"NS \" + name(s[0]) + \" and EW \" + name(s[1]) + \" at once\"]]\n        if s[2] != \"D\":\n            for r in range(0, 2):\n                if s[r] != \"R\" and (r == 0 or s[0] == \"R\"):\n                    found = found + [[t, 3, name(s[2]) + \" showing while \" + road[r] + \" is \" + name(s[r])]]\n        if t > 0:\n            if s[2] != q[2] and s[2] != walk_after[q[2]]:\n                found = found + [[t, 4, \"walk signal went \" + name(q[2]) + \" to \" + name(s[2])]]\n            for r in range(0, 2):\n                if q[r] == \"Y\" and s[r] != \"Y\" and ystart[r] > 0 and t - ystart[r] < yellow:\n                    found = found + [[t, 5, road[r] + \" yellow lasted only \" + str(t - ystart[r]) + \" s\"]]\n            for r in range(0, 2):\n                if q[r] == \"R\" and s[r] == \"G\" and t - allred >= 0:\n                    o = 1 - r\n                    k = t - 1\n                    while k >= t - allred and log[k][o] == \"R\":\n                        k = k - 1\n                    if k >= t - allred:\n                        found = found + [[t, 6, road[r] + \" turned green after only \" + str(t - 1 - k) + \" s of \" + road[o] + \" red\"]]\n        for r in range(0, 2):\n            if s[r] == \"Y\" and (t == 0 or log[t - 1][r] != \"Y\"):\n                ystart[r] = t\n    return found\n\ndef parse(text):\n    out = []\n    w = \"\"\n    for c in text + \" \":\n        if c == \" \":\n            if w != \"\":\n                if len(w) != 3 or not w[0] in {\"G\": 1, \"Y\": 1, \"R\": 1} or not w[1] in {\"G\": 1, \"Y\": 1, \"R\": 1} or not w[2] in {\"D\": 1, \"W\": 1, \"F\": 1}:\n                    return []\n                out = out + [[w[0], w[1], w[2]]]\n            w = \"\"\n        else:\n            w = w + c\n    if len(out) < 2 or len(out) > 60:\n        return []\n    return out\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n2\nlizard\n2\n\n2\nown\nGRD\n2\nown\nGRD GXD\n2\nown\nGRDD RRD\n3\nabc\n3\n120\n3\n1 2 3 4 5 6 7 8 9 10 11\n3\n\n3\nnone\n1\n2\nearly-walk\n4\n4\n61\n20\n2\n7\n3\n0\n6\n4\n21\n\n5\n",
      "screen": "== Traffic lights ==\nA junction with a walk button, second by second - and an audit that checks every second of a log against every rule.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 0\nPick a number from 1 to 5.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> x\nPick a number from 1 to 5.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> lizard\nType run, stuck, no-yellow, short-yellow, early-walk or own.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> \nCancelled.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> own\nOne entry a second, three letters each: NS and EW (G, Y or R), then the walk signal (D don't walk, W walk, F flashing). For example: GRD YRD RRD RGD.\nlog (2 to 60 entries)> GRD\nType 2 to 60 entries like GRD, separated by spaces.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> own\nOne entry a second, three letters each: NS and EW (G, Y or R), then the walk signal (D don't walk, W walk, F flashing). For example: GRD YRD RRD RGD.\nlog (2 to 60 entries)> GRD GXD\nType 2 to 60 entries like GRD, separated by spaces.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> own\nOne entry a second, three letters each: NS and EW (G, Y or R), then the walk signal (D don't walk, W walk, F flashing). For example: GRD YRD RRD RGD.\nlog (2 to 60 entries)> GRDD RRD\nType 2 to 60 entries like GRD, separated by spaces.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 3\nSeconds the walk button is pressed, 0 to 119, up to 10 of them; or none.\npresses> abc\nType up to 10 seconds from 0 to 119, separated by spaces, or none.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 3\nSeconds the walk button is pressed, 0 to 119, up to 10 of them; or none.\npresses> 120\nType up to 10 seconds from 0 to 119, separated by spaces, or none.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 3\nSeconds the walk button is pressed, 0 to 119, up to 10 of them; or none.\npresses> 1 2 3 4 5 6 7 8 9 10 11\nType up to 10 seconds from 0 to 119, separated by spaces, or none.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 3\nSeconds the walk button is pressed, 0 to 119, up to 10 of them; or none.\npresses> \nCancelled.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 3\nSeconds the walk button is pressed, 0 to 119, up to 10 of them; or none.\npresses> none\nNo presses.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 1\nNorth-south (NS) and east-west (EW), 120 seconds: green 20, yellow 3, all red 2, walk 7, flashing 5.\n  seconds NS      EW      walk\n    0-19  green   red     don't walk\n   20-22  yellow  red     don't walk\n   23-24  red     red     don't walk\n   25-44  red     green   don't walk\n   45-47  red     yellow  don't walk\n   48-49  red     red     don't walk\n   50-69  green   red     don't walk\n   70-72  yellow  red     don't walk\n   73-74  red     red     don't walk\n   75-94  red     green   don't walk\n   95-97  red     yellow  don't walk\n   98-99  red     red     don't walk\n  100-119 green   red     don't walk\nNobody pressed the walk button.\nThe button is answered when the next all red ends: both roads have stopped, then walk, flashing, and the next green.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> early-walk\nNobody walks in this run; press the button first.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 4\ngreen (5 to 60)> 4\nType a whole number from 5 to 60.\ngreen (5 to 60)> 61\nType a whole number from 5 to 60.\ngreen (5 to 60)> 20\nyellow (3 to 6)> 2\nType a whole number from 3 to 6.\nyellow (3 to 6)> 7\nType a whole number from 3 to 6.\nyellow (3 to 6)> 3\nall red (1 to 5)> 0\nType a whole number from 1 to 5.\nall red (1 to 5)> 6\nType a whole number from 1 to 5.\nall red (1 to 5)> 4\nwalk (4 to 20)> 21\nType a whole number from 4 to 20.\nwalk (4 to 20)> \nCancelled.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\n2\nrun\n2\nstuck\n2\nno-yellow\n2\nshort-yellow\n2\nearly-walk\n2\nown\nGRD GRD YRD RRD RGD RGW GYD RRD\n3\n30 52 115\n1\n4\n10\n3\n1\n5\n3\n60\n1\n2\nrun\n5\n",
      "screen": "== Traffic lights ==\nA junction with a walk button, second by second - and an audit that checks every second of a log against every rule.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 1\nNorth-south (NS) and east-west (EW), 120 seconds: green 20, yellow 3, all red 2, walk 7, flashing 5.\n  seconds NS      EW      walk\n    0-19  green   red     don't walk\n   20-22  yellow  red     don't walk\n   23-24  red     red     don't walk\n   25-31  red     red     walk\n   32-36  red     red     flashing\n   37-56  red     green   don't walk\n   57-59  red     yellow  don't walk\n   60-61  red     red     don't walk\n   62-81  green   red     don't walk\n   82-84  yellow  red     don't walk\n   85-86  red     red     don't walk\n   87-93  red     red     walk\n   94-98  red     red     flashing\n   99-118 red     green   don't walk\n  119     red     yellow  don't walk\nButton at second 5: walk at second 25, after 20 seconds.\nButton at second 70: walk at second 87, after 17 seconds.\nThe button is answered when the next all red ends: both roads have stopped, then walk, flashing, and the next green.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> run\nEvery second against every rule:\n  1  a light goes green, yellow, red, green - no other change\n  2  never both roads not red\n  3  walk or flashing only while both roads are red\n  4  the walk signal goes don't walk, walk, flashing, don't walk\n  5  a yellow lasts at least 3 seconds\n  6  a road turns green only after the other has been red for 2 seconds\nNo violations.\n120 seconds checked: 120 clean + 0 with a violation.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> stuck\nFault: NS stays green for the first 2 seconds of EW green, like a stuck relay.\nEvery second against every rule:\n  1  a light goes green, yellow, red, green - no other change\n  2  never both roads not red\n  3  walk or flashing only while both roads are red\n  4  the walk signal goes don't walk, walk, flashing, don't walk\n  5  a yellow lasts at least 3 seconds\n  6  a road turns green only after the other has been red for 2 seconds\nEvery violation, not just the first:\n  second  37, rule 2: NS green and EW green at once\n  second  38, rule 2: NS green and EW green at once\n  second  39, rule 1: NS went green to red\n120 seconds checked: 117 clean + 3 with a violation.\n3 in all - rule 1: 1, rule 2: 2.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> no-yellow\nFault: NS's first yellow shows green instead.\nEvery second against every rule:\n  1  a light goes green, yellow, red, green - no other change\n  2  never both roads not red\n  3  walk or flashing only while both roads are red\n  4  the walk signal goes don't walk, walk, flashing, don't walk\n  5  a yellow lasts at least 3 seconds\n  6  a road turns green only after the other has been red for 2 seconds\nEvery violation, not just the first:\n  second  23, rule 1: NS went green to red\n120 seconds checked: 119 clean + 1 with a violation.\n1 in all - rule 1: 1.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> short-yellow\nFault: NS's first yellow lasts 1 second, with red after.\nEvery second against every rule:\n  1  a light goes green, yellow, red, green - no other change\n  2  never both roads not red\n  3  walk or flashing only while both roads are red\n  4  the walk signal goes don't walk, walk, flashing, don't walk\n  5  a yellow lasts at least 3 seconds\n  6  a road turns green only after the other has been red for 2 seconds\nEvery violation, not just the first:\n  second  21, rule 5: NS yellow lasted only 1 s\n120 seconds checked: 119 clean + 1 with a violation.\n1 in all - rule 5: 1.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> early-walk\nFault: the first walk starts a second before the all red, while a road is still yellow.\nEvery second against every rule:\n  1  a light goes green, yellow, red, green - no other change\n  2  never both roads not red\n  3  walk or flashing only while both roads are red\n  4  the walk signal goes don't walk, walk, flashing, don't walk\n  5  a yellow lasts at least 3 seconds\n  6  a road turns green only after the other has been red for 2 seconds\nEvery violation, not just the first:\n  second  22, rule 3: walk showing while NS is yellow\n120 seconds checked: 119 clean + 1 with a violation.\n1 in all - rule 3: 1.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> own\nOne entry a second, three letters each: NS and EW (G, Y or R), then the walk signal (D don't walk, W walk, F flashing). For example: GRD YRD RRD RGD.\nlog (2 to 60 entries)> GRD GRD YRD RRD RGD RGW GYD RRD\nEvery second against every rule:\n  1  a light goes green, yellow, red, green - no other change\n  2  never both roads not red\n  3  walk or flashing only while both roads are red\n  4  the walk signal goes don't walk, walk, flashing, don't walk\n  5  a yellow lasts at least 3 seconds\n  6  a road turns green only after the other has been red for 2 seconds\nEvery violation, not just the first:\n  second   3, rule 5: NS yellow lasted only 1 s\n  second   4, rule 6: EW turned green after only 1 s of NS red\n  second   5, rule 3: walk showing while EW is green\n  second   6, rule 2: NS green and EW yellow at once\n  second   6, rule 4: walk signal went walk to don't walk\n  second   6, rule 6: NS turned green after only 0 s of EW red\n  second   7, rule 1: NS went green to red\n  second   7, rule 5: EW yellow lasted only 1 s\n8 seconds checked: 3 clean + 5 with a violation.\n8 in all - rule 1: 1, rule 2: 1, rule 3: 1, rule 4: 1, rule 5: 2, rule 6: 2.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 3\nSeconds the walk button is pressed, 0 to 119, up to 10 of them; or none.\npresses> 30 52 115\nPresses at 30, 52, 115.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 1\nNorth-south (NS) and east-west (EW), 120 seconds: green 20, yellow 3, all red 2, walk 7, flashing 5.\n  seconds NS      EW      walk\n    0-19  green   red     don't walk\n   20-22  yellow  red     don't walk\n   23-24  red     red     don't walk\n   25-44  red     green   don't walk\n   45-47  red     yellow  don't walk\n   48-49  red     red     don't walk\n   50-56  red     red     walk\n   57-61  red     red     flashing\n   62-81  green   red     don't walk\n   82-84  yellow  red     don't walk\n   85-86  red     red     don't walk\n   87-106 red     green   don't walk\n  107-109 red     yellow  don't walk\n  110-111 red     red     don't walk\n  112-119 green   red     don't walk\nButton at second 30: walk at second 50, after 20 seconds.\nButton at second 52: already walking.\nButton at second 115: no walk before the run ends.\nThe button is answered when the next all red ends: both roads have stopped, then walk, flashing, and the next green.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 4\ngreen (5 to 60)> 10\nyellow (3 to 6)> 3\nall red (1 to 5)> 1\nwalk (4 to 20)> 5\nflashing (3 to 20)> 3\nseconds to run (30 to 300)> 60\nGreen 10, yellow 3, all red 1, walk 5, flashing 3; 60 seconds.\nThe run now ends at second 59; dropped: 115.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 1\nNorth-south (NS) and east-west (EW), 60 seconds: green 10, yellow 3, all red 1, walk 5, flashing 3.\n  seconds NS      EW      walk\n    0-9   green   red     don't walk\n   10-12  yellow  red     don't walk\n   13     red     red     don't walk\n   14-23  red     green   don't walk\n   24-26  red     yellow  don't walk\n   27     red     red     don't walk\n   28-37  green   red     don't walk\n   38-40  yellow  red     don't walk\n   41     red     red     don't walk\n   42-46  red     red     walk\n   47-49  red     red     flashing\n   50-59  red     green   don't walk\nButton at second 30: walk at second 42, after 12 seconds.\nButton at second 52: no walk before the run ends.\nThe button is answered when the next all red ends: both roads have stopped, then walk, flashing, and the next green.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 2\nAudit the run as it is (run), the run with a fault (stuck, no-yellow, short-yellow, early-walk), or a log you type (own).\nlog (run, stuck, no-yellow, short-yellow, early-walk or own)> run\nEvery second against every rule:\n  1  a light goes green, yellow, red, green - no other change\n  2  never both roads not red\n  3  walk or flashing only while both roads are red\n  4  the walk signal goes don't walk, walk, flashing, don't walk\n  5  a yellow lasts at least 3 seconds\n  6  a road turns green only after the other has been red for 1 second\nNo violations.\n60 seconds checked: 60 clean + 0 with a violation.\n\n1) run  2) audit  3) walk button  4) timings  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "traffic-light-simulator",
      "caseId": "063-traffic-light-simulator",
      "title": "Traffic light simulator"
    },
    {
      "slug": "state-machine-trace-audit",
      "caseId": "212-state-machine-trace-audit",
      "title": "Two different ways for a log to be illegal"
    }
  ],
  "updated": "2026-10-15"
}
