Traffic Light


I want to make a Traffic Light that changes color.

preview

These are the tests I have at the end of the chapter

traffic_light/tests/test_traffic_light.py
 1import src.traffic_light
 2import unittest
 3
 4
 5GREEN, YELLOW, RED = 'GREEN', 'YELLOW', 'RED'
 6
 7
 8class TestTrafficLight(unittest.TestCase):
 9
10    def test_parallel_green_cross_red_timer_not_done(self):
11        self.assertEqual(
12            src.traffic_light.control(
13                red_phase='cross',
14                current_parallel=GREEN,
15                current_cross=RED,
16                timer_done=False,
17            ),
18            (GREEN, RED)
19        )
20
21    def test_parallel_green_cross_red_timer_done(self):
22        self.assertEqual(
23            src.traffic_light.control(
24                red_phase='cross',
25                current_parallel=GREEN,
26                current_cross=RED,
27                timer_done=True,
28            ),
29            (YELLOW, RED)
30        )
traffic_light/tests/test_traffic_light.py
32    def test_parallel_yellow_cross_red_timer_not_done(self):
33        self.assertEqual(
34            src.traffic_light.control(
35                red_phase='cross',
36                current_parallel=YELLOW,
37                current_cross=RED,
38                timer_done=False,
39            ),
40            (YELLOW, RED)
41        )
42
43    def test_parallel_yellow_cross_red_timer_done(self):
44        self.assertEqual(
45            src.traffic_light.control(
46                red_phase='cross',
47                current_parallel=YELLOW,
48                current_cross=RED,
49                timer_done=True,
50            ),
51            (RED, RED)
52        )
traffic_light/tests/test_traffic_light.py
54    def test_parallel_red_cross_red_timer_not_done(self):
55        self.assertEqual(
56            src.traffic_light.control(
57                red_phase='cross',
58                current_parallel=RED,
59                current_cross=RED,
60                timer_done=False,
61            ),
62            (RED, RED)
63        )
64
65    def test_parallel_red_cross_red_timer_done(self):
66        self.assertEqual(
67            src.traffic_light.control(
68                red_phase='cross',
69                current_parallel=RED,
70                current_cross=RED,
71                timer_done=True,
72            ),
73            (RED, GREEN)
74        )
traffic_light/tests/test_traffic_light.py
76    def test_cross_green_parallel_red_timer_not_done(self):
77        self.assertEqual(
78            src.traffic_light.control(
79                red_phase='parallel',
80                current_parallel=RED,
81                current_cross=GREEN,
82                timer_done=False,
83            ),
84            (RED, GREEN)
85        )
86
87    def test_cross_green_parallel_red_timer_done(self):
88        self.assertEqual(
89            src.traffic_light.control(
90                red_phase='parallel',
91                current_parallel=RED,
92                current_cross=GREEN,
93                timer_done=True,
94            ),
95            (RED, YELLOW)
96        )
traffic_light/tests/test_traffic_light.py
 98    def test_cross_yellow_parallel_red_timer_not_done(self):
 99        self.assertEqual(
100            src.traffic_light.control(
101                red_phase='parallel',
102                current_parallel=RED,
103                current_cross=YELLOW,
104                timer_done=False,
105            ),
106            (RED, YELLOW)
107        )
108
109    def test_cross_yellow_parallel_red_timer_done(self):
110        self.assertEqual(
111            src.traffic_light.control(
112                red_phase='parallel',
113                current_parallel=RED,
114                current_cross=YELLOW,
115                timer_done=True,
116            ),
117            (RED, RED)
118        )
traffic_light/tests/test_traffic_light.py
120    def test_cross_red_parallel_red_timer_not_done(self):
121        self.assertEqual(
122            src.traffic_light.control(
123                red_phase='parallel',
124                current_parallel=RED,
125                current_cross=RED,
126                timer_done=False,
127            ),
128            (RED, RED)
129        )
130
131    def test_cross_red_parallel_red_timer_done(self):
132        self.assertEqual(
133            src.traffic_light.control(
134                red_phase='parallel',
135                current_parallel=RED,
136                current_cross=RED,
137                timer_done=True,
138            ),
139            (GREEN, RED)
140        )
traffic_light/tests/test_traffic_light.py
142    def test_failsafe(self):
143        self.assertEqual(
144            src.traffic_light.control(
145                red_phase='BOOM',
146                current_parallel='BAP',
147                current_cross=RED,
148                timer_done=False,
149            ),
150            (RED, RED)
151        )
152        self.assertEqual(
153            src.traffic_light.control(
154                red_phase='BOOM',
155                current_parallel=RED,
156                current_cross='POW',
157                timer_done=False,
158            ),
159            (RED, RED)
160        )
traffic_light/tests/test_traffic_light.py
161        self.assertEqual(
162            src.traffic_light.control(
163                red_phase='BOOM',
164                current_parallel=GREEN,
165                current_cross=GREEN,
166                timer_done=False,
167            ),
168            (RED, RED)
169        )
170        self.assertEqual(
171            src.traffic_light.control(
172                red_phase='BOOM',
173                current_parallel=GREEN,
174                current_cross=YELLOW,
175                timer_done=False,
176            ),
177            (RED, RED)
178        )
traffic_light/tests/test_traffic_light.py
179        self.assertEqual(
180            src.traffic_light.control(
181                red_phase='BOOM',
182                current_parallel=YELLOW,
183                current_cross=GREEN,
184                timer_done=False,
185            ),
186            (RED, RED)
187        )
188        self.assertEqual(
189            src.traffic_light.control(
190                red_phase='BOOM',
191                current_parallel=YELLOW,
192                current_cross=YELLOW,
193                timer_done=False,
194            ),
195            (RED, RED)
196        )
197
198
199# Exceptions seen
200# AssertionError
201# NameError
202# AttributeError
203# TypeError

start the project

  • I open a terminal

    • I open makePythonTdd.sh

    • I change the name of the project to traffic_light in makePythonTdd.sh

       1#!/bin/bash
       2uv init traffic_light
       3cd traffic_light
       4mkdir tests
       5touch tests/__init__.py
       6
       7echo "import unittest
       8
       9
      10class TestTrafficLight(unittest.TestCase):
      11
      12    def test_failure(self):
      13        self.assertFalse(True)
      14
      15
      16# Exceptions seen
      17# AssertionError
      18" > tests/test_traffic_light.py
      19
      20echo "pytest" > requirements.txt
      21echo "pytest-watcher" >> requirements.txt
      22uv add --requirement requirements.txt
      23uv run pytest-watcher . --now
      
    • I run makePythonTdd.sh in the terminal to make the traffic_light project

      ./makePythonTdd.sh
      
    • I open makePythonTdd.ps1

    • I change the name of the project to traffic_light in makePythonTdd.ps1

       1uv init traffic_light
       2cd traffic_light
       3mkdir tests
       4New-Item tests/__init__.py
       5
       6"import unittest
       7
       8
       9class TestTrafficLight(unittest.TestCase):
      10
      11    def test_failure(self):
      12        self.assertFalse(True)
      13
      14
      15# Exceptions seen
      16# AssertionError
      17" | Out-File "tests/test_traffic_light.py" -Encoding UTF8
      18
      19"pytest" | Out-File requirements.txt -Encoding UTF8
      20"pytest-watcher" >> requirements.txt
      21uv add --requirement requirements.txt
      22uv run pytest-watcher . --now
      
    • I run makePythonTdd.ps1 in the terminal to make the traffic_light project

      .\makePythonTdd.ps1
      

    the terminal is my friend, and shows AssertionError

    ======================== FAILURES =========================
    ___________ TestTrafficLight.test_failure _________________
    
    self = <tests.test_traffic_light.TestTrafficLight testMethod=test_failure>
    
        def test_failure(self):
    >       self.assertFalse(True)
    E       AssertionError: True is not false
    
    tests/test_traffic_light.py:7: AssertionError
    ================ short test summary info ==================
    FAILED tests/test_traffic_light.py::TestTrafficLight::test_failure - AssertionError: True is not false
    ==================== 1 failed in X.YZs ====================
    
  • I hold ctrl (Windows/Linux) or option/command (MacOS) on the keyboard and use the mouse to click on tests/test_traffic_light.py:7 to open it

  • I change assertFalse to assertTrue in tests/test_traffic_light.py

     4class TestTrafficLight(unittest.TestCase):
     5
     6    def test_failure(self):
     7        # self.assertFalse(True)
     8        self.assertTrue(True)
     9
    10
    11# Exceptions seen
    

    the test passes.

  • I open a new terminal then change directory to traffic_light

    cd traffic_light
    
  • I add the new files and folder to git for tracking

    git add .
    
  • I add a git commit message

    git commit -am 'setup project'
    

I want the Traffic Light to change color based on a timer. If the inputs are

  • what color is the light now?

  • is the timer done?

then I get this truth table

current light

timer

output

GREEN

NOT done

GREEN

GREEN

done

YELLOW

YELLOW

NOT done

YELLOW

YELLOW

done

RED

RED

NOT done

RED

RED

done

GREEN


test_green_light_timer_not_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I change test_failure to test_green_light_timer_not_done, then add an assertion for if the light is GREEN AND the timer is NOT done

    current light

    timer

    output

    GREEN

    NOT done

    GREEN

     4class TestTrafficLight(unittest.TestCase):
     5
     6    def test_green_light_timer_not_done(self):
     7        self.assertEqual(
     8            src.traffic_light.control(
     9                timer_done=False,
    10                current_light='GREEN',
    11            ),
    12            'GREEN'
    13        )
    14
    15
    16# Exceptions seen
    17# AssertionError
    

    the terminal is my friend, and shows NameError

    NameError: name 'src' is not defined
    

    because I do not have a definition for src in this file


GREEN: make it pass


  • I add NameError to the list of Exceptions seen

    16# Exceptions seen
    17# AssertionError
    18# NameError
    
  • I add an import statement at the top of the file

    1import src.traffic_light
    2import unittest
    3
    4
    5class TestTrafficLight(unittest.TestCase):
    

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.traffic_light'
                    has no attribute 'control'
    

    because traffic_light/__init__.py in the src folder does not have anything named control in it

  • I add AttributeError to the list of Exceptions seen

    17# Exceptions seen
    18# AssertionError
    19# NameError
    20# AttributeError
    
  • I open traffic_light/__init__.py from the src folder

  • I delete all the text in the file then add a function to src/traffic_light/__init__.py

    1def control():
    2    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: control() got
               an unexpected keyword argument 'timer_done'
    
  • I add TypeError to the list of Exceptions seen, in tests/test_traffic_light.py

    17# Exceptions seen
    18# AssertionError
    19# NameError
    20# AttributeError
    21# TypeError
    
  • I add timer_done to the function in src/traffic_light/__init__.py

    1def control(timer_done):
    2    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: control() got an
               unexpected keyword argument 'current_light'
    
  • I add current_light to the function signature

    1def control(timer_done, current_light):
    2    return None
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != 'GREEN'
    
  • I change the return statement to give the test what it expects

    1def control(timer_done, current_light):
    2    return 'GREEN'
    

    the test passes.

    control(current_light='GREEN' , timer_done=False) -> 'GREEN'
    
  • I add a git commit message in the other terminal

    git commit -am 'add test_green_light_timer_not_done'
    

test_green_light_timer_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the light is GREEN AND the timer is done, to tests/test_traffic_light.py

    current light

    timer

    output

    GREEN

    done

    YELLOW

     7    def test_green_light_timer_not_done(self):
     8        self.assertEqual(
     9            src.traffic_light.control(
    10                timer_done=False,
    11                current_light='GREEN',
    12            ),
    13            'GREEN'
    14        )
    15
    16    def test_green_light_timer_done(self):
    17        self.assertEqual(
    18            src.traffic_light.control(
    19                timer_done=True,
    20                current_light='GREEN',
    21            ),
    22            'YELLOW'
    23        )
    24
    25
    26# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'GREEN' != 'YELLOW'
    

GREEN: make it pass


  • I add an if statement for this case, to src/traffic_light/__init__.py

    1def control(timer_done, current_light):
    2    if timer_done:
    3        return 'YELLOW'
    4
    5    return 'GREEN'
    

    the test passes.

    control(current_light='GREEN' , timer_done=False) -> 'GREEN'
    control(current_light='GREEN' , timer_done=True ) -> 'YELLOW'
    

REFACTOR: make it better


  • I add a global variable for 'GREEN' to tests/test_traffic_light.py

     1import src.traffic_light
     2import unittest
     3
     4
     5GREEN = 'GREEN'
     6
     7
     8class TestTrafficLight(unittest.TestCase):
     9
    10    def test_green_light_timer_not_done(self):
    
  • I use the new variable for 'GREEN' in test_green_light_timer_not_done

    10    def test_green_light_timer_not_done(self):
    11        self.assertEqual(
    12            src.traffic_light.control(
    13                timer_done=False,
    14                # current_light='GREEN',
    15                current_light=GREEN,
    16            ),
    17            # 'GREEN'
    18            GREEN
    19        )
    20
    21    def test_green_light_timer_done(self):
    

    the test is still green.

  • I remove the commented lines from test_green_light_timer_not_done

    10    def test_green_light_timer_not_done(self):
    11        self.assertEqual(
    12            src.traffic_light.control(
    13                timer_done=False,
    14                current_light=GREEN,
    15            ),
    16            GREEN
    17        )
    18
    19    def test_green_light_timer_done(self):
    
  • I use the new variable for 'GREEN' in test_green_light_timer_done

    19    def test_green_light_timer_done(self):
    20        self.assertEqual(
    21            src.traffic_light.control(
    22                timer_done=True,
    23                # current_light='GREEN',
    24                current_light=GREEN,
    25            ),
    26            'YELLOW'
    27        )
    28
    29
    30# Exceptions seen
    

    still green.

  • I remove the commented lines from test_green_light_timer_done

    19    def test_green_light_timer_done(self):
    20        self.assertEqual(
    21            src.traffic_light.control(
    22                timer_done=True,
    23                current_light=GREEN,
    24            ),
    25            'YELLOW'
    26        )
    27
    28
    29# Exceptions seen
    
  • I add a git commit message in the other terminal

    git commit -am 'add test_green_light_timer_done'
    

test_yellow_light_timer_not_done

RED: make it fail


  • I go back to the terminal where the tests are running.

  • I add a test with an assertion for if the Traffic Light is YELLOW AND the timer is NOT done, to tests/test_traffic_light.py

    current light

    timer

    output

    YELLOW

    NOT done

    YELLOW

    19    def test_green_light_timer_done(self):
    20        self.assertEqual(
    21            src.traffic_light.control(
    22                timer_done=True,
    23                current_light=GREEN,
    24            ),
    25            'YELLOW'
    26        )
    27
    28    def test_yellow_light_timer_not_done(self):
    29        self.assertEqual(
    30            src.traffic_light.control(
    31                timer_done=False,
    32                current_light='YELLOW',
    33            ),
    34            'YELLOW'
    35        )
    36
    37
    38# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'GREEN' != 'YELLOW'
    

GREEN: make it pass


  • I add an if statement for if the current light is YELLOW to src/traffic_light/__init__.py

    1def control(timer_done, current_light):
    2    if timer_done:
    3        return 'YELLOW'
    4
    5    if current_light == 'YELLOW':
    6        return current_light
    7
    8    return 'GREEN'
    

    the test passes.

    control(current_light='GREEN' , timer_done=False) -> 'GREEN'
    control(current_light='GREEN' , timer_done=True ) -> 'YELLOW'
    control(current_light='YELLOW', timer_done=False) -> 'YELLOW'
    

REFACTOR: make it better


  • I add a global variable for 'YELLOW' to tests/test_traffic_light.py

    1import src.traffic_light
    2import unittest
    3
    4
    5GREEN, YELLOW = 'GREEN', 'YELLOW'
    6
    7
    8class TestTrafficLight(unittest.TestCase):
    
  • I use the new variable for 'YELLOW' in test_green_light_timer_done

    19    def test_green_light_timer_done(self):
    20        self.assertEqual(
    21            src.traffic_light.control(
    22                timer_done=True,
    23                current_light=GREEN,
    24            ),
    25            # 'YELLOW'
    26            YELLOW
    27        )
    28
    29    def test_yellow_light_timer_not_done(self):
    

    the test is still green.

  • I remove the commented line from test_green_light_timer_done

    19    def test_green_light_timer_done(self):
    20        self.assertEqual(
    21            src.traffic_light.control(
    22                timer_done=True,
    23                current_light=GREEN,
    24            ),
    25            YELLOW
    26        )
    27
    28    def test_yellow_light_timer_not_done(self):
    
  • I use the new variable for 'YELLOW' in test_yellow_light_timer_not_done

    28    def test_yellow_light_timer_not_done(self):
    29        self.assertEqual(
    30            src.traffic_light.control(
    31                timer_done=False,
    32                # current_light='YELLOW',
    33                current_light=YELLOW,
    34            ),
    35            # 'YELLOW'
    36            YELLOW
    37        )
    38
    39
    40# Exceptions seen
    

    still green.

  • I remove the commented lines from test_yellow_light_timer_not_done

    28    def test_yellow_light_timer_not_done(self):
    29        self.assertEqual(
    30            src.traffic_light.control(
    31                timer_done=False,
    32                current_light=YELLOW,
    33            ),
    34            YELLOW
    35        )
    36
    37
    38# Exceptions seen
    
  • I add a git commit message in the other terminal

    git commit -am 'add test_yellow_light_timer_not_done'
    

test_yellow_light_timer_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the light is YELLOW AND the timer is done, to tests/test_traffic_light.py

    current light

    timer

    output

    YELLOW

    done

    RED

    28    def test_yellow_light_timer_not_done(self):
    29        self.assertEqual(
    30            src.traffic_light.control(
    31                timer_done=False,
    32                current_light=YELLOW,
    33            ),
    34            YELLOW
    35        )
    36
    37    def test_yellow_light_timer_done(self):
    38        self.assertEqual(
    39            src.traffic_light.control(
    40                timer_done=True,
    41                current_light=YELLOW,
    42            ),
    43            'RED'
    44        )
    45
    46
    47# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'YELLOW' != 'RED'
    

GREEN: make it pass


  • I add an if statement for if the timer is done AND the light is YELLOW, in src/traffic_light/__init__.py

     1def control(timer_done, current_light):
     2    if timer_done:
     3        if current_light == 'YELLOW':
     4            return 'RED'
     5        return 'YELLOW'
     6
     7    if current_light == 'YELLOW':
     8        return current_light
     9
    10    return 'GREEN'
    

    the test passes.

    control(current_light='GREEN' , timer_done=False) -> 'GREEN'
    control(current_light='GREEN' , timer_done=True ) -> 'YELLOW'
    control(current_light='YELLOW', timer_done=False) -> 'YELLOW'
    control(current_light='YELLOW', timer_done=True ) -> 'RED'
    
  • I add a git commit message in the other terminal

    git commit -am 'add test_yellow_light_timer_done'
    

test_red_light_timer_not_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the Traffic Light is RED AND the timer is NOT done, to tests/test_traffic_light.py

    current light

    timer

    output

    RED

    NOT done

    RED

    37    def test_yellow_light_timer_done(self):
    38        self.assertEqual(
    39            src.traffic_light.control(
    40                timer_done=True,
    41                current_light=YELLOW,
    42            ),
    43            'RED'
    44        )
    45
    46    def test_red_light_timer_not_done(self):
    47        self.assertEqual(
    48            src.traffic_light.control(
    49                timer_done=False,
    50                current_light='RED'
    51            ),
    52            'RED'
    53        )
    54
    55
    56# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'GREEN' != 'RED'
    

GREEN: make it pass


I add an if statement to src/traffic_light/__init__.py

 7    if current_light == 'YELLOW':
 8        return current_light
 9    if current_light == 'RED':
10        return current_light
11
12    return 'GREEN'

the test passes.

control(current_light='GREEN' , timer_done=False) -> 'GREEN'
control(current_light='GREEN' , timer_done=True ) -> 'YELLOW'
control(current_light='YELLOW', timer_done=False) -> 'YELLOW'
control(current_light='YELLOW', timer_done=True ) -> 'RED'
control(current_light='RED'   , timer_done=False) -> 'RED'

REFACTOR: make it better


  • I add a global variable for 'RED' to tests/test_traffic_light.py

    1import src.traffic_light
    2import unittest
    3
    4
    5GREEN, YELLOW, RED = 'GREEN', 'YELLOW', 'RED'
    6
    7
    8class TestTrafficLight(unittest.TestCase):
    
  • I use the variable for 'RED' in test_yellow_light_timer_done

    37    def test_yellow_light_timer_done(self):
    38        self.assertEqual(
    39            src.traffic_light.control(
    40                timer_done=True,
    41                current_light=YELLOW,
    42            ),
    43            # 'RED'
    44            RED
    45        )
    46
    47    def test_red_light_timer_not_done(self):
    

    the test is still green.

  • I remove the commented line from test_yellow_light_timer_done

    37    def test_yellow_light_timer_done(self):
    38        self.assertEqual(
    39            src.traffic_light.control(
    40                timer_done=True,
    41                current_light=YELLOW,
    42            ),
    43            RED
    44        )
    45
    46    def test_red_light_timer_not_done(self):
    
  • I use the variable for 'RED' in test_red_light_timer_not_done

    46    def test_red_light_timer_not_done(self):
    47        self.assertEqual(
    48            src.traffic_light.control(
    49                timer_done=False,
    50                # current_light='RED'
    51                current_light=RED,
    52            ),
    53            # 'RED'
    54            RED
    55        )
    56
    57
    58# Exceptions seen
    

    still green.

  • I remove the commented line from test_red_light_timer_not_done

    46    def test_red_light_timer_not_done(self):
    47        self.assertEqual(
    48            src.traffic_light.control(
    49                timer_done=False,
    50                current_light=RED,
    51            ),
    52            RED
    53        )
    54
    55
    56# Exceptions seen
    
  • I add a git commit message in the other terminal

    git commit -am 'add test_red_light_timer_not_done'
    

test_red_light_timer_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the light is GREEN AND the timer is done, to tests/test_traffic_light.py

    current light

    timer

    output

    RED

    done

    GREEN

    46    def test_red_light_timer_not_done(self):
    47        self.assertEqual(
    48            src.traffic_light.control(
    49                timer_done=False,
    50                current_light=RED,
    51            ),
    52            RED
    53        )
    54
    55    def test_red_light_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                timer_done=True,
    59                current_light=RED,
    60            ),
    61            GREEN
    62        )
    63
    64
    65# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'YELLOW' != 'GREEN'
    
  • I add an if statement for if the timer is done AND the current light is RED in src/traffic_light/__init__.py

     1def control(timer_done, current_light):
     2    if timer_done:
     3        if current_light == 'YELLOW':
     4            return 'RED'
     5        if current_light == 'RED':
     6            return 'GREEN'
     7        return 'YELLOW'
     8
     9    if current_light == 'YELLOW':
    10        return current_light
    11    if current_light == 'RED':
    12        return current_light
    13
    14    return 'GREEN'
    

    the test passes.

    control(current_light='GREEN' , timer_done=False) -> 'GREEN'
    control(current_light='GREEN' , timer_done=True ) -> 'YELLOW'
    control(current_light='YELLOW', timer_done=False) -> 'YELLOW'
    control(current_light='YELLOW', timer_done=True ) -> 'RED'
    control(current_light='RED'   , timer_done=False) -> 'RED'
    control(current_light='RED'   , timer_done=True ) -> 'GREEN'
    
  • I add a git commit message in the other terminal

    git commit -am 'add test_green_light_timer_not_done'
    

refactor if statements

When the control function is called it checks if the timer is done

  • If the timer is done, it checks the color of the current light

    • If the current light is YELLOW, it returns RED

    • If the current light is RED, it returns GREEN

    • If none of the above conditions are met, it returns YELLOW

  • If none of the above conditions are met, it checks the color of the current light

    • If the current light is YELLOW, it returns YELLOW

    • If the current light is RED, it returns RED

    • If none of the above conditions are met, it returns GREEN

  • I go back to the terminal where the tests are running

  • I add an if statement for if the timer is done AND the light is GREEN, to make it clearer

    1def control(timer_done, current_light):
    2    if timer_done:
    3        if current_light == 'GREEN':
    4            return 'YELLOW'
    5        if current_light == 'YELLOW':
    6            return 'RED'
    7        if current_light == 'RED':
    8            return 'GREEN'
    9        # return 'YELLOW'
    

    the tests are still green.

  • I add an if statement for if the timer is NOT done to be clearer

     1def control(timer_done, current_light):
     2    if timer_done:
     3        if current_light == 'GREEN':
     4            return 'YELLOW'
     5        if current_light == 'YELLOW':
     6            return 'RED'
     7        if current_light == 'RED':
     8            return 'GREEN'
     9        # return 'YELLOW'
    10    if not timer_done:
    11        if current_light == 'YELLOW':
    12            return current_light
    13        if current_light == 'RED':
    14            return current_light
    15
    16    return 'GREEN'
    

    still green.

  • I add an if statement for if the timer is NOT done and the light is GREEN, to make it clearer

    10    if not timer_done:
    11        if current_light == 'GREEN':
    12            return current_light
    13        if current_light == 'YELLOW':
    14            return current_light
    15        if current_light == 'RED':
    16            return current_light
    17
    18    # return 'GREEN'
    

    The control function returns the current light in every case where the timer is NOT done

  • I add a return statement to return the current light if the timer is NOT done

    10    if not timer_done:
    11        return current_light
    12        if current_light == 'GREEN':
    13            return current_light
    14        if current_light == 'YELLOW':
    15            return current_light
    16        if current_light == 'RED':
    17            return current_light
    18
    19    # return 'GREEN'
    

    green.

  • I remove the commented lines and the other if statements from the else block because they are no longer used

     1def control(timer_done, current_light):
     2    if timer_done:
     3        if current_light == 'GREEN':
     4            return 'YELLOW'
     5        if current_light == 'YELLOW':
     6            return 'RED'
     7        if current_light == 'RED':
     8            return 'GREEN'
     9    if not timer_done:
    10        return current_light
    

    still green.

  • I move the if statement for if the timer is NOT done to the top to make the function return a value quicker before it checks the lights

     1def control(timer_done, current_light):
     2    if not timer_done:
     3        return current_light
     4    if timer_done:
     5        if current_light == 'GREEN':
     6            return 'YELLOW'
     7        if current_light == 'YELLOW':
     8            return 'RED'
     9        if current_light == 'RED':
    10            return 'GREEN'
    
  • I add variables for 'RED', 'YELLOW' and 'GREEN'

    1def control(timer_done, current_light):
    2    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    3    if not timer_done:
    
  • I use the new variables for 'RED', 'YELLOW' and 'GREEN'

     1def control(timer_done, current_light):
     2    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
     3    if not timer_done:
     4        return current_light
     5    if timer_done:
     6        # if current_light == 'GREEN':
     7        if current_light == green:
     8            # return 'YELLOW'
     9            return yellow
    10        # if current_light == 'YELLOW':
    11        if current_light == yellow:
    12            # return 'RED'
    13            return red
    14        # if current_light == 'RED':
    15        if current_light == red:
    16            # return 'GREEN'
    17            return green
    

    still green.

  • I remove the commented lines from the control function

     1def control(timer_done, current_light):
     2    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
     3    if not timer_done:
     4        return current_light
     5    if timer_done:
     6        if current_light == green:
     7            return yellow
     8        if current_light == yellow:
     9            return red
    10        if current_light == red:
    11            return green
    
  • I add a git commit message in the other terminal

    git commit -am 'refactor if statements'
    

When the control function is called it checks if the timer is NOT done

  • If the timer is NOT done it returns the value of current_light

    control(current_light='GREEN', timer_done=False) -> 'GREEN'
    └── def control(timer_done, current_light):
        ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
        └── if not timer_done:
            └── return current_light
                return 'GREEN'
            if timer_done:
                if current_light == green:
                    return yellow
                if current_light == yellow:
                    return red
                if current_light == red:
                    return green
    
    control(current_light='YELLOW', timer_done=False) -> 'YELLOW'
    └── def control(timer_done, current_light):
        ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
        └── if not timer_done:
            └── return current_light
                return 'YELLOW'
            if timer_done:
                if current_light == green:
                    return yellow
                if current_light == yellow:
                    return red
                if current_light == red:
                    return green
    
    control(current_light='RED', timer_done=False) -> 'RED'
    └── def control(timer_done, current_light):
        ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
        └── if not timer_done:
            └── return current_light
                return 'RED'
            if timer_done:
                if current_light == green:
                    return yellow
                if current_light == yellow:
                    return red
                if current_light == red:
                    return green
    
  • If the timer is done it checks the value of current_light

    • If the current light is GREEN it returns YELLOW

      control(current_light='GREEN', timer_done=True ) -> 'YELLOW'
      └── def control(timer_done, current_light):
          ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
          ├── if not timer_done:
                return current_light
          └── if timer_done:
              └── if current_light == green:
                  └── return yellow
                  if current_light == yellow:
                      return red
                  if current_light == red:
                      return green
      
    • If the current light is YELLOW it returns RED

      control(current_light='YELLOW', timer_done=True ) -> 'RED'
      └── def control(timer_done, current_light):
          ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
          ├── if not timer_done:
                return current_light
          └── if timer_done:
              ├── if current_light == green:
                     return yellow
              └── if current_light == yellow:
                  └── return red
                  if current_light == red:
                      return green
      
    • If the current light is RED it returns GREEN

      control(current_light='RED', timer_done=True ) -> 'GREEN'
      └── def control(timer_done, current_light):
          ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
          ├── if not timer_done:
                return current_light
          └── if timer_done:
              ├── if current_light == green:
                     return yellow
              ├── if current_light == yellow:
                     return red
              └── if current_light == red:
                  └── return green
      
  • If none of the above conditions are met it returns None because ….

    def control(timer_done, current_light):
    ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    ├── if not timer_done:
          return current_light
    └── if timer_done:
        ├── if current_light == green:
               return yellow
        ├── if current_light == yellow:
               return red
        ├── if current_light == red:
               return green
    

The truth table for the Traffic Light is

current light

timer

output

GREEN

NOT done

GREEN

GREEN

done

YELLOW

YELLOW

NOT done

YELLOW

YELLOW

done

RED

RED

NOT done

RED

RED

done

GREEN

This only shows one set of lights for traffic in one direction, which is not needed if the street has no cross traffic, it is not yet a real Traffic Light.

I want the control function to show what happens in front of me (parallel) and what happens for the traffic crossing the street if the light is RED for me, it has to consider traffic in both directions

  • what traffic phase is this (cross, parallel or both)?

    • what is the light for me (parallel)?

    • what is the light for them (cross)?

  • is the timer done?

The Traffic Light has to make sure that there is never a case where cars move through the intersection at the same time to avoid accidents. The following cases must never happen

parallel

cross

GREEN

GREEN

GREEN

YELLOW

YELLOW

YELLOW

YELLOW

GREEN

The outputs will be the lights for Parallel and Cross Traffic which gives me this truth table

current

current

next

next

parallel

cross

timer

parallel

cross

GREEN

RED

NOT done

GREEN

RED

GREEN

RED

done

YELLOW

RED

YELLOW

RED

NOT done

YELLOW

RED

YELLOW

RED

done

safety RED

safety RED

RED

RED

NOT done

safety RED

safety RED

RED

RED

done

RED

GREEN

current

current

next

next

parallel

cross

timer

parallel

cross

RED

GREEN

NOT done

RED

GREEN

RED

GREEN

done

RED

YELLOW

RED

YELLOW

NOT done

RED

YELLOW

RED

YELLOW

done

safety RED

safety RED

RED

RED

NOT done

safety RED

safety RED

RED

RED

done

GREEN

RED

Where parallel is the light in front of me, and cross is the light for traffic crossing the street. The all RED row (Safety State) makes sure that there are no cars moving through the intersection at the same time to avoid accidents


test_cross_red_parallel_red_timer_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the current parallel light is RED AND the current cross light is RED AND the timer is done

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    RED

    done

    GREEN

    RED

    55    def test_red_light_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                timer_done=True,
    59                current_light=RED,
    60            ),
    61            GREEN
    62        )
    63
    64    def test_cross_red_parallel_red_timer_done(self):
    65        self.assertEqual(
    66            src.traffic_light.control(
    67                current_parallel=RED,
    68                current_cross=RED,
    69                timer_done=True,
    70            ),
    71            (GREEN, RED)
    72        )
    73
    74
    75# Exceptions seen
    

    the terminal is my friend, and shows TypeError

    TypeError: control() got
               an unexpected keyword argument 'current_parallel'
    

GREEN: make it pass


  • I add current_parallel to the function definition in src/traffic_light/__init__.py

    1def control(timer_done, current_light, current_parallel):
    

    the terminal is my friend, and shows TypeError

    FAILED ...test_cross_red_parallel_red_timer_done -
        TypeError: control() got an
            unexpected keyword argument 'current_cross'
    FAILED ...test_green_light_timer_done -
        TypeError: control() missing
            1 required positional argument: 'current_parallel'
    FAILED ...test_green_light_timer_not_done -
        TypeError: control() missing
            1 required positional argument: 'current_parallel'
    FAILED ...test_red_light_timer_done -
         ypeError: control() missing
            1 required positional argument: 'current_parallel'
    FAILED ...test_red_light_timer_not_done -
         TypeError: control() missing
            1 required positional argument: 'current_parallel'
    FAILED ...test_yellow_light_timer_done -
        TypeError: control() missing
            1 required positional argument: 'current_parallel'
    FAILED ...test_yellow_light_timer_not_done -
         TypeError: control() missing
            1 required positional argument: 'current_parallel'
    
  • I add a default value for the current_parallel parameter

    1def control(
    2        timer_done, current_light,
    3        current_parallel='RED',
    4    ):
    

    the terminal is my friend, and shows TypeError

    TypeError: control() got
               an unexpected keyword argument 'current_cross'
    
  • I add current_cross to the function definition

    1def control(
    2        timer_done, current_light,
    3        current_parallel='RED', current_cross='RED',
    4    ):
    

    the terminal is my friend, and shows TypeError

    TypeError: control() missing
               1 required positional argument: 'current_light'
    
  • I add a default value for current_light to the function signature

    1def control(
    2        timer_done, current_light='RED,
    3        current_parallel='RED', current_cross='RED',
    4    ):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'GREEN' != ('GREEN', 'RED')
    
  • I add an if statement to if timer_done: for if the current parallel light is RED AND the current cross light is RED

     8    if timer_done:
     9        if current_light == green:
    10            return yellow
    11        if current_light == yellow:
    12            return red
    13        if current_light == red:
    14            return green
    15        if current_parallel == red and current_cross == red:
    16            return green, red
    

    the terminal still shows AssertionError because the function returns RED if the timer is done AND current_light is RED and the default value for current_light in this assertion is RED.

  • I change the default value for current_light to None

    1def control(
    2        timer_done, current_light=None,
    3        current_parallel='RED', current_cross='RED',
    4    ):
    

    the test passes.

    control(
        current_parallel='RED' , current_cross='RED',
        timer_done=True
    ) -> 'GREEN', 'RED'
    
  • I add a git commit message in the other terminal

    git commit -am
    'add test_cross_red_parallel_red_timer_done'
    

test_cross_red_parallel_red_timer_not_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the current parallel light is RED AND the current cross light is RED AND the timer is NOT done

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    RED

    NOT done

    safety RED

    safety RED

    55    def test_red_light_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                timer_done=True,
    59                current_light=RED,
    60            ),
    61            GREEN
    62        )
    63
    64    def test_cross_red_parallel_red_timer_not_done(self):
    65        self.assertEqual(
    66            src.traffic_light.control(
    67                current_parallel=RED,
    68                current_cross=RED,
    69                timer_done=False,
    70            ),
    71            (RED, RED)
    72        )
    73
    74    def test_cross_red_parallel_red_timer_done(self):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != ('RED', 'RED')
    

GREEN: make it pass


  • I add an if statement for if the current parallel light is RED AND the current cross light is RED to if not timer_done: in src/traffic_light/__init__.py

     6    if not timer_done:
     7        if current_parallel == red and current_cross == red:
     8            return red, red
     9        return current_light
    10    if timer_done:
    

    the terminal is my friend, and shows AssertionError

    FAILED ...test_green_light_timer_not_done -
        AssertionError: ('RED', 'RED') != 'GREEN'
    FAILED ...test_red_light_timer_not_done -
        AssertionError: ('RED', 'RED') != 'RED'
    FAILED ...test_yellow_light_timer_not_done -
        AssertionError: ('RED', 'RED') != 'YELLOW'
    

    because those assertions use the default values for current_parallel and cross_parallel

  • I add an if statements for if the timer is NOT done and the current_light is grouped as True

     6    if not timer_done:
     7        if current_light:
     8            return current_light
     9        if current_parallel == red and current_cross == red:
    10            return red, red
    11        # return current_light
    12    if timer_done:
    

    the test passes.

    control(
        current_parallel='RED' , current_cross='RED',
        timer_done=False
    ) -> 'RED', 'RED'
    control(
        current_parallel='RED' , current_cross='RED',
        timer_done=True
    ) -> 'GREEN', 'RED'
    
  • I remove the commented line

     6    if not timer_done:
     7        if current_light:
     8            return current_light
     9        if current_parallel == red and current_cross == red:
    10            return red, red
    11
    12    if timer_done:
    
  • I add a git commit message in the other terminal

    git commit -am
    'add test_cross_red_parallel_red_timer_not_done'
    

test_cross_yellow_parallel_red_timer_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the current parallel light is RED AND the current cross light is YELLOW AND the timer is done

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    YELLOW

    done

    RED

    RED

    55    def test_red_light_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                timer_done=True,
    59                current_light=RED,
    60            ),
    61            GREEN
    62        )
    63
    64    def test_cross_yellow_parallel_red_timer_done(self):
    65        self.assertEqual(
    66            src.traffic_light.control(
    67                current_parallel=RED,
    68                current_cross=YELLOW,
    69                timer_done=True,
    70            ),
    71            (RED, RED)
    72        )
    73
    74    def test_cross_red_parallel_red_timer_not_done(self):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != ('RED', 'RED')
    

GREEN: make it pass


I add an if statement for if the current parallel light is RED AND the current cross light is YELLOW to if timer_done: in src/traffic_light/__init__.py

12    if timer_done:
13        if current_light == green:
14            return yellow
15        if current_light == yellow:
16            return red
17        if current_light == red:
18            return green
19        if current_parallel == red and current_cross == yellow:
20            return red, red
21        if current_parallel == red and current_cross == red:
22            return green, red

the test passes.

control(
    current_parallel='RED' , current_cross='YELLOW',
    timer_done=True
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=False
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=True
) -> 'GREEN', 'RED'

REFACTOR: make it better


  • Two of the if statements in if timer_done: are for if the current parallel light is RED. I change them to remove repetition of if current_parallel == red

    12    if timer_done:
    13        if current_light == green:
    14            return yellow
    15        if current_light == yellow:
    16            return red
    17        if current_light == red:
    18            return green
    19        # if current_parallel == red and current_cross == yellow:
    20        #     return red, red
    21        # if current_parallel == red and current_cross == red:
    22        #     return green, red
    23        if current_parallel == red:
    24            if current_cross == yellow:
    25                return red, red
    26            if current_cross == red:
    27                return green, red
    

    the tests are still green.

  • I remove the commented lines

    12    if timer_done:
    13        if current_light == green:
    14            return yellow
    15        if current_light == yellow:
    16            return red
    17        if current_light == red:
    18            return green
    19
    20        if current_parallel == red:
    21            if current_cross == yellow:
    22                return red, red
    23            if current_cross == red:
    24                return green, red
    
  • I add a git commit message in the other terminal

    git commit -am
    'add test_cross_yellow_parallel_red_timer_done'
    

test_cross_yellow_parallel_red_timer_not_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the current parallel light is RED AND the current cross light is YELLOW AND the timer is NOT done

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    YELLOW

    NOT done

    RED

    YELLOW

    55    def test_red_light_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                timer_done=True,
    59                current_light=RED,
    60            ),
    61            GREEN
    62        )
    63
    64    def test_cross_yellow_parallel_red_timer_not_done(self):
    65        self.assertEqual(
    66            src.traffic_light.control(
    67                current_parallel=RED,
    68                current_cross=YELLOW,
    69                timer_done=False,
    70            ),
    71            (RED, YELLOW)
    72        )
    73
    74    def test_cross_yellow_parallel_red_timer_done(self):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != ('RED', 'YELLOW')
    

GREEN: make it pass


I add an if statement for if the current parallel light is RED AND the current cross light is YELLOW to if not timer_done: in src/traffic_light/__init__.py

 6    if not timer_done:
 7        if current_light:
 8            return current_light
 9        if current_parallel == red and current_cross == yellow:
10            return red, yellow
11        if current_parallel == red and current_cross == red:
12            return red, red
13
14    if timer_done:

the test passes.

control(
    current_parallel='RED' , current_cross='YELLOW',
    timer_done=False
) -> 'RED', 'YELLOW'
control(
    current_parallel='RED' , current_cross='YELLOW',
    timer_done=True
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=False
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=True
) -> 'GREEN', 'RED'

REFACTOR: make it better


  • Two of the if statements in if not timer_done: are also for if the current parallel light is RED. I change them to remove repetition of if current_parallel == red

     6    if not timer_done:
     7        if current_light:
     8            return current_light
     9        # if current_parallel == red and current_cross == yellow:
    10        #     return red, yellow
    11        # if current_parallel == red and current_cross == red:
    12        #     return red, red
    13        if current_parallel == red:
    14            if current_cross == yellow:
    15                return red, yellow
    16            if current_cross == red:
    17                return red, red
    18
    19    if timer_done:
    

    the tests are still green.

  • I remove the commented lines

     6    if not timer_done:
     7        if current_light:
     8            return current_light
     9
    10        if current_parallel == red:
    11            if current_cross == yellow:
    12                return red, yellow
    13            if current_cross == red:
    14                return red, red
    15
    16    if timer_done:
    
  • I add a git commit message in the other terminal

    git commit -am
    'add test_cross_yellow_parallel_red_timer_not_done'
    

test_cross_green_parallel_red_timer_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the current parallel light is RED AND the current cross light is GREEN AND the timer is done

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    GREEN

    done

    RED

    YELLOW

    55    def test_red_light_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                timer_done=True,
    59                current_light=RED,
    60            ),
    61            GREEN
    62        )
    63
    64    def test_cross_green_parallel_red_timer_done(self):
    65        self.assertEqual(
    66            src.traffic_light.control(
    67                current_parallel=RED,
    68                current_cross=GREEN,
    69                timer_done=True,
    70            ),
    71            (RED, YELLOW)
    72        )
    73
    74    def test_cross_yellow_parallel_red_timer_not_done(self):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != ('RED', 'YELLOW')
    

GREEN: make it pass


I add an if statement for if the current parallel light is RED AND the current cross light is GREEN to if timer_done: in src/traffic_light/__init__.py

16      if timer_done:
17          if current_light == green:
18              return yellow
19          if current_light == yellow:
20              return red
21          if current_light == red:
22              return green
23
24          if current_parallel == red:
25              if current_cross == green:
26                  return red, yellow
27              if current_cross == yellow:
28                  return red, red
29              if current_cross == red:
30                  return green, red

the test passes.

control(
    current_parallel='RED' , current_cross='GREEN',
    timer_done=True
) -> 'RED', 'YELLOW'
control(
    current_parallel='RED' , current_cross='YELLOW',
    timer_done=False
) -> 'RED', 'YELLOW'
control(
    current_parallel='RED' , current_cross='YELLOW',
    timer_done=True
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=False
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=True
) -> 'GREEN', 'RED'
  • I add a git commit message in the other terminal

    git commit -am
    'add test_cross_green_parallel_red_timer_done'
    

test_cross_green_parallel_red_timer_not_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test with an assertion for if the current parallel light is RED AND the current cross light is GREEN AND the timer is NOT done

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    GREEN

    NOT done

    RED

    GREEN

    55    def test_red_light_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                timer_done=True,
    59                current_light=RED,
    60            ),
    61            GREEN
    62        )
    63
    64    def test_cross_green_parallel_red_timer_not_done(self):
    65        self.assertEqual(
    66            src.traffic_light.control(
    67                current_parallel=RED,
    68                current_cross=GREEN,
    69                timer_done=False,
    70            ),
    71            (RED, GREEN)
    72        )
    73
    74    def test_cross_green_parallel_red_timer_done(self):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != ('RED', 'GREEN')
    

GREEN: make it pass


I add an if statement for if the current parallel light is RED AND the current cross light is GREEN to if not timer_done: in src/traffic_light/__init__.py

 6    if not timer_done:
 7        if current_light:
 8            return current_light
 9
10        if current_parallel == red:
11            if current_cross == green:
12                return red, green
13            if current_cross == yellow:
14                return red, yellow
15            if current_cross == red:
16                return red, red
17
18    if timer_done:

the test passes.

control(
    current_parallel='RED' , current_cross='GREEN',
    timer_done=False
) -> 'RED', 'GREEN'
control(
    current_parallel='RED' , current_cross='GREEN',
    timer_done=True
) -> 'RED', 'YELLOW'
control(
    current_parallel='RED' , current_cross='YELLOW',
    timer_done=False
) -> 'RED', 'YELLOW'
control(
    current_parallel='RED' , current_cross='YELLOW',
    timer_done=True
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=False
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=True
) -> 'GREEN', 'RED'

REFACTOR: make it better


  • The three if statements in if not timer_done: for if the current parallel light is RED all return the current parallel light and the current cross light. I write one return statement for all of them

     6    if not timer_done:
     7        if current_light:
     8            return current_light
     9
    10        if current_parallel == red:
    11            return current_parallel, current_cross
    12            if current_cross == green:
    13                return red, green
    14            if current_cross == yellow:
    15                return red, yellow
    16            if current_cross == red:
    17                return red, red
    18
    19    if timer_done:
    

    the tests are still green.

  • I remove the if statements for the other cases since they are no longer used

     6    if not timer_done:
     7        if current_light:
     8            return current_light
     9
    10        if current_parallel == red:
    11            return current_parallel, current_cross
    12
    13    if timer_done:
    

    still green.

  • I add a git commit message in the other terminal

    git commit -am
    'add test_cross_green_parallel_red_timer_not_done'
    

test_parallel_red_cross_red_timer_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I change the assertion in test_red_light_timer_done for if the current parallel light is RED AND the current cross light is RED AND the timer is done

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    RED

    done

    RED

    GREEN

    55    def test_red_light_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                current_parallel=RED,
    59                current_cross=RED,
    60                timer_done=True,
    61                # current_light=RED,
    62            ),
    63            # GREEN
    64            (RED, GREEN)
    65        )
    66
    67    def test_cross_green_parallel_red_timer_not_done(self):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: Tuples differ: ('GREEN', 'RED') != ('RED', 'GREEN')
    

    because the control function cannot tell the difference between

    • if the current parallel light is RED AND the cross light is RED AND the timer is done which returns the next parallel light as GREEN and the next cross light as RED, and

    • if the current parallel light is RED AND the cross light is RED AND the timer is done which returns the next parallel light as RED and the next cross light as GREEN

    • the current lights are the same in both cases but the output is different

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    RED

    done

    GREEN

    RED

    RED

    RED

    done

    RED

    GREEN

    I need a way for the function to know the difference. When I look at the overall table I see that the phases that come right before these two states are the safety state which is also the same for both

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    RED

    NOT done

    safety RED

    safety RED

    RED

    RED

    done

    GREEN

    RED

    RED

    RED

    NOT done

    safety RED

    safety RED

    RED

    RED

    done

    RED

    GREEN

    The difference between them is in the phase before the safety phase

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    YELLOW

    RED

    done

    RED

    RED

    RED

    RED

    NOT done

    safety RED

    safety RED

    RED

    RED

    done

    GREEN

    RED

    current

    current

    next

    next

    parallel

    cross

    timer

    parallel

    cross

    RED

    YELLOW

    done

    RED

    RED

    RED

    RED

    NOT done

    safety RED

    safety RED

    RED

    RED

    done

    RED

    GREEN

    The control function needs to know that it is a sequence based on whether the parallel or cross traffic is in a RED state

    • if it is in the RED state for cross traffic AND the current parallel light is RED AND the cross light is RED AND the timer is done it should keep the parallel light RED and turn the next cross light GREEN

    • if it is in the RED state for parallel traffic AND the current parallel light is RED AND the cross light is RED AND the timer is done it should turn the next parallel light GREEN and keep the next cross light RED


GREEN: make it pass


  • I add red_phase to the call control function in the assertion in test_red_light_timer_done

    55  def test_red_light_timer_done(self):
    56      self.assertEqual(
    57          src.traffic_light.control(
    58              red_phase='cross',
    59              current_parallel=RED,
    60              current_cross=RED,
    61              timer_done=True,
    62              # current_light=RED,
    63          ),
    64          # GREEN
    65          (RED, GREEN)
    66      )
    67
    68  def test_cross_green_parallel_red_timer_not_done(self):
    

    the terminal is my friend, and shows TypeError

    TypeError: control() got an
               unexpected keyword argument 'red_phase'
    
  • I add red_phase with a default value for the other tests, to the function definition in src/traffic_light/__init__.py

    1def control(
    2        timer_done, current_light=None,
    3        current_parallel='RED', current_cross='RED',
    4        red_phase='parallel',
    5    ):
    

    the terminal still shows AssertionError

  • I add an if statement to if timer_done: for if the Traffic Light is currently in the RED phase for cross traffic AND the current parallel light is RED AND the current cross light is RED

    14    if timer_done:
    15        if current_light == green:
    16            return yellow
    17        if current_light == yellow:
    18            return red
    19        if current_light == red:
    20            return green
    21
    22        if red_phase == 'cross':
    23            if current_parallel == red and current_cross == red:
    24                return red, green
    25
    26        if current_parallel == red:
    

    the test passes.

    control(
        current_parallel='RED' , current_cross='RED',
        timer_done=True, red_phase='cross'
    ) -> 'RED', 'GREEN'
    

REFACTOR: make it better


  • I remove the commented lines from test_red_light_timer_done in tests/test_traffic_light.py

    55    def test_red_light_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                red_phase='cross',
    59                current_parallel=RED,
    60                current_cross=RED,
    61                timer_done=True,
    62            ),
    63            (RED, GREEN)
    64        )
    65
    66    def test_cross_green_parallel_red_timer_not_done(self):
    
  • I change the name of the test from test_red_light_timer_done to test_parallel_red_cross_red_timer_done

    46    def test_red_light_timer_not_done(self):
    47        self.assertEqual(
    48            src.traffic_light.control(
    49                timer_done=False,
    50                current_light=RED,
    51            ),
    52            RED
    53        )
    54
    55    def test_parallel_red_cross_red_timer_done(self):
    56        self.assertEqual(
    57            src.traffic_light.control(
    58                red_phase='cross',
    59                current_parallel=RED,
    60                current_cross=RED,
    61                timer_done=True,
    62            ),
    63            (RED, GREEN)
    64        )
    65
    66    def test_cross_green_parallel_red_timer_not_done(self):
    
  • I add a git commit message in the other terminal

    git commit -am
    'add test_parallel_red_cross_red_timer_done'
    

test_parallel_red_cross_red_timer_not_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add values for current_parallel, current_cross and red_phase to the assertion in test_red_light_timer_not_done for if 'cross' traffic is in the RED phase AND the current parallel light is RED AND the current cross light is RED AND the timer is NOT done

    red

    current

    current

    next

    next

    phase

    parallel

    cross

    timer

    parallel

    cross

    ‘cross’

    RED

    RED

    NOT done

    safety RED

    safety RED

    46    def test_red_light_timer_not_done(self):
    47        self.assertEqual(
    48            src.traffic_light.control(
    49                red_phase='cross',
    50                current_parallel=RED,
    51                current_cross=RED,
    52                timer_done=False,
    53                # current_light=RED,
    54            ),
    55            # RED
    56            (RED, RED)
    57        )
    58
    59    def test_parallel_red_cross_red_timer_done(self):
    

    the test is still green.

    control(
        current_parallel='RED' , current_cross='RED',
        timer_done=False, red_phase='cross'
    ) -> 'RED', 'RED'
    control(
        current_parallel='RED' , current_cross='RED',
        timer_done=True, red_phase='cross'
    ) -> 'RED', 'GREEN'
    

GREEN: make it pass


  • I remove the commented lines from test_red_light_timer_not_done

    46  def test_red_light_timer_not_done(self):
    47      self.assertEqual(
    48          src.traffic_light.control(
    49              red_phase='cross',
    50              current_parallel=RED,
    51              current_cross=RED,
    52              timer_done=False,
    53          ),
    54          (RED, RED)
    55      )
    56
    57  def test_parallel_red_cross_red_timer_done(self):
    
  • I change the name of the test from test_red_light_timer_not_done to test_parallel_red_cross_red_timer_not_done

    37    def test_yellow_light_timer_done(self):
    38        self.assertEqual(
    39            src.traffic_light.control(
    40                timer_done=True,
    41                current_light=YELLOW,
    42            ),
    43            RED
    44        )
    45
    46    def test_parallel_red_cross_red_timer_not_done(self):
    47        self.assertEqual(
    48            src.traffic_light.control(
    49                red_phase='cross',
    50                current_parallel=RED,
    51                current_cross=RED,
    52                timer_done=False,
    53            ),
    54            (RED, RED)
    55        )
    56
    57    def test_parallel_red_cross_red_timer_done(self):
    
  • I add a git commit message in the other terminal

    git commit -am
    'add test_parallel_red_cross_red_timer_not_done'
    

test_parallel_yellow_cross_red_timer_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add values for current_parallel, current_cross and red_phase to the assertion in test_yellow_light_timer_done for if 'cross' traffic is in the RED phase AND the current parallel light is YELLOW AND the current cross light is RED AND the timer is done

    red

    current

    current

    next

    next

    phase

    parallel

    cross

    timer

    parallel

    cross

    ‘cross’

    YELLOW

    RED

    done

    RED

    RED

    37    def test_yellow_light_timer_done(self):
    38        self.assertEqual(
    39            src.traffic_light.control(
    40                red_phase='cross',
    41                current_parallel=YELLOW,
    42                current_cross=RED,
    43                timer_done=True,
    44                # current_light=YELLOW,
    45            ),
    46            # RED
    47            (RED, RED)
    48        )
    49
    50    def test_parallel_red_cross_red_timer_not_done(self):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != ('RED', 'RED')
    

GREEN: make it pass


I add an if statement for if the current parallel light is YELLOW AND the current cross light is RED to if timer_done: in src/traffic_light/__init__.py

14      if timer_done:
15          if current_light == green:
16              return yellow
17          if current_light == yellow:
18              return red
19          if current_light == red:
20              return green
21
22          if red_phase == 'cross':
23              if current_parallel == red and current_cross == red:
24                  return red, green
25
26          if current_parallel == yellow and current_cross == red:
27              return red, red
28
29          if current_parallel == red:

the test passes.

control(
    current_parallel='YELLOW' , current_cross='RED',
    timer_done=True, red_phase='cross'
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=False, red_phase='cross'
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=True, red_phase='cross'
) -> 'RED', 'GREEN'

REFACTOR: make it better


  • Two of the if statements in if timer_done: are for if the current cross light is RED which is when cross traffic is in the RED phase. I change them to remove repetition of if current_cross == red

    14    if timer_done:
    15        if current_light == green:
    16            return yellow
    17        if current_light == yellow:
    18            return red
    19        if current_light == red:
    20            return green
    21
    22        if red_phase == 'cross':
    23        #     if current_parallel == red and current_cross == red:
    24        #         return red, green
    25
    26        # if current_parallel == yellow and current_cross == red:
    27        #     return red, red
    28            if current_parallel == yellow:
    29                return red, red
    30            if current_parallel == red:
    31                return red, green
    32
    33        if current_parallel == red:
    

    the tests are still green.

  • I remove the commented lines

    14    if timer_done:
    15        if current_light == green:
    16            return yellow
    17        if current_light == yellow:
    18            return red
    19        if current_light == red:
    20            return green
    21
    22        if red_phase == 'cross':
    23            if current_parallel == yellow:
    24                return red, red
    25            if current_parallel == red:
    26                return red, green
    27
    28        if current_parallel == red:
    
  • I remove the commented lines from test_yellow_light_timer_done

    37    def test_yellow_light_timer_done(self):
    38        self.assertEqual(
    39            src.traffic_light.control(
    40                red_phase='cross',
    41                current_parallel=YELLOW,
    42                current_cross=RED,
    43                timer_done=True,
    44            ),
    45            (RED, RED)
    46        )
    47
    48    def test_parallel_red_cross_red_timer_not_done(self):
    
  • I change the name of the test from test_yellow_light_timer_done to test_parallel_yellow_cross_red_timer_done

    28    def test_yellow_light_timer_not_done(self):
    29        self.assertEqual(
    30            src.traffic_light.control(
    31                timer_done=False,
    32                current_light=YELLOW,
    33            ),
    34            YELLOW
    35        )
    36
    37    def test_parallel_yellow_cross_red_timer_done(self):
    38        self.assertEqual(
    39            src.traffic_light.control(
    40                red_phase='cross',
    41                current_parallel=YELLOW,
    42                current_cross=RED,
    43                timer_done=True,
    44            ),
    45            (RED, RED)
    46        )
    47
    48    def test_parallel_red_cross_red_timer_not_done(self):
    
  • I add a git commit message in the other terminal

    git commit -am
    'add test_parallel_yellow_cross_red_timer_done'
    

test_parallel_yellow_cross_red_timer_not_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add values for current_parallel, current_cross and red_phase to the assertion in test_yellow_light_timer_not_done for if 'cross' traffic is in the RED phase AND the current parallel light is YELLOW AND the current cross light is RED AND the timer is NOT done

    red

    current

    current

    next

    next

    phase

    parallel

    cross

    timer

    parallel

    cross

    ‘cross’

    YELLOW

    RED

    NOT done

    YELLOW

    RED

    28  def test_yellow_light_timer_not_done(self):
    29      self.assertEqual(
    30          src.traffic_light.control(
    31              red_phase='cross',
    32              current_parallel=YELLOW,
    33              current_cross=RED,
    34              timer_done=False,
    35              # current_light=YELLOW,
    36          ),
    37          # YELLOW
    38          (YELLOW, RED)
    39      )
    40
    41  def test_parallel_yellow_cross_red_timer_done(self):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != ('YELLOW', 'RED')
    

GREEN: make it pass


I add an if statement for if the current parallel light is YELLOW AND the current cross light is RED to if not timer_done: in src/traffic_light/__init__.py

 7      if not timer_done:
 8          if current_light:
 9              return current_light
10
11          if current_parallel == yellow and current_cross == red:
12              return yellow, red
13          if current_parallel == red:
14              return current_parallel, current_cross
15
16      if timer_done:

the test passes.

control(
    current_parallel='YELLOW' , current_cross='RED',
    timer_done=False, red_phase='cross'
) -> 'YELLOW', 'RED'
control(
    current_parallel='YELLOW' , current_cross='RED',
    timer_done=True, red_phase='cross'
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=False, red_phase='cross'
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=True, red_phase='cross'
) -> 'RED', 'GREEN'

REFACTOR: make it better


  • I remove the commented lines from test_yellow_light_timer_not_done in tests/test_traffic_light.py

    28    def test_yellow_light_timer_not_done(self):
    29        self.assertEqual(
    30            src.traffic_light.control(
    31                red_phase='cross',
    32                current_parallel=YELLOW,
    33                current_cross=RED,
    34                timer_done=False,
    35            ),
    36            (YELLOW, RED)
    37        )
    38
    39    def test_parallel_yellow_cross_red_timer_done(self):
    
  • I change the name of the test from test_yellow_light_timer_not_done to test_parallel_yellow_cross_red_timer_not_done

    19    def test_green_light_timer_done(self):
    20        self.assertEqual(
    21            src.traffic_light.control(
    22                timer_done=True,
    23                current_light=GREEN,
    24            ),
    25            YELLOW
    26        )
    27
    28    def test_parallel_yellow_cross_red_timer_not_done(self):
    29        self.assertEqual(
    30            src.traffic_light.control(
    31                red_phase='cross',
    32                current_parallel=YELLOW,
    33                current_cross=RED,
    34                timer_done=False,
    35            ),
    36            (YELLOW, RED)
    37        )
    38
    39    def test_parallel_yellow_cross_red_timer_done(self):
    
  • I add a git commit message in the other terminal

    git commit -am
    'add test_parallel_yellow_cross_red_timer_not_done'
    

test_parallel_green_cross_red_timer_done

  • I go back to the terminal where the tests are running

  • I add values for current_parallel, current_cross and red_phase to the assertion in test_green_light_timer_done for if 'cross' traffic is in the RED phase AND the current parallel light is GREEN AND the current cross light is RED AND the timer is done

    red

    current

    current

    next

    next

    phase

    parallel

    cross

    timer

    parallel

    cross

    ‘cross’

    GREEN

    RED

    done

    YELLOW

    RED

    19    def test_green_light_timer_done(self):
    20        self.assertEqual(
    21            src.traffic_light.control(
    22                red_phase='cross',
    23                current_parallel=GREEN,
    24                current_cross=RED,
    25                timer_done=True,
    26                # current_light=GREEN,
    27            ),
    28            # YELLOW
    29            (YELLOW, RED)
    30        )
    31
    32    def test_parallel_yellow_cross_red_timer_not_done(self):
    

    the test is still green.

    control(
        current_parallel='GREEN' , current_cross='RED',
        timer_done=True, red_phase='cross'
    ) -> 'YELLOW', 'RED'
    control(
        current_parallel='YELLOW' , current_cross='RED',
        timer_done=False, red_phase='cross'
    ) -> 'YELLOW', 'RED'
    control(
        current_parallel='YELLOW' , current_cross='RED',
        timer_done=True, red_phase='cross'
    ) -> 'RED', 'RED'
    control(
        current_parallel='RED' , current_cross='RED',
        timer_done=False, red_phase='cross'
    ) -> 'RED', 'RED'
    control(
        current_parallel='RED' , current_cross='RED',
        timer_done=True, red_phase='cross'
    ) -> 'RED', 'GREEN'
    
  • I remove the commented lines from test_green_light_timer_done

    19    def test_green_light_timer_done(self):
    20        self.assertEqual(
    21            src.traffic_light.control(
    22                red_phase='cross',
    23                current_parallel=GREEN,
    24                current_cross=RED,
    25                timer_done=True,
    26            ),
    27            (YELLOW, RED)
    28        )
    29
    30    def test_parallel_yellow_cross_red_timer_not_done(self):
    
  • I change the name of the test from test_green_light_timer_done to test_parallel_green_cross_red_timer_done

    10    def test_green_light_timer_not_done(self):
    11        self.assertEqual(
    12            src.traffic_light.control(
    13                timer_done=False,
    14                current_light=GREEN,
    15            ),
    16            GREEN
    17        )
    18
    19    def test_parallel_green_cross_red_timer_done(self):
    20        self.assertEqual(
    21            src.traffic_light.control(
    22                red_phase='cross',
    23                current_parallel=GREEN,
    24                current_cross=RED,
    25                timer_done=True,
    26            ),
    27            (YELLOW, RED)
    28        )
    29
    30    def test_parallel_yellow_cross_red_timer_not_done(self):
    
  • I add a git commit message in the other terminal

    git commit -am
    'add test_parallel_green_cross_red_timer_done'
    

test_parallel_green_cross_red_timer_not_done

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add values for current_parallel, current_cross and red_phase to the assertion in test_green_light_timer_not_done for if 'cross' traffic is in the RED phase AND the current parallel light is GREEN AND the current cross light is RED AND the timer is NOT done

    red

    current

    current

    next

    next

    phase

    parallel

    cross

    timer

    parallel

    cross

    ‘cross’

    GREEN

    RED

    NOT done

    GREEN

    RED

    10    def test_green_light_timer_not_done(self):
    11        self.assertEqual(
    12            src.traffic_light.control(
    13                red_phase='cross',
    14                current_parallel=GREEN,
    15                current_cross=RED,
    16                timer_done=False,
    17                # current_light=GREEN,
    18            ),
    19            # GREEN
    20            (GREEN, RED)
    21        )
    22
    23    def test_parallel_green_cross_red_timer_done(self):
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != ('GREEN', 'RED')
    

GREEN: make it pass


I add an if statement for if the current parallel light is GREEN AND the current cross light is RED to if not timer_done: in src/traffic_light/__init__.py

 7    if not timer_done:
 8        if current_light:
 9            return current_light
10
11        if current_parallel == green and current_cross == red:
12            return green, red
13        if current_parallel == yellow and current_cross == red:
14            return yellow, red
15        if current_parallel == red:
16            return current_parallel, current_cross
17
18    if timer_done:

the test passes.

control(
    current_parallel='GREEN' , current_cross='RED',
    timer_done=False, red_phase='cross'
) -> 'GREEN', 'RED'
control(
    current_parallel='GREEN' , current_cross='RED',
    timer_done=True, red_phase='cross'
) -> 'YELLOW', 'RED'
control(
    current_parallel='YELLOW' , current_cross='RED',
    timer_done=False, red_phase='cross'
) -> 'YELLOW', 'RED'
control(
    current_parallel='YELLOW' , current_cross='RED',
    timer_done=True, red_phase='cross'
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=False, red_phase='cross'
) -> 'RED', 'RED'
control(
    current_parallel='RED' , current_cross='RED',
    timer_done=True, red_phase='cross'
) -> 'RED', 'GREEN'

REFACTOR: make it better


  • I remove the commented lines from test_green_light_timer_not_done

    10    def test_green_light_timer_not_done(self):
    11        self.assertEqual(
    12            src.traffic_light.control(
    13                red_phase='cross',
    14                current_parallel=GREEN,
    15                current_cross=RED,
    16                timer_done=False,
    17            ),
    18            (GREEN, RED)
    19        )
    20
    21    def test_parallel_green_cross_red_timer_done(self):
    
  • I change the name of the test from test_green_light_timer_not_done to test_parallel_green_cross_red_timer_not_done

     8class TestTrafficLight(unittest.TestCase):
     9
    10    def test_parallel_green_cross_red_timer_not_done(self):
    11        self.assertEqual(
    12            src.traffic_light.control(
    13                red_phase='cross',
    14                current_parallel=GREEN,
    15                current_cross=RED,
    16                timer_done=False,
    17            ),
    18            (GREEN, RED)
    19        )
    
  • I remove the if statements for the current_light parameter since they are no longer used, in src/traffic_light/__init__.py

     7    if not timer_done:
     8        if current_parallel == green and current_cross == red:
     9            return green, red
    10        if current_parallel == yellow and current_cross == red:
    11            return yellow, red
    12        if current_parallel == red:
    13            return current_parallel, current_cross
    14
    15    if timer_done:
    16        if red_phase == 'cross':
    17            if current_parallel == green:
    18                return yellow, red
    19            if current_parallel == yellow:
    20                return red, red
    21            if current_parallel == red:
    22                return red, green
    23        if current_parallel == red:
    24            if current_cross == green:
    25                return red, yellow
    26            if current_cross == yellow:
    27                return red, red
    28            if current_cross == red:
    29                return green, red
    

    the tests are still green.

  • I remove the current_light parameter from the parentheses of the function definition

    1def control(
    2        timer_done, red_phase='parallel',
    3        current_parallel='RED', current_cross='RED',
    4    ):
    5    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    6    if not timer_done:
    
  • The three if statements in if not timer_done: all return the current parallel light and the current cross light. I write one return statement for all of them

     6    if not timer_done:
     7        return current_parallel, current_cross
     8        if current_parallel == green and current_cross == red:
     9            return green, red
    10        if current_parallel == yellow and current_cross == red:
    11            return yellow, red
    12        if current_parallel == red:
    13            return current_parallel, current_cross
    14
    15    if timer_done:
    

    the tests are still green.

  • I change if current_parallel == red to if red_phase == 'parallel': for if the timer is done AND the current parallel light is RED since it is for when parallel traffic is in the RED phase

    15    if timer_done:
    16        if red_phase == 'cross':
    17            if current_parallel == green:
    18                return yellow, red
    19            if current_parallel == yellow:
    20                return red, red
    21            if current_parallel == red:
    22                return red, green
    23        # if current_parallel == red:
    24        if red_phase == 'parallel':
    25            if current_cross == green:
    26                return red, yellow
    27            if current_cross == yellow:
    28                return red, red
    29            if current_cross == red:
    30                return green, red
    

    green.

  • I remove the if statements from if not timer_done: and the commented line since they are no longer used

     1def control(
     2        timer_done, red_phase='parallel',
     3        current_parallel='RED', current_cross='RED',
     4    ):
     5    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
     6
     7    if not timer_done:
     8        return current_parallel, current_cross
     9
    10    if timer_done:
    11        if red_phase == 'cross':
    12            if current_parallel == green:
    13                return yellow, red
    14            if current_parallel == yellow:
    15                return red, red
    16            if current_parallel == red:
    17                return red, green
    18        if red_phase == 'parallel':
    19            if current_cross == green:
    20                return red, yellow
    21            if current_cross == yellow:
    22                return red, red
    23            if current_cross == red:
    24                return green, red
    
  • I add a git commit message in the other terminal

    git commit -am \
    'add test_parallel_green_cross_red_timer_not_done'
    

When the control function is called it checks if the timer is NOT done

  • If the timer is NOT done, it returns the values of current_parallel and current_cross, which means it does not change the parallel or cross lights, it keeps them the same

    control(
        current_parallel='RED', current_cross='GREEN',
        timer_done=False, red_phase='parallel'
    ) -> 'RED', 'GREEN'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'RED'          , 'GREEN'
                if timer_done:
    
    control(
        current_parallel='RED', current_cross='YELLOW',
        timer_done=False, red_phase='parallel'
    ) -> 'RED', 'YELLOW'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'RED'           , 'YELLOW'
                if timer_done:
    
    control(
        current_parallel='RED', current_cross='RED',
        timer_done=False, red_phase='parallel'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'RED'           , 'RED'
                if timer_done:
    
    control(
        current_parallel='GREEN', current_cross='RED',
        timer_done=False, red_phase='cross'
    ) -> 'GREEN', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'GREEN'         , 'RED'
                if timer_done:
    
    control(
        current_parallel='YELLOW', current_cross='RED',
        timer_done=False, red_phase='cross'
    ) -> 'YELLOW', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'YELLOW'        , 'RED'
                if timer_done:
    
    control(
        current_parallel='RED', current_cross='RED',
        timer_done=False, red_phase='cross'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'RED'           , 'RED'
                if timer_done:
    
  • If the timer is done, it checks if cross traffic is in the RED phase

    • If cross traffic is in the RED phase, it checks the value of current_parallel

      • If the current parallel light is GREEN, it returns YELLOW, RED, which means the next parallel light will be YELLOW and the cross light will remain RED because it is still in the RED phase

        control(
            current_parallel='GREEN', current_cross='RED',
            timer_done=True, red_phase='cross'
        ) -> 'YELLOW', 'RED'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    └── if red_phase == 'cross':
                        └── if current_parallel == green:
                            └── return yellow, red
                            if current_parallel == yellow:
                                return red, red
                            if current_parallel == red:
                                return red, green
                        if red_phase == 'parallel':
        
      • If the current parallel light is YELLOW, it returns RED, RED, which means there will be no traffic in the intersection, the parallel and cross lights will both be RED

        control(
            current_parallel='YELLOW', current_cross='RED',
            timer_done=True, red_phase='cross'
        ) -> 'RED', 'RED'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    └── if red_phase == 'cross':
                        ├── if current_parallel == green:
                               return yellow, red
                        └── if current_parallel == yellow:
                            └── return red, red
                            if current_parallel == red:
                                return red, green
                        if red_phase == 'parallel':
        
      • If the current parallel light is RED, it returns RED, GREEN, which means the parallel light will stay RED since it is now in the RED phase and the next cross light will be GREEN

        control(
            current_parallel='RED', current_cross='RED',
            timer_done=True, red_phase='cross'
        ) -> 'RED', 'GREEN'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    └── if red_phase == 'cross':
                        ├── if current_parallel == green:
                               return yellow, red
                        ├── if current_parallel == yellow:
                               return red, red
                        └── if current_parallel == red:
                            └── return red, green
                        if red_phase == 'parallel':
        
      • If cross traffic is not in the RED phase, it checks if parallel traffic is in the RED phase

    • If parallel traffic is in the RED phase, it checks the value of current_cross

      • If the current cross light is GREEN, it returns RED, YELLOW, which means the parallel light will remain RED because it is still in the RED phase and the next cross light will be YELLOW

        control(
            current_parallel='RED', current_cross='GREEN',
            timer_done=True, red_phase='parallel'
        ) -> 'RED', 'YELLOW'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    ├── if red_phase == 'cross':
                           ...
                    └── if red_phase == 'parallel':
                        └── if current_cross == green:
                            └── return red, yellow
                            if current_cross == yellow:
                                return red, red
                            if current_cross == red:
                                return green, red
        
      • If the current parallel light is YELLOW, it returns RED, RED, which means there will be no traffic in the intersection, the parallel and cross lights will both be RED

        control(
            current_parallel='RED', current_cross='YELLOW',
            timer_done=True, red_phase='parallel'
        ) -> 'RED', 'RED'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    ├── if red_phase == 'cross':
                           ...
                    └── if red_phase == 'parallel':
                        ├── if current_cross == green:
                               return red, yellow
                        └── if current_cross == yellow:
                            └── return red, red
                            if current_cross == red:
                                return green, red
        
      • If the current cross light is RED, it returns GREEN, RED, which means the next parallel light will be GREEN and the cross light will stay RED since it is now in the RED phase

        control(
            current_parallel='RED', current_cross='RED',
            timer_done=True, red_phase='parallel'
        ) -> 'GREEN', 'RED'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    ├── if red_phase == 'cross':
                           ...
                    └── if red_phase == 'parallel':
                        ├── if current_cross == green:
                               return red, yellow
                        ├── if current_cross == yellow:
                               return red, red
                        └── if current_cross == red:
                            └── return green, red
        
  • If none of the above conditions are met it returns None

    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN'
            ├── if not timer_done:
                   return current_parallel, current_cross
            └── if timer_done:
                ├── if red_phase == 'cross':
                       ...
                ├── if red_phase == 'parallel':
                       ...
    

test_failsafe

The Traffic Light has to make sure that there is never a case where cars move through the intersection at the same time to avoid accidents. The following cases must never happen

parallel

cross

GREEN

GREEN

GREEN

YELLOW

YELLOW

YELLOW

YELLOW

GREEN

It should be RED for both cross and parallel traffic for any of the above cases and for any cases that are outside the safe cases, for example a power failure.


RED: make it fail


  • I add a test for the safety state in tests/test_traffic_light.py

    131    def test_cross_red_parallel_red_timer_done(self):
    132        self.assertEqual(
    133            src.traffic_light.control(
    134                red_phase='parallel',
    135                current_parallel=RED,
    136                current_cross=RED,
    137                timer_done=True,
    138            ),
    139            (GREEN, RED)
    140        )
    141
    142    def test_failsafe(self):
    143        self.assertEqual(
    144            src.traffic_light.control(
    145                red_phase='BOOM',
    146                current_parallel='BAP',
    147                current_cross=RED,
    148                timer_done=False,
    149            ),
    150            (RED, RED)
    151        )
    152
    153
    154# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: Tuples differ: ('BAP', 'RED') != ('RED', 'RED')
    

GREEN: make it pass


I add an if statement for if current_parallel is NOT GREEN or YELLOW or RED, in src/traffic_light/__init__.py

 5      red, yellow, green = 'RED', 'YELLOW', 'GREEN'
 6
 7      if not (
 8          current_parallel == green
 9          or current_parallel == yellow
10          or current_parallel == red
11      ):
12          return red, red
13
14      if not timer_done:

the test passes.

control(
    current_parallel='BAP', current_cross='RED',
    timer_done=False, red_phase='BOOM'
) -> 'RED', 'RED'

REFACTOR: make it better


  • I add an assertion for if current_cross is NOT GREEN or YELLOW or RED to test_failsafe in tests/test_traffic_light.py

    142    def test_failsafe(self):
    143        self.assertEqual(
    144            src.traffic_light.control(
    145                red_phase='BOOM',
    146                current_parallel='BAP',
    147                current_cross=RED,
    148                timer_done=False,
    149            ),
    150            (RED, RED)
    151        )
    152        self.assertEqual(
    153            src.traffic_light.control(
    154                red_phase='BOOM',
    155                current_parallel='BAP',
    156                current_cross='POW',
    157                timer_done=False,
    158            ),
    159            (RED, RED)
    160        )
    161
    162
    163# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: Tuples differ: ('RED', 'POW') != ('RED', 'RED')
    
  • I add an if statement for if current_cross is NOT GREEN or YELLOW or RED to test_failsafe in src/traffic_light/__init__.py

     7    if not (
     8        current_parallel == green
     9        or current_parallel == yellow
    10        or current_parallel == red
    11    ):
    12        return red, red
    13
    14    if not (
    15        current_cross == green
    16        or current_cross == yellow
    17        or current_cross == red
    18    ):
    19        return red, red
    20
    21    if not timer_done:
    

    the test passes.

    control(
        current_parallel='RED', current_cross='POW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='BAP', current_cross='RED',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    
  • I add an assertion to test_failsafe for if both lights are GREEN, in tests/test_traffic_light.py

    152        self.assertEqual(
    153            src.traffic_light.control(
    154                red_phase='BOOM',
    155                current_parallel=RED,
    156                current_cross='POW',
    157                timer_done=False,
    158            ),
    159            (RED, RED)
    160        )
    161        self.assertEqual(
    162            src.traffic_light.control(
    163                red_phase='BOOM',
    164                current_parallel=GREEN,
    165                current_cross=GREEN,
    166                timer_done=False,
    167            ),
    168            (RED, RED)
    169        )
    170
    171
    172# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: Tuples differ: ('GREEN', 'GREEN') != ('RED', 'RED')
    
  • I add an if statement for if both lights are GREEN, in src/traffic_light/__init__.py

    14    if not (
    15        current_cross == green
    16        or current_cross == yellow
    17        or current_cross == red
    18    ):
    19        return red, red
    20
    21    if current_parallel == current_cross == green:
    22        return red, red
    23
    24    if not timer_done:
    

    the test passes.

    control(
        current_parallel='RED', current_cross='POW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='BAP', current_cross='RED',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='GREEN', current_cross='GREEN',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    
  • I add an assertion to test_failsafe for if the parallel lights are GREEN AND the cross lights are YELLOW, in tests/test_traffic_light.py

    161        self.assertEqual(
    162            src.traffic_light.control(
    163                red_phase='BOOM',
    164                current_parallel=GREEN,
    165                current_cross=GREEN,
    166                timer_done=False,
    167            ),
    168            (RED, RED)
    169        )
    170        self.assertEqual(
    171            src.traffic_light.control(
    172                red_phase='BOOM',
    173                current_parallel=GREEN,
    174                current_cross=YELLOW,
    175                timer_done=False,
    176            ),
    177            (RED, RED)
    178        )
    179
    180
    181# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: Tuples differ: ('GREEN', 'YELLOW') != ('RED', 'RED')
    
  • I add an if statement for if the parallel lights are GREEN AND the cross lights are YELLOW, in src/traffic_light/__init__.py

    21    if current_parallel == current_cross == green:
    22        return red, red
    23    if current_parallel == green and current_cross == yellow:
    24        return red, red
    25
    26    if not timer_done:
    

    the test passes.

    control(
        current_parallel='RED', current_cross='POW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='BAP', current_cross='RED',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='GREEN', current_cross='GREEN',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='GREEN', current_cross='YELLOW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    
  • I add an assertion to test_failsafe for if the parallel lights are YELLOW AND the cross lights are GREEN, in tests/test_traffic_light.py

    170        self.assertEqual(
    171            src.traffic_light.control(
    172                red_phase='BOOM',
    173                current_parallel=GREEN,
    174                current_cross=YELLOW,
    175                timer_done=False,
    176            ),
    177            (RED, RED)
    178        )
    179        self.assertEqual(
    180            src.traffic_light.control(
    181                red_phase='BOOM',
    182                current_parallel=YELLOW,
    183                current_cross=GREEN,
    184                timer_done=False,
    185            ),
    186            (RED, RED)
    187        )
    188
    189
    190# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: Tuples differ: ('YELLOW', 'GREEN') != ('RED', 'RED')
    
  • I add an if statement for if the parallel lights are YELLOW AND the cross lights are GREEN, in src/traffic_light/__init__.py

    21    if current_parallel == current_cross == green:
    22        return red, red
    23    if current_parallel == green and current_cross == yellow:
    24        return red, red
    25    if current_parallel == yellow and current_cross == green:
    26        return red, red
    27
    28    if not timer_done:
    

    the test passes.

    control(
        current_parallel='RED', current_cross='POW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='BAP', current_cross='RED',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='GREEN', current_cross='GREEN',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='GREEN', current_cross='YELLOW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='YELLOW', current_cross='GREEN',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    
  • I add an assertion to test_failsafe for if both lights are YELLOW, in tests/test_traffic_light.py

    179        self.assertEqual(
    180            src.traffic_light.control(
    181                red_phase='BOOM',
    182                current_parallel=YELLOW,
    183                current_cross=GREEN,
    184                timer_done=False,
    185            ),
    186            (RED, RED)
    187        )
    188        self.assertEqual(
    189            src.traffic_light.control(
    190                red_phase='BOOM',
    191                current_parallel=YELLOW,
    192                current_cross=YELLOW,
    193                timer_done=False,
    194            ),
    195            (RED, RED)
    196        )
    197
    198
    199# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: Tuples differ: ('YELLOW', 'YELLOW') != ('RED', 'RED')
    
  • I add an if statement for if both lights are YELLOW, in src/traffic_light/__init__.py

    21    if current_parallel == current_cross == green:
    22        return red, red
    23    if current_parallel == green and current_cross == yellow:
    24        return red, red
    25    if current_parallel == yellow and current_cross == green:
    26        return red, red
    27    if current_parallel == current_cross == yellow:
    28        return red, red
    29
    30    if not timer_done:
    

    the test passes.

    control(
        current_parallel='RED', current_cross='POW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='BAP', current_cross='RED',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='GREEN', current_cross='GREEN',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='GREEN', current_cross='YELLOW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='YELLOW', current_cross='GREEN',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    control(
        current_parallel='YELLOW', current_cross='YELLOW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    

  • I add an if statement for if the parallel lights and cross lights are the same AND are not equal to RED

    21    # if current_parallel == current_cross == green:
    22    if current_parallel == current_cross != red:
    23        return red, red
    24    if current_parallel == green and current_cross == yellow:
    25        return red, red
    26    if current_parallel == yellow and current_cross == green:
    27        return red, red
    28    # if current_parallel == current_cross == yellow:
    29    #     return red, red
    30
    31    if not timer_done:
    

    the tests are still green.

  • I remove the commented lines

    14    if not (
    15        current_cross == green
    16        or current_cross == yellow
    17        or current_cross == red
    18    ):
    19        return red, red
    20
    21    if current_parallel == current_cross != red:
    22        return red, red
    23    if current_parallel == green and current_cross == yellow:
    24        return red, red
    25    if current_parallel == yellow and current_cross == green:
    26        return red, red
    27
    28    if not timer_done:
    
  • I add a return statement with the safety state as what the control function returns by default

    39        if red_phase == 'parallel':
    40            if current_cross == green:
    41                return red, yellow
    42            if current_cross == yellow:
    43                return red, red
    44            if current_cross == red:
    45                return green, red
    46
    47    return red, red
    

    still green.

  • I remove if current_cross == yellow: from if red_phase == 'parallel': since it returns the safety state

    39        if red_phase == 'parallel':
    40            if current_cross == green:
    41                return red, yellow
    42            if current_cross == red:
    43                return green, red
    44
    45    return red, red
    

    green.

  • I remove if current_parallel == yellow: from if red_phase == 'cross': since it returns the safety state

    31    if timer_done:
    32        if red_phase == 'cross':
    33            if current_parallel == green:
    34                return yellow, red
    35            if current_parallel == red:
    36                return red, green
    37        if red_phase == 'parallel':
    

    still green.

  • I add a git commit message in the other terminal

    git commit -am 'add test_failsafe'
    

extract is_not_safe function

  • I add a function to check for when both lights allow traffic at the same time

     1def is_not_safe(parallel, cross):
     2    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
     3    if parallel == cross != red:
     4        return True
     5    if parallel == green and cross == yellow:
     6        return True
     7    if parallel == yellow and cross == green:
     8        return True
     9
    10
    11def control(
    12        timer_done, red_phase='parallel',
    13        current_parallel='RED', current_cross='RED',
    14    ):
    15    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    
  • I add a call to the is_not_safe function for the if statements that check if the lights allow traffic both ways

    15    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    16
    17    if not (
    18        current_parallel == green
    19        or current_parallel == yellow
    20        or current_parallel == red
    21    ):
    22        return red, red
    23
    24    if not (
    25        current_cross == green
    26        or current_cross == yellow
    27        or current_cross == red
    28    ):
    29        return red, red
    30
    31    if is_not_safe(current_parallel, current_cross):
    32        return red, red
    33    if current_parallel == current_cross != red:
    34    # if current_parallel == current_cross != red:
    35    #     return red, red
    36    # if current_parallel == green and current_cross == yellow:
    37    #     return red, red
    38    # if current_parallel == yellow and current_cross == green:
    39    #     return red, red
    40
    41    if not timer_done:
    

    the tests are still green.

  • I remove the other if statements for the if statements that check if the lights allow traffic both ways, because they are no longer needed.

    31    if is_not_safe(current_parallel, current_cross):
    32        return red, red
    33
    34    if not timer_done:
    35        return current_parallel, current_cross
    
  • I write a conditional expression for the if statements in the is_not_safe function

     1def is_not_safe(parallel, cross):
     2    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
     3    return (
     4        (parallel == cross != red)
     5        or (parallel == green and cross == yellow)
     6        or (parallel == yellow and cross == green)
     7    )
     8    if parallel == cross != red:
     9        return True
    10    if parallel == green and cross == yellow:
    11        return True
    12    if parallel == yellow and cross == green:
    13        return True
    14
    15
    16
    17def control(
    18        timer_done, red_phase='parallel',
    19        current_parallel='RED', current_cross='RED',
    20    ):
    

    still green.

  • I remove the other if statements because they are no longer used

     1def is_not_safe(parallel, cross):
     2    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
     3    return (
     4        (parallel == cross != red)
     5        or (parallel == green and cross == yellow)
     6        or (parallel == yellow and cross == green)
     7    )
     8
     9
    10
    11def control(
    12        timer_done, red_phase='parallel',
    13        current_parallel='RED', current_cross='RED',
    14    ):
    
  • I add a git commit message in the other terminal

    git commit -am 'extract is_not_safe function'
    

extract is_not_light function


  • I add a function to check if the value of a light is GREEN or YELLOW or RED

     1def is_not_safe(parallel, cross):
     2    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
     3    return (
     4        (parallel == cross != red)
     5        or (parallel == green and cross == yellow)
     6        or (parallel == yellow and cross == green)
     7    )
     8
     9
    10def is_not_light(light):
    11    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    12    if not (
    13        light == green or light == yellow or light == red
    14    ):
    15        return True
    16
    17
    18def control(
    19        timer_done, red_phase='parallel',
    20        current_parallel='RED', current_cross='RED',
    21    ):
    
  • I add a call to the is_not_light function for the if statements that check if current_parallel is GREEN or YELLOW or RED

    18def control(
    19        timer_done, red_phase='parallel',
    20        current_parallel='RED', current_cross='RED',
    21    ):
    22    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    23
    24    if is_not_light(current_parallel):
    25        return red, red
    26    # if not (
    27    #     current_parallel == green
    28    #     or current_parallel == yellow
    29    #     or current_parallel == red
    30    # ):
    31    #     return red, red
    

    green.

  • I add a call to the is_not_light function for the if statements that check if current_cross is GREEN or YELLOW or RED

    31    #     return red, red
    32
    33    if is_not_light(current_cross):
    34        return red, red
    35    # if not (
    36    #     current_cross == green
    37    #     or current_cross == yellow
    38    #     or current_cross == red
    39    # ):
    40    #     return red, red
    41
    42    if is_not_safe(current_parallel, current_cross):
    

    green.

  • I remove the commented lines from the control function

    18def control(
    19        timer_done, red_phase='parallel',
    20        current_parallel='RED', current_cross='RED',
    21    ):
    22    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    23
    24    if is_not_light(current_parallel):
    25        return red, red
    26    if is_not_light(current_cross):
    27        return red, red
    28    if is_not_safe(current_parallel, current_cross):
    29        return red, red
    30
    31    if not timer_done:
    32        return current_parallel, current_cross
    33
    34    if timer_done:
    35        if red_phase == 'cross':
    36            if current_parallel == green:
    37                return yellow, red
    38            if current_parallel == red:
    39                return red, green
    40        if red_phase == 'parallel':
    41            if current_cross == green:
    42                return red, yellow
    43            if current_cross == red:
    44                return green, red
    45
    46    return red, red
    
  • I add a conditional expression to the is_not_light function

    10def is_not_light(light):
    11    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    12    return not (
    13        light == green or light == yellow or light == red
    14    )
    15    if not (
    16        light == green or light == yellow or light == red
    17    ):
    18        return True
    

    still green.

  • I remove the if statement from the is_not_light function

    10def is_not_light(light):
    11    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    12    return not (
    13        light == green or light == yellow or light == red
    14    )
    15
    16
    17def control(
    18        timer_done, red_phase='parallel',
    19        current_parallel='RED', current_cross='RED',
    20    ):
    21    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    
  • I add a git commit message in the other terminal

    git commit -am 'extract is_not_light function'
    

extract triggers_failsafe function

  • I add a function for the three Functions which trigger the fail safe

    10def is_not_light(light):
    11    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    12    return not (
    13        light == green or light == yellow or light == red
    14    )
    15
    16
    17def triggers_failsafe(parallel, cross):
    18    return (
    19        is_not_light(parallel) or is_not_light(cross)
    20        or is_not_safe(parallel, cross)
    21    )
    22
    23
    24def control(
    25        timer_done, red_phase='parallel',
    26        current_parallel='RED', current_cross='RED',
    27    ):
    
  • I add a call to the triggers_failsafe function from the control function

    24def control(
    25        timer_done, red_phase='parallel',
    26        current_parallel='RED', current_cross='RED',
    27    ):
    28    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    29
    30    if triggers_failsafe(current_parallel, current_cross):
    31        return red, red
    32    # if is_not_light(current_parallel):
    33    #     return red, red
    34    # if is_not_light(current_cross):
    35    #     return red, red
    36    # if is_not_safe(current_parallel, current_cross):
    37    #     return red, red
    38
    39    if not timer_done:
    

    the tests are still green.

  • I remove the commented lines from the control function

    24def control(
    25        timer_done, red_phase='parallel',
    26        current_parallel='RED', current_cross='RED',
    27    ):
    28    red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    29
    30    if triggers_failsafe(current_parallel, current_cross):
    31        return red, red
    32
    33    if not timer_done:
    34        return current_parallel, current_cross
    
  • I add a git commit message in the other terminal

    git commit -am 'extract triggers_failsafe function'
    

extract global variables for lights

  • I add global variables for GREEN, YELLOW and RED

    1GREEN, YELLOW, RED = 'GREEN', 'YELLOW', 'RED'
    2
    3
    4def is_not_safe(parallel, cross):
    
  • I use the variables for GREEN, YELLOW and RED in the is_not_safe function

     4def is_not_safe(parallel, cross):
     5    # red, yellow, green = 'RED', 'YELLOW', 'GREEN'
     6    return (
     7        # (parallel == cross != red)
     8        (parallel == cross != RED)
     9        # or (parallel == green and cross == yellow)
    10        or (parallel == GREEN and cross == YELLOW)
    11        # or (parallel == yellow and cross == green)
    12        or (parallel == YELLOW and cross == GREEN)
    13    )
    

    still green.

  • I remove the commented lines from the is_not_safe function

     4def is_not_safe(parallel, cross):
     5    return (
     6        (parallel == cross != RED)
     7        or (parallel == GREEN and cross == YELLOW)
     8        or (parallel == YELLOW and cross == GREEN)
     9    )
    10
    11
    12def is_not_light(light):
    
  • I use the variables for GREEN, YELLOW and RED in the is_not_light function

    12def is_not_light(light):
    13    # red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    14    return not (
    15        # light == green or light == yellow or light == red
    16        light == GREEN or light == YELLOW or light == RED
    17    )
    18
    19
    20def triggers_failsafe(parallel, cross):
    

    green.

  • I remove the commented lines from the is_not_light function

    12def is_not_light(light):
    13    return not (
    14        light == GREEN or light == YELLOW or light == RED
    15    )
    16
    17
    18def triggers_failsafe(parallel, cross):
    
  • I use the variables for GREEN, YELLOW and RED in the control function

    25def control(
    26        timer_done, red_phase='parallel',
    27        # current_parallel='RED', current_cross='RED',
    28        current_parallel=RED, current_cross=RED,
    29    ):
    30    # red, yellow, green = 'RED', 'YELLOW', 'GREEN'
    31
    32    if triggers_failsafe(current_parallel, current_cross):
    33        # return red, red
    34        return RED, RED
    35
    36    if not timer_done:
    37        return current_parallel, current_cross
    38
    39    if timer_done:
    
    39    if timer_done:
    40        if red_phase == 'cross':
    41            # if current_parallel == green:
    42            if current_parallel == GREEN:
    43                # return yellow, red
    44                return YELLOW, RED
    45            # if current_parallel == red:
    46            if current_parallel == RED:
    47                # return red, green
    48                return RED, GREEN
    49        if red_phase == 'parallel':
    50            # if current_cross == green:
    51            if current_cross == GREEN:
    52                # return red, yellow
    53                return RED, YELLOW
    54            # if current_cross == red:
    55            if current_cross == RED:
    56                # return green, red
    57                return GREEN, RED
    58
    59    # return red, red
    60    return RED, RED
    

    still green.

  • I remove the commented lines from the control function

    25def control(
    26        timer_done, red_phase='parallel',
    27        current_parallel=RED, current_cross=RED,
    28    ):
    29    if triggers_failsafe(current_parallel, current_cross):
    30        return RED, RED
    31
    32    if not timer_done:
    33        return current_parallel, current_cross
    34
    35    if timer_done:
    36        if red_phase == 'cross':
    37            if current_parallel == GREEN:
    38                return YELLOW, RED
    39            if current_parallel == RED:
    40                return RED, GREEN
    41        if red_phase == 'parallel':
    42            if current_cross == GREEN:
    43                return RED, YELLOW
    44            if current_cross == RED:
    45                return GREEN, RED
    46
    47    return RED, RED
    
  • I add a git commit message in the other terminal

    git commit -am 'extract global variables for lights'
    

extract next_light function

  • I add a function for when the timer is done and none of the fail safes are triggered

    18def triggers_failsafe(parallel, cross):
    19    return (
    20        is_not_light(parallel) or is_not_light(cross)
    21        or is_not_safe(parallel, cross)
    22    )
    23
    24
    25def next_light(red_phase, parallel, cross):
    26    if red_phase == 'cross':
    27        if parallel == GREEN:
    28            return YELLOW, RED
    29        if parallel == RED:
    30            return RED, GREEN
    31    if red_phase == 'parallel':
    32        if cross == GREEN:
    33            return RED, YELLOW
    34        if cross == RED:
    35            return GREEN, RED
    36    return RED, RED
    37
    38
    39def control(
    40        timer_done, red_phase='parallel',
    41        current_parallel=RED, current_cross=RED,
    42    ):
    
  • I add a call to the next_light function from if timer_done: in the control function

    39def control(
    40        timer_done, red_phase='parallel',
    41        current_parallel=RED, current_cross=RED,
    42    ):
    43    if triggers_failsafe(current_parallel, current_cross):
    44        return RED, RED
    45
    46    if not timer_done:
    47        return current_parallel, current_cross
    48
    49    if timer_done:
    50        return next_light(
    51            red_phase, current_parallel, current_cross
    52        )
    53        if red_phase == 'cross':
    

    the tests are still green.

  • I remove the other statements in the control function

    39def control(
    40        timer_done, red_phase='parallel',
    41        current_parallel=RED, current_cross=RED,
    42    ):
    43    if triggers_failsafe(current_parallel, current_cross):
    44        return RED, RED
    45
    46    if not timer_done:
    47        return current_parallel, current_cross
    48
    49    if timer_done:
    50        return next_light(
    51            red_phase, current_parallel, current_cross
    52        )
    53
    54    return RED, RED
    
  • I add a git commit message in the other terminal

    git commit -am 'extract next_light function'
    

When the control function is called it calls the triggers_failsafe function to check if the values of current_parallel or current_cross trigger the failsafe. The triggers_failsafe function calls the is_not_light function or is_not_safe function to check the values of current_parallel and current_cross

  • If the failsafe is triggered, it turns the parallel and cross lights RED

    control(
        current_parallel='RED', current_cross='POW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel=RED, current_cross=RED,
            ):
            └── if triggers_failsafe(current_parallel, current_cross):
                ├── def triggers_failsafe(parallel, cross):
                   └── return (
                          is_not_light(parallel)
                       └── or is_not_light(cross)
                           or is_not_safe(parallel, cross)
                       )
                       └── def is_not_light(light):
                           └── return not (
                                   light == GREEN or light == YELLOW
                                   or light == RED
                               )
                               return True
                └── return RED, RED
                if not timer_done:
    
    control(
        current_parallel='BAP', current_cross='RED',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel=RED, current_cross=RED,
            ):
            └── if triggers_failsafe(current_parallel, current_cross):
                ├── def triggers_failsafe(parallel, cross):
                   └── return (
                       └── is_not_light(parallel)
                           or is_not_light(cross)
                           or is_not_safe(parallel, cross)
                       )
                       └── def is_not_light(light):
                           └── return not (
                                   light == GREEN or light == YELLOW
                                   or light == RED
                               )
                               return True
                └── return RED, RED
                if not timer_done:
    
    control(
        current_parallel='GREEN', current_cross='GREEN',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel=RED, current_cross=RED,
            ):
            └── if triggers_failsafe(current_parallel, current_cross):
                ├── def triggers_failsafe(parallel, cross):
                   └── return (
                          is_not_light(parallel) or is_not_light(cross)
                       └── or is_not_safe(parallel, cross)
                       )
                       └── def is_not_safe(parallel, cross):
                           └── return (
                               └── (parallel == cross != RED)
                                   or (parallel == GREEN and cross == YELLOW)
                                   or (parallel == YELLOW and cross == GREEN)
                               )
                               return True
                └── return RED, RED
                if not timer_done:
    
    control(
        current_parallel='GREEN', current_cross='YELLOW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel=RED, current_cross=RED,
            ):
            └── if triggers_failsafe(current_parallel, current_cross):
                ├── def triggers_failsafe(parallel, cross):
                   └── return (
                          is_not_light(parallel) or is_not_light(cross)
                       └── or is_not_safe(parallel, cross)
                       )
                       └── def is_not_safe(parallel, cross):
                           └── return (
                                  (parallel == cross != RED)
                               └── or (parallel == GREEN and cross == YELLOW)
                                   or (parallel == YELLOW and cross == GREEN)
                               )
                               return True
                └── return RED, RED
                if not timer_done:
    
    control(
        current_parallel='YELLOW', current_cross='GREEN',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel=RED, current_cross=RED,
            ):
            └── if triggers_failsafe(current_parallel, current_cross):
                ├── def triggers_failsafe(parallel, cross):
                   └── return (
                          is_not_light(parallel) or is_not_light(cross)
                       └── or is_not_safe(parallel, cross)
                       )
                       └── def is_not_safe(parallel, cross):
                           └── return (
                                  (parallel == cross != RED)
                                  or (parallel == GREEN and cross == YELLOW)
                               └── or (parallel == YELLOW and cross == GREEN)
                               )
                               return True
                └── return RED, RED
                if not timer_done:
    
    control(
        current_parallel='YELLOW', current_cross='YELLOW',
        timer_done=False, red_phase='BOOM'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel=RED, current_cross=RED,
            ):
            └── if triggers_failsafe(current_parallel, current_cross):
                ├── def triggers_failsafe(parallel, cross):
                   └── return (
                          is_not_light(parallel) or is_not_light(cross)
                       └── or is_not_safe(parallel, cross)
                       )
                       └── def is_not_safe(parallel, cross):
                           └── return (
                               └── (parallel == cross != RED)
                                   or (parallel == GREEN and cross == YELLOW)
                                   or (parallel == YELLOW and cross == GREEN)
                               )
                               return True
                └── return RED, RED
                if not timer_done:
    

    If the failsafe is NOT triggered, it checks if the timer is NOT done

  • If the timer is NOT done, it returns the values of current_parallel and current_cross, which means it does not change the parallel or cross lights, it keeps them the same

    control(
        current_parallel='RED', current_cross='GREEN',
        timer_done=False, red_phase='parallel'
    ) -> 'RED', 'GREEN'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel=RED, current_cross=RED,
            ):
            ├── if triggers_failsafe(current_parallel, current_cross):
                   return RED, RED
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'RED'           , 'GREEN'
                if timer_done:
    
    control(
        current_parallel='RED', current_cross='YELLOW',
        timer_done=False, red_phase='parallel'
    ) -> 'RED', 'YELLOW'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── if triggers_failsafe(current_parallel, current_cross):
                   return RED, RED
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'RED'           , 'YELLOW'
                if timer_done:
    
    control(
        current_parallel='RED', current_cross='RED',
        timer_done=False, red_phase='parallel'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── if triggers_failsafe(current_parallel, current_cross):
                   return RED, RED
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'RED'           , 'RED'
                if timer_done:
    
    control(
        current_parallel='GREEN', current_cross='RED',
        timer_done=False, red_phase='cross'
    ) -> 'GREEN', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── if triggers_failsafe(current_parallel, current_cross):
                   return RED, RED
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'GREEN'         , 'RED'
                if timer_done:
    
    control(
        current_parallel='YELLOW', current_cross='RED',
        timer_done=False, red_phase='cross'
    ) -> 'YELLOW', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── if triggers_failsafe(current_parallel, current_cross):
                   return RED, RED
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'YELLOW'        , 'RED'
                if timer_done:
    
    control(
        current_parallel='RED', current_cross='RED',
        timer_done=False, red_phase='cross'
    ) -> 'RED', 'RED'
    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── if triggers_failsafe(current_parallel, current_cross):
                   return RED, RED
            └── if not timer_done:
                └── return current_parallel, current_cross
                    return 'RED'           , 'RED'
                if timer_done:
    
  • If the timer is done, it calls the next_light function which checks if cross traffic is in the RED phase

    • If cross traffic is in the RED phase, it checks the value of current_parallel

      • If the current parallel light is GREEN, it returns YELLOW, RED, which means the next parallel light will be YELLOW and the cross light will remain RED because it is still in the RED phase

        control(
            current_parallel='GREEN', current_cross='RED',
            timer_done=True, red_phase='cross'
        ) -> 'YELLOW', 'RED'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── if triggers_failsafe(current_parallel, current_cross):
                       return RED, RED
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    └── return next_light(
                            red_phase, current_parallel, current_cross
                        )
                        └── def next_light(red_phase, parallel, cross):
                            └── if red_phase == 'cross':
                                └── if parallel == GREEN:
                                    └── return YELLOW, RED
                                    if parallel == RED:
        
      • If the current parallel light is RED, it returns RED, GREEN, which means the parallel light will stay RED since it is now in the RED phase and the next cross light will be GREEN

        control(
            current_parallel='RED', current_cross='RED',
            timer_done=True, red_phase='cross'
        ) -> 'RED', 'GREEN'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── if triggers_failsafe(current_parallel, current_cross):
                       return RED, RED
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    └── return next_light(
                            red_phase, current_parallel, current_cross
                        )
                        └── def next_light(red_phase, parallel, cross):
                            └── if red_phase == 'cross':
                                ├── if parallel == GREEN:
                                       return YELLOW, RED
                                └── if parallel == RED:
                                    └── return RED, GREEN
                                if red_phase == 'parallel':
        
      • If cross traffic is not in the RED phase, it checks if parallel traffic is in the RED phase

    • If parallel traffic is in the RED phase, it checks the value of current_cross

      • If the current cross light is GREEN, it returns RED, YELLOW, which means the parallel light will remain RED because it is still in the RED phase and the next cross light will be YELLOW

        control(
            current_parallel='RED', current_cross='GREEN',
            timer_done=True, red_phase='parallel'
        ) -> 'RED', 'YELLOW'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── if triggers_failsafe(current_parallel, current_cross):
                       return RED, RED
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    └── return next_light(
                            red_phase, current_parallel, current_cross
                        )
                        └── def next_light(red_phase, parallel, cross):
                            ├── if red_phase == 'cross':
                                   ...
                            └── if red_phase == 'parallel':
                                └── if cross == GREEN:
                                    └── return RED, YELLOW
                                    if cross == RED:
        
      • If the current cross light is RED, it returns GREEN, RED, which means the next parallel light will be GREEN and the cross light will stay RED since it is now in the RED phase

        control(
            current_parallel='RED', current_cross='RED',
            timer_done=True, red_phase='parallel'
        ) -> 'GREEN', 'RED'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── if triggers_failsafe(current_parallel, current_cross):
                       return RED, RED
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    └── return next_light(
                            red_phase, current_parallel, current_cross
                        )
                        └── def next_light(red_phase, parallel, cross):
                            ├── if red_phase == 'cross':
                                   ...
                            └── if red_phase == 'parallel':
                                ├── if cross == GREEN:
                                       return RED, YELLOW
                                └── if cross == RED:
                                    └── return GREEN, RED
                                return RED, RED
        
      • If none of the above conditions are met, it returns RED, RED, which means there will be no traffic in the intersection, the parallel and cross lights will both be RED

        control(
            current_parallel='YELLOW', current_cross='RED',
            timer_done=True, red_phase='cross'
        ) -> 'RED', 'RED'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── if triggers_failsafe(current_parallel, current_cross):
                       return RED, RED
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    └── return next_light(
                            red_phase, current_parallel, current_cross
                        )
                        └── def next_light(red_phase, parallel, cross):
                            └── if red_phase == 'cross':
                                ├── if parallel == GREEN:
                                       return YELLOW, RED
                            ┌───┴── if parallel == RED:
                                       return RED, GREEN
                               if red_phase == 'parallel':
                                   if cross == GREEN:
                                       return RED, YELLOW
                                   if cross == RED:
                                       return GREEN, RED
                            └── return RED, RED
        
        control(
            current_parallel='RED', current_cross='YELLOW',
            timer_done=True, red_phase='parallel'
        ) -> 'RED', 'RED'
        └── def control(
                    timer_done, red_phase='parallel',
                    current_parallel='RED', current_cross='RED',
                ):
                ├── if triggers_failsafe(current_parallel, current_cross):
                       return RED, RED
                ├── if not timer_done:
                       return current_parallel, current_cross
                └── if timer_done:
                    └── return next_light(
                            red_phase, current_parallel, current_cross
                        )
                        └── def next_light(red_phase, parallel, cross):
                            ├── if red_phase == 'cross':
                                   if parallel == GREEN:
                                       return YELLOW, RED
                                   if parallel == RED:
                                       return RED, GREEN
                            └── if red_phase == 'parallel':
                                ├── if cross == GREEN:
                                       return RED, YELLOW
                            ┌───┴── if cross == RED:
                                       return GREEN, RED
                            └── return RED, RED
        
  • If none of the above conditions are met, it returns RED, RED, which means there will be no traffic in the intersection, the parallel and cross lights will both be RED

    └── def control(
                timer_done, red_phase='parallel',
                current_parallel='RED', current_cross='RED',
            ):
            ├── if triggers_failsafe(current_parallel, current_cross):
                   return RED, RED
            ├── if not timer_done:
                   return current_parallel, current_cross
            ├── if timer_done:
                   return next_light(
                       red_phase, current_parallel, current_cross
                    )
            └── return RED, RED
    

close the project

  • I close tests/test_traffic_light.py and src/traffic_light/__init__.py

  • I click in the terminal where the tests are running

  • I use q on the keyboard to leave the tests. The terminal shows

    .../pumping_python
    

    I am back in the pumping_python directory.


review

I ran tests for a Traffic Light that changes lights based on what RED phase the traffic is in ('cross' or 'parallel') AND if a timer is done or NOT done

The outputs are the next lights for Parallel and Cross Traffic which gave me this truth table

red

current

current

next

next

phase

parallel

cross

timer

parallel

cross

‘cross’

GREEN

RED

NOT done

GREEN

RED

‘cross’

GREEN

RED

done

YELLOW

RED

‘cross’

YELLOW

RED

NOT done

YELLOW

RED

‘cross’

YELLOW

RED

done

safety RED

safety RED

‘cross’

RED

RED

NOT done

safety RED

safety RED

‘cross’

RED

RED

done

RED

GREEN

red

current

current

next

next

phase

parallel

cross

timer

parallel

cross

‘parallel’

RED

GREEN

NOT done

RED

GREEN

‘parallel’

RED

GREEN

done

RED

YELLOW

‘parallel’

RED

YELLOW

NOT done

RED

YELLOW

‘parallel’

RED

YELLOW

done

safety RED

safety RED

‘parallel’

RED

RED

NOT done

safety RED

safety RED

‘parallel’

RED

RED

done

GREEN

RED

It also makes sure that there is never a case where cars move through the intersection at the same time to avoid accidents.

What if the Traffic Light has a walk button and I push it? What if the Traffic Light changes based on if there is an emergency vehicle? What would the inputs be and what truth table do I get?


code from the chapter

Do you want to see all the CODE I typed in this chapter?


what is next?

I changed the name of the project in a few places every time I ran makePythonTdd, that is too many steps. Would you like to see a better way to make a Python Test Driven Development environment automatically?


rate pumping python

If this has been a 7 star experience for you, please CLICK HERE to leave a 5 star review of pumping python. It helps other people get into the book too.